]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OpenSSL: Avoid SSL*_use_default_passwd_cb()
authorDavid Benjamin <davidben@google.com>
Mon, 18 Sep 2017 15:47:47 +0000 (11:47 -0400)
committerJouni Malinen <j@w1.fi>
Sat, 9 Dec 2017 16:29:08 +0000 (18:29 +0200)
These functions are a bit awkward to use for one-off file loads, as
suggested by the tls_clear_default_passwd_cb() logic. There was also
some historical mess with OpenSSL versions and either not having per-SSL
settings, having per-SSL settings but ignoring them, and requiring the
per-SSL settings.

Instead, loading the key with the lower-level functions seems a bit
tidier and also allows abstracting away trying both formats, one after
another.

Signed-off-by: David Benjamin <davidben@google.com>
src/crypto/tls_openssl.c

index f905d9adcea80f08fd9c6af0c62fd5995a7c8ac8..92aa711d2c59948e35e5ae5de1cc007bbcc91526 100644 (file)
@@ -2686,16 +2686,6 @@ static int tls_global_client_cert(struct tls_data *data,
 }
 
 
-static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
-{
-       if (password == NULL) {
-               return 0;
-       }
-       os_strlcpy(buf, (char *) password, size);
-       return os_strlen(buf);
-}
-
-
 #ifdef PKCS12_FUNCS
 static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
                            const char *passwd)
@@ -3014,20 +3004,61 @@ static int tls_connection_engine_private_key(struct tls_connection *conn)
 }
 
 
-static void tls_clear_default_passwd_cb(SSL_CTX *ssl_ctx, SSL *ssl)
+#ifndef OPENSSL_NO_STDIO
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-#ifndef LIBRESSL_VERSION_NUMBER
-#ifndef OPENSSL_IS_BORINGSSL
-       if (ssl) {
-               SSL_set_default_passwd_cb(ssl, NULL);
-               SSL_set_default_passwd_cb_userdata(ssl, NULL);
-       }
-#endif /* !BoringSSL */
-#endif /* !LibreSSL */
-#endif /* >= 1.1.0f */
-       SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
-       SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, NULL);
+       if (!password)
+               return 0;
+       os_strlcpy(buf, (const char *) password, size);
+       return os_strlen(buf);
+}
+#endif /* OPENSSL_NO_STDIO */
+
+
+static int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
+                                   const char *private_key,
+                                   const char *private_key_passwd)
+{
+#ifndef OPENSSL_NO_STDIO
+       BIO *bio;
+       EVP_PKEY *pkey;
+       int ret;
+
+       /* First try ASN.1 (DER). */
+       bio = BIO_new_file(private_key, "r");
+       if (!bio)
+               return -1;
+       pkey = d2i_PrivateKey_bio(bio, NULL);
+       BIO_free(bio);
+
+       if (pkey) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: %s (DER) --> loaded", __func__);
+       } else {
+               /* Try PEM with the provided password. */
+               bio = BIO_new_file(private_key, "r");
+               if (!bio)
+                       return -1;
+               pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
+                                              (void *) private_key_passwd);
+               BIO_free(bio);
+               if (!pkey)
+                       return -1;
+               wpa_printf(MSG_DEBUG, "OpenSSL: %s (PEM) --> loaded", __func__);
+               /* Clear errors from the previous failed load. */
+               ERR_clear_error();
+       }
+
+       if (ssl)
+               ret = SSL_use_PrivateKey(ssl, pkey);
+       else
+               ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
+
+       EVP_PKEY_free(pkey);
+       return ret == 1 ? 0 : -1;
+#else /* OPENSSL_NO_STDIO */
+       wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+       return -1;
+#endif /* OPENSSL_NO_STDIO */
 }
 
 
@@ -3038,30 +3069,11 @@ static int tls_connection_private_key(struct tls_data *data,
                                      const u8 *private_key_blob,
                                      size_t private_key_blob_len)
 {
-       SSL_CTX *ssl_ctx = data->ssl;
        int ok;
 
        if (private_key == NULL && private_key_blob == NULL)
                return 0;
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-#ifndef LIBRESSL_VERSION_NUMBER
-#ifndef OPENSSL_IS_BORINGSSL
-       /*
-        * In OpenSSL >= 1.1.0f SSL_use_PrivateKey_file() uses the callback
-        * from the SSL object. See OpenSSL commit d61461a75253.
-        */
-       SSL_set_default_passwd_cb(conn->ssl, tls_passwd_cb);
-       SSL_set_default_passwd_cb_userdata(conn->ssl,
-                                          (void *) private_key_passwd);
-#endif /* !BoringSSL */
-#endif /* !LibreSSL */
-#endif /* >= 1.1.0f && */
-       /* Keep these for OpenSSL < 1.1.0f */
-       SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
-       SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx,
-                                              (void *) private_key_passwd);
-
        ok = 0;
        while (private_key_blob) {
                if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
@@ -3104,27 +3116,12 @@ static int tls_connection_private_key(struct tls_data *data,
        }
 
        while (!ok && private_key) {
-#ifndef OPENSSL_NO_STDIO
-               if (SSL_use_PrivateKey_file(conn->ssl, private_key,
-                                           SSL_FILETYPE_ASN1) == 1) {
-                       wpa_printf(MSG_DEBUG, "OpenSSL: "
-                                  "SSL_use_PrivateKey_File (DER) --> OK");
+               if (tls_use_private_key_file(data, conn->ssl, private_key,
+                                            private_key_passwd) == 0) {
                        ok = 1;
                        break;
                }
 
-               if (SSL_use_PrivateKey_file(conn->ssl, private_key,
-                                           SSL_FILETYPE_PEM) == 1) {
-                       wpa_printf(MSG_DEBUG, "OpenSSL: "
-                                  "SSL_use_PrivateKey_File (PEM) --> OK");
-                       ok = 1;
-                       break;
-               }
-#else /* OPENSSL_NO_STDIO */
-               wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
-                          __func__);
-#endif /* OPENSSL_NO_STDIO */
-
                if (tls_read_pkcs12(data, conn->ssl, private_key,
                                    private_key_passwd) == 0) {
                        wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
@@ -3146,11 +3143,9 @@ static int tls_connection_private_key(struct tls_data *data,
        if (!ok) {
                tls_show_errors(MSG_INFO, __func__,
                                "Failed to load private key");
-               tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
                return -1;
        }
        ERR_clear_error();
-       tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
 
        if (!SSL_check_private_key(conn->ssl)) {
                tls_show_errors(MSG_INFO, __func__, "Private key failed "
@@ -3172,24 +3167,14 @@ static int tls_global_private_key(struct tls_data *data,
        if (private_key == NULL)
                return 0;
 
-       SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
-       SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx,
-                                              (void *) private_key_passwd);
-       if (
-#ifndef OPENSSL_NO_STDIO
-           SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
-                                       SSL_FILETYPE_ASN1) != 1 &&
-           SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
-                                       SSL_FILETYPE_PEM) != 1 &&
-#endif /* OPENSSL_NO_STDIO */
+       if (tls_use_private_key_file(data, NULL, private_key,
+                                    private_key_passwd) &&
            tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
                tls_show_errors(MSG_INFO, __func__,
                                "Failed to load private key");
-               tls_clear_default_passwd_cb(ssl_ctx, NULL);
                ERR_clear_error();
                return -1;
        }
-       tls_clear_default_passwd_cb(ssl_ctx, NULL);
        ERR_clear_error();
 
        if (!SSL_CTX_check_private_key(ssl_ctx)) {