EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) { const unsigned char *npa; unsigned int npalen; int ret; int npn_seen = s->s3->npn_seen; s->s3->npn_seen = 0; if (!npn_seen || s->ctx->ext.npn_advertised_cb == NULL) return EXT_RETURN_NOT_SENT; ret = s->ctx->ext.npn_advertised_cb(s, &npa, &npalen, s->ctx->ext.npn_advertised_cb_arg); if (ret == SSL_TLSEXT_ERR_OK) { if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg) || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } s->s3->npn_seen = 1; } return EXT_RETURN_SENT; }
int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, int *al) { s->s3->alpn_sent = 0; /* * finish_md_len is non-zero during a renegotiation, so * this avoids sending ALPN during the renegotiation */ if (s->alpn_client_proto_list == NULL || s->s3->tmp.finish_md_len != 0) return 1; if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_application_layer_protocol_negotiation) /* Sub-packet ALPN extension */ || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_sub_memcpy_u16(pkt, s->alpn_client_proto_list, s->alpn_client_proto_list_len) || !WPACKET_close(pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_ALPN, ERR_R_INTERNAL_ERROR); return 0; } s->s3->alpn_sent = 1; return 1; }
int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, int *al) { const unsigned char *npa; unsigned int npalen; int ret; int next_proto_neg_seen = s->s3->next_proto_neg_seen; s->s3->next_proto_neg_seen = 0; if (!next_proto_neg_seen || s->ctx->next_protos_advertised_cb == NULL) return 1; ret = s->ctx->next_protos_advertised_cb(s, &npa, &npalen, s->ctx->next_protos_advertised_cb_arg); if (ret == SSL_TLSEXT_ERR_OK) { if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg) || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG, ERR_R_INTERNAL_ERROR); return 0; } s->s3->next_proto_neg_seen = 1; } return 1; }
int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, int *al) { unsigned char *encodedPoint; size_t encoded_pt_len = 0; EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL; if (s->hit) return 1; if (ckey == NULL) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share) || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } skey = ssl_generate_pkey(ckey); if (skey == NULL) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_MALLOC_FAILURE); return 0; } /* Generate encoding of server key */ encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint); if (encoded_pt_len == 0) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_EC_LIB); EVP_PKEY_free(skey); return 0; } if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len) || !WPACKET_close(pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); EVP_PKEY_free(skey); OPENSSL_free(encodedPoint); return 0; } OPENSSL_free(encodedPoint); /* This causes the crypto state to be updated based on the derived keys */ s->s3->tmp.pkey = skey; if (ssl_derive(s, skey, ckey, 1) == 0) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } return 1; }
static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id) { unsigned char *encoded_point; EVP_PKEY *key_share_key; size_t encodedlen; key_share_key = ssl_generate_pkey_curve(curve_id); if (key_share_key == NULL) { SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EVP_LIB); return 0; } /* Encode the public key. */ encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key, &encoded_point); if (encodedlen == 0) { SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EC_LIB); EVP_PKEY_free(key_share_key); return 0; } /* Create KeyShareEntry */ if (!WPACKET_put_bytes_u16(pkt, curve_id) || !WPACKET_sub_memcpy_u16(pkt, encoded_point, encodedlen)) { SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_INTERNAL_ERROR); EVP_PKEY_free(key_share_key); OPENSSL_free(encoded_point); return 0; } /* * TODO(TLS1.3): When changing to send more than one key_share we're * going to need to be able to save more than one EVP_PKEY. For now * we reuse the existing tmp.pkey */ s->s3->tmp.pkey = key_share_key; s->s3->group_id = curve_id; OPENSSL_free(encoded_point); return 1; }
int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) { size_t ticklen; if (!tls_use_ticket(s)) return 1; if (!s->new_session && s->session != NULL && s->session->ext.tick != NULL && s->session->ssl_version != TLS1_3_VERSION) { ticklen = s->session->ext.ticklen; } else if (s->session && s->ext.session_ticket != NULL && s->ext.session_ticket->data != NULL) { ticklen = s->ext.session_ticket->length; s->session->ext.tick = OPENSSL_malloc(ticklen); if (s->session->ext.tick == NULL) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET, ERR_R_INTERNAL_ERROR); return 0; } memcpy(s->session->ext.tick, s->ext.session_ticket->data, ticklen); s->session->ext.ticklen = ticklen; } else { ticklen = 0; } if (ticklen == 0 && s->ext.session_ticket != NULL && s->ext.session_ticket->data == NULL) return 1; if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket) || !WPACKET_sub_memcpy_u16(pkt, s->session->ext.tick, ticklen)) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET, ERR_R_INTERNAL_ERROR); return 0; } return 1; }
int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) { s->s3->alpn_sent = 0; if (s->ext.alpn == NULL || !SSL_IS_FIRST_HANDSHAKE(s)) return 1; if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_application_layer_protocol_negotiation) /* Sub-packet ALPN extension */ || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_sub_memcpy_u16(pkt, s->ext.alpn, s->ext.alpn_len) || !WPACKET_close(pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_ALPN, ERR_R_INTERNAL_ERROR); return 0; } s->s3->alpn_sent = 1; return 1; }
int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, int *al) { if (s->tlsext_hostname == NULL) return 1; /* Add TLS extension servername to the Client Hello message */ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name) /* Sub-packet for server_name extension */ || !WPACKET_start_sub_packet_u16(pkt) /* Sub-packet for servername list (always 1 hostname)*/ || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_put_bytes_u8(pkt, TLSEXT_NAMETYPE_host_name) || !WPACKET_sub_memcpy_u16(pkt, s->tlsext_hostname, strlen(s->tlsext_hostname)) || !WPACKET_close(pkt) || !WPACKET_close(pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME, ERR_R_INTERNAL_ERROR); return 0; } return 1; }
EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) { #ifndef OPENSSL_NO_TLS1_3 unsigned char *encodedPoint; size_t encoded_pt_len = 0; EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL; if (ckey == NULL) { /* No key_share received from client */ if (s->hello_retry_request) { if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share) || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_put_bytes_u16(pkt, s->s3->group_id) || !WPACKET_close(pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } return EXT_RETURN_SENT; } /* Must be resuming. */ if (!s->hit || !tls13_generate_handshake_secret(s, NULL, 0)) { *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } return EXT_RETURN_NOT_SENT; } if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share) || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } skey = ssl_generate_pkey(ckey); if (skey == NULL) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_MALLOC_FAILURE); return EXT_RETURN_FAIL; } /* Generate encoding of server key */ encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint); if (encoded_pt_len == 0) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_EC_LIB); EVP_PKEY_free(skey); return EXT_RETURN_FAIL; } if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len) || !WPACKET_close(pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); EVP_PKEY_free(skey); OPENSSL_free(encodedPoint); return EXT_RETURN_FAIL; } OPENSSL_free(encodedPoint); /* This causes the crypto state to be updated based on the derived keys */ s->s3->tmp.pkey = skey; if (ssl_derive(s, skey, ckey, 1) == 0) { SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } #endif return EXT_RETURN_SENT; }
/* * Construct the pre_shared_key extension */ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) { #ifndef OPENSSL_NO_TLS1_3 uint32_t now, agesec, agems; size_t hashsize, binderoffset, msglen; unsigned char *binder = NULL, *msgstart = NULL; const EVP_MD *md; int ret = 0; s->session->ext.tick_identity = TLSEXT_PSK_BAD_IDENTITY; /* * If this is an incompatible or new session then we have nothing to resume * so don't add this extension. */ if (s->session->ssl_version != TLS1_3_VERSION || s->session->ext.ticklen == 0) return 1; if (s->session->cipher == NULL) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR); goto err; } md = ssl_md(s->session->cipher->algorithm2); if (md == NULL) { /* Don't recognise this cipher so we can't use the session. Ignore it */ 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); agesec = now - (uint32_t)s->session->time; if (s->session->ext.tick_lifetime_hint < agesec) { /* Ticket is too old. Ignore it. */ return 1; } /* * Calculate age in ms. We're just doing it to nearest second. Should be * good enough. */ agems = agesec * (uint32_t)1000; if (agesec != 0 && agems / (uint32_t)1000 != agesec) { /* * Overflow. Shouldn't happen unless this is a *really* old session. If * so we just ignore it. */ return 1; } /* * Obfuscate the age. Overflow here is fine, this addition is supposed to * be mod 2^32. */ agems += s->session->ext.tick_age_add; 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; if (tls_psk_do_binder(s, md, msgstart, binderoffset, NULL, binder, s->session, 1) != 1) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR); goto err; } s->session->ext.tick_identity = 0; ret = 1; err: return ret; #else return 1; #endif }
int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, int *al) { size_t i, sharessent = 0, num_curves = 0; const unsigned char *pcurves = NULL; /* key_share extension */ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share) /* Extension data sub-packet */ || !WPACKET_start_sub_packet_u16(pkt) /* KeyShare list sub-packet */ || !WPACKET_start_sub_packet_u16(pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } pcurves = s->tlsext_supportedgroupslist; if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } /* * TODO(TLS1.3): Make the number of key_shares sent configurable. For * now, just send one */ for (i = 0; i < num_curves && sharessent < 1; i++, pcurves += 2) { unsigned char *encodedPoint = NULL; unsigned int curve_id = 0; EVP_PKEY *key_share_key = NULL; size_t encodedlen; if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) continue; if (s->s3->tmp.pkey != NULL) { /* Shouldn't happen! */ SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } /* Generate a key for this key_share */ curve_id = (pcurves[0] << 8) | pcurves[1]; key_share_key = ssl_generate_pkey_curve(curve_id); if (key_share_key == NULL) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EVP_LIB); return 0; } /* Encode the public key. */ encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key, &encodedPoint); if (encodedlen == 0) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EC_LIB); EVP_PKEY_free(key_share_key); return 0; } /* Create KeyShareEntry */ if (!WPACKET_put_bytes_u16(pkt, curve_id) || !WPACKET_sub_memcpy_u16(pkt, encodedPoint, encodedlen)) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); EVP_PKEY_free(key_share_key); OPENSSL_free(encodedPoint); return 0; } /* * TODO(TLS1.3): When changing to send more than one key_share we're * going to need to be able to save more than one EVP_PKEY. For now * we reuse the existing tmp.pkey */ s->s3->group_id = curve_id; s->s3->tmp.pkey = key_share_key; sharessent++; OPENSSL_free(encodedPoint); } if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR); return 0; } return 1; }