Fold away certificate slots mechanism.
This allows us to remove the confusing EVP_PKEY argument to the
SSL_PRIVATE_KEY_METHOD wrapper functions. It also simplifies some of the
book-keeping around the CERT structure, as well as the API for
configuring certificates themselves. The current one is a little odd as
some functions automatically route to the slot while others affect the
most recently touched slot. Others still (extra_certs) apply to all
slots, making them not terribly useful.
Consumers with complex needs should use cert_cb or the early callback
(select_certificate_cb) to configure whatever they like based on the
ClientHello.
BUG=486295
Change-Id: Ice29ffeb867fa4959898b70dfc50fc00137f01f3
Reviewed-on: https://boringssl-review.googlesource.com/5351
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 7b9d051..1295d87 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -495,8 +495,7 @@
/* Configuring certificates and private keys.
*
* TODO(davidben): Move the other, more conventional, certificate and key
- * configuration functions here, possibly after simplifying the multiple slots
- * machinery first. https://crbug.com/486295. */
+ * configuration functions here. */
enum ssl_private_key_result_t {
ssl_private_key_success,
@@ -549,11 +548,8 @@
size_t *out_len, size_t max_out);
} SSL_PRIVATE_KEY_METHOD;
-/* SSL_use_private_key_method configures a custom private key on
- * |ssl|. |key_method| must remain valid for the lifetime of |ssl|. Using custom
- * keys with the multiple certificate slots feature is not supported.
- *
- * TODO(davidben): Remove the multiple certificate slots feature. */
+/* SSL_use_private_key_method configures a custom private key on |ssl|.
+ * |key_method| must remain valid for the lifetime of |ssl|. */
OPENSSL_EXPORT void SSL_set_private_key_method(
SSL *ssl, const SSL_PRIVATE_KEY_METHOD *key_method);
@@ -1054,8 +1050,6 @@
CRYPTO_EX_DATA ex_data;
- STACK_OF(X509) *extra_certs;
-
/* Default values used when no per-SSL value is defined follow */
diff --git a/ssl/internal.h b/ssl/internal.h
index 838fce7..327f52b 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -254,17 +254,12 @@
STACK_OF(SSL_CIPHER) **out_cipher_list_by_id,
const char *rule_str);
-/* SSL_PKEY_* denote certificate types. */
-#define SSL_PKEY_RSA 0
-#define SSL_PKEY_ECC 1
-#define SSL_PKEY_NUM 2
-
/* ssl_cipher_get_value returns the cipher suite id of |cipher|. */
uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher);
-/* ssl_cipher_get_cert_index returns the |SSL_PKEY_*| value corresponding to the
- * certificate type of |cipher| or -1 if there is none. */
-int ssl_cipher_get_cert_index(const SSL_CIPHER *cipher);
+/* ssl_cipher_get_key_type returns the |EVP_PKEY_*| value corresponding to the
+ * server key used in |cipher| or |EVP_PKEY_NONE| if there is none. */
+int ssl_cipher_get_key_type(const SSL_CIPHER *cipher);
/* ssl_cipher_has_server_public_key returns 1 if |cipher| involves a server
* public key in the key exchange, sent in a server Certificate message.
@@ -353,21 +348,17 @@
/* ssl_private_key_* call the corresponding function on the
* |SSL_PRIVATE_KEY_METHOD| for |ssl|, if configured. Otherwise, they implement
- * the operation on |pkey|.
- *
- * TODO(davidben): The |EVP_PKEY| must be passed in to due to the multiple
- * certificate slots feature. Remove it. */
+ * the operation with |EVP_PKEY|. */
-int ssl_private_key_type(SSL *ssl, const EVP_PKEY *pkey);
+int ssl_private_key_type(SSL *ssl);
-int ssl_private_key_supports_digest(SSL *ssl, const EVP_PKEY *pkey,
- const EVP_MD *md);
+int ssl_private_key_supports_digest(SSL *ssl, const EVP_MD *md);
-size_t ssl_private_key_max_signature_len(SSL *ssl, const EVP_PKEY *pkey);
+size_t ssl_private_key_max_signature_len(SSL *ssl);
enum ssl_private_key_result_t ssl_private_key_sign(
- SSL *ssl, EVP_PKEY *pkey, uint8_t *out, size_t *out_len, size_t max_out,
- const EVP_MD *md, const uint8_t *in, size_t in_len);
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md,
+ const uint8_t *in, size_t in_len);
enum ssl_private_key_result_t ssl_private_key_sign_complete(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out);
@@ -516,13 +507,6 @@
ssl_hash_message,
};
-typedef struct cert_pkey_st {
- X509 *x509;
- EVP_PKEY *privatekey;
- /* Chain for this certificate */
- STACK_OF(X509) *chain;
-} CERT_PKEY;
-
/* Structure containing decoded values of signature algorithms extension */
typedef struct tls_sigalgs_st {
uint8_t rsign;
@@ -530,10 +514,10 @@
} TLS_SIGALGS;
typedef struct cert_st {
- /* Current active set */
- CERT_PKEY *key; /* ALWAYS points to an element of the pkeys array
- * Probably it would make more sense to store
- * an index, not a pointer. */
+ X509 *x509;
+ EVP_PKEY *privatekey;
+ /* Chain for this certificate */
+ STACK_OF(X509) *chain;
/* key_method, if non-NULL, is a set of callbacks to call for private key
* operations. */
@@ -562,7 +546,6 @@
* keys. If NULL, a curve is selected automatically. See
* |SSL_CTX_set_tmp_ecdh_callback|. */
EC_KEY *(*ecdh_tmp_cb)(SSL *ssl, int is_export, int keysize);
- CERT_PKEY pkeys[SSL_PKEY_NUM];
/* Server-only: client_certificate_types is list of certificate types to
* include in the CertificateRequest message.
@@ -845,21 +828,18 @@
STACK_OF(SSL_CIPHER) *ciphers);
struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *s);
-int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain);
-int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain);
-int ssl_cert_add0_chain_cert(CERT *c, X509 *x);
-int ssl_cert_add1_chain_cert(CERT *c, X509 *x);
-int ssl_cert_select_current(CERT *c, X509 *x);
-void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg);
+int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain);
+int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain);
+int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509);
+int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509);
+void ssl_cert_set_cert_cb(CERT *cert,
+ int (*cb)(SSL *ssl, void *arg), void *arg);
int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk);
-int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l);
+int ssl_add_cert_chain(SSL *s, unsigned long *l);
int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags);
int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref);
-CERT_PKEY *ssl_get_server_send_pkey(const SSL *s);
-EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *c);
void ssl_update_cache(SSL *s, int mode);
-int ssl_cert_type(EVP_PKEY *pkey);
/* ssl_get_compatible_server_ciphers determines the key exchange and
* authentication cipher suite masks compatible with the server configuration
@@ -918,7 +898,7 @@
int ssl3_cert_verify_mac(SSL *s, int md_nid, uint8_t *p);
int ssl3_finish_mac(SSL *s, const uint8_t *buf, int len);
void ssl3_free_digest_list(SSL *s);
-int ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk);
+int ssl3_output_cert_chain(SSL *s);
const SSL_CIPHER *ssl3_choose_cipher(
SSL *ssl, STACK_OF(SSL_CIPHER) *clnt,
struct ssl_cipher_preference_list_st *srvr);
@@ -1112,8 +1092,10 @@
size_t ticket_len, const uint8_t *session_id,
size_t session_id_len);
-int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_PKEY *pk,
- const EVP_MD *md);
+/* tls12_get_sigandhash assembles the SignatureAndHashAlgorithm corresponding to
+ * |ssl|'s private key and |md|. The two-byte value is written to |p|. It
+ * returns one on success and zero on failure. */
+int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md);
int tls12_get_sigid(int pkey_type);
const EVP_MD *tls12_get_hash(uint8_t hash_alg);
@@ -1178,9 +1160,9 @@
uint32_t ssl_get_algorithm2(SSL *s);
int tls1_process_sigalgs(SSL *s, const CBS *sigalgs);
-/* tls1_choose_signing_digest returns a digest for use with |pkey| based on the
- * peer's preferences recorded for |s| and the digests supported by |pkey|. */
-const EVP_MD *tls1_choose_signing_digest(SSL *s, EVP_PKEY *pkey);
+/* tls1_choose_signing_digest returns a digest for use with |ssl|'s private key
+ * based on the peer's preferences the digests supported. */
+const EVP_MD *tls1_choose_signing_digest(SSL *ssl);
size_t tls12_get_psigalgs(SSL *s, const uint8_t **psigs);
int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s,
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 4bbf1c2..017bda4 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -301,17 +301,11 @@
return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
}
-int ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk) {
+int ssl3_output_cert_chain(SSL *s) {
uint8_t *p;
unsigned long l = 3 + SSL_HM_HEADER_LENGTH(s);
- if (cpk == NULL) {
- /* TLSv1 sends a chain with nothing in it, instead of an alert. */
- if (!BUF_MEM_grow_clean(s->init_buf, l)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_output_cert_chain, ERR_R_BUF_LIB);
- return 0;
- }
- } else if (!ssl_add_cert_chain(s, cpk, &l)) {
+ if (!ssl_add_cert_chain(s, &l)) {
return 0;
}
@@ -502,17 +496,6 @@
return 1;
}
-int ssl_cert_type(EVP_PKEY *pkey) {
- switch (pkey->type) {
- case EVP_PKEY_RSA:
- return SSL_PKEY_RSA;
- case EVP_PKEY_EC:
- return SSL_PKEY_ECC;
- default:
- return -1;
- }
-}
-
int ssl_verify_alarm_type(long type) {
int al;
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 40df103..d004f2b 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -930,15 +930,9 @@
}
/* Check the certificate's type matches the cipher. */
- int cert_type = ssl_cert_type(pkey);
- if (cert_type < 0) {
- OPENSSL_PUT_ERROR(SSL, ssl3_check_certificate_for_cipher,
- SSL_R_UNKNOWN_CERTIFICATE_TYPE);
- goto err;
- }
- int expected_type = ssl_cipher_get_cert_index(cipher);
- assert(expected_type >= 0);
- if (cert_type != expected_type) {
+ int expected_type = ssl_cipher_get_key_type(cipher);
+ assert(expected_type != EVP_PKEY_NONE);
+ if (pkey->type != expected_type) {
OPENSSL_PUT_ERROR(SSL, ssl3_check_certificate_for_cipher,
SSL_R_WRONG_CERTIFICATE_TYPE);
goto err;
@@ -2020,8 +2014,7 @@
uint8_t *p = ssl_handshake_start(s);
size_t signature_length = 0;
unsigned long n = 0;
- EVP_PKEY *pkey = s->cert->key->privatekey;
- assert(pkey != NULL || s->cert->key_method != NULL);
+ assert(s->cert->privatekey != NULL || s->cert->key_method != NULL);
if (s->state == SSL3_ST_CW_CERT_VRFY_A) {
uint8_t *buf = (uint8_t *)s->init_buf->data;
@@ -2031,8 +2024,8 @@
/* Write out the digest type if need be. */
if (SSL_USE_SIGALGS(s)) {
- md = tls1_choose_signing_digest(s, pkey);
- if (!tls12_get_sigandhash(s, p, pkey, md)) {
+ md = tls1_choose_signing_digest(s);
+ if (!tls12_get_sigandhash(s, p, md)) {
OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_INTERNAL_ERROR);
return -1;
}
@@ -2041,7 +2034,7 @@
}
/* Compute the digest. */
- const int pkey_type = ssl_private_key_type(s, pkey);
+ const int pkey_type = ssl_private_key_type(s);
if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey_type)) {
return -1;
}
@@ -2053,7 +2046,7 @@
}
/* Sign the digest. */
- signature_length = ssl_private_key_max_signature_len(s, pkey);
+ signature_length = ssl_private_key_max_signature_len(s);
if (p + 2 + signature_length > buf + SSL3_RT_MAX_PLAIN_LENGTH) {
OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify,
SSL_R_DATA_LENGTH_TOO_LONG);
@@ -2061,7 +2054,7 @@
}
s->rwstate = SSL_PRIVATE_KEY_OPERATION;
- sign_result = ssl_private_key_sign(s, pkey, &p[2], &signature_length,
+ sign_result = ssl_private_key_sign(s, &p[2], &signature_length,
signature_length, md, digest,
digest_length);
} else {
@@ -2070,7 +2063,7 @@
p += 2;
n += 2;
}
- signature_length = ssl_private_key_max_signature_len(s, pkey);
+ signature_length = ssl_private_key_max_signature_len(s);
s->rwstate = SSL_PRIVATE_KEY_OPERATION;
sign_result = ssl_private_key_sign_complete(s, &p[2], &signature_length,
signature_length);
@@ -2098,9 +2091,9 @@
/* ssl3_has_client_certificate returns true if a client certificate is
* configured. */
-static int ssl3_has_client_certificate(SSL *s) {
- return s->cert && s->cert->key->x509 && (s->cert->key->privatekey ||
- s->cert->key_method);
+static int ssl3_has_client_certificate(SSL *ssl) {
+ return ssl->cert && ssl->cert->x509 && (ssl->cert->privatekey ||
+ ssl->cert->key_method);
}
int ssl3_send_client_certificate(SSL *s) {
@@ -2179,8 +2172,14 @@
}
if (s->state == SSL3_ST_CW_CERT_C) {
- CERT_PKEY *cert_pkey = (s->s3->tmp.cert_req == 2) ? NULL : s->cert->key;
- if (!ssl3_output_cert_chain(s, cert_pkey)) {
+ if (s->s3->tmp.cert_req == 2) {
+ /* Send an empty Certificate message. */
+ uint8_t *p = ssl_handshake_start(s);
+ l2n3(0, p);
+ if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, 3)) {
+ return -1;
+ }
+ } else if (!ssl3_output_cert_chain(s)) {
return -1;
}
s->state = SSL3_ST_CW_CERT_D;
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 0f685e7..c4e0704 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -390,12 +390,12 @@
}
case SSL_CTRL_GET_CHAIN_CERTS:
- *(STACK_OF(X509) **)parg = s->cert->key->chain;
+ *(STACK_OF(X509) **)parg = s->cert->chain;
ret = 1;
break;
case SSL_CTRL_SELECT_CURRENT_CERT:
- return ssl_cert_select_current(s->cert, (X509 *)parg);
+ return 1;
case SSL_CTRL_GET_CURVES: {
const uint16_t *clist = s->s3->tmp.peer_ellipticcurvelist;
@@ -493,26 +493,16 @@
return ssl_cert_set_cert_store(ctx->cert, parg, 1, larg);
case SSL_CTRL_EXTRA_CHAIN_CERT:
- if (ctx->extra_certs == NULL) {
- ctx->extra_certs = sk_X509_new_null();
- if (ctx->extra_certs == NULL) {
- return 0;
- }
- }
- sk_X509_push(ctx->extra_certs, (X509 *)parg);
- break;
+ return ssl_cert_add0_chain_cert(ctx->cert, (X509 *)parg);
case SSL_CTRL_GET_EXTRA_CHAIN_CERTS:
- if (ctx->extra_certs == NULL) {
- *(STACK_OF(X509) **)parg = ctx->cert->key->chain;
- } else {
- *(STACK_OF(X509) **)parg = ctx->extra_certs;
- }
+ case SSL_CTRL_GET_CHAIN_CERTS:
+ *(STACK_OF(X509) **)parg = ctx->cert->chain;
break;
case SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS:
- sk_X509_pop_free(ctx->extra_certs, X509_free);
- ctx->extra_certs = NULL;
+ sk_X509_pop_free(ctx->cert->chain, X509_free);
+ ctx->cert->chain = NULL;
break;
case SSL_CTRL_CHAIN:
@@ -529,12 +519,8 @@
return ssl_cert_add0_chain_cert(ctx->cert, (X509 *)parg);
}
- case SSL_CTRL_GET_CHAIN_CERTS:
- *(STACK_OF(X509) **)parg = ctx->cert->key->chain;
- break;
-
case SSL_CTRL_SELECT_CURRENT_CERT:
- return ssl_cert_select_current(ctx->cert, (X509 *)parg);
+ return 1;
default:
return 0;
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 3130a3f..ceab0ae 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -1418,7 +1418,7 @@
}
if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
- pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher);
+ pkey = s->cert->privatekey;
if (pkey == NULL) {
al = SSL_AD_DECODE_ERROR;
goto f_err;
@@ -1478,8 +1478,8 @@
/* Determine signature algorithm. */
if (SSL_USE_SIGALGS(s)) {
- md = tls1_choose_signing_digest(s, pkey);
- if (!tls12_get_sigandhash(s, p, pkey, md)) {
+ md = tls1_choose_signing_digest(s);
+ if (!tls12_get_sigandhash(s, p, md)) {
/* Should never happen */
al = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange,
@@ -1692,7 +1692,7 @@
uint8_t good;
size_t rsa_size, decrypt_len, premaster_index, j;
- pkey = s->cert->pkeys[SSL_PKEY_RSA].privatekey;
+ pkey = s->cert->privatekey;
if (pkey == NULL || pkey->type != EVP_PKEY_RSA || pkey->pkey.rsa == NULL) {
al = SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, ssl3_get_client_key_exchange,
@@ -2291,17 +2291,8 @@
}
int ssl3_send_server_certificate(SSL *s) {
- CERT_PKEY *cpk;
-
if (s->state == SSL3_ST_SW_CERT_A) {
- cpk = ssl_get_server_send_pkey(s);
- if (cpk == NULL) {
- OPENSSL_PUT_ERROR(SSL, ssl3_send_server_certificate,
- ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (!ssl3_output_cert_chain(s, cpk)) {
+ if (!ssl3_output_cert_chain(s)) {
return 0;
}
s->state = SSL3_ST_SW_CERT_B;
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index a442ec3..a389cc4 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -149,34 +149,24 @@
}
CERT *ssl_cert_new(void) {
- CERT *ret;
-
- ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
+ CERT *ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
if (ret == NULL) {
OPENSSL_PUT_ERROR(SSL, ssl_cert_new, ERR_R_MALLOC_FAILURE);
return NULL;
}
memset(ret, 0, sizeof(CERT));
- ret->key = &ret->pkeys[SSL_PKEY_RSA];
return ret;
}
CERT *ssl_cert_dup(CERT *cert) {
- CERT *ret;
- int i;
-
- ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
+ CERT *ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
if (ret == NULL) {
OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE);
return NULL;
}
memset(ret, 0, sizeof(CERT));
- ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]];
- /* or ret->key = ret->pkeys + (cert->key - cert->pkeys), if you find that
- * more readable */
-
ret->mask_k = cert->mask_k;
ret->mask_a = cert->mask_a;
@@ -208,23 +198,19 @@
ret->ecdh_nid = cert->ecdh_nid;
ret->ecdh_tmp_cb = cert->ecdh_tmp_cb;
- for (i = 0; i < SSL_PKEY_NUM; i++) {
- CERT_PKEY *cpk = cert->pkeys + i;
- CERT_PKEY *rpk = ret->pkeys + i;
- if (cpk->x509 != NULL) {
- rpk->x509 = X509_up_ref(cpk->x509);
- }
+ if (cert->x509 != NULL) {
+ ret->x509 = X509_up_ref(cert->x509);
+ }
- if (cpk->privatekey != NULL) {
- rpk->privatekey = EVP_PKEY_up_ref(cpk->privatekey);
- }
+ if (cert->privatekey != NULL) {
+ ret->privatekey = EVP_PKEY_up_ref(cert->privatekey);
+ }
- if (cpk->chain) {
- rpk->chain = X509_chain_up_ref(cpk->chain);
- if (!rpk->chain) {
- OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE);
- goto err;
- }
+ if (cert->chain) {
+ ret->chain = X509_chain_up_ref(cert->chain);
+ if (!ret->chain) {
+ OPENSSL_PUT_ERROR(SSL, ssl_cert_dup, ERR_R_MALLOC_FAILURE);
+ goto err;
}
}
@@ -277,27 +263,17 @@
}
/* Free up and clear all certificates and chains */
-void ssl_cert_clear_certs(CERT *c) {
- int i;
- if (c == NULL) {
+void ssl_cert_clear_certs(CERT *cert) {
+ if (cert == NULL) {
return;
}
- for (i = 0; i < SSL_PKEY_NUM; i++) {
- CERT_PKEY *cpk = c->pkeys + i;
- if (cpk->x509) {
- X509_free(cpk->x509);
- cpk->x509 = NULL;
- }
- if (cpk->privatekey) {
- EVP_PKEY_free(cpk->privatekey);
- cpk->privatekey = NULL;
- }
- if (cpk->chain) {
- sk_X509_pop_free(cpk->chain, X509_free);
- cpk->chain = NULL;
- }
- }
+ X509_free(cert->x509);
+ cert->x509 = NULL;
+ EVP_PKEY_free(cert->privatekey);
+ cert->privatekey = NULL;
+ sk_X509_pop_free(cert->chain, X509_free);
+ cert->chain = NULL;
}
void ssl_cert_free(CERT *c) {
@@ -319,28 +295,24 @@
OPENSSL_free(c);
}
-int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain) {
- CERT_PKEY *cpk = c->key;
- if (!cpk) {
- return 0;
- }
- sk_X509_pop_free(cpk->chain, X509_free);
- cpk->chain = chain;
+int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) {
+ sk_X509_pop_free(cert->chain, X509_free);
+ cert->chain = chain;
return 1;
}
-int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain) {
+int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) {
STACK_OF(X509) *dchain;
- if (!chain) {
- return ssl_cert_set0_chain(c, NULL);
+ if (chain == NULL) {
+ return ssl_cert_set0_chain(cert, NULL);
}
dchain = X509_chain_up_ref(chain);
- if (!dchain) {
+ if (dchain == NULL) {
return 0;
}
- if (!ssl_cert_set0_chain(c, dchain)) {
+ if (!ssl_cert_set0_chain(cert, dchain)) {
sk_X509_pop_free(dchain, X509_free);
return 0;
}
@@ -348,54 +320,26 @@
return 1;
}
-int ssl_cert_add0_chain_cert(CERT *c, X509 *x) {
- CERT_PKEY *cpk = c->key;
- if (!cpk) {
- return 0;
+int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) {
+ if (cert->chain == NULL) {
+ cert->chain = sk_X509_new_null();
}
-
- if (!cpk->chain) {
- cpk->chain = sk_X509_new_null();
- }
- if (!cpk->chain || !sk_X509_push(cpk->chain, x)) {
+ if (cert->chain == NULL || !sk_X509_push(cert->chain, x509)) {
return 0;
}
return 1;
}
-int ssl_cert_add1_chain_cert(CERT *c, X509 *x) {
- if (!ssl_cert_add0_chain_cert(c, x)) {
+int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) {
+ if (!ssl_cert_add0_chain_cert(cert, x509)) {
return 0;
}
- X509_up_ref(x);
+ X509_up_ref(x509);
return 1;
}
-int ssl_cert_select_current(CERT *c, X509 *x) {
- int i;
- if (x == NULL) {
- return 0;
- }
-
- for (i = 0; i < SSL_PKEY_NUM; i++) {
- if (c->pkeys[i].x509 == x) {
- c->key = &c->pkeys[i];
- return 1;
- }
- }
-
- for (i = 0; i < SSL_PKEY_NUM; i++) {
- if (c->pkeys[i].x509 && !X509_cmp(c->pkeys[i].x509, x)) {
- c->key = &c->pkeys[i];
- return 1;
- }
- }
-
- return 0;
-}
-
void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg) {
c->cert_cb = cb;
c->cert_cb_arg = arg;
@@ -789,13 +733,14 @@
}
/* Add certificate chain to internal SSL BUF_MEM structure. */
-int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) {
- BUF_MEM *buf = s->init_buf;
+int ssl_add_cert_chain(SSL *ssl, unsigned long *l) {
+ CERT *cert = ssl->cert;
+ BUF_MEM *buf = ssl->init_buf;
int no_chain = 0;
size_t i;
- X509 *x = cpk->x509;
- STACK_OF(X509) *extra_certs;
+ X509 *x = cert->x509;
+ STACK_OF(X509) *chain = cert->chain;
X509_STORE *chain_store;
if (x == NULL) {
@@ -803,20 +748,13 @@
return 0;
}
- if (s->cert->chain_store) {
- chain_store = s->cert->chain_store;
+ if (ssl->cert->chain_store) {
+ chain_store = ssl->cert->chain_store;
} else {
- chain_store = s->ctx->cert_store;
+ chain_store = ssl->ctx->cert_store;
}
- /* If we have a certificate specific chain use it, else use parent ctx. */
- if (cpk && cpk->chain) {
- extra_certs = cpk->chain;
- } else {
- extra_certs = s->ctx->extra_certs;
- }
-
- if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extra_certs) {
+ if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || chain != NULL) {
no_chain = 1;
}
@@ -825,8 +763,8 @@
return 0;
}
- for (i = 0; i < sk_X509_num(extra_certs); i++) {
- x = sk_X509_value(extra_certs, i);
+ for (i = 0; i < sk_X509_num(chain); i++) {
+ x = sk_X509_value(chain, i);
if (!ssl_add_cert_to_buf(buf, l, x)) {
return 0;
}
@@ -856,15 +794,14 @@
}
/* Build a certificate chain for current certificate */
-int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags) {
- CERT_PKEY *cpk = c->key;
+int ssl_build_cert_chain(CERT *cert, X509_STORE *chain_store, int flags) {
X509_STORE_CTX xs_ctx;
STACK_OF(X509) *chain = NULL, *untrusted = NULL;
X509 *x;
int i, rv = 0;
uint32_t error;
- if (!cpk->x509) {
+ if (cert->x509 == NULL) {
OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, SSL_R_NO_CERTIFICATE_SET);
goto err;
}
@@ -877,8 +814,8 @@
goto err;
}
- for (j = 0; j < sk_X509_num(cpk->chain); j++) {
- x = sk_X509_value(cpk->chain, j);
+ for (j = 0; j < sk_X509_num(cert->chain); j++) {
+ x = sk_X509_value(cert->chain, j);
if (!X509_STORE_add_cert(chain_store, x)) {
error = ERR_peek_last_error();
if (ERR_GET_LIB(error) != ERR_LIB_X509 ||
@@ -890,7 +827,7 @@
}
/* Add EE cert too: it might be self signed */
- if (!X509_STORE_add_cert(chain_store, cpk->x509)) {
+ if (!X509_STORE_add_cert(chain_store, cert->x509)) {
error = ERR_peek_last_error();
if (ERR_GET_LIB(error) != ERR_LIB_X509 ||
ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
@@ -899,16 +836,16 @@
ERR_clear_error();
}
} else {
- if (c->chain_store) {
- chain_store = c->chain_store;
+ if (cert->chain_store) {
+ chain_store = cert->chain_store;
}
if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED) {
- untrusted = cpk->chain;
+ untrusted = cert->chain;
}
}
- if (!X509_STORE_CTX_init(&xs_ctx, chain_store, cpk->x509, untrusted)) {
+ if (!X509_STORE_CTX_init(&xs_ctx, chain_store, cert->x509, untrusted)) {
OPENSSL_PUT_ERROR(SSL, ssl_build_cert_chain, ERR_R_X509_LIB);
goto err;
}
@@ -936,8 +873,8 @@
}
X509_STORE_CTX_cleanup(&xs_ctx);
- if (cpk->chain) {
- sk_X509_pop_free(cpk->chain, X509_free);
+ if (cert->chain) {
+ sk_X509_pop_free(cert->chain, X509_free);
}
/* Remove EE certificate from chain */
@@ -955,7 +892,7 @@
}
}
- cpk->chain = chain;
+ cert->chain = chain;
if (rv == 0) {
rv = 1;
}
diff --git a/ssl/ssl_cipher.c b/ssl/ssl_cipher.c
index 1a8c0b2..ca0807f 100644
--- a/ssl/ssl_cipher.c
+++ b/ssl/ssl_cipher.c
@@ -1676,16 +1676,16 @@
const char *SSL_COMP_get_name(const COMP_METHOD *comp) { return NULL; }
-int ssl_cipher_get_cert_index(const SSL_CIPHER *cipher) {
+int ssl_cipher_get_key_type(const SSL_CIPHER *cipher) {
uint32_t alg_a = cipher->algorithm_auth;
if (alg_a & SSL_aECDSA) {
- return SSL_PKEY_ECC;
+ return EVP_PKEY_EC;
} else if (alg_a & SSL_aRSA) {
- return SSL_PKEY_RSA;
+ return EVP_PKEY_RSA;
}
- return -1;
+ return EVP_PKEY_NONE;
}
int ssl_cipher_has_server_public_key(const SSL_CIPHER *cipher) {
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 0064b43..6a694b3 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -799,20 +799,19 @@
/* Fix this so it checks all the valid key/cert options */
int SSL_CTX_check_private_key(const SSL_CTX *ctx) {
- if (ctx == NULL || ctx->cert == NULL || ctx->cert->key->x509 == NULL) {
+ if (ctx == NULL || ctx->cert == NULL || ctx->cert->x509 == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_CTX_check_private_key,
SSL_R_NO_CERTIFICATE_ASSIGNED);
return 0;
}
- if (ctx->cert->key->privatekey == NULL) {
+ if (ctx->cert->privatekey == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_CTX_check_private_key,
SSL_R_NO_PRIVATE_KEY_ASSIGNED);
return 0;
}
- return X509_check_private_key(ctx->cert->key->x509,
- ctx->cert->key->privatekey);
+ return X509_check_private_key(ctx->cert->x509, ctx->cert->privatekey);
}
/* Fix this function so that it takes an optional type parameter */
@@ -828,20 +827,19 @@
return 0;
}
- if (ssl->cert->key->x509 == NULL) {
+ if (ssl->cert->x509 == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_check_private_key,
SSL_R_NO_CERTIFICATE_ASSIGNED);
return 0;
}
- if (ssl->cert->key->privatekey == NULL) {
+ if (ssl->cert->privatekey == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_check_private_key,
SSL_R_NO_PRIVATE_KEY_ASSIGNED);
return 0;
}
- return X509_check_private_key(ssl->cert->key->x509,
- ssl->cert->key->privatekey);
+ return X509_check_private_key(ssl->cert->x509, ssl->cert->privatekey);
}
int SSL_accept(SSL *s) {
@@ -1716,8 +1714,6 @@
CRYPTO_new_ex_data(&g_ex_data_class_ssl_ctx, ret, &ret->ex_data);
- ret->extra_certs = NULL;
-
ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
ret->tlsext_servername_callback = 0;
@@ -1781,7 +1777,6 @@
ssl_cipher_preference_list_free(ctx->cipher_list_tls11);
ssl_cert_free(ctx->cert);
sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free);
- sk_X509_pop_free(ctx->extra_certs, X509_free);
sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles);
OPENSSL_free(ctx->psk_identity_hint);
OPENSSL_free(ctx->tlsext_ecpointformatlist);
@@ -1827,17 +1822,12 @@
ssl_cert_set_cert_cb(s->cert, cb, arg);
}
-static int ssl_has_key(SSL *s, size_t idx) {
- CERT_PKEY *cpk = &s->cert->pkeys[idx];
- return cpk->x509 && cpk->privatekey;
-}
-
void ssl_get_compatible_server_ciphers(SSL *s, uint32_t *out_mask_k,
uint32_t *out_mask_a) {
CERT *c = s->cert;
- int have_rsa_cert, dh_tmp;
+ int have_rsa_cert = 0, dh_tmp;
uint32_t mask_k, mask_a;
- int have_ecc_cert, ecdsa_ok;
+ int have_ecc_cert = 0, ecdsa_ok;
X509 *x;
if (c == NULL) {
@@ -1849,8 +1839,13 @@
dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
- have_rsa_cert = ssl_has_key(s, SSL_PKEY_RSA);
- have_ecc_cert = ssl_has_key(s, SSL_PKEY_ECC);
+ if (s->cert->x509 != NULL && s->cert->privatekey != NULL) {
+ if (s->cert->privatekey->type == EVP_PKEY_RSA) {
+ have_rsa_cert = 1;
+ } else if (s->cert->privatekey->type == EVP_PKEY_EC) {
+ have_ecc_cert = 1;
+ }
+ }
mask_k = 0;
mask_a = 0;
@@ -1865,7 +1860,7 @@
/* An ECC certificate may be usable for ECDSA cipher suites depending on the
* key usage extension and on the client's curve preferences. */
if (have_ecc_cert) {
- x = c->pkeys[SSL_PKEY_ECC].x509;
+ x = c->x509;
/* This call populates extension flags (ex_flags). */
X509_check_purpose(x, -1, 0);
ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE)
@@ -1895,47 +1890,6 @@
*out_mask_a = mask_a;
}
-static int ssl_get_server_cert_index(const SSL *s) {
- int idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
- if (idx == -1) {
- OPENSSL_PUT_ERROR(SSL, ssl_get_server_cert_index, ERR_R_INTERNAL_ERROR);
- }
- return idx;
-}
-
-CERT_PKEY *ssl_get_server_send_pkey(const SSL *s) {
- int i = ssl_get_server_cert_index(s);
-
- /* This may or may not be an error. */
- if (i < 0) {
- return NULL;
- }
-
- /* May be NULL. */
- return &s->cert->pkeys[i];
-}
-
-EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *cipher) {
- uint32_t alg_a = cipher->algorithm_auth;
- CERT *c = s->cert;
- int idx = -1;
-
- if ((alg_a & SSL_aRSA) &&
- (c->pkeys[SSL_PKEY_RSA].privatekey != NULL)) {
- idx = SSL_PKEY_RSA;
- } else if ((alg_a & SSL_aECDSA) &&
- (c->pkeys[SSL_PKEY_ECC].privatekey != NULL)) {
- idx = SSL_PKEY_ECC;
- }
-
- if (idx == -1) {
- OPENSSL_PUT_ERROR(SSL, ssl_get_sign_pkey, ERR_R_INTERNAL_ERROR);
- return NULL;
- }
-
- return c->pkeys[idx].privatekey;
-}
-
void ssl_update_cache(SSL *s, int mode) {
/* Never cache sessions with empty session IDs. */
if (s->session->session_id_length == 0) {
@@ -2164,7 +2118,7 @@
X509 *SSL_get_certificate(const SSL *s) {
if (s->cert != NULL) {
- return s->cert->key->x509;
+ return s->cert->x509;
}
return NULL;
@@ -2172,7 +2126,7 @@
EVP_PKEY *SSL_get_privatekey(const SSL *s) {
if (s->cert != NULL) {
- return s->cert->key->privatekey;
+ return s->cert->privatekey;
}
return NULL;
@@ -2180,7 +2134,7 @@
X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) {
if (ctx->cert != NULL) {
- return ctx->cert->key->x509;
+ return ctx->cert->x509;
}
return NULL;
@@ -2188,7 +2142,7 @@
EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) {
if (ctx->cert != NULL) {
- return ctx->cert->key->privatekey;
+ return ctx->cert->privatekey;
}
return NULL;
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index b95b231..8432455 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -69,6 +69,10 @@
static int ssl_set_cert(CERT *c, X509 *x509);
static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey);
+static int is_key_type_supported(int key_type) {
+ return key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_EC;
+}
+
int SSL_use_certificate(SSL *ssl, X509 *x) {
if (x == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_use_certificate, ERR_R_PASSED_NULL_PARAMETER);
@@ -160,28 +164,24 @@
}
static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) {
- int i;
-
- i = ssl_cert_type(pkey);
- if (i < 0) {
+ if (!is_key_type_supported(pkey->type)) {
OPENSSL_PUT_ERROR(SSL, ssl_set_pkey, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
return 0;
}
- if (c->pkeys[i].x509 != NULL) {
+ if (c->x509 != NULL) {
/* Sanity-check that the private key and the certificate match, unless the
* key is opaque (in case of, say, a smartcard). */
if (!EVP_PKEY_is_opaque(pkey) &&
- !X509_check_private_key(c->pkeys[i].x509, pkey)) {
- X509_free(c->pkeys[i].x509);
- c->pkeys[i].x509 = NULL;
+ !X509_check_private_key(c->x509, pkey)) {
+ X509_free(c->x509);
+ c->x509 = NULL;
return 0;
}
}
- EVP_PKEY_free(c->pkeys[i].privatekey);
- c->pkeys[i].privatekey = EVP_PKEY_up_ref(pkey);
- c->key = &(c->pkeys[i]);
+ EVP_PKEY_free(c->privatekey);
+ c->privatekey = EVP_PKEY_up_ref(pkey);
return 1;
}
@@ -324,32 +324,28 @@
}
static int ssl_set_cert(CERT *c, X509 *x) {
- EVP_PKEY *pkey;
- int i;
-
- pkey = X509_get_pubkey(x);
+ EVP_PKEY *pkey = X509_get_pubkey(x);
if (pkey == NULL) {
OPENSSL_PUT_ERROR(SSL, ssl_set_cert, SSL_R_X509_LIB);
return 0;
}
- i = ssl_cert_type(pkey);
- if (i < 0) {
+ if (!is_key_type_supported(pkey->type)) {
OPENSSL_PUT_ERROR(SSL, ssl_set_cert, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
EVP_PKEY_free(pkey);
return 0;
}
- if (c->pkeys[i].privatekey != NULL) {
+ if (c->privatekey != NULL) {
/* Sanity-check that the private key and the certificate match, unless the
* key is opaque (in case of, say, a smartcard). */
- if (!EVP_PKEY_is_opaque(c->pkeys[i].privatekey) &&
- !X509_check_private_key(x, c->pkeys[i].privatekey)) {
+ if (!EVP_PKEY_is_opaque(c->privatekey) &&
+ !X509_check_private_key(x, c->privatekey)) {
/* don't fail for a cert/key mismatch, just free current private key
* (when switching to a different cert & key, first this function should
* be used, then ssl_set_pkey */
- EVP_PKEY_free(c->pkeys[i].privatekey);
- c->pkeys[i].privatekey = NULL;
+ EVP_PKEY_free(c->privatekey);
+ c->privatekey = NULL;
/* clear error queue */
ERR_clear_error();
}
@@ -357,9 +353,8 @@
EVP_PKEY_free(pkey);
- X509_free(c->pkeys[i].x509);
- c->pkeys[i].x509 = X509_up_ref(x);
- c->key = &(c->pkeys[i]);
+ X509_free(c->x509);
+ c->x509 = X509_up_ref(x);
return 1;
}
@@ -650,38 +645,37 @@
ssl->cert->key_method = key_method;
}
-int ssl_private_key_type(SSL *ssl, const EVP_PKEY *pkey) {
+int ssl_private_key_type(SSL *ssl) {
if (ssl->cert->key_method != NULL) {
return ssl->cert->key_method->type(ssl);
}
- return EVP_PKEY_id(pkey);
+ return EVP_PKEY_id(ssl->cert->privatekey);
}
-int ssl_private_key_supports_digest(SSL *ssl, const EVP_PKEY *pkey,
- const EVP_MD *md) {
+int ssl_private_key_supports_digest(SSL *ssl, const EVP_MD *md) {
if (ssl->cert->key_method != NULL) {
return ssl->cert->key_method->supports_digest(ssl, md);
}
- return EVP_PKEY_supports_digest(pkey, md);
+ return EVP_PKEY_supports_digest(ssl->cert->privatekey, md);
}
-size_t ssl_private_key_max_signature_len(SSL *ssl, const EVP_PKEY *pkey) {
+size_t ssl_private_key_max_signature_len(SSL *ssl) {
if (ssl->cert->key_method != NULL) {
return ssl->cert->key_method->max_signature_len(ssl);
}
- return EVP_PKEY_size(pkey);
+ return EVP_PKEY_size(ssl->cert->privatekey);
}
enum ssl_private_key_result_t ssl_private_key_sign(
- SSL *ssl, EVP_PKEY *pkey, uint8_t *out, size_t *out_len, size_t max_out,
- const EVP_MD *md, const uint8_t *in, size_t in_len) {
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md,
+ const uint8_t *in, size_t in_len) {
if (ssl->cert->key_method != NULL) {
return ssl->cert->key_method->sign(ssl, out, out_len, max_out, md, in,
in_len);
}
enum ssl_private_key_result_t ret = ssl_private_key_failure;
- EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL);
if (ctx == NULL) {
goto end;
}
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index e867e35..7daa864 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -2438,8 +2438,7 @@
sizeof(tls12_sig) / sizeof(tls12_lookup));
}
-int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_PKEY *pk,
- const EVP_MD *md) {
+int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md) {
int sig_id, md_id;
if (!md) {
@@ -2452,7 +2451,7 @@
return 0;
}
- sig_id = tls12_get_sigid(ssl_private_key_type(ssl, pk));
+ sig_id = tls12_get_sigid(ssl_private_key_type(ssl));
if (sig_id == -1) {
return 0;
}
@@ -2602,17 +2601,17 @@
return 1;
}
-const EVP_MD *tls1_choose_signing_digest(SSL *s, EVP_PKEY *pkey) {
- CERT *c = s->cert;
- int type = ssl_private_key_type(s, pkey);
+const EVP_MD *tls1_choose_signing_digest(SSL *ssl) {
+ CERT *cert = ssl->cert;
+ int type = ssl_private_key_type(ssl);
size_t i;
/* Select the first shared digest supported by our key. */
- for (i = 0; i < c->shared_sigalgslen; i++) {
- const EVP_MD *md = tls12_get_hash(c->shared_sigalgs[i].rhash);
+ for (i = 0; i < cert->shared_sigalgslen; i++) {
+ const EVP_MD *md = tls12_get_hash(cert->shared_sigalgs[i].rhash);
if (md == NULL ||
- tls12_get_pkey_type(c->shared_sigalgs[i].rsign) != type ||
- !ssl_private_key_supports_digest(s, pkey, md)) {
+ tls12_get_pkey_type(cert->shared_sigalgs[i].rsign) != type ||
+ !ssl_private_key_supports_digest(ssl, md)) {
continue;
}
return md;