]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Android: Support multiple CA certs when connecting to EAP network
authorRubin Xu <rubinxu@google.com>
Tue, 10 Nov 2015 17:14:51 +0000 (17:14 +0000)
committerJouni Malinen <j@w1.fi>
Fri, 5 Feb 2016 15:31:46 +0000 (17:31 +0200)
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.

Signed-off-by: Rubin Xu <rubinxu@google.com>
src/crypto/tls_openssl.c

index b16b51972929cfbf7fd5fe1d67116b190e5e43c8..2bb606d37a1a6216a0c427eebcd00666ed82d853 100644 (file)
@@ -105,6 +105,66 @@ 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);
+       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 @@ 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]) < 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;
        }