Przeglądaj źródła

Hold certificates in an SSL_SESSION as CRYPTO_BUFFERSs as well.

This change adds a STACK_OF(CRYPTO_BUFFER) to an SSL_SESSION which
contains the raw form of the received certificates. The X509-based
members still exist, but their |enc| buffer will alias the
CRYPTO_BUFFERs.

The serialisation format of SSL_SESSIONs is also changed, in a backwards
compatible way. Previously, some sessions would duplicate the leaf
certificate in the certificate chain. These sessions can still be read,
but will be written in a way incompatible with older versions of the
code. This should be fine because the situation where multiple versions
exchange serialised sessions is at the server, and the server doesn't
duplicate the leaf certifiate in the chain anyway.

Change-Id: Id3b75d24f1745795315cb7f8089a4ee4263fa938
Reviewed-on: https://boringssl-review.googlesource.com/12163
Reviewed-by: Adam Langley <alangley@gmail.com>
kris/onging/CECPQ3_patch15
Adam Langley 8 lat temu
committed by Adam Langley
rodzic
commit
e8509090cf
10 zmienionych plików z 434 dodań i 104 usunięć
  1. +11
    -0
      include/openssl/ssl.h
  2. +8
    -3
      ssl/handshake_client.c
  3. +11
    -7
      ssl/handshake_server.c
  4. +22
    -10
      ssl/internal.h
  5. +104
    -34
      ssl/ssl_asn1.c
  6. +27
    -30
      ssl/ssl_cert.c
  7. +70
    -0
      ssl/ssl_session.c
  8. +153
    -2
      ssl/ssl_test.cc
  9. +27
    -18
      ssl/tls13_both.c
  10. +1
    -0
      ssl/tls13_server.c

+ 11
- 0
include/openssl/ssl.h Wyświetl plik

@@ -149,6 +149,7 @@
#include <openssl/hmac.h>
#include <openssl/lhash.h>
#include <openssl/pem.h>
#include <openssl/pool.h>
#include <openssl/ssl3.h>
#include <openssl/thread.h>
#include <openssl/tls1.h>
@@ -3706,6 +3707,11 @@ struct ssl_session_st {
uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH];

char *psk_identity;

/* certs contains the certificate chain from the peer, starting with the leaf
* certificate. */
STACK_OF(CRYPTO_BUFFER) *certs;

/* x509_peer is the peer's certificate. */
X509 *x509_peer;

@@ -3772,6 +3778,11 @@ struct ssl_session_st {

/* ticket_age_add_valid is non-zero if |ticket_age_add| is valid. */
unsigned ticket_age_add_valid:1;

/* x509_chain_should_include_leaf is true if the |STACK_OF(X509)| certificate
* chain should include the leaf certificate. Due to history, this is false
* for server sessions and true for client sessions. */
unsigned x509_chain_should_include_leaf:1;
};

/* ssl_cipher_preference_list_st contains a list of SSL_CIPHERs with


+ 8
- 3
ssl/handshake_client.c Wyświetl plik

@@ -1041,14 +1041,15 @@ static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) {

CBS cbs;
CBS_init(&cbs, ssl->init_msg, ssl->init_num);
STACK_OF(CRYPTO_BUFFER) *buffers = NULL;
STACK_OF(X509) *chain = NULL;
uint8_t alert;
STACK_OF(X509) *chain = ssl_parse_cert_chain(ssl, &alert, NULL, &cbs);
if (chain == NULL) {
if (!ssl_parse_cert_chain(ssl, &buffers, &chain, &alert, NULL, &cbs)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
goto err;
}

if (sk_X509_num(chain) == 0 || CBS_len(&cbs) != 0) {
if (sk_CRYPTO_BUFFER_num(buffers) == 0 || CBS_len(&cbs) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
goto err;
@@ -1062,8 +1063,11 @@ static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) {

/* NOTE: Unlike the server half, the client's copy of |x509_chain| includes
* the leaf. */
sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
ssl->s3->new_session->certs = buffers;
sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
ssl->s3->new_session->x509_chain = chain;
ssl->s3->new_session->x509_chain_should_include_leaf = 1;

