[PATCH] Android: Support multiple CA certs when connecting to EAP network

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From dd90559fa3bfa3d606b51f97a66afff2ab4758d2 Mon Sep 17 00:00:00 2001
From: Rubin Xu <rubinxu@xxxxxxxxxx>
Date: Tue, 10 Nov 2015 17:14:51 +0000
Subject: [PATCH] Android: Support multiple CA certs when connecting to EAP
 network

In the Android-specific case, Make ca_cert directive parse a space-separated
list of hex-encoded CA certificate aliases following the "keystores://" prefix.
Server certificate validation should succeed as long as the chain ends with
one of them.

Bug: 22547958
Change-Id: I9c98f06f8ddf94ea1332f7ac291a14b7f1d96406
Signed-off-by: Rubin Xu <rubinxu@xxxxxxxxxx>
---
src/crypto/tls_openssl.c | 98 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 76 insertions(+), 22 deletions(-)

diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index b16b519..087210d 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -105,6 +105,56 @@ static BIO * BIO_from_keystore(const char *key)
 	free(value);
 	return bio;
 }
+
+static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
+{
+	BIO *bio = BIO_from_keystore(key_alias);
+	STACK_OF(X509_INFO) *stack = NULL;
+	stack_index_t i;
+
+	if (bio) {
+		stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+		BIO_free(bio);
+	}
+	if (!stack) {
+ wpa_printf(MSG_WARNING, "TLS: failed to parse certificate: %s", key_alias);
+		return -1;
+	}
+
+	for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+		X509_INFO *info = sk_X509_INFO_value(stack, i);
+		if (info->x509) {
+			X509_STORE_add_cert(ctx,
+					    info->x509);
+		}
+		if (info->crl) {
+			X509_STORE_add_crl(ctx,
+					   info->crl);
+		}
+	}
+	sk_X509_INFO_pop_free(stack, X509_INFO_free);
+	return 0;
+}
+
+static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx, const char *encoded_key_alias)
+{
+	int rc = -1;
+	int len = os_strlen(encoded_key_alias);
+	if (len & 1) {
+		// Hex-encoded string should have an even number of characters.
+ wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s", encoded_key_alias);
+		return rc;
+	}
+	unsigned char* decoded_alias = malloc(len / 2 + 1);
+	if (decoded_alias) {
+		if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
+			decoded_alias[len / 2] = '\0';
+			rc = tls_add_ca_from_keystore(ctx, (char*) decoded_alias);
+		}
+		free(decoded_alias);
+	}
+	return rc;
+}
 #endif /* ANDROID */

 static int tls_openssl_ref_count = 0;
@@ -1989,32 +2039,36 @@ static int tls_connection_ca_cert(struct tls_data *data,
 	}

 #ifdef ANDROID
+	/* Single alias */
 	if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
-		BIO *bio = BIO_from_keystore(&ca_cert[11]);
-		STACK_OF(X509_INFO) *stack = NULL;
-		stack_index_t i;
-
-		if (bio) {
-			stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
-			BIO_free(bio);
-		}
-		if (!stack)
+		if (!tls_add_ca_from_keystore(ssl_ctx->cert_store, &ca_cert[11])) {
+			SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+			return 0;
+		} else {
 			return -1;
-
-		for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
-			X509_INFO *info = sk_X509_INFO_value(stack, i);
-			if (info->x509) {
-				X509_STORE_add_cert(ssl_ctx->cert_store,
-						    info->x509);
-			}
-			if (info->crl) {
-				X509_STORE_add_crl(ssl_ctx->cert_store,
-						   info->crl);
+		}
+	/* Multiple aliases separated by space */
+	} else if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
+		char *aliases = strdup(&ca_cert[12]);
+		const char *DELIMITER = " ";
+		int rc = 0;
+		char *savedptr;
+		char *alias = strtok_r(aliases, DELIMITER, &savedptr);
+		for(; alias; alias = strtok_r(NULL, DELIMITER, &savedptr)) {
+			if (tls_add_ca_from_keystore_encoded(ssl_ctx->cert_store, alias)) {
+				wpa_printf(MSG_WARNING, "OpenSSL: %s - fail to add ca_cert"
+				        " %s from keystore", __func__, alias);
+				rc = -1;
+				break;
 			}
 		}
-		sk_X509_INFO_pop_free(stack, X509_INFO_free);
-		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
-		return 0;
+		free(aliases);
+		if (!rc) {
+			SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+			return 0;
+		} else {
+			return -1;
+		}
 	}
 #endif /* ANDROID */

--
2.7.0.rc3.207.g0ac5344

