summaryrefslogtreecommitdiffstats
path: root/ssl/statem
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/statem')
-rw-r--r--ssl/statem/extensions.c10
-rw-r--r--ssl/statem/extensions_clnt.c164
-rw-r--r--ssl/statem/statem_lib.c2
-rw-r--r--ssl/statem/statem_locl.h2
-rw-r--r--ssl/statem/statem_srvr.c2
5 files changed, 177 insertions, 3 deletions
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index dc992010ec..5837720eb7 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -264,12 +264,20 @@ static const EXTENSION_DEFINITION ext_defs[] = {
NULL, NULL, NULL, tls_construct_stoc_cryptopro_bug, NULL, NULL
},
{
- /* Last in the list because it must be added as the last extension */
+ /* Must be immediately before pre_shared_key */
+ /* TODO(TLS1.3): Fix me */
TLSEXT_TYPE_padding,
EXT_CLIENT_HELLO,
NULL,
/* We send this, but don't read it */
NULL, NULL, NULL, tls_construct_ctos_padding, NULL
+ },
+ {
+ /* Required by the TLSv1.3 spec to always be the last extension */
+ TLSEXT_TYPE_psk,
+ EXT_CLIENT_HELLO | EXT_TLS1_3_SERVER_HELLO | EXT_TLS_IMPLEMENTATION_ONLY
+ | EXT_TLS1_3_ONLY,
+ NULL, NULL, NULL, NULL, tls_construct_ctos_psk, NULL
}
};
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 57f6564678..c6a8124c9e 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -657,6 +657,170 @@ int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
}
/*
+ * Construct the pre_shared_key extension
+ */
+int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
+ int *al)
+{
+#ifndef OPENSSL_NO_TLS1_3
+ const SSL_CIPHER *cipher;
+ uint32_t now, ages, agems;
+ size_t hashsize, bindersize, binderoffset, msglen;
+ unsigned char *binder = NULL, *msgstart = NULL;
+ EVP_PKEY *mackey = NULL;
+ const EVP_MD *md;
+ EVP_MD_CTX *mctx = NULL;
+ unsigned char hash[EVP_MAX_MD_SIZE], binderkey[EVP_MAX_MD_SIZE];
+ unsigned char finishedkey[EVP_MAX_MD_SIZE];
+ const char resumption_label[] = "resumption psk binder key";
+ int ret = 0;
+
+ s->session->ext.tick_identity = TLSEXT_PSK_BAD_IDENTITY;
+
+ /*
+ * If this is a new session then we have nothing to resume so don't add
+ * this extension.
+ */
+ if (s->session->ext.ticklen == 0)
+ return 1;
+
+ /*
+ * Technically the C standard just says time() returns a time_t and says
+ * nothing about the encoding of that type. In practice most implementations
+ * follow POSIX which holds it as an integral type in seconds since epoch.
+ * We've already made the assumption that we can do this in multiple places
+ * in the code, so portability shouldn't be an issue.
+ */
+ now = (uint32_t)time(NULL);
+ ages = now - (uint32_t)s->session->time;
+
+ /*
+ * Calculate age in ms. We're just doing it to nearest second. Should be
+ * good enough.
+ */
+ agems = ages * (uint32_t)1000;
+
+ if (ages != 0 && agems / (uint32_t)1000 != ages) {
+ /*
+ * Overflow. Shouldn't happen unless this is a *really* old session. If
+ * so we just ignore it.
+ */
+ return 1;
+ }
+
+ /* TODO(TLS1.3): Obfuscate the age here */
+
+ cipher = ssl3_get_cipher_by_id(s->session->cipher_id);
+ if (cipher == NULL) {
+ /* Don't recognise this cipher so we can't use the session. Ignore it */
+ return 1;
+ }
+ md = ssl_md(cipher->algorithm2);
+ if (md == NULL) {
+ /* Shouldn't happen!! */
+ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ hashsize = EVP_MD_size(md);
+
+ /* Create the extension, but skip over the binder for now */
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_sub_memcpy_u16(pkt, s->session->ext.tick,
+ s->session->ext.ticklen)
+ || !WPACKET_put_bytes_u32(pkt, agems)
+ || !WPACKET_close(pkt)
+ || !WPACKET_get_total_written(pkt, &binderoffset)
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_sub_allocate_bytes_u8(pkt, hashsize, &binder)
+ || !WPACKET_close(pkt)
+ || !WPACKET_close(pkt)
+ || !WPACKET_get_total_written(pkt, &msglen)
+ /*
+ * We need to fill in all the sub-packet lengths now so we can
+ * calculate the HMAC of the message up to the binders
+ */
+ || !WPACKET_fill_lengths(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ msgstart = WPACKET_get_curr(pkt) - msglen;
+
+ /* Generate the early_secret */
+ if (!tls13_generate_secret(s, md, NULL, s->session->master_key,
+ s->session->master_key_length,
+ (unsigned char *)&s->early_secret)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /*
+ * Create the handshake hash for the binder key...the messages so far are
+ * empty!
+ */
+ mctx = EVP_MD_CTX_new();
+ if (mctx == NULL
+ || EVP_DigestInit_ex(mctx, md, NULL) <= 0
+ || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* Generate the binder key */
+ if (!tls13_hkdf_expand(s, md, s->early_secret,
+ (unsigned char *)resumption_label,
+ sizeof(resumption_label) - 1, hash, binderkey,
+ hashsize)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* Generate the finished key */
+ if (!tls13_derive_finishedkey(s, md, binderkey, finishedkey, hashsize)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /*
+ * Get a hash of the ClientHello up to the start of the binders.
+ * TODO(TLS1.3): This will need to be tweaked when we implement
+ * HelloRetryRequest to include the digest of the previous messages here.
+ */
+ if (EVP_DigestInit_ex(mctx, md, NULL) <= 0
+ || EVP_DigestUpdate(mctx, msgstart, binderoffset) <= 0
+ || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ mackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, finishedkey, hashsize);
+ bindersize = hashsize;
+ if (binderkey == NULL
+ || EVP_DigestSignInit(mctx, NULL, md, NULL, mackey) <= 0
+ || EVP_DigestSignUpdate(mctx, hash, hashsize) <= 0
+ || EVP_DigestSignFinal(mctx, binder, &bindersize) <= 0
+ || bindersize != hashsize) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ s->session->ext.tick_identity = 0;
+
+ ret = 1;
+ err:
+ OPENSSL_cleanse(binderkey, sizeof(binderkey));
+ EVP_PKEY_free(mackey);
+ EVP_MD_CTX_free(mctx);
+
+ return ret;
+#else
+ return 1;
+#endif
+}
+
+/*
* Parse the server's renegotiation binding and abort if it's not right
*/
int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index ad1466f9a9..3a6b672a0f 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -650,7 +650,7 @@ MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
}
} else {
if (!s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key, s->handshake_secret, 0,
+ s->master_secret, s->handshake_secret, 0,
&s->session->master_key_length)) {
SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_CANNOT_CHANGE_CIPHER);
goto f_err;
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index d15c69686e..67858057f7 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -290,6 +290,8 @@ int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, X509 *x,
size_t chainidx, int *al);
int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
int *al);
+int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
+ int *al);
int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
int *al);
int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 6b3d4f7749..20e521a9d6 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -800,7 +800,7 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
#endif
if (SSL_IS_TLS13(s)) {
if (!s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key, s->handshake_secret, 0,
+ s->master_secret, s->handshake_secret, 0,
&s->session->master_key_length)
|| !s->method->ssl3_enc->change_cipher_state(s,
SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_WRITE))