#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>
#include <openssl/ocsp.h>
#include <openssl/opensslconf.h>
#include "bytestring.h"
#include "ssl_local.h"
#include "ssl_sigalgs.h"
#include "ssl_tlsext.h"
#define TLSEXT_TYPE_alpn TLSEXT_TYPE_application_layer_protocol_negotiation
#define TLSEXT_MAX_SUPPORTED_GROUPS 64
static int
tlsext_alpn_client_needs(SSL *s, uint16_t msg_type)
{
return s->alpn_client_proto_list != NULL &&
s->s3->hs.finished_len == 0;
}
static int
tlsext_alpn_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB protolist;
if (!CBB_add_u16_length_prefixed(cbb, &protolist))
return 0;
if (!CBB_add_bytes(&protolist, s->alpn_client_proto_list,
s->alpn_client_proto_list_len))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
int
tlsext_alpn_check_format(CBS *cbs)
{
CBS proto_name_list;
if (CBS_len(cbs) == 0)
return 0;
CBS_dup(cbs, &proto_name_list);
while (CBS_len(&proto_name_list) > 0) {
CBS proto_name;
if (!CBS_get_u8_length_prefixed(&proto_name_list, &proto_name))
return 0;
if (CBS_len(&proto_name) == 0)
return 0;
}
return 1;
}
static int
tlsext_alpn_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS alpn, selected_cbs;
const unsigned char *selected;
unsigned char selected_len;
int r;
if (!CBS_get_u16_length_prefixed(cbs, &alpn))
return 0;
if (!tlsext_alpn_check_format(&alpn))
return 0;
if (s->ctx->alpn_select_cb == NULL)
return 1;
r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
CBS_data(&alpn), CBS_len(&alpn), s->ctx->alpn_select_cb_arg);
if (r == SSL_TLSEXT_ERR_OK) {
CBS_init(&selected_cbs, selected, selected_len);
if (!CBS_stow(&selected_cbs, &s->s3->alpn_selected,
&s->s3->alpn_selected_len)) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
return 1;
}
if (r == SSL_TLSEXT_ERR_NOACK)
return 1;
*alert = SSL_AD_NO_APPLICATION_PROTOCOL;
SSLerror(s, SSL_R_NO_APPLICATION_PROTOCOL);
return 0;
}
static int
tlsext_alpn_server_needs(SSL *s, uint16_t msg_type)
{
return s->s3->alpn_selected != NULL;
}
static int
tlsext_alpn_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB list, selected;
if (!CBB_add_u16_length_prefixed(cbb, &list))
return 0;
if (!CBB_add_u8_length_prefixed(&list, &selected))
return 0;
if (!CBB_add_bytes(&selected, s->s3->alpn_selected,
s->s3->alpn_selected_len))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_alpn_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS list, proto;
if (s->alpn_client_proto_list == NULL) {
*alert = SSL_AD_UNSUPPORTED_EXTENSION;
return 0;
}
if (!CBS_get_u16_length_prefixed(cbs, &list))
return 0;
if (!CBS_get_u8_length_prefixed(&list, &proto))
return 0;
if (CBS_len(&list) != 0)
return 0;
if (CBS_len(&proto) == 0)
return 0;
if (!CBS_stow(&proto, &s->s3->alpn_selected, &s->s3->alpn_selected_len))
return 0;
return 1;
}
static int
tlsext_supportedgroups_client_needs(SSL *s, uint16_t msg_type)
{
return ssl_has_ecc_ciphers(s) ||
(s->s3->hs.our_max_tls_version >= TLS1_3_VERSION);
}
static int
tlsext_supportedgroups_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
const uint16_t *groups;
size_t groups_len;
CBB grouplist;
int i;
tls1_get_group_list(s, 0, &groups, &groups_len);
if (groups_len == 0) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return 0;
}
if (!CBB_add_u16_length_prefixed(cbb, &grouplist))
return 0;
for (i = 0; i < groups_len; i++) {
if (!ssl_security_supported_group(s, groups[i]))
continue;
if (!CBB_add_u16(&grouplist, groups[i]))
return 0;
}
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_supportedgroups_server_process(SSL *s, uint16_t msg_type, CBS *cbs,
int *alert)
{
uint16_t *groups = NULL;
size_t groups_len;
CBS grouplist;
int i, j;
int ret = 0;
if (!CBS_get_u16_length_prefixed(cbs, &grouplist))
goto err;
groups_len = CBS_len(&grouplist);
if (groups_len == 0 || groups_len % 2 != 0)
goto err;
groups_len /= 2;
if (groups_len > TLSEXT_MAX_SUPPORTED_GROUPS)
goto err;
if (s->hit)
goto done;
if (s->s3->hs.tls13.hrr) {
if (s->session->tlsext_supportedgroups == NULL) {
*alert = SSL_AD_HANDSHAKE_FAILURE;
return 0;
}
goto done;
}
if (s->session->tlsext_supportedgroups != NULL)
goto err;
if ((groups = reallocarray(NULL, groups_len, sizeof(uint16_t))) == NULL) {
*alert = SSL_AD_INTERNAL_ERROR;
goto err;
}
for (i = 0; i < groups_len; i++) {
if (!CBS_get_u16(&grouplist, &groups[i]))
goto err;
for (j = 0; j < i; j++) {
if (groups[i] == groups[j]) {
*alert = SSL_AD_ILLEGAL_PARAMETER;
goto err;
}
}
}
if (CBS_len(&grouplist) != 0)
goto err;
s->session->tlsext_supportedgroups = groups;
s->session->tlsext_supportedgroups_length = groups_len;
groups = NULL;
done:
ret = 1;
err:
free(groups);
return ret;
}
static int
tlsext_supportedgroups_server_needs(SSL *s, uint16_t msg_type)
{
return 0;
}
static int
tlsext_supportedgroups_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return 0;
}
static int
tlsext_supportedgroups_client_process(SSL *s, uint16_t msg_type, CBS *cbs,
int *alert)
{
if (msg_type != SSL_TLSEXT_MSG_EE)
return 0;
if (!CBS_skip(cbs, CBS_len(cbs))) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
return 1;
}
static int
tlsext_ecpf_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB ecpf;
size_t formats_len;
const uint8_t *formats;
tls1_get_formatlist(s, 0, &formats, &formats_len);
if (formats_len == 0) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return 0;
}
if (!CBB_add_u8_length_prefixed(cbb, &ecpf))
return 0;
if (!CBB_add_bytes(&ecpf, formats, formats_len))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_ecpf_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS ecpf;
if (!CBS_get_u8_length_prefixed(cbs, &ecpf))
return 0;
if (CBS_len(&ecpf) == 0)
return 0;
if (!CBS_contains_zero_byte(&ecpf)) {
SSLerror(s, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
*alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
if (!s->hit) {
if (!CBS_stow(&ecpf, &(s->session->tlsext_ecpointformatlist),
&(s->session->tlsext_ecpointformatlist_length))) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
}
return 1;
}
static int
tlsext_ecpf_client_needs(SSL *s, uint16_t msg_type)
{
return ssl_has_ecc_ciphers(s);
}
static int
tlsext_ecpf_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return tlsext_ecpf_build(s, msg_type, cbb);
}
static int
tlsext_ecpf_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
return tlsext_ecpf_process(s, msg_type, cbs, alert);
}
static int
tlsext_ecpf_server_needs(SSL *s, uint16_t msg_type)
{
return ssl_using_ecc_cipher(s);
}
static int
tlsext_ecpf_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return tlsext_ecpf_build(s, msg_type, cbb);
}
static int
tlsext_ecpf_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
return tlsext_ecpf_process(s, msg_type, cbs, alert);
}
static int
tlsext_ri_client_needs(SSL *s, uint16_t msg_type)
{
return (s->renegotiate);
}
static int
tlsext_ri_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB reneg;
if (!CBB_add_u8_length_prefixed(cbb, &reneg))
return 0;
if (!CBB_add_bytes(&reneg, s->s3->previous_client_finished,
s->s3->previous_client_finished_len))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_ri_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS reneg;
if (!CBS_get_u8_length_prefixed(cbs, &reneg)) {
SSLerror(s, SSL_R_RENEGOTIATION_ENCODING_ERR);
return 0;
}
if (!CBS_mem_equal(&reneg, s->s3->previous_client_finished,
s->s3->previous_client_finished_len)) {
SSLerror(s, SSL_R_RENEGOTIATION_MISMATCH);
*alert = SSL_AD_HANDSHAKE_FAILURE;
return 0;
}
s->s3->renegotiate_seen = 1;
s->s3->send_connection_binding = 1;
return 1;
}
static int
tlsext_ri_server_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.negotiated_tls_version < TLS1_3_VERSION &&
s->s3->send_connection_binding);
}
static int
tlsext_ri_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB reneg;
if (!CBB_add_u8_length_prefixed(cbb, &reneg))
return 0;
if (!CBB_add_bytes(&reneg, s->s3->previous_client_finished,
s->s3->previous_client_finished_len))
return 0;
if (!CBB_add_bytes(&reneg, s->s3->previous_server_finished,
s->s3->previous_server_finished_len))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_ri_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS reneg, prev_client, prev_server;
if ((s->s3->previous_client_finished_len == 0 &&
s->s3->previous_server_finished_len != 0) ||
(s->s3->previous_client_finished_len != 0 &&
s->s3->previous_server_finished_len == 0)) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
if (!CBS_get_u8_length_prefixed(cbs, &reneg)) {
SSLerror(s, SSL_R_RENEGOTIATION_ENCODING_ERR);
return 0;
}
if (!CBS_get_bytes(&reneg, &prev_client,
s->s3->previous_client_finished_len)) {
SSLerror(s, SSL_R_RENEGOTIATION_ENCODING_ERR);
return 0;
}
if (!CBS_get_bytes(&reneg, &prev_server,
s->s3->previous_server_finished_len)) {
SSLerror(s, SSL_R_RENEGOTIATION_ENCODING_ERR);
return 0;
}
if (CBS_len(&reneg) != 0) {
SSLerror(s, SSL_R_RENEGOTIATION_ENCODING_ERR);
return 0;
}
if (!CBS_mem_equal(&prev_client, s->s3->previous_client_finished,
s->s3->previous_client_finished_len)) {
SSLerror(s, SSL_R_RENEGOTIATION_MISMATCH);
*alert = SSL_AD_HANDSHAKE_FAILURE;
return 0;
}
if (!CBS_mem_equal(&prev_server, s->s3->previous_server_finished,
s->s3->previous_server_finished_len)) {
SSLerror(s, SSL_R_RENEGOTIATION_MISMATCH);
*alert = SSL_AD_HANDSHAKE_FAILURE;
return 0;
}
s->s3->renegotiate_seen = 1;
s->s3->send_connection_binding = 1;
return 1;
}
static int
tlsext_sigalgs_client_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.our_max_tls_version >= TLS1_2_VERSION);
}
static int
tlsext_sigalgs_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
uint16_t tls_version = s->s3->hs.negotiated_tls_version;
CBB sigalgs;
if (msg_type == SSL_TLSEXT_MSG_CH)
tls_version = s->s3->hs.our_min_tls_version;
if (!CBB_add_u16_length_prefixed(cbb, &sigalgs))
return 0;
if (!ssl_sigalgs_build(tls_version, &sigalgs, SSL_get_security_level(s)))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_sigalgs_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS sigalgs;
if (!CBS_get_u16_length_prefixed(cbs, &sigalgs))
return 0;
if (CBS_len(&sigalgs) % 2 != 0 || CBS_len(&sigalgs) > 64)
return 0;
if (!CBS_stow(&sigalgs, &s->s3->hs.sigalgs, &s->s3->hs.sigalgs_len))
return 0;
return 1;
}
static int
tlsext_sigalgs_server_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.negotiated_tls_version >= TLS1_3_VERSION);
}
static int
tlsext_sigalgs_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB sigalgs;
if (!CBB_add_u16_length_prefixed(cbb, &sigalgs))
return 0;
if (!ssl_sigalgs_build(s->s3->hs.negotiated_tls_version, &sigalgs,
SSL_get_security_level(s)))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_sigalgs_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS sigalgs;
if (ssl_effective_tls_version(s) < TLS1_3_VERSION)
return 0;
if (!CBS_get_u16_length_prefixed(cbs, &sigalgs))
return 0;
if (CBS_len(&sigalgs) % 2 != 0 || CBS_len(&sigalgs) > 64)
return 0;
if (!CBS_stow(&sigalgs, &s->s3->hs.sigalgs, &s->s3->hs.sigalgs_len))
return 0;
return 1;
}
static int
tlsext_sni_client_needs(SSL *s, uint16_t msg_type)
{
return (s->tlsext_hostname != NULL);
}
static int
tlsext_sni_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB server_name_list, host_name;
if (!CBB_add_u16_length_prefixed(cbb, &server_name_list))
return 0;
if (!CBB_add_u8(&server_name_list, TLSEXT_NAMETYPE_host_name))
return 0;
if (!CBB_add_u16_length_prefixed(&server_name_list, &host_name))
return 0;
if (!CBB_add_bytes(&host_name, (const uint8_t *)s->tlsext_hostname,
strlen(s->tlsext_hostname)))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_sni_is_ip_literal(CBS *cbs, int *is_ip)
{
union {
struct in_addr ip4;
struct in6_addr ip6;
} addrbuf;
char *hostname = NULL;
*is_ip = 0;
if (!CBS_strdup(cbs, &hostname))
return 0;
if (inet_pton(AF_INET, hostname, &addrbuf) == 1 ||
inet_pton(AF_INET6, hostname, &addrbuf) == 1)
*is_ip = 1;
free(hostname);
return 1;
}
int
tlsext_sni_is_valid_hostname(CBS *cbs, int *is_ip)
{
uint8_t prev, c = 0;
int component = 0;
CBS hostname;
*is_ip = 0;
CBS_dup(cbs, &hostname);
if (CBS_len(&hostname) > TLSEXT_MAXLEN_host_name)
return 0;
if (!tlsext_sni_is_ip_literal(&hostname, is_ip))
return 0;
if (*is_ip)
return 0;
while (CBS_len(&hostname) > 0) {
prev = c;
if (!CBS_get_u8(&hostname, &c))
return 0;
if (!isascii(c) || c == '\0')
return 0;
if (!isalnum(c) && c != '-' && c != '.')
return 0;
if (component == 0 || CBS_len(&hostname) == 0) {
if (c == '-' || c == '.')
return 0;
}
if (c == '.') {
if (prev == '-')
return 0;
component = 0;
continue;
}
if (++component > 63)
return 0;
}
return 1;
}
static int
tlsext_sni_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS server_name_list, host_name;
uint8_t name_type;
int is_ip;
if (!CBS_get_u16_length_prefixed(cbs, &server_name_list))
goto err;
if (!CBS_get_u8(&server_name_list, &name_type))
goto err;
if (name_type != TLSEXT_NAMETYPE_host_name) {
*alert = SSL_AD_ILLEGAL_PARAMETER;
goto err;
}
if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name))
goto err;
if (CBS_len(&host_name) < 1)
goto err;
if (!tlsext_sni_is_valid_hostname(&host_name, &is_ip)) {
if (is_ip)
goto done;
*alert = SSL_AD_ILLEGAL_PARAMETER;
goto err;
}
if (s->hit || s->s3->hs.tls13.hrr) {
if (s->session->tlsext_hostname == NULL) {
*alert = SSL_AD_UNRECOGNIZED_NAME;
goto err;
}
if (!CBS_mem_equal(&host_name, s->session->tlsext_hostname,
strlen(s->session->tlsext_hostname))) {
*alert = SSL_AD_UNRECOGNIZED_NAME;
goto err;
}
} else {
if (s->session->tlsext_hostname != NULL)
goto err;
if (!CBS_strdup(&host_name, &s->session->tlsext_hostname)) {
*alert = SSL_AD_INTERNAL_ERROR;
goto err;
}
}
done:
if (CBS_len(&server_name_list) != 0) {
*alert = SSL_AD_ILLEGAL_PARAMETER;
goto err;
}
return 1;
err:
return 0;
}
static int
tlsext_sni_server_needs(SSL *s, uint16_t msg_type)
{
if (s->hit)
return 0;
return (s->session->tlsext_hostname != NULL);
}
static int
tlsext_sni_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return 1;
}
static int
tlsext_sni_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
if (s->tlsext_hostname == NULL || CBS_len(cbs) != 0) {
*alert = SSL_AD_UNRECOGNIZED_NAME;
return 0;
}
if (s->hit) {
if (s->session->tlsext_hostname == NULL) {
*alert = SSL_AD_UNRECOGNIZED_NAME;
return 0;
}
if (strcmp(s->tlsext_hostname,
s->session->tlsext_hostname) != 0) {
*alert = SSL_AD_UNRECOGNIZED_NAME;
return 0;
}
} else {
if (s->session->tlsext_hostname != NULL)
return 0;
if ((s->session->tlsext_hostname =
strdup(s->tlsext_hostname)) == NULL) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
}
return 1;
}
static int
tlsext_ocsp_client_needs(SSL *s, uint16_t msg_type)
{
if (msg_type != SSL_TLSEXT_MSG_CH)
return 0;
return (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp);
}
static int
tlsext_ocsp_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB respid_list, respid, exts;
unsigned char *ext_data;
size_t ext_len;
int i;
if (!CBB_add_u8(cbb, TLSEXT_STATUSTYPE_ocsp))
return 0;
if (!CBB_add_u16_length_prefixed(cbb, &respid_list))
return 0;
for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) {
unsigned char *respid_data;
OCSP_RESPID *id;
size_t id_len;
if ((id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids,
i)) == NULL)
return 0;
if ((id_len = i2d_OCSP_RESPID(id, NULL)) == -1)
return 0;
if (!CBB_add_u16_length_prefixed(&respid_list, &respid))
return 0;
if (!CBB_add_space(&respid, &respid_data, id_len))
return 0;
if ((i2d_OCSP_RESPID(id, &respid_data)) != id_len)
return 0;
}
if (!CBB_add_u16_length_prefixed(cbb, &exts))
return 0;
if ((ext_len = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts,
NULL)) == -1)
return 0;
if (!CBB_add_space(&exts, &ext_data, ext_len))
return 0;
if ((i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ext_data) !=
ext_len))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_ocsp_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
int alert_desc = SSL_AD_DECODE_ERROR;
CBS respid_list, respid, exts;
const unsigned char *p;
uint8_t status_type;
int ret = 0;
if (msg_type != SSL_TLSEXT_MSG_CH)
goto err;
if (!CBS_get_u8(cbs, &status_type))
goto err;
if (status_type != TLSEXT_STATUSTYPE_ocsp) {
s->tlsext_status_type = -1;
if (!CBS_skip(cbs, CBS_len(cbs))) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
return 1;
}
s->tlsext_status_type = status_type;
if (!CBS_get_u16_length_prefixed(cbs, &respid_list))
goto err;
sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
s->tlsext_ocsp_ids = NULL;
if (CBS_len(&respid_list) > 0) {
s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null();
if (s->tlsext_ocsp_ids == NULL) {
alert_desc = SSL_AD_INTERNAL_ERROR;
goto err;
}
}
while (CBS_len(&respid_list) > 0) {
OCSP_RESPID *id;
if (!CBS_get_u16_length_prefixed(&respid_list, &respid))
goto err;
p = CBS_data(&respid);
if ((id = d2i_OCSP_RESPID(NULL, &p, CBS_len(&respid))) == NULL)
goto err;
if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id)) {
alert_desc = SSL_AD_INTERNAL_ERROR;
OCSP_RESPID_free(id);
goto err;
}
}
if (!CBS_get_u16_length_prefixed(cbs, &exts))
goto err;
if (CBS_len(&exts) > 0) {
sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
X509_EXTENSION_free);
p = CBS_data(&exts);
if ((s->tlsext_ocsp_exts = d2i_X509_EXTENSIONS(NULL,
&p, CBS_len(&exts))) == NULL)
goto err;
}
ret = 1;
err:
if (ret == 0)
*alert = alert_desc;
return ret;
}
static int
tlsext_ocsp_server_needs(SSL *s, uint16_t msg_type)
{
if (s->s3->hs.negotiated_tls_version >= TLS1_3_VERSION &&
s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
s->ctx->tlsext_status_cb != NULL) {
s->tlsext_status_expected = 0;
if (s->ctx->tlsext_status_cb(s,
s->ctx->tlsext_status_arg) == SSL_TLSEXT_ERR_OK &&
s->tlsext_ocsp_resp_len > 0)
s->tlsext_status_expected = 1;
}
return s->tlsext_status_expected;
}
static int
tlsext_ocsp_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB ocsp_response;
if (s->s3->hs.negotiated_tls_version >= TLS1_3_VERSION) {
if (!CBB_add_u8(cbb, TLSEXT_STATUSTYPE_ocsp))
return 0;
if (!CBB_add_u24_length_prefixed(cbb, &ocsp_response))
return 0;
if (!CBB_add_bytes(&ocsp_response,
s->tlsext_ocsp_resp,
s->tlsext_ocsp_resp_len))
return 0;
if (!CBB_flush(cbb))
return 0;
}
return 1;
}
static int
tlsext_ocsp_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
uint8_t status_type;
CBS response;
if (ssl_effective_tls_version(s) >= TLS1_3_VERSION) {
if (msg_type == SSL_TLSEXT_MSG_CR) {
if (CBS_len(cbs) == 0)
return 1;
SSLerror(s, SSL_R_LENGTH_MISMATCH);
return 0;
}
if (!CBS_get_u8(cbs, &status_type)) {
SSLerror(s, SSL_R_LENGTH_MISMATCH);
return 0;
}
if (status_type != TLSEXT_STATUSTYPE_ocsp) {
SSLerror(s, SSL_R_UNSUPPORTED_STATUS_TYPE);
return 0;
}
if (!CBS_get_u24_length_prefixed(cbs, &response)) {
SSLerror(s, SSL_R_LENGTH_MISMATCH);
return 0;
}
if (CBS_len(&response) > 65536) {
SSLerror(s, SSL_R_DATA_LENGTH_TOO_LONG);
return 0;
}
if (!CBS_stow(&response, &s->tlsext_ocsp_resp,
&s->tlsext_ocsp_resp_len)) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
} else {
if (s->tlsext_status_type == -1) {
*alert = SSL_AD_UNSUPPORTED_EXTENSION;
return 0;
}
s->tlsext_status_expected = 1;
}
return 1;
}
static int
tlsext_sessionticket_client_needs(SSL *s, uint16_t msg_type)
{
if ((SSL_get_options(s) & SSL_OP_NO_TICKET) != 0)
return 0;
if (!ssl_security_tickets(s))
return 0;
if (s->new_session)
return 1;
if (s->tlsext_session_ticket != NULL &&
s->tlsext_session_ticket->data == NULL)
return 0;
return 1;
}
static int
tlsext_sessionticket_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
if (s->new_session || s->session == NULL)
return 1;
if (s->session->tlsext_tick != NULL) {
if (!CBB_add_bytes(cbb, s->session->tlsext_tick,
s->session->tlsext_ticklen))
return 0;
} else if (s->tlsext_session_ticket != NULL) {
if (s->tlsext_session_ticket->length > 0) {
size_t ticklen = s->tlsext_session_ticket->length;
if ((s->session->tlsext_tick = malloc(ticklen)) == NULL)
return 0;
memcpy(s->session->tlsext_tick,
s->tlsext_session_ticket->data,
ticklen);
s->session->tlsext_ticklen = ticklen;
if (!CBB_add_bytes(cbb, s->session->tlsext_tick,
s->session->tlsext_ticklen))
return 0;
}
}
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_sessionticket_server_process(SSL *s, uint16_t msg_type, CBS *cbs,
int *alert)
{
if (s->tls_session_ticket_ext_cb) {
if (!s->tls_session_ticket_ext_cb(s, CBS_data(cbs),
(int)CBS_len(cbs),
s->tls_session_ticket_ext_cb_arg)) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
}
if (!CBS_skip(cbs, CBS_len(cbs))) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
return 1;
}
static int
tlsext_sessionticket_server_needs(SSL *s, uint16_t msg_type)
{
return (s->tlsext_ticket_expected &&
!(SSL_get_options(s) & SSL_OP_NO_TICKET) &&
ssl_security_tickets(s));
}
static int
tlsext_sessionticket_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return 1;
}
static int
tlsext_sessionticket_client_process(SSL *s, uint16_t msg_type, CBS *cbs,
int *alert)
{
if (s->tls_session_ticket_ext_cb) {
if (!s->tls_session_ticket_ext_cb(s, CBS_data(cbs),
(int)CBS_len(cbs),
s->tls_session_ticket_ext_cb_arg)) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
}
if ((SSL_get_options(s) & SSL_OP_NO_TICKET) != 0 || CBS_len(cbs) > 0) {
*alert = SSL_AD_UNSUPPORTED_EXTENSION;
return 0;
}
s->tlsext_ticket_expected = 1;
return 1;
}
#ifndef OPENSSL_NO_SRTP
static int
tlsext_srtp_client_needs(SSL *s, uint16_t msg_type)
{
return SSL_is_dtls(s) && SSL_get_srtp_profiles(s) != NULL;
}
static int
tlsext_srtp_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB profiles, mki;
int ct, i;
STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = NULL;
const SRTP_PROTECTION_PROFILE *prof;
if ((clnt = SSL_get_srtp_profiles(s)) == NULL) {
SSLerror(s, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST);
return 0;
}
if ((ct = sk_SRTP_PROTECTION_PROFILE_num(clnt)) < 1) {
SSLerror(s, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST);
return 0;
}
if (!CBB_add_u16_length_prefixed(cbb, &profiles))
return 0;
for (i = 0; i < ct; i++) {
if ((prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i)) == NULL)
return 0;
if (!CBB_add_u16(&profiles, prof->id))
return 0;
}
if (!CBB_add_u8_length_prefixed(cbb, &mki))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_srtp_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
const SRTP_PROTECTION_PROFILE *cprof, *sprof;
STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = NULL, *srvr;
int i, j;
int ret;
uint16_t id;
CBS profiles, mki;
ret = 0;
if (!CBS_get_u16_length_prefixed(cbs, &profiles))
goto err;
if (CBS_len(&profiles) == 0 || CBS_len(&profiles) % 2 != 0)
goto err;
if ((clnt = sk_SRTP_PROTECTION_PROFILE_new_null()) == NULL)
goto err;
while (CBS_len(&profiles) > 0) {
if (!CBS_get_u16(&profiles, &id))
goto err;
if (!srtp_find_profile_by_num(id, &cprof)) {
if (!sk_SRTP_PROTECTION_PROFILE_push(clnt, cprof))
goto err;
}
}
if (!CBS_get_u8_length_prefixed(cbs, &mki) || CBS_len(&mki) != 0) {
SSLerror(s, SSL_R_BAD_SRTP_MKI_VALUE);
goto done;
}
if ((srvr = SSL_get_srtp_profiles(s)) == NULL)
goto err;
for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(srvr); i++) {
if ((sprof = sk_SRTP_PROTECTION_PROFILE_value(srvr, i)) == NULL)
goto err;
for (j = 0; j < sk_SRTP_PROTECTION_PROFILE_num(clnt); j++) {
if ((cprof = sk_SRTP_PROTECTION_PROFILE_value(clnt, j))
== NULL)
goto err;
if (cprof->id == sprof->id) {
s->srtp_profile = sprof;
ret = 1;
goto done;
}
}
}
ret = 1;
goto done;
err:
SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
done:
sk_SRTP_PROTECTION_PROFILE_free(clnt);
return ret;
}
static int
tlsext_srtp_server_needs(SSL *s, uint16_t msg_type)
{
return SSL_is_dtls(s) && SSL_get_selected_srtp_profile(s) != NULL;
}
static int
tlsext_srtp_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
SRTP_PROTECTION_PROFILE *profile;
CBB srtp, mki;
if (!CBB_add_u16_length_prefixed(cbb, &srtp))
return 0;
if ((profile = SSL_get_selected_srtp_profile(s)) == NULL)
return 0;
if (!CBB_add_u16(&srtp, profile->id))
return 0;
if (!CBB_add_u8_length_prefixed(cbb, &mki))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_srtp_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
STACK_OF(SRTP_PROTECTION_PROFILE) *clnt;
const SRTP_PROTECTION_PROFILE *prof;
int i;
uint16_t id;
CBS profile_ids, mki;
if (!CBS_get_u16_length_prefixed(cbs, &profile_ids)) {
SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
return 0;
}
if (!CBS_get_u16(&profile_ids, &id) || CBS_len(&profile_ids) != 0) {
SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
return 0;
}
if (!CBS_get_u8_length_prefixed(cbs, &mki) || CBS_len(&mki) != 0) {
SSLerror(s, SSL_R_BAD_SRTP_MKI_VALUE);
*alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
if ((clnt = SSL_get_srtp_profiles(s)) == NULL) {
SSLerror(s, SSL_R_NO_SRTP_PROFILES);
return 0;
}
for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(clnt); i++) {
if ((prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i))
== NULL) {
SSLerror(s, SSL_R_NO_SRTP_PROFILES);
return 0;
}
if (prof->id == id) {
s->srtp_profile = prof;
return 1;
}
}
SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST);
return 0;
}
#endif
static int
tlsext_keyshare_client_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.our_max_tls_version >= TLS1_3_VERSION);
}
static int
tlsext_keyshare_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB client_shares, key_exchange, key_exchange2;
if (!CBB_add_u16_length_prefixed(cbb, &client_shares))
return 0;
if (!CBB_add_u16(&client_shares,
tls_key_share_group(s->s3->hs.key_share)))
return 0;
if (!CBB_add_u16_length_prefixed(&client_shares, &key_exchange))
return 0;
if (!tls_key_share_public(s->s3->hs.key_share, &key_exchange))
return 0;
if (s->s3->hs.negotiated_tls_version == 0 &&
s->s3->hs.our_max_tls_version >= TLS1_3_VERSION) {
if (s->s3->hs.tls13.key_share != NULL) {
if (!CBB_add_u16(&client_shares,
tls_key_share_group(s->s3->hs.tls13.key_share)))
return 0;
if (!CBB_add_u16_length_prefixed(&client_shares,
&key_exchange2))
return 0;
if (!tls_key_share_public(s->s3->hs.tls13.key_share,
&key_exchange2))
return 0;
}
}
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
const uint16_t *client_groups = NULL, *server_groups = NULL;
size_t client_groups_len = 0, server_groups_len = 0;
size_t i, j, client_groups_index;
int preferred_group_found = 0;
int decode_error;
uint16_t client_preferred_group = 0;
uint16_t group;
CBS client_shares, key_exchange;
if (!tlsext_extension_seen(s, TLSEXT_TYPE_supported_groups)) {
*alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
if (!tlsext_extension_processed(s, TLSEXT_TYPE_supported_groups)) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
if (s->s3->hs.tls13.hrr) {
if (!CBS_get_u16_length_prefixed(cbs, &client_shares))
return 0;
if (!CBS_get_u16(&client_shares, &group))
return 0;
if (!CBS_get_u16_length_prefixed(&client_shares, &key_exchange))
return 0;
if (CBS_len(&client_shares) != 0)
return 0;
if (group != s->s3->hs.tls13.server_group) {
*alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
if (s->s3->hs.key_share != NULL) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
if ((s->s3->hs.key_share = tls_key_share_new(group)) == NULL) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
if (!tls_key_share_server_peer_public(s->s3->hs.key_share,
&key_exchange, &decode_error, NULL)) {
if (!decode_error)
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
return 1;
}
tls1_get_group_list(s, 0, &server_groups, &server_groups_len);
tls1_get_group_list(s, 1, &client_groups, &client_groups_len);
for (i = 0; i < client_groups_len && !preferred_group_found; i++) {
if (!ssl_security_supported_group(s, client_groups[i]))
continue;
for (j = 0; j < server_groups_len; j++) {
if (server_groups[j] == client_groups[i]) {
client_preferred_group = client_groups[i];
s->s3->hs.tls13.server_group = client_preferred_group;
preferred_group_found = 1;
break;
}
}
}
if (!CBS_get_u16_length_prefixed(cbs, &client_shares))
return 0;
client_groups_index = 0;
while (CBS_len(&client_shares) > 0) {
int client_sent_group;
if (!CBS_get_u16(&client_shares, &group))
return 0;
if (!CBS_get_u16_length_prefixed(&client_shares, &key_exchange))
return 0;
if (s->s3->hs.our_max_tls_version < TLS1_3_VERSION)
continue;
client_sent_group = 0;
while (client_groups_index < client_groups_len) {
if (group == client_groups[client_groups_index++]) {
client_sent_group = 1;
break;
}
}
if (!client_sent_group) {
*alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
if (s->s3->hs.key_share != NULL)
continue;
if (!preferred_group_found || group != client_preferred_group)
continue;
if ((s->s3->hs.key_share = tls_key_share_new(group)) == NULL) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
if (!tls_key_share_server_peer_public(s->s3->hs.key_share,
&key_exchange, &decode_error, NULL)) {
if (!decode_error)
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
}
return 1;
}
static int
tlsext_keyshare_server_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.negotiated_tls_version >= TLS1_3_VERSION &&
tlsext_extension_seen(s, TLSEXT_TYPE_key_share));
}
static int
tlsext_keyshare_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB key_exchange;
if (s->s3->hs.tls13.hrr) {
if (s->s3->hs.tls13.server_group == 0)
return 0;
return CBB_add_u16(cbb, s->s3->hs.tls13.server_group);
}
if (s->s3->hs.key_share == NULL)
return 0;
if (!CBB_add_u16(cbb, tls_key_share_group(s->s3->hs.key_share)))
return 0;
if (!CBB_add_u16_length_prefixed(cbb, &key_exchange))
return 0;
if (!tls_key_share_public(s->s3->hs.key_share, &key_exchange))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_keyshare_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS key_exchange;
int decode_error;
uint16_t group;
if (!CBS_get_u16(cbs, &group))
return 0;
if (CBS_len(cbs) == 0) {
if (msg_type != SSL_TLSEXT_MSG_HRR)
return 0;
s->s3->hs.tls13.server_group = group;
return 1;
}
if (!CBS_get_u16_length_prefixed(cbs, &key_exchange))
return 0;
if (s->s3->hs.key_share == NULL) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
if (s->s3->hs.tls13.server_version >= TLS1_3_VERSION &&
tls_key_share_group(s->s3->hs.key_share) != group &&
s->s3->hs.tls13.key_share != NULL &&
tls_key_share_group(s->s3->hs.tls13.key_share) == group) {
tls_key_share_free(s->s3->hs.key_share);
s->s3->hs.key_share = s->s3->hs.tls13.key_share;
s->s3->hs.tls13.key_share = NULL;
}
if (tls_key_share_group(s->s3->hs.key_share) != group) {
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
tls_key_share_free(s->s3->hs.tls13.key_share);
s->s3->hs.tls13.key_share = NULL;
if (!tls_key_share_client_peer_public(s->s3->hs.key_share,
&key_exchange, &decode_error, NULL)) {
if (!decode_error)
*alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
return 1;
}
static int
tlsext_versions_client_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.our_max_tls_version >= TLS1_3_VERSION);
}
static int
tlsext_versions_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
uint16_t max, min;
uint16_t version;
CBB versions;
max = s->s3->hs.our_max_tls_version;
min = s->s3->hs.our_min_tls_version;
if (!CBB_add_u8_length_prefixed(cbb, &versions))
return 0;
for (version = max; version >= min; version--) {
if (!CBB_add_u16(&versions, version))
return 0;
}
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_versions_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS versions;
uint16_t version;
uint16_t max, min;
uint16_t matched_version = 0;
max = s->s3->hs.our_max_tls_version;
min = s->s3->hs.our_min_tls_version;
if (!CBS_get_u8_length_prefixed(cbs, &versions))
return 0;
while (CBS_len(&versions) > 0) {
if (!CBS_get_u16(&versions, &version))
return 0;
if (matched_version == 0 && version >= min && version <= max)
matched_version = version;
}
if (matched_version > 0) {
s->version = matched_version;
return 1;
}
*alert = SSL_AD_PROTOCOL_VERSION;
return 0;
}
static int
tlsext_versions_server_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.negotiated_tls_version >= TLS1_3_VERSION);
}
static int
tlsext_versions_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return CBB_add_u16(cbb, TLS1_3_VERSION);
}
static int
tlsext_versions_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
uint16_t selected_version;
if (!CBS_get_u16(cbs, &selected_version))
return 0;
if (selected_version < TLS1_3_VERSION) {
*alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
s->s3->hs.tls13.server_version = selected_version;
return 1;
}
static int
tlsext_cookie_client_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.our_max_tls_version >= TLS1_3_VERSION &&
s->s3->hs.tls13.cookie_len > 0 && s->s3->hs.tls13.cookie != NULL);
}
static int
tlsext_cookie_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB cookie;
if (!CBB_add_u16_length_prefixed(cbb, &cookie))
return 0;
if (!CBB_add_bytes(&cookie, s->s3->hs.tls13.cookie,
s->s3->hs.tls13.cookie_len))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_cookie_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS cookie;
if (!CBS_get_u16_length_prefixed(cbs, &cookie))
return 0;
if (CBS_len(&cookie) != s->s3->hs.tls13.cookie_len)
return 0;
if (!CBS_mem_equal(&cookie, s->s3->hs.tls13.cookie,
s->s3->hs.tls13.cookie_len)) {
*alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
return 1;
}
static int
tlsext_cookie_server_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.our_max_tls_version >= TLS1_3_VERSION &&
s->s3->hs.tls13.cookie_len > 0 && s->s3->hs.tls13.cookie != NULL);
}
static int
tlsext_cookie_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB cookie;
if (!CBB_add_u16_length_prefixed(cbb, &cookie))
return 0;
if (!CBB_add_bytes(&cookie, s->s3->hs.tls13.cookie,
s->s3->hs.tls13.cookie_len))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_cookie_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
CBS cookie;
if (s->s3->hs.tls13.cookie != NULL ||
s->s3->hs.tls13.cookie_len != 0) {
*alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
if (!CBS_get_u16_length_prefixed(cbs, &cookie))
return 0;
if (!CBS_stow(&cookie, &s->s3->hs.tls13.cookie,
&s->s3->hs.tls13.cookie_len))
return 0;
return 1;
}
static int
tlsext_psk_kex_modes_client_needs(SSL *s, uint16_t msg_type)
{
return (s->s3->hs.tls13.use_psk_dhe_ke &&
s->s3->hs.our_max_tls_version >= TLS1_3_VERSION);
}
static int
tlsext_psk_kex_modes_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
CBB ke_modes;
if (!CBB_add_u8_length_prefixed(cbb, &ke_modes))
return 0;
if (!CBB_add_u8(&ke_modes, TLS13_PSK_DHE_KE))
return 0;
if (!CBB_flush(cbb))
return 0;
return 1;
}
static int
tlsext_psk_kex_modes_server_process(SSL *s, uint16_t msg_type, CBS *cbs,
int *alert)
{
CBS ke_modes;
uint8_t ke_mode;
if (!CBS_get_u8_length_prefixed(cbs, &ke_modes))
return 0;
while (CBS_len(&ke_modes) > 0) {
if (!CBS_get_u8(&ke_modes, &ke_mode))
return 0;
if (ke_mode == TLS13_PSK_DHE_KE)
s->s3->hs.tls13.use_psk_dhe_ke = 1;
}
return 1;
}
static int
tlsext_psk_kex_modes_server_needs(SSL *s, uint16_t msg_type)
{
return 0;
}
static int
tlsext_psk_kex_modes_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return 0;
}
static int
tlsext_psk_kex_modes_client_process(SSL *s, uint16_t msg_type, CBS *cbs,
int *alert)
{
return 0;
}
static int
tlsext_psk_client_needs(SSL *s, uint16_t msg_type)
{
return 0;
}
static int
tlsext_psk_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return 0;
}
static int
tlsext_psk_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
return CBS_skip(cbs, CBS_len(cbs));
}
static int
tlsext_psk_server_needs(SSL *s, uint16_t msg_type)
{
return 0;
}
static int
tlsext_psk_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return 0;
}
static int
tlsext_psk_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
return CBS_skip(cbs, CBS_len(cbs));
}
static int
tlsext_quic_transport_parameters_client_needs(SSL *s, uint16_t msg_type)
{
return SSL_is_quic(s) && s->quic_transport_params_len > 0;
}
static int
tlsext_quic_transport_parameters_client_build(SSL *s, uint16_t msg_type,
CBB *cbb)
{
if (!CBB_add_bytes(cbb, s->quic_transport_params,
s->quic_transport_params_len))
return 0;
return 1;
}
static int
tlsext_quic_transport_parameters_client_process(SSL *s, uint16_t msg_type,
CBS *cbs, int *alert)
{
if (!SSL_is_quic(s)) {
*alert = SSL_AD_UNSUPPORTED_EXTENSION;
return 0;
}
if (!CBS_stow(cbs, &s->s3->peer_quic_transport_params,
&s->s3->peer_quic_transport_params_len))
return 0;
if (!CBS_skip(cbs, s->s3->peer_quic_transport_params_len))
return 0;
return 1;
}
static int
tlsext_quic_transport_parameters_server_needs(SSL *s, uint16_t msg_type)
{
return SSL_is_quic(s) && s->quic_transport_params_len > 0;
}
static int
tlsext_quic_transport_parameters_server_build(SSL *s, uint16_t msg_type,
CBB *cbb)
{
if (!CBB_add_bytes(cbb, s->quic_transport_params,
s->quic_transport_params_len))
return 0;
return 1;
}
static int
tlsext_quic_transport_parameters_server_process(SSL *s, uint16_t msg_type,
CBS *cbs, int *alert)
{
if (!SSL_is_quic(s)) {
*alert = SSL_AD_UNSUPPORTED_EXTENSION;
return 0;
}
if (!CBS_stow(cbs, &s->s3->peer_quic_transport_params,
&s->s3->peer_quic_transport_params_len))
return 0;
if (!CBS_skip(cbs, s->s3->peer_quic_transport_params_len))
return 0;
return 1;
}
struct tls_extension_funcs {
int (*needs)(SSL *s, uint16_t msg_type);
int (*build)(SSL *s, uint16_t msg_type, CBB *cbb);
int (*process)(SSL *s, uint16_t msg_type, CBS *cbs, int *alert);
};
struct tls_extension {
uint16_t type;
uint16_t messages;
struct tls_extension_funcs client;
struct tls_extension_funcs server;
};
static const struct tls_extension tls_extensions[] = {
{
.type = TLSEXT_TYPE_supported_versions,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH |
SSL_TLSEXT_MSG_HRR,
.client = {
.needs = tlsext_versions_client_needs,
.build = tlsext_versions_client_build,
.process = tlsext_versions_client_process,
},
.server = {
.needs = tlsext_versions_server_needs,
.build = tlsext_versions_server_build,
.process = tlsext_versions_server_process,
},
},
{
.type = TLSEXT_TYPE_supported_groups,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_EE,
.client = {
.needs = tlsext_supportedgroups_client_needs,
.build = tlsext_supportedgroups_client_build,
.process = tlsext_supportedgroups_client_process,
},
.server = {
.needs = tlsext_supportedgroups_server_needs,
.build = tlsext_supportedgroups_server_build,
.process = tlsext_supportedgroups_server_process,
},
},
{
.type = TLSEXT_TYPE_key_share,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH |
SSL_TLSEXT_MSG_HRR,
.client = {
.needs = tlsext_keyshare_client_needs,
.build = tlsext_keyshare_client_build,
.process = tlsext_keyshare_client_process,
},
.server = {
.needs = tlsext_keyshare_server_needs,
.build = tlsext_keyshare_server_build,
.process = tlsext_keyshare_server_process,
},
},
{
.type = TLSEXT_TYPE_server_name,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_EE,
.client = {
.needs = tlsext_sni_client_needs,
.build = tlsext_sni_client_build,
.process = tlsext_sni_client_process,
},
.server = {
.needs = tlsext_sni_server_needs,
.build = tlsext_sni_server_build,
.process = tlsext_sni_server_process,
},
},
{
.type = TLSEXT_TYPE_renegotiate,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH,
.client = {
.needs = tlsext_ri_client_needs,
.build = tlsext_ri_client_build,
.process = tlsext_ri_client_process,
},
.server = {
.needs = tlsext_ri_server_needs,
.build = tlsext_ri_server_build,
.process = tlsext_ri_server_process,
},
},
{
.type = TLSEXT_TYPE_status_request,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_CR |
SSL_TLSEXT_MSG_CT,
.client = {
.needs = tlsext_ocsp_client_needs,
.build = tlsext_ocsp_client_build,
.process = tlsext_ocsp_client_process,
},
.server = {
.needs = tlsext_ocsp_server_needs,
.build = tlsext_ocsp_server_build,
.process = tlsext_ocsp_server_process,
},
},
{
.type = TLSEXT_TYPE_ec_point_formats,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH,
.client = {
.needs = tlsext_ecpf_client_needs,
.build = tlsext_ecpf_client_build,
.process = tlsext_ecpf_client_process,
},
.server = {
.needs = tlsext_ecpf_server_needs,
.build = tlsext_ecpf_server_build,
.process = tlsext_ecpf_server_process,
},
},
{
.type = TLSEXT_TYPE_session_ticket,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH,
.client = {
.needs = tlsext_sessionticket_client_needs,
.build = tlsext_sessionticket_client_build,
.process = tlsext_sessionticket_client_process,
},
.server = {
.needs = tlsext_sessionticket_server_needs,
.build = tlsext_sessionticket_server_build,
.process = tlsext_sessionticket_server_process,
},
},
{
.type = TLSEXT_TYPE_signature_algorithms,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_CR,
.client = {
.needs = tlsext_sigalgs_client_needs,
.build = tlsext_sigalgs_client_build,
.process = tlsext_sigalgs_client_process,
},
.server = {
.needs = tlsext_sigalgs_server_needs,
.build = tlsext_sigalgs_server_build,
.process = tlsext_sigalgs_server_process,
},
},
{
.type = TLSEXT_TYPE_alpn,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_EE,
.client = {
.needs = tlsext_alpn_client_needs,
.build = tlsext_alpn_client_build,
.process = tlsext_alpn_client_process,
},
.server = {
.needs = tlsext_alpn_server_needs,
.build = tlsext_alpn_server_build,
.process = tlsext_alpn_server_process,
},
},
{
.type = TLSEXT_TYPE_cookie,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_HRR,
.client = {
.needs = tlsext_cookie_client_needs,
.build = tlsext_cookie_client_build,
.process = tlsext_cookie_client_process,
},
.server = {
.needs = tlsext_cookie_server_needs,
.build = tlsext_cookie_server_build,
.process = tlsext_cookie_server_process,
},
},
#ifndef OPENSSL_NO_SRTP
{
.type = TLSEXT_TYPE_use_srtp,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH |
SSL_TLSEXT_MSG_EE,
.client = {
.needs = tlsext_srtp_client_needs,
.build = tlsext_srtp_client_build,
.process = tlsext_srtp_client_process,
},
.server = {
.needs = tlsext_srtp_server_needs,
.build = tlsext_srtp_server_build,
.process = tlsext_srtp_server_process,
},
},
#endif
{
.type = TLSEXT_TYPE_quic_transport_parameters,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_EE,
.client = {
.needs = tlsext_quic_transport_parameters_client_needs,
.build = tlsext_quic_transport_parameters_client_build,
.process = tlsext_quic_transport_parameters_client_process,
},
.server = {
.needs = tlsext_quic_transport_parameters_server_needs,
.build = tlsext_quic_transport_parameters_server_build,
.process = tlsext_quic_transport_parameters_server_process,
},
},
{
.type = TLSEXT_TYPE_psk_key_exchange_modes,
.messages = SSL_TLSEXT_MSG_CH,
.client = {
.needs = tlsext_psk_kex_modes_client_needs,
.build = tlsext_psk_kex_modes_client_build,
.process = tlsext_psk_kex_modes_client_process,
},
.server = {
.needs = tlsext_psk_kex_modes_server_needs,
.build = tlsext_psk_kex_modes_server_build,
.process = tlsext_psk_kex_modes_server_process,
},
},
{
.type = TLSEXT_TYPE_pre_shared_key,
.messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH,
.client = {
.needs = tlsext_psk_client_needs,
.build = tlsext_psk_client_build,
.process = tlsext_psk_client_process,
},
.server = {
.needs = tlsext_psk_server_needs,
.build = tlsext_psk_server_build,
.process = tlsext_psk_server_process,
},
},
};
#define N_TLS_EXTENSIONS (sizeof(tls_extensions) / sizeof(*tls_extensions))
CTASSERT(N_TLS_EXTENSIONS <= (sizeof(uint32_t) * 8));
struct tlsext_data {
CBS extensions[N_TLS_EXTENSIONS];
};
static struct tlsext_data *
tlsext_data_new(void)
{
return calloc(1, sizeof(struct tlsext_data));
}
static void
tlsext_data_free(struct tlsext_data *td)
{
freezero(td, sizeof(*td));
}
uint16_t
tls_extension_type(const struct tls_extension *extension)
{
return extension->type;
}
const struct tls_extension *
tls_extension_find(uint16_t type, size_t *tls_extensions_idx)
{
size_t i;
for (i = 0; i < N_TLS_EXTENSIONS; i++) {
if (tls_extensions[i].type == type) {
if (tls_extensions_idx != NULL)
*tls_extensions_idx = i;
return &tls_extensions[i];
}
}
return NULL;
}
int
tlsext_extension_seen(SSL *s, uint16_t type)
{
size_t idx;
if (tls_extension_find(type, &idx) == NULL)
return 0;
return ((s->s3->hs.extensions_seen & (1 << idx)) != 0);
}
int
tlsext_extension_processed(SSL *s, uint16_t type)
{
size_t idx;
if (tls_extension_find(type, &idx) == NULL)
return 0;
return ((s->s3->hs.extensions_processed & (1 << idx)) != 0);
}
const struct tls_extension_funcs *
tlsext_funcs(const struct tls_extension *tlsext, int is_server)
{
if (is_server)
return &tlsext->server;
return &tlsext->client;
}
int
tlsext_randomize_build_order(SSL *s)
{
const struct tls_extension *psk_ext;
size_t idx, new_idx;
free(s->tlsext_build_order);
s->tlsext_build_order_len = 0;
if ((s->tlsext_build_order = calloc(N_TLS_EXTENSIONS,
sizeof(*s->tlsext_build_order))) == NULL)
return 0;
s->tlsext_build_order_len = N_TLS_EXTENSIONS;
if ((psk_ext = tls_extension_find(TLSEXT_TYPE_pre_shared_key,
NULL)) == NULL)
return 0;
s->tlsext_build_order[N_TLS_EXTENSIONS - 1] = psk_ext;
for (idx = 0; idx < N_TLS_EXTENSIONS - 1; idx++) {
new_idx = arc4random_uniform(idx + 1);
s->tlsext_build_order[idx] = s->tlsext_build_order[new_idx];
s->tlsext_build_order[new_idx] = &tls_extensions[idx];
}
return 1;
}
int
tlsext_linearize_build_order(SSL *s)
{
size_t idx;
free(s->tlsext_build_order);
s->tlsext_build_order_len = 0;
if ((s->tlsext_build_order = calloc(N_TLS_EXTENSIONS,
sizeof(*s->tlsext_build_order))) == NULL)
return 0;
s->tlsext_build_order_len = N_TLS_EXTENSIONS;
for (idx = 0; idx < N_TLS_EXTENSIONS; idx++)
s->tlsext_build_order[idx] = &tls_extensions[idx];
return 1;
}
static int
tlsext_build(SSL *s, int is_server, uint16_t msg_type, CBB *cbb)
{
const struct tls_extension_funcs *ext;
const struct tls_extension *tlsext;
CBB extensions, extension_data;
int extensions_present = 0;
uint16_t tls_version;
size_t i;
tls_version = ssl_effective_tls_version(s);
if (!CBB_add_u16_length_prefixed(cbb, &extensions))
return 0;
for (i = 0; i < N_TLS_EXTENSIONS; i++) {
tlsext = s->tlsext_build_order[i];
ext = tlsext_funcs(tlsext, is_server);
if (tls_version >= TLS1_3_VERSION &&
!(tlsext->messages & msg_type))
continue;
if (!ext->needs(s, msg_type))
continue;
if (!CBB_add_u16(&extensions, tlsext->type))
return 0;
if (!CBB_add_u16_length_prefixed(&extensions, &extension_data))
return 0;
if (!ext->build(s, msg_type, &extension_data))
return 0;
extensions_present = 1;
}
if (!extensions_present &&
(msg_type & (SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH)) != 0)
CBB_discard_child(cbb);
if (!CBB_flush(cbb))
return 0;
return 1;
}
int
tlsext_clienthello_hash_extension(SSL *s, uint16_t type, CBS *cbs)
{
struct tls13_ctx *ctx = s->tls13;
if (type == TLSEXT_TYPE_early_data || type == TLSEXT_TYPE_cookie ||
type == TLSEXT_TYPE_padding)
return 1;
if (!tls13_clienthello_hash_update_bytes(ctx, (void *)&type,
sizeof(type)))
return 0;
if (type == TLSEXT_TYPE_pre_shared_key || type == TLSEXT_TYPE_key_share)
return 1;
if (!tls13_clienthello_hash_update(ctx, cbs))
return 0;
return 1;
}
static int
tlsext_parse(SSL *s, struct tlsext_data *td, int is_server, uint16_t msg_type,
CBS *cbs, int *alert)
{
const struct tls_extension *tlsext;
CBS extensions, extension_data;
uint16_t type;
size_t idx;
uint16_t tls_version;
int alert_desc;
tls_version = ssl_effective_tls_version(s);
s->s3->hs.extensions_seen = 0;
if (CBS_len(cbs) == 0)
return 1;
alert_desc = SSL_AD_DECODE_ERROR;
if (!CBS_get_u16_length_prefixed(cbs, &extensions))
goto err;
while (CBS_len(&extensions) > 0) {
if (!CBS_get_u16(&extensions, &type))
goto err;
if (!CBS_get_u16_length_prefixed(&extensions, &extension_data))
goto err;
if (s->tlsext_debug_cb != NULL)
s->tlsext_debug_cb(s, !is_server, type,
(unsigned char *)CBS_data(&extension_data),
CBS_len(&extension_data),
s->tlsext_debug_arg);
if ((tlsext = tls_extension_find(type, &idx)) == NULL)
continue;
if (tls_version >= TLS1_3_VERSION && is_server &&
msg_type == SSL_TLSEXT_MSG_CH) {
if (!tlsext_clienthello_hash_extension(s, type,
&extension_data))
goto err;
}
if (tls_version >= TLS1_3_VERSION &&
!(tlsext->messages & msg_type)) {
alert_desc = SSL_AD_ILLEGAL_PARAMETER;
goto err;
}
if ((s->s3->hs.extensions_seen & (1 << idx)) != 0)
goto err;
s->s3->hs.extensions_seen |= (1 << idx);
CBS_dup(&extension_data, &td->extensions[idx]);
}
return 1;
err:
*alert = alert_desc;
return 0;
}
static int
tlsext_process(SSL *s, struct tlsext_data *td, int is_server, uint16_t msg_type,
int *alert)
{
const struct tls_extension_funcs *ext;
const struct tls_extension *tlsext;
int alert_desc;
size_t idx;
alert_desc = SSL_AD_DECODE_ERROR;
s->s3->hs.extensions_processed = 0;
for (idx = 0; idx < N_TLS_EXTENSIONS; idx++) {
tlsext = &tls_extensions[idx];
if ((s->s3->hs.extensions_seen & (1 << idx)) == 0)
continue;
ext = tlsext_funcs(tlsext, is_server);
if (ext->process == NULL)
continue;
if (!ext->process(s, msg_type, &td->extensions[idx], &alert_desc))
goto err;
if (CBS_len(&td->extensions[idx]) != 0)
goto err;
s->s3->hs.extensions_processed |= (1 << idx);
}
return 1;
err:
*alert = alert_desc;
return 0;
}
static void
tlsext_server_reset_state(SSL *s)
{
s->tlsext_status_type = -1;
s->s3->renegotiate_seen = 0;
free(s->s3->alpn_selected);
s->s3->alpn_selected = NULL;
s->s3->alpn_selected_len = 0;
s->srtp_profile = NULL;
}
int
tlsext_server_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return tlsext_build(s, 1, msg_type, cbb);
}
int
tlsext_server_parse(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
struct tlsext_data *td;
int ret = 0;
if ((td = tlsext_data_new()) == NULL)
goto err;
if (msg_type == SSL_TLSEXT_MSG_CH)
tlsext_server_reset_state(s);
if (!tlsext_parse(s, td, 1, msg_type, cbs, alert))
goto err;
if (!tlsext_process(s, td, 1, msg_type, alert))
goto err;
ret = 1;
err:
tlsext_data_free(td);
return ret;
}
static void
tlsext_client_reset_state(SSL *s)
{
s->s3->renegotiate_seen = 0;
free(s->s3->alpn_selected);
s->s3->alpn_selected = NULL;
s->s3->alpn_selected_len = 0;
}
int
tlsext_client_build(SSL *s, uint16_t msg_type, CBB *cbb)
{
return tlsext_build(s, 0, msg_type, cbb);
}
int
tlsext_client_parse(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
{
struct tlsext_data *td;
int ret = 0;
if ((td = tlsext_data_new()) == NULL)
goto err;
if (msg_type == SSL_TLSEXT_MSG_SH)
tlsext_client_reset_state(s);
if (!tlsext_parse(s, td, 0, msg_type, cbs, alert))
goto err;
if (!tlsext_process(s, td, 0, msg_type, alert))
goto err;
ret = 1;
err:
tlsext_data_free(td);
return ret;
}