summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Štetiar <ynezz@true.cz>2020-12-09 17:51:18 +0100
committerPetr Štetiar <ynezz@true.cz>2020-12-10 12:24:34 +0100
commitc6b4c48689a3e80a6fd26a66f8699a2d8aaece6d (patch)
tree7420ee9b4cbd91e87f6ec2970b8f03cfa39078c3
parent3bc05402bfabc711a335262cbb40664b6dfb1240 (diff)
downloadustream-ssl-c6b4c48689a3e80a6fd26a66f8699a2d8aaece6d.tar.gz
ustream-openssl: wolfSSL: fix certificate validation
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>
-rw-r--r--ustream-internal.h1
-rw-r--r--ustream-openssl.c73
-rw-r--r--ustream-ssl.c1
-rw-r--r--ustream-ssl.h19
4 files changed, 86 insertions, 8 deletions
diff --git a/ustream-internal.h b/ustream-internal.h
index 147141a..e80abf8 100644
--- a/ustream-internal.h
+++ b/ustream-internal.h
@@ -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);
diff --git a/ustream-openssl.c b/ustream-openssl.c
index ad77e72..9b4ac6c 100644
--- a/ustream-openssl.c
+++ b/ustream-openssl.c
@@ -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;
}
diff --git a/ustream-ssl.c b/ustream-ssl.c
index dbc3bee..46ac552 100644
--- a/ustream-ssl.c
+++ b/ustream-ssl.c
@@ -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,
diff --git a/ustream-ssl.h b/ustream-ssl.h
index db89297..87c0ae6 100644
--- a/ustream-ssl.h
+++ b/ustream-ssl.h
@@ -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