/*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-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
static int final_alpn(SSL *s, unsigned int context, int sent, int *al);
static int init_sig_algs(SSL *s, unsigned int context);
static int init_certificate_authorities(SSL *s, unsigned int context);
-static int tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
- unsigned int context, X509 *x,
- size_t chainidx, int *al);
+static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
+ unsigned int context,
+ X509 *x,
+ size_t chainidx,
+ int *al);
static int tls_parse_certificate_authorities(SSL *s, PACKET *pkt,
unsigned int context, X509 *x,
size_t chainidx, int *al);
int (*parse_stoc)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx, int *al);
/* Construct extension sent from server to client */
- int (*construct_stoc)(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx, int *al);
+ EXT_RETURN (*construct_stoc)(SSL *s, WPACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al);
/* Construct extension sent from client to server */
- int (*construct_ctos)(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx, int *al);
+ EXT_RETURN (*construct_ctos)(SSL *s, WPACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al);
/*
* Finalise extension after parsing. Always called where an extensions was
* initialised even if the extension was not present. |sent| is set to 1 if
/*
* Definitions of all built-in extensions. NOTE: Changes in the number or order
- * of these extensions should be mirrored with equivalent changes to the
+ * of these extensions should be mirrored with equivalent changes to the
* indexes ( TLSEXT_IDX_* ) defined in ssl_locl.h.
* Each extension has an initialiser, a client and
* server side parser and a finaliser. The initialiser is called (if the
return 0;
}
+ i = 0;
while (PACKET_remaining(&extensions) > 0) {
- unsigned int type;
+ unsigned int type, idx;
PACKET extension;
RAW_EXTENSION *thisex;
*al = SSL_AD_ILLEGAL_PARAMETER;
goto err;
}
+ idx = thisex - raw_extensions;
+ /*-
+ * Check that we requested this extension (if appropriate). Requests can
+ * be sent in the ClientHello and CertificateRequest. Unsolicited
+ * extensions can be sent in the NewSessionTicket. We only do this for
+ * the built-in extensions. Custom extensions have a different but
+ * similar check elsewhere.
+ * Special cases:
+ * - The HRR cookie extension is unsolicited
+ * - The renegotiate extension is unsolicited (the client signals
+ * support via an SCSV)
+ * - The signed_certificate_timestamp extension can be provided by a
+ * custom extension or by the built-in version. We let the extension
+ * itself handle unsolicited response checks.
+ */
+ if (idx < OSSL_NELEM(ext_defs)
+ && (context & (SSL_EXT_CLIENT_HELLO
+ | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
+ | SSL_EXT_TLS1_3_NEW_SESSION_TICKET)) == 0
+ && type != TLSEXT_TYPE_cookie
+ && type != TLSEXT_TYPE_renegotiate
+ && type != TLSEXT_TYPE_signed_certificate_timestamp
+ && (s->ext.extflags[idx] & SSL_EXT_FLAG_SENT) == 0) {
+ SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_UNSOLICITED_EXTENSION);
+ *al = SSL_AD_UNSUPPORTED_EXTENSION;
+ goto err;
+ }
if (thisex != NULL) {
thisex->data = extension;
thisex->present = 1;
thisex->type = type;
+ thisex->received_order = i++;
+ if (s->ext.debug_cb)
+ s->ext.debug_cb(s, !s->server, thisex->type,
+ PACKET_data(&thisex->data),
+ PACKET_remaining(&thisex->data),
+ s->ext.debug_arg);
}
}
if (!currext->present)
return 1;
- if (s->ext.debug_cb)
- s->ext.debug_cb(s, !s->server, currext->type,
- PACKET_data(&currext->data),
- PACKET_remaining(&currext->data),
- s->ext.debug_arg);
-
/* Skip if we've already parsed this extension */
if (currext->parsed)
return 1;
}
for (i = 0, thisexd = ext_defs; i < OSSL_NELEM(ext_defs); i++, thisexd++) {
- int (*construct)(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
- size_t chainidx, int *al);
+ EXT_RETURN (*construct)(SSL *s, WPACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx, int *al);
+ EXT_RETURN ret;
/* Skip if not relevant for our context */
if (!should_add_extension(s, thisexd->context, context, max_version))
if (construct == NULL)
continue;
- if (!construct(s, pkt, context, x, chainidx, &tmpal))
+ ret = construct(s, pkt, context, x, chainidx, &tmpal);
+ if (ret == EXT_RETURN_FAIL)
goto err;
+ if (ret == EXT_RETURN_SENT
+ && (context & (SSL_EXT_CLIENT_HELLO
+ | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST
+ | SSL_EXT_TLS1_3_NEW_SESSION_TICKET)) != 0)
+ s->ext.extflags[i] |= SSL_EXT_FLAG_SENT;
}
if (!WPACKET_close(pkt)) {
return 1;
}
-static int tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
- unsigned int context, X509 *x,
- size_t chainidx, int *al)
+static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
+ unsigned int context,
+ X509 *x,
+ size_t chainidx,
+ int *al)
{
const STACK_OF(X509_NAME) *ca_sk = SSL_get0_CA_list(s);
if (ca_sk == NULL || sk_X509_NAME_num(ca_sk) == 0)
- return 1;
+ return EXT_RETURN_NOT_SENT;
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_certificate_authorities)
|| !WPACKET_start_sub_packet_u16(pkt)
|| !WPACKET_close(pkt)) {
SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_AUTHORITIES,
ERR_R_INTERNAL_ERROR);
- return 0;
+ return EXT_RETURN_FAIL;
}
- return 1;
+ return EXT_RETURN_SENT;
}
static int tls_parse_certificate_authorities(SSL *s, PACKET *pkt,
static int final_sig_algs(SSL *s, unsigned int context, int sent, int *al)
{
- if (!sent && SSL_IS_TLS13(s)) {
+ if (!sent && SSL_IS_TLS13(s) && !s->hit) {
*al = TLS13_AD_MISSING_EXTENSION;
SSLerr(SSL_F_FINAL_SIG_ALGS, SSL_R_MISSING_SIGALGS_EXTENSION);
return 0;
&& (!s->hit
|| (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0)) {
/* Nothing left we can do - just fail */
- *al = SSL_AD_HANDSHAKE_FAILURE;
+ *al = SSL_AD_MISSING_EXTENSION;
SSLerr(SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
return 0;
}
if (!s->hit
|| (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0) {
/* Nothing left we can do - just fail */
- *al = SSL_AD_HANDSHAKE_FAILURE;
+ if (!sent)
+ *al = SSL_AD_MISSING_EXTENSION;
+ else
+ *al = SSL_AD_HANDSHAKE_FAILURE;
SSLerr(SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
return 0;
}
int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
size_t binderoffset, const unsigned char *binderin,
- unsigned char *binderout,
- SSL_SESSION *sess, int sign)
+ unsigned char *binderout, SSL_SESSION *sess, int sign,
+ int external)
{
EVP_PKEY *mackey = NULL;
EVP_MD_CTX *mctx = NULL;
unsigned char hash[EVP_MAX_MD_SIZE], binderkey[EVP_MAX_MD_SIZE];
unsigned char finishedkey[EVP_MAX_MD_SIZE], tmpbinder[EVP_MAX_MD_SIZE];
+ unsigned char tmppsk[EVP_MAX_MD_SIZE];
+ unsigned char *early_secret, *psk;
const char resumption_label[] = "res binder";
- size_t bindersize, hashsize = EVP_MD_size(md);
+ const char external_label[] = "ext binder";
+ const char nonce_label[] = "resumption";
+ const char *label;
+ size_t bindersize, labelsize, hashsize = EVP_MD_size(md);
int ret = -1;
- /* Generate the early_secret */
- if (!tls13_generate_secret(s, md, NULL, sess->master_key,
- sess->master_key_length,
- (unsigned char *)&s->early_secret)) {
+ if (external) {
+ label = external_label;
+ labelsize = sizeof(external_label) - 1;
+ } else {
+ label = resumption_label;
+ labelsize = sizeof(resumption_label) - 1;
+ }
+
+ if (sess->master_key_length != hashsize) {
+ SSLerr(SSL_F_TLS_PSK_DO_BINDER, SSL_R_BAD_PSK);
+ goto err;
+ }
+
+ if (external) {
+ psk = sess->master_key;
+ } else {
+ psk = tmppsk;
+ if (!tls13_hkdf_expand(s, md, sess->master_key,
+ (const unsigned char *)nonce_label,
+ sizeof(nonce_label) - 1, sess->ext.tick_nonce,
+ sess->ext.tick_nonce_len, psk, hashsize)) {
+ SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ /*
+ * Generate the early_secret. On the server side we've selected a PSK to
+ * resume with (internal or external) so we always do this. On the client
+ * side we do this for a non-external (i.e. resumption) PSK so that it
+ * is in place for sending early data. For client side external PSK we
+ * generate it but store it away for later use.
+ */
+ if (s->server || !external)
+ early_secret = (unsigned char *)s->early_secret;
+ else
+ early_secret = (unsigned char *)sess->early_secret;
+ if (!tls13_generate_secret(s, md, NULL, psk, hashsize, early_secret)) {
SSLerr(SSL_F_TLS_PSK_DO_BINDER, 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)) {
+ if (!tls13_hkdf_expand(s, md, early_secret, (unsigned char *)label,
+ labelsize, hash, hashsize, binderkey, hashsize)) {
SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
goto err;
}