}
#endif
-/*
- * Comparison function used in a call to qsort (see tls_collect_extensions()
- * below.)
- * The two arguments |p1| and |p2| are expected to be pointers to RAW_EXTENSIONs
- *
- * Returns:
- * 1 if the type for p1 is greater than p2
- * 0 if the type for p1 and p2 are the same
- * -1 if the type for p1 is less than p2
- */
-static int compare_extensions(const void *p1, const void *p2)
-{
- const RAW_EXTENSION *e1 = (const RAW_EXTENSION *)p1;
- const RAW_EXTENSION *e2 = (const RAW_EXTENSION *)p2;
-
- if (e1->type < e2->type)
- return -1;
- else if (e1->type > e2->type)
- return 1;
-
- return 0;
-}
-
-/*
- * Gather a list of all the extensions. We don't actually process the content
- * of the extensions yet, except to check their types.
- *
- * Per http://tools.ietf.org/html/rfc5246#section-7.4.1.4, there may not be
- * more than one extension of the same type in a ClientHello or ServerHello.
- * This function returns 1 if all extensions are unique and we have parsed their
- * types, and 0 if the extensions contain duplicates, could not be successfully
- * parsed, or an internal error occurred.
- */
-/*
- * TODO(TLS1.3): Refactor ServerHello extension parsing to use this and then
- * remove tls1_check_duplicate_extensions()
- */
-int tls_collect_extensions(PACKET *packet, RAW_EXTENSION **res,
- size_t *numfound, int *ad)
-{
- PACKET extensions = *packet;
- size_t num_extensions = 0, i = 0;
- RAW_EXTENSION *raw_extensions = NULL;
-
- /* First pass: count the extensions. */
- while (PACKET_remaining(&extensions) > 0) {
- unsigned int type;
- PACKET extension;
-
- if (!PACKET_get_net_2(&extensions, &type) ||
- !PACKET_get_length_prefixed_2(&extensions, &extension)) {
- *ad = SSL_AD_DECODE_ERROR;
- goto err;
- }
- num_extensions++;
- }
-
- if (num_extensions > 0) {
- raw_extensions = OPENSSL_malloc(sizeof(*raw_extensions)
- * num_extensions);
- if (raw_extensions == NULL) {
- *ad = SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- /* Second pass: collect the extensions. */
- for (i = 0; i < num_extensions; i++) {
- if (!PACKET_get_net_2(packet, &raw_extensions[i].type) ||
- !PACKET_get_length_prefixed_2(packet,
- &raw_extensions[i].data)) {
- /* This should not happen. */
- *ad = SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- }
-
- if (PACKET_remaining(packet) != 0) {
- *ad = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_LENGTH_MISMATCH);
- goto err;
- }
- /* Sort the extensions and make sure there are no duplicates. */
- qsort(raw_extensions, num_extensions, sizeof(*raw_extensions),
- compare_extensions);
- for (i = 1; i < num_extensions; i++) {
- if (raw_extensions[i - 1].type == raw_extensions[i].type) {
- *ad = SSL_AD_DECODE_ERROR;
- goto err;
- }
- }
- }
-
- *res = raw_extensions;
- *numfound = num_extensions;
- return 1;
-
- err:
- OPENSSL_free(raw_extensions);
- return 0;
-}
-
-
-
MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt)
{
int al;
MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
{
- int al;
+ int al = SSL_AD_INTERNAL_ERROR;
size_t md_len;
/* If this occurs, we have missed a message */
- if (!s->s3->change_cipher_spec) {
+ if (!SSL_IS_TLS13(s) && !s->s3->change_cipher_spec) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
goto f_err;
s->s3->previous_server_finished_len = md_len;
}
+ /*
+ * In TLS1.3 we also have to change cipher state and do any final processing
+ * of the initial server flight (if we are a client)
+ */
+ if (SSL_IS_TLS13(s)) {
+ if (s->server) {
+ if (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_READ)) {
+ SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_CANNOT_CHANGE_CIPHER);
+ goto f_err;
+ }
+ } else {
+ if (!s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key, s->handshake_secret, 0,
+ &s->session->master_key_length)) {
+ SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_CANNOT_CHANGE_CIPHER);
+ goto f_err;
+ }
+ if (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_CLIENT_READ)) {
+ SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_CANNOT_CHANGE_CIPHER);
+ goto f_err;
+ }
+ if (!tls_process_initial_server_flight(s, &al))
+ goto f_err;
+ }
+ }
+
return MSG_PROCESS_FINISHED_READING;
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
return 1;
}
-unsigned long ssl3_output_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk)
+/* Add a certificate to the WPACKET */
+static int ssl_add_cert_to_wpacket(SSL *s, WPACKET *pkt, X509 *x, int chain,
+ int *al)
+{
+ int len;
+ unsigned char *outbytes;
+
+ len = i2d_X509(x, NULL);
+ if (len < 0) {
+ SSLerr(SSL_F_SSL_ADD_CERT_TO_WPACKET, ERR_R_BUF_LIB);
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ if (!WPACKET_sub_allocate_bytes_u24(pkt, len, &outbytes)
+ || i2d_X509(x, &outbytes) != len) {
+ SSLerr(SSL_F_SSL_ADD_CERT_TO_WPACKET, ERR_R_INTERNAL_ERROR);
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ if (SSL_IS_TLS13(s)
+ && !tls_construct_extensions(s, pkt, EXT_TLS1_3_CERTIFICATE, x,
+ chain, al))
+ return 0;
+
+ return 1;
+}
+
+/* Add certificate chain to provided WPACKET */
+static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk, int *al)
{
+ int i, chain_count;
+ X509 *x;
+ STACK_OF(X509) *extra_certs;
+ STACK_OF(X509) *chain = NULL;
+ X509_STORE *chain_store;
+ int tmpal = SSL_AD_INTERNAL_ERROR;
+
+ if (cpk == NULL || cpk->x509 == NULL)
+ return 1;
+
+ x = cpk->x509;
+
+ /*
+ * If we have a certificate specific chain use it, else use parent ctx.
+ */
+ if (cpk->chain != NULL)
+ extra_certs = cpk->chain;
+ else
+ extra_certs = s->ctx->extra_certs;
+
+ if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extra_certs)
+ chain_store = NULL;
+ else if (s->cert->chain_store)
+ chain_store = s->cert->chain_store;
+ else
+ chain_store = s->ctx->cert_store;
+
+ if (chain_store != NULL) {
+ X509_STORE_CTX *xs_ctx = X509_STORE_CTX_new();
+
+ if (xs_ctx == NULL) {
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!X509_STORE_CTX_init(xs_ctx, chain_store, x, NULL)) {
+ X509_STORE_CTX_free(xs_ctx);
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, ERR_R_X509_LIB);
+ goto err;
+ }
+ /*
+ * It is valid for the chain not to be complete (because normally we
+ * don't include the root cert in the chain). Therefore we deliberately
+ * ignore the error return from this call. We're not actually verifying
+ * the cert - we're just building as much of the chain as we can
+ */
+ (void)X509_verify_cert(xs_ctx);
+ /* Don't leave errors in the queue */
+ ERR_clear_error();
+ chain = X509_STORE_CTX_get0_chain(xs_ctx);
+ i = ssl_security_cert_chain(s, chain, NULL, 0);
+ if (i != 1) {
+#if 0
+ /* Dummy error calls so mkerr generates them */
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, SSL_R_EE_KEY_TOO_SMALL);
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, SSL_R_CA_KEY_TOO_SMALL);
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, SSL_R_CA_MD_TOO_WEAK);
+#endif
+ X509_STORE_CTX_free(xs_ctx);
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, i);
+ goto err;
+ }
+ chain_count = sk_X509_num(chain);
+ for (i = 0; i < chain_count; i++) {
+ x = sk_X509_value(chain, i);
+
+ if (!ssl_add_cert_to_wpacket(s, pkt, x, i, &tmpal)) {
+ X509_STORE_CTX_free(xs_ctx);
+ goto err;
+ }
+ }
+ X509_STORE_CTX_free(xs_ctx);
+ } else {
+ i = ssl_security_cert_chain(s, extra_certs, x, 0);
+ if (i != 1) {
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, i);
+ goto err;
+ }
+ if (!ssl_add_cert_to_wpacket(s, pkt, x, 0, &tmpal))
+ goto err;
+ for (i = 0; i < sk_X509_num(extra_certs); i++) {
+ x = sk_X509_value(extra_certs, i);
+ if (!ssl_add_cert_to_wpacket(s, pkt, x, i + 1, &tmpal))
+ goto err;
+ }
+ }
+ return 1;
+
+ err:
+ *al = tmpal;
+ return 0;
+}
+
+unsigned long ssl3_output_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk,
+ int *al)
+{
+ int tmpal = SSL_AD_INTERNAL_ERROR;
+
if (!WPACKET_start_sub_packet_u24(pkt)
- || !ssl_add_cert_chain(s, pkt, cpk)
+ || !ssl_add_cert_chain(s, pkt, cpk, &tmpal)
|| !WPACKET_close(pkt)) {
SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN, ERR_R_INTERNAL_ERROR);
+ *al = tmpal;
return 0;
}
return 1;
switch (server_version) {
default:
+ /*
+ * TODO(TLS1.3): This check will fail if someone attempts to do
+ * renegotiation in TLS1.3 at the moment. We need to ensure we disable
+ * renegotiation for TLS1.3
+ */
if (version_cmp(s, client_version, s->version) < 0)
return SSL_R_WRONG_SSL_VERSION;
/*
break;
}
- suppversions = tls_get_extension_by_type(hello->pre_proc_exts,
- hello->num_extensions,
- TLSEXT_TYPE_supported_versions);
+ suppversions = &hello->pre_proc_exts[TLSEXT_IDX_supported_versions];
- if (suppversions != NULL && !SSL_IS_DTLS(s)) {
+ if (suppversions->present && !SSL_IS_DTLS(s)) {
unsigned int candidate_vers = 0;
unsigned int best_vers = 0;
const SSL_METHOD *best_method = NULL;
PACKET versionslist;
+ suppversions->parsed = 1;
+
if (!PACKET_as_length_prefixed_1(&suppversions->data, &versionslist)) {
/* Trailing or invalid data? */
return SSL_R_LENGTH_MISMATCH;
/* TODO(TLS1.3): Remove this before release */
if (candidate_vers == TLS1_3_VERSION_DRAFT)
candidate_vers = TLS1_3_VERSION;
- if ((int)candidate_vers > s->client_version)
- s->client_version = candidate_vers;
+ /*
+ * TODO(TLS1.3): There is some discussion on the TLS list about
+ * wheter to ignore versions <TLS1.2 in supported_versions. At the
+ * moment we honour them if present. To be reviewed later
+ */
if (version_cmp(s, candidate_vers, best_vers) <= 0)
continue;
for (vent = table;
vent->version != 0 && vent->version != (int)candidate_vers;
++vent)
- ;
+ continue;
if (vent->version != 0 && vent->smeth != NULL) {
const SSL_METHOD *method;
const version_info *vent;
const version_info *table;
+ /* TODO(TLS1.3): Remove this before release */
+ if (version == TLS1_3_VERSION_DRAFT)
+ version = TLS1_3_VERSION;
+
switch (s->method->version) {
default:
if (version != s->version)
/*
* ssl_set_client_hello_version - Work out what version we should be using for
- * the initial ClientHello.
+ * the initial ClientHello.legacy_version field.
*
* @s: client SSL handle.
*
if (ret != 0)
return ret;
- s->client_version = s->version = ver_max;
+ s->version = ver_max;
+
+ /* TLS1.3 always uses TLS1.2 in the legacy_version field */
+ if (!SSL_IS_DTLS(s) && ver_max > TLS1_2_VERSION)
+ ver_max = TLS1_2_VERSION;
+
+ s->client_version = ver_max;
return 0;
}