Cumulative patch from commit c06c9099f0d0827feae5622097bd8ac946eca5ea

c06c909 Use stronger PRNG for MS-MPPE-Send/Recv-Key salt
9e1f1bd eloop: Clean up coding style for eloop debug prints
f9982b3 Implement kqueue(2) support via CONFIG_ELOOP_KQUEUE
2e69bdd eloop: Add eloop_sock_requeue()
70f4f05 wpa_ctrl: Retry select() on EINTR
df9e2c2 D-Bus: Don't do <deny send_interface="..." /> in dbus service file
9684c75 mesh: Fix peer link counting when a mesh peer reconnects
83fe38b P2P: Fall back to no VHT when starting AP/P2P GO
360a9d5 P2P: Reduce off channel wait time for some P2P Action frames
1fc63fe RADIUS: Share a single function for generating session IDs
2cbc6ff RADIUS: Redesign Request Authenticator generation
b71a64a Send an Acct-Multi-Session-Id attribute in Access-Request packets
4260e1a Add Acct-Session-Id to Accounting-On/Off
d72a005 RADIUS: Use more likely unique accounting Acct-{,Multi-}Session-Id
d689317 EAPOL auth: Move radius_cui/identity freeing to eapol_auth_free()
0ae86f9 wpa_supplicant: Fix couple of C++ compiler errors with header files
9b6177a Add Event-Timestamp to all Accounting-Request packets
d179089 GAS: Calculate response buffer length of ANQP elements
dda091c OpenSSL: Fix server side PKCS#12 processing with extra certificates
443c8e1 OpenSSL: Fix possible null pointer dereference on an OCSP error path
a3cc64f Remove -w support from wpa_supplicant README
e265838 EAP-FAST: Fix an error path in PAC binary format parsing
f91e11f D-Bus: Fix p2p interface capability message
479f46c Do not send Acct-Authentic in Accounting-On/Off
696544e RADIUS: Do not include Acct-Terminate-Cause in Accounting-On/Off
236053e Make fallback from HT40 to HT20 work
cb22e3b BSD: Zero ifindex on interface removal
a8ef133 Android: Support multiple CA certs when connecting to EAP network
80ce804 WNM: Workaround for broken AP operating class behavior
af06093 BSD: Disable interface on down
dc0ad60 BSD: Use correct ifindex from route messages
5f17b2c BSD: __FUNCTION__ -> __func__
2088ecb OSU: Add debug printing of more LogotypeExtn fields
0b905c8 Add the selector suite into wpa_parse_wpa_ie_rsn() "invalid group cipher"
03a72ea VHT: Add an interoperability workaround for 80+80 and 160 MHz channels

Change-Id: Ief9174bdec380e81025e1467c47bf1656eb39cd9
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index b16b519..e34a3d0 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -105,6 +105,66 @@
 	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);
+	unsigned char *decoded_alias;
+
+	if (len & 1) {
+		wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
+			   encoded_key_alias);
+		return rc;
+	}
+
+	decoded_alias = os_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, (const char *) decoded_alias);
+		}
+		os_free(decoded_alias);
+	}
+
+	return rc;
+}
+
 #endif /* ANDROID */
 
 static int tls_openssl_ref_count = 0;
@@ -1989,30 +2049,40 @@
 	}
 
 #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]) < 0)
 			return -1;
+		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+		return 0;
+	}
 
-		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 */
+	if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
+		char *aliases = os_strdup(&ca_cert[12]);
+		const char *delim = " ";
+		int rc = 0;
+		char *savedptr;
+		char *alias;
+
+		if (!aliases)
+			return -1;
+		alias = strtok_r(aliases, delim, &savedptr);
+		for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
+			if (tls_add_ca_from_keystore_encoded(
+				    ssl_ctx->cert_store, alias)) {
+				wpa_printf(MSG_WARNING,
+					   "OpenSSL: %s - Failed to add ca_cert %s from keystore",
+					   __func__, alias);
+				rc = -1;
+				break;
 			}
 		}
-		sk_X509_INFO_pop_free(stack, X509_INFO_free);
+		os_free(aliases);
+		if (rc)
+			return rc;
+
 		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
 		return 0;
 	}
@@ -2393,13 +2463,18 @@
 
 	if (certs) {
 #if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
-		SSL_clear_chain_certs(ssl);
+		if (ssl)
+			SSL_clear_chain_certs(ssl);
+		else
+			SSL_CTX_clear_chain_certs(data->ssl);
 		while ((cert = sk_X509_pop(certs)) != NULL) {
 			X509_NAME_oneline(X509_get_subject_name(cert), buf,
 					  sizeof(buf));
 			wpa_printf(MSG_DEBUG, "TLS: additional certificate"
 				   " from PKCS12: subject='%s'", buf);
-			if (SSL_add1_chain_cert(ssl, cert) != 1) {
+			if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
+			    (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
+							     cert) != 1)) {
 				tls_show_errors(MSG_DEBUG, __func__,
 						"Failed to add additional certificate");
 				res = -1;
@@ -2411,9 +2486,16 @@
 		}
 		sk_X509_free(certs);
 #ifndef OPENSSL_IS_BORINGSSL
-		res = SSL_build_cert_chain(ssl,
-					   SSL_BUILD_CHAIN_FLAG_CHECK |
-					   SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+		if (ssl)
+			res = SSL_build_cert_chain(
+				ssl,
+				SSL_BUILD_CHAIN_FLAG_CHECK |
+				SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+		else
+			res = SSL_CTX_build_cert_chain(
+				data->ssl,
+				SSL_BUILD_CHAIN_FLAG_CHECK |
+				SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
 		if (!res) {
 			tls_show_errors(MSG_DEBUG, __func__,
 					"Failed to build certificate chain");