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

Rubin Xu rubinxu at google.com
Mon Jan 25 09:09:45 PST 2016


 From 0e58b2f7be834d0a727b6553ae5f6c7a6789e3c4 Mon Sep 17 00:00:00 2001
From: Rubin Xu <rubinxu at google.com>
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 at google.com>
---
  src/crypto/tls_openssl.c | 104 
+++++++++++++++++++++++++++++++++++++----------
  1 file changed, 82 insertions(+), 22 deletions(-)

diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index b16b519..2cf9a71 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,42 @@ 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 = " ";
+		char *savedptr;
+		char *alias;
+		int rc;
+		alias = strtok_r(aliases, DELIMITER, &savedptr);
+		if (!alias) {
+			rc = tls_add_ca_from_keystore_encoded(ssl_ctx->cert_store, aliases);
+		} else {
+			rc = 0;
+			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




More information about the Hostap mailing list