summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/err/openssl.txt4
-rw-r--r--doc/man3/SSL_CTX_use_certificate.pod21
-rw-r--r--doc/man7/ssl.pod4
-rw-r--r--include/openssl/ssl.h4
-rw-r--r--include/openssl/sslerr.h4
-rw-r--r--ssl/ssl_err.c7
-rw-r--r--ssl/ssl_rsa.c111
-rw-r--r--util/libssl.num2
8 files changed, 155 insertions, 2 deletions
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 842a4209dc..d867007b2e 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -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
diff --git a/doc/man3/SSL_CTX_use_certificate.pod b/doc/man3/SSL_CTX_use_certificate.pod
index 22420f97d8..a0c92e6e7b 100644
--- a/doc/man3/SSL_CTX_use_certificate.pod
+++ b/doc/man3/SSL_CTX_use_certificate.pod
@@ -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
diff --git a/doc/man7/ssl.pod b/doc/man7/ssl.pod
index 63b47baa16..03efc52007 100644
--- a/doc/man7/ssl.pod
+++ b/doc/man7/ssl.pod
@@ -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);
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 825490b5c2..3561dee33b 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -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);
diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h
index 32fe3662f2..454877df85 100644
--- a/include/openssl/sslerr.h
+++ b/include/openssl/sslerr.h
@@ -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
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);
+}
diff --git a/util/libssl.num b/util/libssl.num
index 48c5eca19d..b299035042 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -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: