ustream-openssl: wolfSSL: fix certificate validation
authorPetr Štetiar <ynezz@true.cz>
Wed, 9 Dec 2020 16:51:18 +0000 (17:51 +0100)
committerPetr Štetiar <ynezz@true.cz>
Thu, 10 Dec 2020 11:24:34 +0000 (12:24 +0100)
Currently wolfSSL doesn't validate any certificates, quoting from
README:

 wolfSSL takes a different approach to certificate verification than
 OpenSSL does. The default policy for the client is to verify the server,
 this means that if you don't load CAs to verify the server you'll get a
 connect error, no signer error to confirm failure (-188).

 If you want to mimic OpenSSL behavior of having SSL_connect succeed even if
 verifying the server fails and reducing security you can do this by calling:

  wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);

 before calling wolfSSL_new();. Though it's not recommended.

wolfSSL simply behaves differently then OpenSSL so once you set
SSL_VERIFY_NONE wolfSSL doesn't care about the certificates anymore so
every call to SSL_get_verify_result() is going to succeed (returns
X509_V_OK) even for invalid certificates and current OpenSSL based post
connection verification logic thus doesn't work.

So in order to get the validation working we need to use SSL_VERIFY_PEER
for wolfSSL by default and allow disabling it explicitly by new
`context_set_require_validation()` call. In order to keep the same error
handling/messages via `notify_verify_error()` callback we as well need
to handle certificate errors manually.

Fixes: FS#3465
Signed-off-by: Petr Štetiar <ynezz@true.cz>
ustream-internal.h
ustream-openssl.c
ustream-ssl.c
ustream-ssl.h

index 147141ab5f05930fb4298c01b05c2c1230d3d139..e80abf827515fde4d2c7dea0605a0ddae85e5b6e 100644 (file)
@@ -39,6 +39,7 @@ int __ustream_ssl_add_ca_crt_file(struct ustream_ssl_ctx *ctx, const char *file)
 int __ustream_ssl_set_crt_file(struct ustream_ssl_ctx *ctx, const char *file);
 int __ustream_ssl_set_key_file(struct ustream_ssl_ctx *ctx, const char *file);
 int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *ciphers);
+int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx *ctx, bool require);
 void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx);
 enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us);
 int __ustream_ssl_read(struct ustream_ssl *us, char *buf, int len);
index ad77e721534c7dafa12c6060c7c687392b2477cc..9b4ac6c8089449e63ded2cd1410c1cfef15616a7 100644 (file)
@@ -130,7 +130,15 @@ __ustream_ssl_context_new(bool server)
        if (!c)
                return NULL;
 
+#if defined(HAVE_WOLFSSL)
+       if (server)
+               SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
+       else
+               SSL_CTX_set_verify(c, SSL_VERIFY_PEER, NULL);
+#else
        SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
+#endif
+
        SSL_CTX_set_options(c, SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_ECDH_USE |
                               SSL_OP_CIPHER_SERVER_PREFERENCE);
 #if defined(SSL_CTX_set_ecdh_auto) && OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -203,6 +211,18 @@ __hidden int __ustream_ssl_set_ciphers(struct ustream_ssl_ctx *ctx, const char *
        return 0;
 }
 
+__hidden int __ustream_ssl_set_require_validation(struct ustream_ssl_ctx *ctx, bool require)
+{
+       int mode = SSL_VERIFY_PEER;
+
+       if (!require)
+               mode = SSL_VERIFY_NONE;
+
+       SSL_CTX_set_verify((void *) ctx, mode, NULL);
+
+       return 0;
+}
+
 __hidden void __ustream_ssl_context_free(struct ustream_ssl_ctx *ctx)
 {
        SSL_CTX_free((void *) ctx);
@@ -270,6 +290,54 @@ static void ustream_ssl_verify_cert(struct ustream_ssl *us)
        X509_free(cert);
 }
 
