diff options
author | Todd Short <tshort@akamai.com> | 2015-12-28 09:13:20 -0500 |
---|---|---|
committer | Ben Kaduk <kaduk@mit.edu> | 2018-03-09 10:28:04 -0600 |
commit | 37933acbeafef6db9a5c5681c1b5174cd91494bc (patch) | |
tree | 68baa103ddb6b721bca122931479a107e4266273 /ssl | |
parent | 5936e8884bc6f3b9ff9abf8ebbeb772809882f92 (diff) |
Add SSL/SSL_CTX_use_cert_and_key()
Add functions that will do the work of assigning certificate, privatekey
and chain certs to an SSL or SSL_CTX. If no privatekey is given, use the
publickey. This will permit the keys to pass validation for both ECDSA
and RSA. If a private key has already been set for the certificate, it
is discarded. A real private key can be set later.
This is an all-or-nothing setting of these parameters. Unlike the
SSL/SSL_CTX_use_certificate() and SSL/SSL_CTX_use_PrivateKey() functions,
the existing cert or privatekey is not modified (i.e. parameters copied).
This permits the existing cert/privatekey to be replaced.
It replaces the sequence of:
* SSL_use_certificate()
* SSL_use_privatekey()
* SSL_set1_chain()
And may actually be faster, as multiple checks are consolidated.
The private key can be NULL, if so an ENGINE module needs to contain the
actual private key that is to be used.
Note that ECDH (using the certificate's ECDSA key) ciphers do not work
without the private key being present, based on how the private key is
used in ECDH. ECDH does not offer PFS; ECDHE ciphers should be used instead.
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Ben Kaduk <kaduk@mit.edu>
(Merged from https://github.com/openssl/openssl/pull/1130)
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/ssl_err.c | 7 | ||||
-rw-r--r-- | ssl/ssl_rsa.c | 111 |
2 files changed, 118 insertions, 0 deletions
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 34e8ec4076..e367a364bb 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -306,6 +306,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_ALPN_PROTOS, 0), "SSL_set_alpn_protos"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CERT, 0), "ssl_set_cert"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CERT_AND_KEY, 0), + "ssl_set_cert_and_key"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CIPHER_LIST, 0), "SSL_set_cipher_list"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CT_VALIDATION_CALLBACK, 0), @@ -914,6 +916,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_ECDSA_SIGNING_CERT), "missing ecdsa signing cert"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_FATAL), "missing fatal"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PARAMETERS), "missing parameters"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_CERTIFICATE), "missing rsa certificate"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_ENCRYPTING_CERT), @@ -933,6 +936,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { "missing tmp ecdh key"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_ON_RECORD_BOUNDARY), "not on record boundary"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_REPLACING_CERTIFICATE), + "not replacing certificate"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_SERVER), "not server"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_APPLICATION_PROTOCOL), "no application protocol"}, @@ -997,6 +1002,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PIPELINE_FAILURE), "pipeline failure"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR), "post handshake auth encoding err"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PRIVATE_KEY_MISMATCH), + "private key mismatch"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PROTOCOL_IS_SHUTDOWN), "protocol is shutdown"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_IDENTITY_NOT_FOUND), diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index fe2dd867ad..7eff731e41 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -1035,3 +1035,114 @@ int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file) BIO_free(bin); return ret; } + +static int ssl_set_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey, + STACK_OF(X509) *chain, int override) +{ + int ret = 0; + size_t i; + int j; + int rv; + CERT *c = ssl != NULL ? ssl->cert : ctx->cert; + STACK_OF(X509) *dup_chain = NULL; + EVP_PKEY *pubkey = NULL; + + /* Do all security checks before anything else */ + rv = ssl_security_cert(ssl, ctx, x509, 0, 1); + if (rv != 1) { + SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, rv); + goto out; + } + for (j = 0; j < sk_X509_num(chain); j++) { + rv = ssl_security_cert(ssl, ctx, sk_X509_value(chain, j), 0, 0); + if (rv != 1) { + SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, rv); + goto out; + } + } + + pubkey = X509_get_pubkey(x509); /* bumps reference */ + if (pubkey == NULL) + goto out; + if (privatekey == NULL) { + privatekey = pubkey; + } else { + /* For RSA, which has no parameters, missing returns 0 */ + if (EVP_PKEY_missing_parameters(privatekey)) { + if (EVP_PKEY_missing_parameters(pubkey)) { + /* nobody has parameters? - error */ + SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_MISSING_PARAMETERS); + goto out; + } else { + /* copy to privatekey from pubkey */ + EVP_PKEY_copy_parameters(privatekey, pubkey); + } + } else if (EVP_PKEY_missing_parameters(pubkey)) { + /* copy to pubkey from privatekey */ + EVP_PKEY_copy_parameters(pubkey, privatekey); + } /* else both have parameters */ + + /* Copied from ssl_set_cert/pkey */ +#ifndef OPENSSL_NO_RSA + if ((EVP_PKEY_id(privatekey) == EVP_PKEY_RSA) && + ((RSA_flags(EVP_PKEY_get0_RSA(privatekey)) & RSA_METHOD_FLAG_NO_CHECK))) + /* no-op */ ; + else +#endif + /* check that key <-> cert match */ + if (EVP_PKEY_cmp(pubkey, privatekey) != 1) { + SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_PRIVATE_KEY_MISMATCH); + goto out; + } + } + if (ssl_cert_lookup_by_pkey(pubkey, &i) == NULL) { + SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + goto out; + } + + if (!override && (c->pkeys[i].x509 != NULL + || c->pkeys[i].privatekey != NULL + || c->pkeys[i].chain != NULL)) { + /* No override, and something already there */ + SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_NOT_REPLACING_CERTIFICATE); + goto out; + } + + if (chain != NULL) { + dup_chain = X509_chain_up_ref(chain); + if (dup_chain == NULL) { + SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, ERR_R_MALLOC_FAILURE); + goto out; + } + } + + sk_X509_pop_free(c->pkeys[i].chain, X509_free); + c->pkeys[i].chain = dup_chain; + + X509_free(c->pkeys[i].x509); + X509_up_ref(x509); + c->pkeys[i].x509 = x509; + + EVP_PKEY_free(c->pkeys[i].privatekey); + EVP_PKEY_up_ref(privatekey); + c->pkeys[i].privatekey = privatekey; + + c->key = &(c->pkeys[i]); + + ret = 1; + out: + EVP_PKEY_free(pubkey); + return ret; +} + +int SSL_use_cert_and_key(SSL *ssl, X509 *x509, EVP_PKEY *privatekey, + STACK_OF(X509) *chain, int override) +{ + return ssl_set_cert_and_key(ssl, NULL, x509, privatekey, chain, override); +} + +int SSL_CTX_use_cert_and_key(SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey, + STACK_OF(X509) *chain, int override) +{ + return ssl_set_cert_and_key(NULL, ctx, x509, privatekey, chain, override); +} |