OpenSSL: Avoid SSL*_use_default_passwd_cb()

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>
This commit is contained in:
David Benjamin 2017-09-18 11:47:47 -04:00 committed by Jouni Malinen
parent 149143e31d
commit 63942cf0f3

View 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 #ifdef PKCS12_FUNCS
static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12, static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
const char *passwd) 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 if (!password)
#ifndef LIBRESSL_VERSION_NUMBER return 0;
#ifndef OPENSSL_IS_BORINGSSL os_strlcpy(buf, (const char *) password, size);
if (ssl) { return os_strlen(buf);
SSL_set_default_passwd_cb(ssl, NULL); }
SSL_set_default_passwd_cb_userdata(ssl, NULL); #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();
} }
#endif /* !BoringSSL */
#endif /* !LibreSSL */ if (ssl)
#endif /* >= 1.1.0f */ ret = SSL_use_PrivateKey(ssl, pkey);
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); else
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, NULL); 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, const u8 *private_key_blob,
size_t private_key_blob_len) size_t private_key_blob_len)
{ {
SSL_CTX *ssl_ctx = data->ssl;
int ok; int ok;
if (private_key == NULL && private_key_blob == NULL) if (private_key == NULL && private_key_blob == NULL)
return 0; 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; ok = 0;
while (private_key_blob) { while (private_key_blob) {
if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, 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) { while (!ok && private_key) {
#ifndef OPENSSL_NO_STDIO if (tls_use_private_key_file(data, conn->ssl, private_key,
if (SSL_use_PrivateKey_file(conn->ssl, private_key, private_key_passwd) == 0) {
SSL_FILETYPE_ASN1) == 1) {
wpa_printf(MSG_DEBUG, "OpenSSL: "
"SSL_use_PrivateKey_File (DER) --> OK");
ok = 1; ok = 1;
break; 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, if (tls_read_pkcs12(data, conn->ssl, private_key,
private_key_passwd) == 0) { private_key_passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file " 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) { if (!ok) {
tls_show_errors(MSG_INFO, __func__, tls_show_errors(MSG_INFO, __func__,
"Failed to load private key"); "Failed to load private key");
tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
return -1; return -1;
} }
ERR_clear_error(); ERR_clear_error();
tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
if (!SSL_check_private_key(conn->ssl)) { if (!SSL_check_private_key(conn->ssl)) {
tls_show_errors(MSG_INFO, __func__, "Private key failed " 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) if (private_key == NULL)
return 0; return 0;
SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); if (tls_use_private_key_file(data, NULL, private_key,
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, private_key_passwd) &&
(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 */
tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) { tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
tls_show_errors(MSG_INFO, __func__, tls_show_errors(MSG_INFO, __func__,
"Failed to load private key"); "Failed to load private key");
tls_clear_default_passwd_cb(ssl_ctx, NULL);
ERR_clear_error(); ERR_clear_error();
return -1; return -1;
} }
tls_clear_default_passwd_cb(ssl_ctx, NULL);
ERR_clear_error(); ERR_clear_error();
if (!SSL_CTX_check_private_key(ssl_ctx)) { if (!SSL_CTX_check_private_key(ssl_ctx)) {