+#ifdef WOLFSSL_SSL_H
+static bool handle_wolfssl_asn_error(struct ustream_ssl *us, int r)
+{
+       switch (r) {
+       case ASN_PARSE_E:
+       case ASN_VERSION_E:
+       case ASN_GETINT_E:
+       case ASN_RSA_KEY_E:
+       case ASN_OBJECT_ID_E:
+       case ASN_TAG_NULL_E:
+       case ASN_EXPECT_0_E:
+       case ASN_BITSTR_E:
+       case ASN_UNKNOWN_OID_E:
+       case ASN_DATE_SZ_E:
+       case ASN_BEFORE_DATE_E:
+       case ASN_AFTER_DATE_E:
+       case ASN_SIG_OID_E:
+       case ASN_TIME_E:
+       case ASN_INPUT_E:
+       case ASN_SIG_CONFIRM_E:
+       case ASN_SIG_HASH_E:
+       case ASN_SIG_KEY_E:
+       case ASN_DH_KEY_E:
+       case ASN_NTRU_KEY_E:
+       case ASN_CRIT_EXT_E:
+       case ASN_ALT_NAME_E:
+       case ASN_NO_PEM_HEADER:
+       case ASN_ECC_KEY_E:
+       case ASN_NO_SIGNER_E:
+       case ASN_CRL_CONFIRM_E:
+       case ASN_CRL_NO_SIGNER_E:
+       case ASN_OCSP_CONFIRM_E:
+       case ASN_NAME_INVALID_E:
+       case ASN_NO_SKID:
+       case ASN_NO_AKID:
+       case ASN_NO_KEYUSAGE:
+       case ASN_COUNTRY_SIZE_E:
+       case ASN_PATHLEN_SIZE_E:
+       case ASN_PATHLEN_INV_E:
+       case ASN_SELF_SIGNED_E:
+               if (us->notify_verify_error)
+                       us->notify_verify_error(us, r, wc_GetErrorString(r));
+               return true;
+       }
+
+       return false;
+}
+#endif
 
 __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us)
 {
@@ -292,6 +360,11 @@ __hidden enum ssl_conn_status __ustream_ssl_connect(struct ustream_ssl *us)
        if (r == SSL_ERROR_WANT_READ || r == SSL_ERROR_WANT_WRITE)
                return U_SSL_PENDING;
 
+#ifdef WOLFSSL_SSL_H
+       if (handle_wolfssl_asn_error(us, r))
+               return U_SSL_OK;
+#endif
+
        ustream_ssl_error(us, r);
        return U_SSL_ERROR;
 }
index dbc3bee00e27af3f0815236857ef2823fb266fb5..46ac5523d999ab3b53830248f89ccc3d15b537f8 100644 (file)
@@ -232,6 +232,7 @@ const struct ustream_ssl_ops ustream_ssl_ops = {
        .context_set_key_file = __ustream_ssl_set_key_file,
        .context_add_ca_crt_file = __ustream_ssl_add_ca_crt_file,
        .context_set_ciphers = __ustream_ssl_set_ciphers,
+       .context_set_require_validation = __ustream_ssl_set_require_validation,
        .context_free = __ustream_ssl_context_free,
        .init = _ustream_ssl_init,
        .set_peer_cn = _ustream_ssl_set_peer_cn,
index db89297604a9c7da5581e81ca945b5eccbaf1441..87c0ae6da59564d03acbb030335a8a6326c58616 100644 (file)
@@ -42,6 +42,7 @@ struct ustream_ssl {
 
        bool valid_cert;
        bool valid_cn;
+       bool require_validation;
 };
 
 struct ustream_ssl_ctx;
@@ -58,17 +59,19 @@ struct ustream_ssl_ops {
        int (*set_peer_cn)(struct ustream_ssl *conn, const char *name);
 
        int (*context_set_ciphers)(struct ustream_ssl_ctx *ctx, const char *ciphers);
+       int (*context_set_require_validation)(struct ustream_ssl_ctx *ctx, bool require);
 };
 
 extern const struct ustream_ssl_ops ustream_ssl_ops;
 
-#define ustream_ssl_context_new                        ustream_ssl_ops.context_new
-#define ustream_ssl_context_set_crt_file       ustream_ssl_ops.context_set_crt_file
-#define ustream_ssl_context_set_key_file       ustream_ssl_ops.context_set_key_file
-#define ustream_ssl_context_add_ca_crt_file    ustream_ssl_ops.context_add_ca_crt_file
-#define ustream_ssl_context_set_ciphers                ustream_ssl_ops.context_set_ciphers
-#define ustream_ssl_context_free               ustream_ssl_ops.context_free
-#define ustream_ssl_init                       ustream_ssl_ops.init
-#define ustream_ssl_set_peer_cn                        ustream_ssl_ops.set_peer_cn
+#define ustream_ssl_context_new                                ustream_ssl_ops.context_new
+#define ustream_ssl_context_set_crt_file               ustream_ssl_ops.context_set_crt_file
+#define ustream_ssl_context_set_key_file               ustream_ssl_ops.context_set_key_file
+#define ustream_ssl_context_add_ca_crt_file            ustream_ssl_ops.context_add_ca_crt_file
+#define ustream_ssl_context_set_ciphers                        ustream_ssl_ops.context_set_ciphers
+#define ustream_ssl_context_set_require_validation     ustream_ssl_ops.context_set_require_validation
+#define ustream_ssl_context_free                       ustream_ssl_ops.context_free
+#define ustream_ssl_init                               ustream_ssl_ops.init
+#define ustream_ssl_set_peer_cn                                ustream_ssl_ops.set_peer_cn
 
 #endif