Browse Source

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>
Petr Štetiar 3 years ago
parent
commit
c6b4c48689
4 changed files with 86 additions and 8 deletions
  1. 1 0
      ustream-internal.h
  2. 73 0
      ustream-openssl.c
  3. 1 0
      ustream-ssl.c
  4. 11 8
      ustream-ssl.h

+ 1 - 0
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);

+ 73 - 0
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;
 }

+ 1 - 0
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,

+ 11 - 8
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