>From dd90559fa3bfa3d606b51f97a66afff2ab4758d2 Mon Sep 17 00:00:00 2001
From: Rubin Xu <rubinxu@xxxxxxxxxx>
Date: Tue, 10 Nov 2015 17:14:51 +0000
Subject: [PATCH] Android: Support multiple CA certs when connecting to EAP
 network

In the Android-specific case, Make ca_cert directive parse a space-separated
list of hex-encoded CA certificate aliases following the "keystores://" prefix.
Server certificate validation should succeed as long as the chain ends with
one of them.

Bug: 22547958
Change-Id: I9c98f06f8ddf94ea1332f7ac291a14b7f1d96406
Signed-off-by: Rubin Xu <rubinxu@xxxxxxxxxx>
---
 src/crypto/tls_openssl.c | 98 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 76 insertions(+), 22 deletions(-)

diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index b16b519..087210d 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -105,6 +105,56 @@ static BIO * BIO_from_keystore(const char *key)
 	free(value);
 	return bio;
 }
+
+static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
+{
+	BIO *bio = BIO_from_keystore(key_alias);
+	STACK_OF(X509_INFO) *stack = NULL;
+	stack_index_t i;
+
+	if (bio) {
+		stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+		BIO_free(bio);
+	}
+	if (!stack) {
+		wpa_printf(MSG_WARNING, "TLS: failed to parse certificate: %s", key_alias);
+		return -1;
+	}
+
+	for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+		X509_INFO *info = sk_X509_INFO_value(stack, i);
+		if (info->x509) {
+			X509_STORE_add_cert(ctx,
+					    info->x509);
+		}
+		if (info->crl) {
+			X509_STORE_add_crl(ctx,
+					   info->crl);
+		}
+	}
+	sk_X509_INFO_pop_free(stack, X509_INFO_free);
+	return 0;
+}
+
+static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx, const char *encoded_key_alias)
+{
+	int rc = -1;
+	int len = os_strlen(encoded_key_alias);
+	if (len & 1) {
+		// Hex-encoded string should have an even number of characters.
+		wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s", encoded_key_alias);
+		return rc;
+	}
+	unsigned char* decoded_alias = malloc(len / 2 + 1);
+	if (decoded_alias) {
+		if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
+			decoded_alias[len / 2] = '\0';
+			rc = tls_add_ca_from_keystore(ctx, (char*) decoded_alias);
+		}
+		free(decoded_alias);
+	}
+	return rc;
+}
 #endif /* ANDROID */
 
 static int tls_openssl_ref_count = 0;
@@ -1989,32 +2039,36 @@ static int tls_connection_ca_cert(struct tls_data *data,
 	}
 
 #ifdef ANDROID
+	/* Single alias */
 	if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
-		BIO *bio = BIO_from_keystore(&ca_cert[11]);
-		STACK_OF(X509_INFO) *stack = NULL;
-		stack_index_t i;
-
-		if (bio) {
-			stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
-			BIO_free(bio);
-		}
-		if (!stack)
+		if (!tls_add_ca_from_keystore(ssl_ctx->cert_store, &ca_cert[11])) {
+			SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+			return 0;
+		} else {
 			return -1;
-
-		for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
-			X509_INFO *info = sk_X509_INFO_value(stack, i);
-			if (info->x509) {
-				X509_STORE_add_cert(ssl_ctx->cert_store,
-						    info->x509);
-			}
-			if (info->crl) {
-				X509_STORE_add_crl(ssl_ctx->cert_store,
-						   info->crl);
+		}
+	/* Multiple aliases separated by space */
+	} else if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
+		char *aliases = strdup(&ca_cert[12]);
+		const char *DELIMITER = " ";
+		int rc = 0;
+		char *savedptr;
+		char *alias = strtok_r(aliases, DELIMITER, &savedptr);
+		for(; alias; alias = strtok_r(NULL, DELIMITER, &savedptr)) {
+			if (tls_add_ca_from_keystore_encoded(ssl_ctx->cert_store, alias)) {
+				wpa_printf(MSG_WARNING, "OpenSSL: %s - fail to add ca_cert"
+				        " %s from keystore", __func__, alias);
+				rc = -1;
+				break;
 			}
 		}
-		sk_X509_INFO_pop_free(stack, X509_INFO_free);
-		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
-		return 0;
+		free(aliases);
+		if (!rc) {
+			SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+			return 0;
+		} else {
+			return -1;
+		}
 	}
 #endif /* ANDROID */
 
-- 
2.7.0.rc3.207.g0ac5344

_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap

[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux