From e2722bf81db3463b698e61908a5e9380184ce13d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 12 Jul 2019 18:11:53 +0300 Subject: [PATCH] OpenSSL: Allow two server certificates/keys to be configured on server hostapd EAP server can now be configured with two separate server certificates/keys to enable parallel operations using both RSA and ECC public keys. The server will pick which one to use based on the client preferences for the cipher suite (in the TLS ClientHello message). It should be noted that number of deployed EAP peer implementations do not filter out the cipher suite list based on their local configuration and as such, configuration of alternative types of certificates on the server may result in interoperability issues. Signed-off-by: Jouni Malinen --- hostapd/config_file.c | 9 +++++++++ hostapd/hostapd.conf | 17 +++++++++++++++++ src/ap/ap_config.c | 3 +++ src/ap/ap_config.h | 3 +++ src/ap/authsrv.c | 6 +++++- src/crypto/tls.h | 3 +++ src/crypto/tls_openssl.c | 3 +++ 7 files changed, 43 insertions(+), 1 deletion(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 3a294386f..df41f1424 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2589,12 +2589,21 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "server_cert") == 0) { os_free(bss->server_cert); bss->server_cert = os_strdup(pos); + } else if (os_strcmp(buf, "server_cert2") == 0) { + os_free(bss->server_cert2); + bss->server_cert2 = os_strdup(pos); } else if (os_strcmp(buf, "private_key") == 0) { os_free(bss->private_key); bss->private_key = os_strdup(pos); + } else if (os_strcmp(buf, "private_key2") == 0) { + os_free(bss->private_key2); + bss->private_key2 = os_strdup(pos); } else if (os_strcmp(buf, "private_key_passwd") == 0) { os_free(bss->private_key_passwd); bss->private_key_passwd = os_strdup(pos); + } else if (os_strcmp(buf, "private_key_passwd2") == 0) { + os_free(bss->private_key_passwd2); + bss->private_key_passwd2 = os_strdup(pos); } else if (os_strcmp(buf, "check_cert_subject") == 0) { if (!pos[0]) { wpa_printf(MSG_ERROR, "Line %d: unknown check_cert_subject '%s'", diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index d67a40573..f2d587388 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -977,6 +977,23 @@ eap_server=0 # Passphrase for private key #private_key_passwd=secret passphrase +# An alternative server certificate and private key can be configured with the +# following parameters (with values just like the parameters above without the +# '2' suffix). The ca_cert file (in PEM encoding) is used to add the trust roots +# for both server certificates and/or client certificates). +# +# The main use case for this alternative server certificate configuration is to +# enable both RSA and ECC public keys. The server will pick which one to use +# based on the client preferences for the cipher suite (in the TLS ClientHello +# message). It should be noted that number of deployed EAP peer implementations +# do not filter out the cipher suite list based on their local configuration and +# as such, configuration of alternative types of certificates on the server may +# result in interoperability issues. +#server_cert2=/etc/hostapd.server-ecc.pem +#private_key2=/etc/hostapd.server-ecc.prv +#private_key_passwd2=secret passphrase + + # Server identity # EAP methods that provide mechanism for authenticated server identity delivery # use this value. If not set, "hostapd" is used as a default. diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 6a2deb6de..a061bd863 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -629,8 +629,11 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->ctrl_interface); os_free(conf->ca_cert); os_free(conf->server_cert); + os_free(conf->server_cert2); os_free(conf->private_key); + os_free(conf->private_key2); os_free(conf->private_key_passwd); + os_free(conf->private_key_passwd2); os_free(conf->check_cert_subject); os_free(conf->ocsp_stapling_response); os_free(conf->ocsp_stapling_response_multi); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index b1007622c..eebf8981d 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -403,8 +403,11 @@ struct hostapd_bss_config { char *ca_cert; char *server_cert; + char *server_cert2; char *private_key; + char *private_key2; char *private_key_passwd; + char *private_key_passwd2; char *check_cert_subject; int check_crl; int check_crl_strict; diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index 3dd6b7bee..b3d910742 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -197,7 +197,8 @@ int authsrv_init(struct hostapd_data *hapd) #ifdef EAP_TLS_FUNCS if (hapd->conf->eap_server && (hapd->conf->ca_cert || hapd->conf->server_cert || - hapd->conf->private_key || hapd->conf->dh_file)) { + hapd->conf->private_key || hapd->conf->dh_file || + hapd->conf->server_cert2 || hapd->conf->private_key2)) { struct tls_config conf; struct tls_connection_params params; @@ -226,8 +227,11 @@ int authsrv_init(struct hostapd_data *hapd) os_memset(¶ms, 0, sizeof(params)); params.ca_cert = hapd->conf->ca_cert; params.client_cert = hapd->conf->server_cert; + params.client_cert2 = hapd->conf->server_cert2; params.private_key = hapd->conf->private_key; + params.private_key2 = hapd->conf->private_key2; params.private_key_passwd = hapd->conf->private_key_passwd; + params.private_key_passwd2 = hapd->conf->private_key_passwd2; params.dh_file = hapd->conf->dh_file; params.openssl_ciphers = hapd->conf->openssl_ciphers; params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves; diff --git a/src/crypto/tls.h b/src/crypto/tls.h index a9ba7d11a..c8b1a824e 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -188,12 +188,15 @@ struct tls_connection_params { const char *suffix_match; const char *domain_match; const char *client_cert; + const char *client_cert2; const u8 *client_cert_blob; size_t client_cert_blob_len; const char *private_key; + const char *private_key2; const u8 *private_key_blob; size_t private_key_blob_len; const char *private_key_passwd; + const char *private_key_passwd2; const char *dh_file; const u8 *dh_blob; size_t dh_blob_len; diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 48b48e9bc..d45543e66 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -5228,6 +5228,9 @@ int tls_global_set_params(void *tls_ctx, tls_global_client_cert(data, params->client_cert) || tls_global_private_key(data, params->private_key, params->private_key_passwd) || + tls_global_client_cert(data, params->client_cert2) || + tls_global_private_key(data, params->private_key2, + params->private_key_passwd2) || tls_global_dh(data, params->dh_file)) { wpa_printf(MSG_INFO, "TLS: Failed to set global parameters"); return -1;