mirror of
https://github.com/openssl/openssl.git
synced 2025-01-18 13:44:20 +08:00
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)
This commit is contained in:
parent
5936e8884b
commit
37933acbea
@ -1183,6 +1183,7 @@ SSL_F_SSL_SESSION_SET1_ID:423:SSL_SESSION_set1_id
|
||||
SSL_F_SSL_SESSION_SET1_ID_CONTEXT:312:SSL_SESSION_set1_id_context
|
||||
SSL_F_SSL_SET_ALPN_PROTOS:344:SSL_set_alpn_protos
|
||||
SSL_F_SSL_SET_CERT:191:ssl_set_cert
|
||||
SSL_F_SSL_SET_CERT_AND_KEY:621:ssl_set_cert_and_key
|
||||
SSL_F_SSL_SET_CIPHER_LIST:271:SSL_set_cipher_list
|
||||
SSL_F_SSL_SET_CT_VALIDATION_CALLBACK:399:SSL_set_ct_validation_callback
|
||||
SSL_F_SSL_SET_FD:192:SSL_set_fd
|
||||
@ -2525,6 +2526,7 @@ SSL_R_LIBRARY_HAS_NO_CIPHERS:161:library has no ciphers
|
||||
SSL_R_MISSING_DSA_SIGNING_CERT:165:missing dsa signing cert
|
||||
SSL_R_MISSING_ECDSA_SIGNING_CERT:381:missing ecdsa signing cert
|
||||
SSL_R_MISSING_FATAL:256:missing fatal
|
||||
SSL_R_MISSING_PARAMETERS:290:missing parameters
|
||||
SSL_R_MISSING_RSA_CERTIFICATE:168:missing rsa certificate
|
||||
SSL_R_MISSING_RSA_ENCRYPTING_CERT:169:missing rsa encrypting cert
|
||||
SSL_R_MISSING_RSA_SIGNING_CERT:170:missing rsa signing cert
|
||||
@ -2535,6 +2537,7 @@ SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION:209:missing supported groups extension
|
||||
SSL_R_MISSING_TMP_DH_KEY:171:missing tmp dh key
|
||||
SSL_R_MISSING_TMP_ECDH_KEY:311:missing tmp ecdh key
|
||||
SSL_R_NOT_ON_RECORD_BOUNDARY:182:not on record boundary
|
||||
SSL_R_NOT_REPLACING_CERTIFICATE:289:not replacing certificate
|
||||
SSL_R_NOT_SERVER:284:not server
|
||||
SSL_R_NO_APPLICATION_PROTOCOL:235:no application protocol
|
||||
SSL_R_NO_CERTIFICATES_RETURNED:176:no certificates returned
|
||||
@ -2577,6 +2580,7 @@ SSL_R_PEM_NAME_BAD_PREFIX:391:pem name bad prefix
|
||||
SSL_R_PEM_NAME_TOO_SHORT:392:pem name too short
|
||||
SSL_R_PIPELINE_FAILURE:406:pipeline failure
|
||||
SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR:278:post handshake auth encoding err
|
||||
SSL_R_PRIVATE_KEY_MISMATCH:288:private key mismatch
|
||||
SSL_R_PROTOCOL_IS_SHUTDOWN:207:protocol is shutdown
|
||||
SSL_R_PSK_IDENTITY_NOT_FOUND:223:psk identity not found
|
||||
SSL_R_PSK_NO_CLIENT_CB:224:psk no client cb
|
||||
|
@ -11,7 +11,8 @@ SSL_CTX_use_PrivateKey_file, SSL_CTX_use_RSAPrivateKey,
|
||||
SSL_CTX_use_RSAPrivateKey_ASN1, SSL_CTX_use_RSAPrivateKey_file,
|
||||
SSL_use_PrivateKey_file, SSL_use_PrivateKey_ASN1, SSL_use_PrivateKey,
|
||||
SSL_use_RSAPrivateKey, SSL_use_RSAPrivateKey_ASN1,
|
||||
SSL_use_RSAPrivateKey_file, SSL_CTX_check_private_key, SSL_check_private_key
|
||||
SSL_use_RSAPrivateKey_file, SSL_CTX_check_private_key, SSL_check_private_key,
|
||||
SSL_CTX_use_cert_and_key, SSL_use_cert_and_key
|
||||
- load certificate and key data
|
||||
|
||||
=head1 SYNOPSIS
|
||||
@ -45,6 +46,9 @@ SSL_use_RSAPrivateKey_file, SSL_CTX_check_private_key, SSL_check_private_key
|
||||
int SSL_CTX_check_private_key(const SSL_CTX *ctx);
|
||||
int SSL_check_private_key(const SSL *ssl);
|
||||
|
||||
int SSL_CTX_use_cert_and_key(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override);
|
||||
int SSL_use_cert_and_key(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
These functions load the certificates and private keys into the SSL_CTX
|
||||
@ -94,6 +98,19 @@ key pair the new certificate needs to be set with SSL_use_certificate()
|
||||
or SSL_CTX_use_certificate() before setting the private key with
|
||||
SSL_CTX_use_PrivateKey() or SSL_use_PrivateKey().
|
||||
|
||||
SSL_CTX_use_cert_and_key() and SSL_use_cert_and_key() assign the X.509
|
||||
certificate B<x>, private key B<key>, and certificate B<chain> onto the
|
||||
corresponding B<ssl> or B<ctx>. The B<pkey> argument must be the private
|
||||
key of the X.509 certificate B<x>. If the B<override> argument is 0, then
|
||||
B<x>, B<pkey> and B<chain> are set only if all were not previously set.
|
||||
If B<override> is non-0, then the certificate, private key and chain certs
|
||||
are always set. If B<pkey> is NULL, then the public key of B<x> is used as
|
||||
the private key. This is intended to be used with hardware (via the ENGINE
|
||||
inteface) that stores the private key securely, such that it cannot be
|
||||
accessed by OpenSSL. The reference count of the public key is incremented
|
||||
(twice if there is no private key); it is not copied nor duplicated. This
|
||||
allows all private key validations checks to succeed without an actual
|
||||
private key being assigned via SSL_CTX_use_PrivateKey(), etc.
|
||||
|
||||
SSL_CTX_use_PrivateKey_ASN1() adds the private key of type B<pk>
|
||||
stored at memory location B<d> (length B<len>) to B<ctx>.
|
||||
@ -170,7 +187,7 @@ L<SSL_CTX_add_extra_chain_cert(3)>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
Copyright 2000-2017 The OpenSSL Project Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the OpenSSL license (the "License"). You may not use
|
||||
this file except in compliance with the License. You can obtain a copy
|
||||
|
@ -403,6 +403,8 @@ Use the file path to locate trusted CA certificates.
|
||||
|
||||
=item int B<SSL_CTX_use_certificate_file>(SSL_CTX *ctx, const char *file, int type);
|
||||
|
||||
=item int B<SSL_CTX_use_cert_and_key>(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override);
|
||||
|
||||
=item X509 *B<SSL_CTX_get0_certificate>(const SSL_CTX *ctx);
|
||||
|
||||
=item EVP_PKEY *B<SSL_CTX_get0_privatekey>(const SSL_CTX *ctx);
|
||||
@ -712,6 +714,8 @@ Returns the current handshake state.
|
||||
|
||||
=item int B<SSL_use_certificate_file>(SSL *ssl, const char *file, int type);
|
||||
|
||||
=item int B<SSL_use_cert_and_key>(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override);
|
||||
|
||||
=item int B<SSL_version>(const SSL *ssl);
|
||||
|
||||
=item int B<SSL_want>(const SSL *ssl);
|
||||
|
@ -1505,6 +1505,8 @@ __owur int SSL_use_PrivateKey_ASN1(int pk, SSL *ssl, const unsigned char *d,
|
||||
long len);
|
||||
__owur int SSL_use_certificate(SSL *ssl, X509 *x);
|
||||
__owur int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
|
||||
__owur int SSL_use_cert_and_key(SSL *ssl, X509 *x509, EVP_PKEY *privatekey,
|
||||
STACK_OF(X509) *chain, int override);
|
||||
|
||||
|
||||
/* serverinfo file format versions */
|
||||
@ -1634,6 +1636,8 @@ __owur int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx,
|
||||
__owur int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);
|
||||
__owur int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len,
|
||||
const unsigned char *d);
|
||||
__owur int SSL_CTX_use_cert_and_key(SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey,
|
||||
STACK_OF(X509) *chain, int override);
|
||||
|
||||
void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb);
|
||||
void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u);
|
||||
|
@ -211,6 +211,7 @@ int ERR_load_SSL_strings(void);
|
||||
# define SSL_F_SSL_SESSION_SET1_ID_CONTEXT 312
|
||||
# define SSL_F_SSL_SET_ALPN_PROTOS 344
|
||||
# define SSL_F_SSL_SET_CERT 191
|
||||
# define SSL_F_SSL_SET_CERT_AND_KEY 621
|
||||
# define SSL_F_SSL_SET_CIPHER_LIST 271
|
||||
# define SSL_F_SSL_SET_CT_VALIDATION_CALLBACK 399
|
||||
# define SSL_F_SSL_SET_FD 192
|
||||
@ -566,6 +567,7 @@ int ERR_load_SSL_strings(void);
|
||||
# define SSL_R_MISSING_DSA_SIGNING_CERT 165
|
||||
# define SSL_R_MISSING_ECDSA_SIGNING_CERT 381
|
||||
# define SSL_R_MISSING_FATAL 256
|
||||
# define SSL_R_MISSING_PARAMETERS 290
|
||||
# define SSL_R_MISSING_RSA_CERTIFICATE 168
|
||||
# define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169
|
||||
# define SSL_R_MISSING_RSA_SIGNING_CERT 170
|
||||
@ -576,6 +578,7 @@ int ERR_load_SSL_strings(void);
|
||||
# define SSL_R_MISSING_TMP_DH_KEY 171
|
||||
# define SSL_R_MISSING_TMP_ECDH_KEY 311
|
||||
# define SSL_R_NOT_ON_RECORD_BOUNDARY 182
|
||||
# define SSL_R_NOT_REPLACING_CERTIFICATE 289
|
||||
# define SSL_R_NOT_SERVER 284
|
||||
# define SSL_R_NO_APPLICATION_PROTOCOL 235
|
||||
# define SSL_R_NO_CERTIFICATES_RETURNED 176
|
||||
@ -616,6 +619,7 @@ int ERR_load_SSL_strings(void);
|
||||
# define SSL_R_PEM_NAME_TOO_SHORT 392
|
||||
# define SSL_R_PIPELINE_FAILURE 406
|
||||
# define SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR 278
|
||||
# define SSL_R_PRIVATE_KEY_MISMATCH 288
|
||||
# define SSL_R_PROTOCOL_IS_SHUTDOWN 207
|
||||
# define SSL_R_PSK_IDENTITY_NOT_FOUND 223
|
||||
# define SSL_R_PSK_NO_CLIENT_CB 224
|
||||
|
@ -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),
|
||||
|
111
ssl/ssl_rsa.c
111
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);
|
||||
}
|
||||
|
@ -477,3 +477,5 @@ SSL_stateless 477 1_1_1 EXIST::FUNCTION:
|
||||
SSL_verify_client_post_handshake 478 1_1_1 EXIST::FUNCTION:
|
||||
SSL_force_post_handshake_auth 479 1_1_1 EXIST::FUNCTION:
|
||||
SSL_export_keying_material_early 480 1_1_1 EXIST::FUNCTION:
|
||||
SSL_CTX_use_cert_and_key 481 1_1_1 EXIST::FUNCTION:
|
||||
SSL_use_cert_and_key 482 1_1_1 EXIST::FUNCTION:
|
||||
|
Loading…
Reference in New Issue
Block a user