Implement client side of TLS signed certificate stamps extension.
https://crbug.com/389420 and 3.3 in rfc6962.
Change-Id: Ib22bcd4e4bde5a314ed33e123e19a76cdb714da4
Reviewed-on: https://boringssl-review.googlesource.com/1491
Reviewed-by: David Benjamin <davidben@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 9f372f9..05c6462 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -119,12 +119,13 @@
ASN1_OCTET_STRING psk_identity;
ASN1_OCTET_STRING peer_sha256;
ASN1_OCTET_STRING original_handshake_hash;
+ ASN1_OCTET_STRING tlsext_signed_cert_timestamp_list;
} SSL_SESSION_ASN1;
int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
{
#define LSIZE2 (sizeof(long)*2)
- int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0,v13=0,v14=0;
+ int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0,v13=0,v14=0,v15=0;
unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
int v6=0,v9=0,v10=0;
@@ -259,6 +260,15 @@
a.original_handshake_hash.data = in->original_handshake_hash;
}
+ if (in->tlsext_signed_cert_timestamp_list_length > 0)
+ {
+ a.tlsext_signed_cert_timestamp_list.length =
+ in->tlsext_signed_cert_timestamp_list_length;
+ a.tlsext_signed_cert_timestamp_list.type = V_ASN1_OCTET_STRING;
+ a.tlsext_signed_cert_timestamp_list.data =
+ in->tlsext_signed_cert_timestamp_list;
+ }
+
M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER);
M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER);
M_ASN1_I2D_len(&(a.cipher), i2d_ASN1_OCTET_STRING);
@@ -290,6 +300,9 @@
M_ASN1_I2D_len_EXP_opt(&(a.peer_sha256),i2d_ASN1_OCTET_STRING,13,v13);
if (in->original_handshake_hash_len > 0)
M_ASN1_I2D_len_EXP_opt(&(a.original_handshake_hash),i2d_ASN1_OCTET_STRING,14,v14);
+ if (in->tlsext_signed_cert_timestamp_list_length > 0)
+ M_ASN1_I2D_len_EXP_opt(&(a.tlsext_signed_cert_timestamp_list),
+ i2d_ASN1_OCTET_STRING, 15, v15);
M_ASN1_I2D_seq_total();
@@ -324,6 +337,9 @@
M_ASN1_I2D_put_EXP_opt(&(a.peer_sha256),i2d_ASN1_OCTET_STRING,13,v13);
if (in->original_handshake_hash_len > 0)
M_ASN1_I2D_put_EXP_opt(&(a.original_handshake_hash),i2d_ASN1_OCTET_STRING,14,v14);
+ if (in->tlsext_signed_cert_timestamp_list_length > 0)
+ M_ASN1_I2D_put_EXP_opt(&(a.tlsext_signed_cert_timestamp_list),
+ i2d_ASN1_OCTET_STRING, 15, v15);
M_ASN1_I2D_finish();
}
@@ -572,5 +588,18 @@
os.data = NULL;
}
+ os.length = 0;
+ os.data = NULL;
+ M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 15);
+ if (os.data)
+ {
+ if (ret->tlsext_signed_cert_timestamp_list)
+ OPENSSL_free(ret->tlsext_signed_cert_timestamp_list);
+ ret->tlsext_signed_cert_timestamp_list = os.data;
+ ret->tlsext_signed_cert_timestamp_list_length = os.length;
+ os.data = NULL;
+ }
+
+
M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
}
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 43ce97b..4722b3e 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -404,6 +404,9 @@
s->psk_client_callback=ctx->psk_client_callback;
s->psk_server_callback=ctx->psk_server_callback;
+ if (!s->server)
+ s->signed_cert_timestamps_enabled = s->ctx->signed_cert_timestamps_enabled;
+
return(s);
err:
if (s != NULL)
@@ -1675,6 +1678,34 @@
return -1;
}
+void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx)
+ {
+ ctx->signed_cert_timestamps_enabled = 1;
+ }
+
+int SSL_enable_signed_cert_timestamps(SSL *ssl)
+ {
+ /* Currently not implemented server side */
+ if (ssl->server)
+ return 0;
+
+ ssl->signed_cert_timestamps_enabled = 1;
+ return 1;
+ }
+
+void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, uint8_t **out, size_t *out_len)
+ {
+ *out_len = 0;
+ *out = NULL;
+ if (ssl->server)
+ return;
+ SSL_SESSION *session = ssl->session;
+ if (!session || !session->tlsext_signed_cert_timestamp_list)
+ return;
+ *out = session->tlsext_signed_cert_timestamp_list;
+ *out_len = session->tlsext_signed_cert_timestamp_list_length;
+ }
+
/* SSL_select_next_proto implements the standard protocol selection. It is
* expected that this function is called from the callback set by
* SSL_CTX_set_next_proto_select_cb.
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index 8881042..56ba7c9 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -211,18 +211,7 @@
ss->references=1;
ss->timeout = SSL_DEFAULT_SESSION_TIMEOUT;
ss->time=(unsigned long)time(NULL);
- ss->prev=NULL;
- ss->next=NULL;
- ss->tlsext_hostname = NULL;
-#ifndef OPENSSL_NO_EC
- ss->tlsext_ecpointformatlist_length = 0;
- ss->tlsext_ecpointformatlist = NULL;
- ss->tlsext_ellipticcurvelist_length = 0;
- ss->tlsext_ellipticcurvelist = NULL;
-#endif
CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
- ss->psk_identity_hint=NULL;
- ss->psk_identity=NULL;
return(ss);
}
@@ -727,6 +716,8 @@
ss->tlsext_ellipticcurvelist_length = 0;
if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist);
#endif /* OPENSSL_NO_EC */
+ if (ss->tlsext_signed_cert_timestamp_list != NULL)
+ OPENSSL_free(ss->tlsext_signed_cert_timestamp_list);
if (ss->psk_identity_hint != NULL)
OPENSSL_free(ss->psk_identity_hint);
if (ss->psk_identity != NULL)
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 855d1d0..d23b41e 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1109,6 +1109,16 @@
}
#endif
+ if (s->signed_cert_timestamps_enabled && !s->s3->tmp.finish_md_len)
+ {
+ /* The client advertises an empty extension to indicate its support for
+ * certificate timestamps. */
+ if (limit - ret - 4 < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_certificate_timestamp,ret);
+ s2n(0,ret);
+ }
+
if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len)
{
if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len)
@@ -2234,7 +2244,26 @@
s->s3->tlsext_channel_id_valid = 1;
s->s3->tlsext_channel_id_new = 1;
}
+ else if (type == TLSEXT_TYPE_certificate_timestamp)
+ {
+ if (CBS_len(&extension) == 0)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ /* Session resumption uses the original session information. */
+ if (!s->hit)
+ {
+ if (!CBS_stow(&extension,
+ &s->session->tlsext_signed_cert_timestamp_list,
+ &s->session->tlsext_signed_cert_timestamp_list_length))
+ {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+ }
else if (type == TLSEXT_TYPE_renegotiate)
{
if (!ssl_parse_serverhello_renegotiate_ext(s, &extension, out_alert))