X509_free(ssl->s3->new_session->x509_peer);
X509_up_ref(leaf);
@@ -1072,6 +1076,7 @@ static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) {
return 1;

err:
sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
sk_X509_pop_free(chain, X509_free);
return -1;
}


+ 11
- 7
ssl/handshake_server.c Wyświetl plik

@@ -1475,13 +1475,14 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) {

CBS certificate_msg;
CBS_init(&certificate_msg, ssl->init_msg, ssl->init_num);
STACK_OF(CRYPTO_BUFFER) *buffers = NULL;
STACK_OF(X509) *chain = NULL;
uint8_t alert;
STACK_OF(X509) *chain = ssl_parse_cert_chain(
ssl, &alert, ssl->retain_only_sha256_of_client_certs
? ssl->s3->new_session->peer_sha256
: NULL,
&certificate_msg);
if (chain == NULL) {
if (!ssl_parse_cert_chain(ssl, &buffers, &chain, &alert,
ssl->retain_only_sha256_of_client_certs
? ssl->s3->new_session->peer_sha256
: NULL,
&certificate_msg)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
goto err;
}
@@ -1492,7 +1493,7 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) {
goto err;
}

if (sk_X509_num(chain) == 0) {
if (sk_CRYPTO_BUFFER_num(buffers) == 0) {
/* No client certificate so the handshake buffer may be discarded. */
ssl3_free_handshake_buffer(ssl);

@@ -1533,10 +1534,13 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) {
ssl->s3->new_session->x509_chain = chain;
/* Inconsistency alert: x509_chain does *not* include the peer's own
* certificate, while we do include it in s3_clnt.c */
sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
ssl->s3->new_session->certs = buffers;

return 1;

err:
sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
sk_X509_pop_free(chain, X509_free);
return -1;
}


+ 22
- 10
ssl/internal.h Wyświetl plik

@@ -748,18 +748,30 @@ void ssl_write_buffer_clear(SSL *ssl);
* configured and zero otherwise. */
int ssl_has_certificate(const SSL *ssl);

/* ssl_parse_x509 parses a X509 certificate from |cbs|. It returns NULL
* on error. */
X509 *ssl_parse_x509(CBS *cbs);
/* x509_chain_from_buffers parses a number of X.509 certificates from |buffers|
* and sets |*out| to a corresponding stack of |X509*|. It returns one on
* success or zero on error. */
int x509_chain_from_buffers(STACK_OF(X509) **out,
STACK_OF(CRYPTO_BUFFER) *buffers);

/* ssl_session_set_x509_peer sets |sess->x509_peer| to the first element of
* |sess->x509_chain| and copies |chain_should_include_leaf| to
* |sess->x509_chain_should_include_leaf|. If |chain_should_include_leaf| is
* true then |x509_peer| is a additional reference to the first element of the
* chain. Otherwise the first element of the chain is removed and |x509_peer|
* is the only reference to it. */
void ssl_session_set_x509_peer(SSL_SESSION *sess,
int chain_should_include_leaf);

/* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used
* by a TLS Certificate message. On success, it returns a newly-allocated
* |X509| list and advances |cbs|. Otherwise, it returns NULL and sets
* |*out_alert| to an alert to send to the peer. If the list is non-empty and
* |out_leaf_sha256| is non-NULL, it writes the SHA-256 hash of the leaf to
* |out_leaf_sha256|. */
STACK_OF(X509) *ssl_parse_cert_chain(SSL *ssl, uint8_t *out_alert,
uint8_t *out_leaf_sha256, CBS *cbs);
* by a TLS Certificate message. On success, it returns newly-allocated
* |CRYPTO_BUFFER| and |X509| lists, advances |cbs| and returns one. Otherwise,
* it returns zero and sets |*out_alert| to an alert to send to the peer. If
* the list is non-empty and |out_leaf_sha256| is non-NULL, it writes the
* SHA-256 hash of the leaf to |out_leaf_sha256|. */
int ssl_parse_cert_chain(SSL *ssl, STACK_OF(CRYPTO_BUFFER) **out_buffers,
STACK_OF(X509) **out_x509s, uint8_t *out_alert,
uint8_t *out_leaf_sha256, CBS *cbs);

/* ssl_add_cert_to_cbb adds |x509| to |cbb|. It returns one on success and zero
* on error. */


+ 104
- 34
ssl/ssl_asn1.c Wyświetl plik

@@ -122,6 +122,7 @@
* keyExchangeInfo [18] INTEGER OPTIONAL,
* certChain [19] SEQUENCE OF Certificate OPTIONAL,
* ticketAgeAdd [21] OCTET STRING OPTIONAL,
* x509ChainIncludeLeaf [22] BOOLEAN OPTIONAL,
* }
*
* Note: historically this serialization has included other optional
@@ -132,7 +133,16 @@
* compressionMethod [11] OCTET STRING OPTIONAL,
* srpUsername [12] OCTET STRING OPTIONAL,
* ticketFlags [20] INTEGER OPTIONAL,
*/
*
*
* When serialising, the first element of |certChain| does not duplicate the
* contents of |peer|, but that was not always true. When parsing, the returned
* |x509_chain| sometimes needs to contain the leaf certificate at the
* beginning (clients) and sometimes not (servers). The |x509ChainIncludeLeaf|
* value specifies whether this duplication should be done for the in-memory
* representation. If not given, the parsing code looks to see whether the
* first cert in |certChain| matches the |peer| and assumes that it's parsing
* old session data and thus that |x509ChainIncludeLeaf| should be true. */

static const unsigned kVersion = 1;

@@ -170,6 +180,8 @@ static const int kCertChainTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19;
static const int kTicketAgeAddTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 21;
static const int kX509ChainIncludeLeafTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 22;

static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
size_t *out_len, int for_ticket) {
@@ -218,16 +230,14 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
goto err;
}

/* The peer certificate is only serialized if the SHA-256 isn't
* serialized instead. */
if (in->x509_peer && !in->peer_sha256_valid) {
if (!CBB_add_asn1(&session, &child, kPeerTag)) {
if (sk_CRYPTO_BUFFER_num(in->certs) > 0 && !in->peer_sha256_valid) {
const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, 0);
if (!CBB_add_asn1(&session, &child, kPeerTag) ||
!CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
CRYPTO_BUFFER_len(buffer))) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!ssl_add_cert_to_cbb(&child, in->x509_peer)) {
goto err;
}
}

/* Although it is OPTIONAL and usually empty, OpenSSL has
@@ -340,13 +350,18 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,

/* The certificate chain is only serialized if the leaf's SHA-256 isn't
* serialized instead. */
if (in->x509_chain != NULL && !in->peer_sha256_valid) {
if (in->certs != NULL &&
!in->peer_sha256_valid &&
sk_CRYPTO_BUFFER_num(in->certs) > 1) {
if (!CBB_add_asn1(&session, &child, kCertChainTag)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
for (size_t i = 0; i < sk_X509_num(in->x509_chain); i++) {
if (!ssl_add_cert_to_cbb(&child, sk_X509_value(in->x509_chain, i))) {
for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(in->certs); i++) {
const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, i);
if (!CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
CRYPTO_BUFFER_len(buffer))) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
@@ -361,6 +376,15 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
}
}

if (in->x509_chain_should_include_leaf) {
if (!CBB_add_asn1(&session, &child, kX509ChainIncludeLeafTag) ||
!CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
!CBB_add_u8(&child2, 0xff)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}

if (!CBB_finish(&cbb, out_data, out_len)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
@@ -572,22 +596,12 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {

CBS peer;
int has_peer;
if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag)) {
if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) ||
(has_peer && CBS_len(&peer) == 0)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
X509_free(ret->x509_peer);
ret->x509_peer = NULL;
if (has_peer) {
ret->x509_peer = ssl_parse_x509(&peer);
if (ret->x509_peer == NULL) {
goto err;
}
if (CBS_len(&peer) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
}
/* |peer| is processed with the certificate chain. */

if (!SSL_SESSION_parse_bounded_octet_string(
&session, ret->sid_ctx, &ret->sid_ctx_length, sizeof(ret->sid_ctx),
@@ -650,28 +664,70 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
}

CBS cert_chain;
CBS_init(&cert_chain, NULL, 0);
int has_cert_chain;
if (!CBS_get_optional_asn1(&session, &cert_chain, &has_cert_chain,
kCertChainTag)) {
kCertChainTag) ||
(has_cert_chain && CBS_len(&cert_chain) == 0)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
sk_X509_pop_free(ret->x509_chain, X509_free);
ret->x509_chain = NULL;
if (has_cert_chain) {
ret->x509_chain = sk_X509_new_null();
if (ret->x509_chain == NULL) {
sk_CRYPTO_BUFFER_pop_free(ret->certs, CRYPTO_BUFFER_free);
ret->certs = NULL;

int x509_chain_should_include_leaf_default = 0;

if (has_peer || has_cert_chain) {
ret->certs = sk_CRYPTO_BUFFER_new_null();
if (ret->certs == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}

if (has_peer) {
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, NULL);
if (buffer == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}

if (!sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
CRYPTO_BUFFER_free(buffer);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}

size_t chain_i = 0;
while (CBS_len(&cert_chain) > 0) {
X509 *x509 = ssl_parse_x509(&cert_chain);
if (x509 == NULL) {
chain_i++;

CBS cert;
if (!CBS_get_any_asn1_element(&cert_chain, &cert, NULL, NULL) ||
CBS_len(&cert) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}

if (has_peer && chain_i == 1) {
/* If a certificate was parsed from |peer| then it may, or may not, be
* duplicated as the first element of |cert_chain|. */
if (CBS_len(&peer) == CBS_len(&cert) &&
memcmp(CBS_data(&peer), CBS_data(&cert), CBS_len(&peer)) == 0) {
x509_chain_should_include_leaf_default = 1;
continue;
}
}

CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, NULL);
if (buffer == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!sk_X509_push(ret->x509_chain, x509)) {

if (!sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
CRYPTO_BUFFER_free(buffer);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
X509_free(x509);
goto err;
}
}
@@ -688,11 +744,25 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
}
ret->ticket_age_add_valid = age_add_present;

int x509_chain_should_include_leaf;
if (!CBS_get_optional_asn1_bool(&session, &x509_chain_should_include_leaf,
kX509ChainIncludeLeafTag,
x509_chain_should_include_leaf_default)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}

if (CBS_len(&session) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}

if (!x509_chain_from_buffers(&ret->x509_chain, ret->certs)) {
goto err;
}

ssl_session_set_x509_peer(ret, x509_chain_should_include_leaf);

return ret;

err:


+ 27
- 30
ssl/ssl_cert.c Wyświetl plik

@@ -448,30 +448,18 @@ int ssl_has_certificate(const SSL *ssl) {
return ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl);
}

X509 *ssl_parse_x509(CBS *cbs) {
if (CBS_len(cbs) > LONG_MAX) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return NULL;
}
const uint8_t *ptr = CBS_data(cbs);
X509 *ret = d2i_X509(NULL, &ptr, (long)CBS_len(cbs));
if (ret == NULL) {
return NULL;
}
CBS_skip(cbs, ptr - CBS_data(cbs));
return ret;
}
int ssl_parse_cert_chain(SSL *ssl, STACK_OF(CRYPTO_BUFFER) **out_buffers,
STACK_OF(X509) **out_x509s, uint8_t *out_alert,
uint8_t *out_leaf_sha256, CBS *cbs) {
*out_buffers = NULL;

STACK_OF(X509) *ssl_parse_cert_chain(SSL *ssl, uint8_t *out_alert,
uint8_t *out_leaf_sha256, CBS *cbs) {
STACK_OF(X509) *ret = sk_X509_new_null();
if (ret == NULL) {
STACK_OF(CRYPTO_BUFFER) *buffers = sk_CRYPTO_BUFFER_new_null();
if (buffers == NULL) {
*out_alert = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return NULL;
return 0;
}

X509 *x = NULL;
CBS certificate_list;
if (!CBS_get_u24_length_prefixed(cbs, &certificate_list)) {
*out_alert = SSL_AD_DECODE_ERROR;
@@ -481,36 +469,45 @@ STACK_OF(X509) *ssl_parse_cert_chain(SSL *ssl, uint8_t *out_alert,

while (CBS_len(&certificate_list) > 0) {
CBS certificate;
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) {
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
CBS_len(&certificate) == 0) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
goto err;
}

/* Retain the hash of the leaf certificate if requested. */
if (sk_X509_num(ret) == 0 && out_leaf_sha256 != NULL) {
if (sk_CRYPTO_BUFFER_num(buffers) == 0 && out_leaf_sha256 != NULL) {
SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256);
}

x = ssl_parse_x509(&certificate);
if (x == NULL || CBS_len(&certificate) != 0) {
*out_alert = SSL_AD_DECODE_ERROR;
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&certificate, NULL);
if (buffer == NULL) {
*out_alert = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!sk_X509_push(ret, x)) {

if (!sk_CRYPTO_BUFFER_push(buffers, buffer)) {
CRYPTO_BUFFER_free(buffer);
*out_alert = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
x = NULL;
}

return ret;
STACK_OF(X509) *x509s;
if (!x509_chain_from_buffers(&x509s, buffers)) {
goto err;
}

*out_buffers = buffers;
*out_x509s = x509s;
return 1;

err:
X509_free(x);
sk_X509_pop_free(ret, X509_free);
return NULL;
sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
return 0;
}

int ssl_add_cert_to_cbb(CBB *cbb, X509 *x509) {


+ 70
- 0
ssl/ssl_session.c Wyświetl plik

@@ -199,6 +199,20 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
goto err;
}
}
if (session->certs != NULL) {
new_session->certs = sk_CRYPTO_BUFFER_new_null();
if (new_session->certs == NULL) {
goto err;
}
for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(session->certs); i++) {
CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(session->certs, i);
CRYPTO_BUFFER_up_ref(buffer);
if (!sk_CRYPTO_BUFFER_push(new_session->certs, buffer)) {
CRYPTO_BUFFER_free(buffer);
goto err;
}
}
}
if (session->x509_peer != NULL) {
X509_up_ref(session->x509_peer);
new_session->x509_peer = session->x509_peer;
@@ -326,6 +340,7 @@ void SSL_SESSION_free(SSL_SESSION *session) {
OPENSSL_cleanse(session->master_key, sizeof(session->master_key));
OPENSSL_cleanse(session->session_id, sizeof(session->session_id));
X509_free(session->x509_peer);
sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free);
sk_X509_pop_free(session->x509_chain, X509_free);
OPENSSL_free(session->tlsext_hostname);
OPENSSL_free(session->tlsext_tick);
@@ -966,6 +981,61 @@ static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session) {
}
}

int x509_chain_from_buffers(STACK_OF(X509) **out,
STACK_OF(CRYPTO_BUFFER) *buffers) {
*out = NULL;

if (sk_CRYPTO_BUFFER_num(buffers) == 0) {
return 1;
}

STACK_OF(X509) *ret = sk_X509_new_null();
if (ret == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}

for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(buffers); i++) {
CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(buffers, i);
X509 *x509 = X509_parse_from_buffer(buffer);
if (x509 == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_AD_DECODE_ERROR);
goto err;
}
if (!sk_X509_push(ret, x509)) {
X509_free(x509);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
}

*out = ret;
return 1;

err:
sk_X509_pop_free(ret, X509_free);
return 0;
}

void ssl_session_set_x509_peer(SSL_SESSION *sess,
int chain_should_include_leaf) {
sess->x509_chain_should_include_leaf = chain_should_include_leaf;
X509_free(sess->x509_peer);
sess->x509_peer = NULL;

if (sk_X509_num(sess->x509_chain) > 0) {
if (chain_should_include_leaf) {
X509 *leaf = sk_X509_value(sess->x509_chain, 0);
X509_up_ref(leaf);
sess->x509_peer = leaf;
} else {
sess->x509_peer = sk_X509_shift(sess->x509_chain);
/* |sess->x509_chain| may now be empty, but code still expects it to be
* non-NULL. */
}
}
}

void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,
int (*cb)(SSL *ssl, SSL_SESSION *session)) {
ctx->new_session_cb = cb;


+ 153
- 2
ssl/ssl_test.cc Wyświetl plik

@@ -546,6 +546,81 @@ static const char kCustomSession[] =

// kBoringSSLSession is a serialized SSL_SESSION generated from bssl client.
static const char kBoringSSLSession[] =
"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"
"ZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTAyMDUyMTA0MDAwMFoXDTE4"
"MDgyMTA0MDAwMFowQjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
"Yy4xGzAZBgNVBAMTEkdlb1RydXN0IEdsb2JhbCBDQTCCASIwDQYJKoZIhvcNAQEB"
"BQADggEPADCCAQoCggEBANrMGGMw/fQXIxpWflvfPGw45HG3eJHUvKHYTPioQ7YD"
"6U0hBwiI2lgvZjkpvQV4i5046AW3an5xpObEYKaw74DkiSgPniXW7YPzraaRx5jJ"
"Qhg1FJ2tmEaSLk/K8YdDwRaVVy1Q74ktgHpXrfLuX2vSAI25FPgUFTXZwEaje3LI"
"kb/JVSvN0Jc+nCZkzN/Ogxlxyk7m1NV7qRnNVd7I7NJeOFPlXE+MLf5QIzb8ZubL"
"jqQ5GQC3lQI5kQsO/jgu0R0FmvZNPm8PBx2vLB6PYDni+jZTEznUXiYr2z2oFL0y"
"6xgDKFIEceWrMz3hOLsHNoRinHnqFjD0X8Ar6HFr5PkCAwEAAaOB8DCB7TAfBgNV"
"HSMEGDAWgBRI5mj5K9KylddH2CMgEE8zmJCf1DAdBgNVHQ4EFgQUwHqYaI2J+6sF"
"ZAwRfap9ZbjKzE4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwOgYD"
"VR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9zZWN1"
"cmVjYS5jcmwwTgYDVR0gBEcwRTBDBgRVHSAAMDswOQYIKwYBBQUHAgEWLWh0dHBz"
"Oi8vd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeTANBgkqhkiG"
"9w0BAQUFAAOBgQB24RJuTksWEoYwBrKBCM/wCMfHcX5m7sLt1Dsf//DwyE7WQziw"
"uTB9GNBVg6JqyzYRnOhIZqNtf7gT1Ef+i1pcc/yu2RsyGTirlzQUqpbS66McFAhJ"
"trvlke+DNusdVm/K2rxzY5Dkf3s+Iss9B+1fOHSc4wNQTqGvmO5h8oQ/Eg==";

// kLeafInChainSession is a serialized SSL_SESSION generated from bssl client.
// It contains a chain that includes the leaf certificate.
static const char kLeafInChainSession[] =
"MIIRwQIBAQICAwMEAsAvBCDdoGxGK26mR+8lM0uq6+k9xYuxPnwAjpcF9n0Yli9R"
"kQQwbyshfWhdi5XQ1++7n2L1qqrcVlmHBPpr6yknT/u4pUrpQB5FZ7vqvNn8MdHf"
"9rWgoQYCBFXgs7uiBAICHCCjggR6MIIEdjCCA16gAwIBAgIIf+yfD7Y6UicwDQYJ"
@@ -706,7 +781,8 @@ static bool TestSSL_SESSIONEncoding(const char *input_b64) {
}

// Verify the SSL_SESSION decodes.
bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size()));
bssl::UniquePtr<SSL_SESSION> session(
SSL_SESSION_from_bytes(input.data(), input.size()));
if (!session) {
fprintf(stderr, "SSL_SESSION_from_bytes failed\n");
return false;
@@ -775,7 +851,8 @@ static bool TestBadSSL_SESSIONEncoding(const char *input_b64) {
}

// Verify that the SSL_SESSION fails to decode.
bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size()));
bssl::UniquePtr<SSL_SESSION> session(
SSL_SESSION_from_bytes(input.data(), input.size()));
if (session) {
fprintf(stderr, "SSL_SESSION_from_bytes unexpectedly succeeded\n");
return false;
@@ -784,6 +861,79 @@ static bool TestBadSSL_SESSIONEncoding(const char *input_b64) {
return true;
}

static bool TestLeafInChainSession() {
std::vector<uint8_t> input;
if (!DecodeBase64(&input, kLeafInChainSession)) {
return false;
}

bssl::UniquePtr<SSL_SESSION> session(
SSL_SESSION_from_bytes(input.data(), input.size()));
if (!session) {
fprintf(stderr, "TestLeafInChainSession: failed to decode.\n");
return false;
}

// kLeafInChainSession contains a session where the leaf is duplicated in the
// certificate chain. |certs| should contain the chain without duplication,
// but |x509_chain| should reflect the structure from the serialised session.
if (X509_cmp(session->x509_peer, sk_X509_value(session->x509_chain, 0)) !=
0) {
fprintf(stderr,
"TestLeafInChainSession: leaf is not first element of chain.\n");
return false;
}

if (sk_X509_num(session->x509_chain) !=
sk_CRYPTO_BUFFER_num(session->certs)) {
fprintf(
stderr,
"TestLeafInChainSession: chain length differs from certs length.\n");
return false;
}

if (!session->x509_chain_should_include_leaf) {
fprintf(stderr,
"TestLeafInChainSession: x509_chain_should_include_leaf flag not "
"set.\n");
return false;
}

size_t encoded_len;
bssl::UniquePtr<uint8_t> encoded;
uint8_t *encoded_raw;
if (!SSL_SESSION_to_bytes(session.get(), &encoded_raw, &encoded_len)) {
fprintf(stderr, "TestLeafInChainSession: SSL_SESSION_to_bytes failed\n");
return false;
}
encoded.reset(encoded_raw);

// After reencoding, the duplication should be eliminated.
if (encoded_len >= input.size()) {
fprintf(stderr,
"TestLeafInChainSession: reencoding didn't end up smaller\n");
return false;
}

// But the duplication should be preserved when parsing again.
bssl::UniquePtr<SSL_SESSION> session2(
SSL_SESSION_from_bytes(encoded_raw, encoded_len));
if (!session2) {
fprintf(stderr, "TestLeafInChainSession: failed to redecode.\n");
return false;
}

if (X509_cmp(session2->x509_peer, sk_X509_value(session2->x509_chain, 0)) !=
0 ||
sk_X509_num(session2->x509_chain) != sk_X509_num(session->x509_chain)) {
fprintf(stderr,
"TestLeafInChainSession: redecode didn't preserve duplication.\n");
return false;
}

return true;
}

static bool TestDefaultVersion(uint16_t min_version, uint16_t max_version,
const SSL_METHOD *(*method)(void)) {
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method()));
@@ -2827,6 +2977,7 @@ int main() {
!TestBadSSL_SESSIONEncoding(kBadSessionExtraField) ||
!TestBadSSL_SESSIONEncoding(kBadSessionVersion) ||
!TestBadSSL_SESSIONEncoding(kBadSessionTrailingData) ||
!TestLeafInChainSession() ||
// TODO(svaldez): Update this when TLS 1.3 is enabled by default.
!TestDefaultVersion(SSL3_VERSION, TLS1_2_VERSION, &TLS_method) ||
!TestDefaultVersion(SSL3_VERSION, SSL3_VERSION, &SSLv3_method) ||


+ 27
- 18
ssl/tls13_both.c Wyświetl plik

@@ -177,8 +177,9 @@ int tls13_process_certificate(SSL *ssl, int allow_anonymous) {
ssl->server && ssl->retain_only_sha256_of_client_certs;
int ret = 0;

STACK_OF(X509) *chain = sk_X509_new_null();
if (chain == NULL) {
STACK_OF(X509) *chain = NULL;
STACK_OF(CRYPTO_BUFFER) *buffers = sk_CRYPTO_BUFFER_new_null();
if (buffers == NULL) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
@@ -193,28 +194,30 @@ int tls13_process_certificate(SSL *ssl, int allow_anonymous) {
while (CBS_len(&certificate_list) > 0) {
CBS certificate, extensions;
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
!CBS_get_u16_length_prefixed(&certificate_list, &extensions)) {
!CBS_get_u16_length_prefixed(&certificate_list, &extensions) ||
CBS_len(&certificate) == 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
goto err;
}

/* Retain the hash of the leaf certificate if requested. */
if (sk_X509_num(chain) == 0 && retain_sha256) {
if (sk_CRYPTO_BUFFER_num(buffers) == 0 && retain_sha256) {
SHA256(CBS_data(&certificate), CBS_len(&certificate),
ssl->s3->new_session->peer_sha256);
}

X509 *x = ssl_parse_x509(&certificate);
if (x == NULL || CBS_len(&certificate) != 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
X509_free(x);
CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&certificate, NULL);
if (buffer == NULL) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!sk_X509_push(chain, x)) {

if (!sk_CRYPTO_BUFFER_push(buffers, buffer)) {
CRYPTO_BUFFER_free(buffer);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
X509_free(x);
goto err;
}

@@ -253,7 +256,7 @@ int tls13_process_certificate(SSL *ssl, int allow_anonymous) {
goto err;
}

if (sk_X509_num(chain) == 1 &&
if (sk_CRYPTO_BUFFER_num(buffers) == 1 &&
!CBS_stow(&ocsp_response, &ssl->s3->new_session->ocsp_response,
&ssl->s3->new_session->ocsp_response_length)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
@@ -274,7 +277,7 @@ int tls13_process_certificate(SSL *ssl, int allow_anonymous) {
goto err;
}

if (sk_X509_num(chain) == 1 &&
if (sk_CRYPTO_BUFFER_num(buffers) == 1 &&
!CBS_stow(&sct,
&ssl->s3->new_session->tlsext_signed_cert_timestamp_list,
&ssl->s3->new_session
@@ -291,7 +294,7 @@ int tls13_process_certificate(SSL *ssl, int allow_anonymous) {
goto err;
}

if (sk_X509_num(chain) == 0) {
if (sk_CRYPTO_BUFFER_num(buffers) == 0) {
if (!allow_anonymous) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED);
@@ -309,24 +312,30 @@ int tls13_process_certificate(SSL *ssl, int allow_anonymous) {

ssl->s3->new_session->peer_sha256_valid = retain_sha256;

if (!x509_chain_from_buffers(&chain, buffers)) {
goto err;
}

if (!ssl_verify_cert_chain(ssl, &ssl->s3->new_session->verify_result,
chain)) {
goto err;
}

X509_free(ssl->s3->new_session->x509_peer);
X509 *leaf = sk_X509_value(chain, 0);
X509_up_ref(leaf);
ssl->s3->new_session->x509_peer = leaf;

sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
ssl->s3->new_session->certs = buffers;
buffers = NULL;
sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
ssl->s3->new_session->x509_chain = chain;
chain = NULL;

ssl_session_set_x509_peer(ssl->s3->new_session,
1 /* chain should include leaf */);

ret = 1;

err:
sk_X509_pop_free(chain, X509_free);
sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
return ret;
}



+ 1
- 0
ssl/tls13_server.c Wyświetl plik

@@ -557,6 +557,7 @@ static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) {
if (sk_X509_num(ssl->s3->new_session->x509_chain) > 0) {
X509_free(sk_X509_shift(ssl->s3->new_session->x509_chain));
}
ssl->s3->new_session->x509_chain_should_include_leaf = 0;

hs->state = state_process_client_certificate_verify;
return ssl_hs_read_message;


Ładowanie…
Anuluj
Zapisz