blob: 60aea534b05f6d4eec99d7fb9e41942c3a3c525c [file]
/*
* Copyright (C) 2026 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
FILE_SECBOOT ( PERMITTED );
/** @file
*
* TLS data formats
*
*/
#include <string.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/tls.h>
#include <ipxe/tlsfmt.h>
/**
* Get data structure descriptor mapping name (for debugging)
*
* @v map Data structure descriptor mapping
* @ret name Data structure name
*/
static const char * tls_map_name ( const uint8_t *map ) {
if ( map == tls_certificate_map ) {
return "Certificate";
} else if ( map == tls_certificate_entry_map ) {
return "CertificateEntry";
} else if ( map == tls_client_hello_map ) {
return "ClientHello";
} else if ( ( map == tls_client_key_exchange_dhe_map ) ||
( map == tls_client_key_exchange_ecdhe_map ) ||
( map == tls_client_key_exchange_pubkey_map ) ) {
return "ClientKeyExchange";
} else if ( map == tls_digitally_signed_map ) {
return "DigitallySigned";
} else if ( map == tls_extension_map ) {
return "Extension";
} else if ( map == tls_hello_request_map ) {
return "HelloRequest";
} else if ( map == tls_key_share_client_hello_map ) {
return "KeyShareClientHello";
} else if ( map == tls_key_share_entry_map ) {
return "KeyShareEntry";
} else if ( map == tls_key_share_hello_retry_request_map ) {
return "KeyShareHelloRetryRequest";
} else if ( map == tls_key_share_server_hello_map ) {
return "KeyShareServerHello";
} else if ( map == tls_max_fragment_length_map ) {
return "MaxFragmentLength";
} else if ( map == tls_named_group_list_map ) {
return "NamedGroupList";
} else if ( map == tls_new_session_ticket_map ) {
return "NewSessionTicket";
} else if ( map == tls_psk_key_exchange_modes_map ) {
return "PskKeyExchangeModes";
} else if ( map == tls_renegotiation_info_map ) {
return "RenegotiationInfo";
} else if ( map == tls_server_hello_map ) {
return "ServerHello";
} else if ( map == tls_server_hello_done_map ) {
return "ServerHelloDone";
} else if ( ( map == tls_server_key_exchange_dhe_map ) ||
( map == tls_server_key_exchange_ecdhe_map ) ) {
return "ServerKeyExchange";
} else if ( map == tls_server_name_map ) {
return "ServerName";
} else if ( map == tls_server_name_list_map ) {
return "ServerNameList";
} else if ( map == tls_signature_scheme_list_map ) {
return "SignatureSchemeList";
} else if ( ( map == tls_supported_versions_map ) ||
( map == tls_supported_version_map ) ) {
return "SupportedVersions";
} else {
return "<UNKNOWN>";
}
}
/**
* Parse TLS extensions within a data structure
*
* @v map Data structure descriptor mapping
* @v index Current index within mapping
* @v fields Extensions data fields
* @v count Number of extensions
* @ret rc Return status code
*/
static int tls_parse_extensions ( const uint8_t *map, unsigned int index,
struct tls_cursor *fields,
unsigned int count ) {
const uint16_t __attribute__ (( aligned ( 1 ) )) *invtypes;
const struct tls_cursor *cursor = &fields[0];
struct tls_extension extension;
unsigned int i;
uint16_t type;
int rc;
/* Extension types are encoded as inverted */
invtypes = ( ( const void * ) &map[index] );
for ( i = 1 ; i <= count ; i++ ) {
if ( ! invtypes[i] ) {
DBGC ( map, "TLSFMT %s #%d mapping missing extension "
"%d\n", tls_map_name ( map ), index, i );
return -EINVAL;
}
}
/* Parse extensions */
for ( ; cursor->len ; cursor = &extension.next ) {
/* Parse next extension */
if ( ( rc = tls_parse ( tls_extension, TLS_VERSION_BASE,
cursor, &extension ) ) != 0 )
return rc;
/* Scan for matching extensions */
for ( i = 1 ; i <= count ; i++ ) {
type = ~invtypes[i];
if ( type != *(extension.type) )
continue;
if ( fields[i].data ) {
DBGC ( map, "TLSFMT %s #%d has duplicate "
"extension %#04x\n",
tls_map_name ( map ), index,
ntohs ( type ) );
return -EPROTO;
}
fields[i].data = extension.data.data;
fields[i].len = extension.data.len;
DBGC2 ( map, "TLSFMT %s #%d extension %#04x len "
"%zd\n", tls_map_name ( map ), index,
ntohs ( type ), fields[i].len );
DBGC2_HDA ( map, 0, fields[i].data, fields[i].len );
}
}
return 0;
}
/**
* Parse TLS data structure
*
* @v map Data structure descriptor mapping
* @v version Protocol version
* @v cursor Cursor containing TLS data structure
* @v desc Data structure descriptor to fill in
* @ret rc Return status code
*/
int tls_parse_map ( const uint8_t *map, unsigned int version,
const struct tls_cursor *cursor,
union tls_ptr_len *desc ) {
struct tls_cursor *field;
void *data;
size_t remaining;
unsigned int count;
unsigned int index;
unsigned int next;
unsigned int byte;
unsigned int minimum;
unsigned int len_len;
unsigned int len;
int fixed;
int exts;
int rc;
/* Read initial cursor (may overlap output data structure) */
data = cursor->data;
remaining = cursor->len;
DBGC2 ( map, "TLSFMT %s parsing len %zd\n",
tls_map_name ( map ), remaining );
DBGC2_HDA ( map, 0, data, remaining );
/* Get mapping length */
count = map[0];
if ( ! count ) {
DBGC ( map, "TLSFMT %s mapping has no count\n",
tls_map_name ( map ) );
return -EINVAL;
}
/* Clear data structure descriptor */
memset ( desc, 0, ( ( count - 1 ) * sizeof ( desc[0] ) ) );
/* Parse data via mapping */
for ( index = 1 ; ( next = index ) < count ; index = next ) {
/* Prepare to store field description */
field = container_of ( &desc[ index - 1 ].data,
struct tls_cursor, data );
/* Interpret byte as `llllllvv` */
byte = map[next++];
minimum = TLS_MAP_MIN ( byte );
fixed = TLS_MAP_FIXED ( byte );
if ( fixed < 0 ) {
DBGC ( map, "TLSFMT %s #%d mapping missing\n",
tls_map_name ( map ), index );
return -EINVAL;
}
assert ( next <= count );
/* Handle fixed-length fields */
if ( fixed ) {
if ( version < minimum ) {
DBGC2 ( map, "TLSFMT %s #%d not in version "
"%d.%d\n", tls_map_name ( map ),
index, ( version >> 8 ),
( version & 0xff ) );
continue;
}
if ( ( ( size_t ) fixed ) > remaining ) {
DBGC ( map, "TLSFMT %s #%d too short for "
"fixed length %d:\n",
tls_map_name ( map ), index, fixed );
DBGC_HDA ( map, 0, data, remaining );
return -EPROTO;
}
field->data = data;
DBGC2 ( map, "TLSFMT %s #%d len %d\n",
tls_map_name ( map ), index, fixed );
DBGC2_HDA ( map, 0, field->data, fixed );
data += fixed;
remaining -= fixed;
continue;
}
/* Interpret next byte as `xxxxxxnn` */
if ( next >= count ) {
DBGC ( map, "TLSFMT %s #%d mapping overrun\n",
tls_map_name ( map ), index );
return -EINVAL;
}
byte = map[next++];
len_len = TLS_MAP_LEN_LEN ( byte );
exts = TLS_MAP_EXTENSIONS ( byte );
if ( exts >= 0 )
next += ( exts * 2 );
if ( next > count ) {
DBGC ( map, "TLSFMT %s #%d mapping extensions "
"overrun\n", tls_map_name ( map ), index );
return -EINVAL;
}
if ( version < minimum ) {
DBGC2 ( map, "TLSFMT %s #%d not in version %d.%d\n",
tls_map_name ( map ), index, ( version >> 8 ),
( version & 0xff ) );
continue;
}
/* Allow for optional extensions fields */
if ( ( exts >= 0 ) && ( ! remaining ) &&
( version < TLS_VERSION_TLS_1_3 ) ) {
DBGC2 ( map, "TLSFMT %s #%d optional in version "
"%d.%d\n", tls_map_name ( map ), index,
( version >> 8 ), ( version & 0xff ) );
continue;
}
/* Handle variable-length fields */
if ( remaining < len_len ) {
DBGC ( map, "TLSFMT %s #%d too short for %d-byte "
"variable length:\n", tls_map_name ( map ),
index, len_len );
DBGC_HDA ( map, 0, data, remaining );
return -EPROTO;
}
if ( len_len ) {
for ( len = 0 ; len_len ; len_len-- ) {
len <<= 8;
len |= *( ( const uint8_t * ) data++ );
remaining--;
}
} else {
len = remaining;
}
if ( remaining < len ) {
DBGC ( map, "TLSFMT %s #%d too short for variable "
"length %d:\n",
tls_map_name ( map ), index, len );
DBGC_HDA ( map, 0, data, remaining );
return -EPROTO;
}
field->data = data;
field->len = len;
DBGC2 ( map, "TLSFMT %s #%d len %zd\n",
tls_map_name ( map ), index, field->len );
DBGC2_HDA ( map, 0, field->data, field->len );
data += len;
remaining -= len;
if ( exts < 0 )
continue;
/* Handle fields containing extensions */
if ( ( rc = tls_parse_extensions ( map, index, field,
exts ) ) != 0 ) {
return rc;
}
}
/* Check that all data was consumed */
if ( remaining ) {
DBGC ( map, "TLSFMT %s has excess data:\n",
tls_map_name ( map ) );
DBGC_HDA ( map, 0, data, remaining );
return -EPROTO;
}
return 0;
}
/**
* Parse optional TLS data structure
*
* @v map Data structure descriptor mapping
* @v version Protocol version
* @v cursor Cursor containing TLS data structure
* @v desc Data structure descriptor to fill in
* @ret rc Return status code
*/
int tls_parse_opt_map ( const uint8_t *map, unsigned int version,
const struct tls_cursor *cursor,
union tls_ptr_len *desc ) {
unsigned int count;
int rc;
/* Get mapping length */
count = map[0];
if ( ! count ) {
DBGC ( map, "TLSFMT %s mapping has no count\n",
tls_map_name ( map ) );
return -EINVAL;
}
/* Clear data structure descriptor */
memset ( desc, 0, ( ( count - 1 ) * sizeof ( desc[0] ) ) );
/* Do nothing if optional data structure is not present */
if ( ! cursor->data )
return 0;
/* Parse data structure */
if ( ( rc = tls_parse_map ( map, version, cursor, desc ) ) != 0 )
return rc;
return 0;
}
/**
* Build TLS extensions within a data structure
*
* @v map Data structure descriptor mapping
* @v index Current index within mapping
* @v fields Extensions data fields
* @v count Number of extensions
* @ret rc Return status code
*/
static int tls_build_extensions ( const uint8_t *map, unsigned int index,
struct tls_cursor *fields,
unsigned int count ) {
const uint16_t __attribute__ (( aligned ( 1 ) )) *invtypes;
struct tls_cursor *cursor = &fields[0];
struct tls_cursor *subcursor;
struct tls_extension extension;
unsigned int i;
uint16_t type;
int rc;
/* Prepare per-extension subcursor */
subcursor = &extension.next;
subcursor->data = cursor->data;
cursor->len = 0;
/* Extension types are encoded as inverted */
invtypes = ( ( const void * ) &map[index] );
for ( i = 1 ; i <= count ; i++ ) {
if ( ! invtypes[i] ) {
DBGC ( map, "TLSFMT %s #%d mapping missing extension "
"%d\n", tls_map_name ( map ), index, i );
return -EINVAL;
}
}
/* Build extensions */
for ( i = 1 ; i <= count ; i++ ) {
/* Skip extensions that will not be included */
if ( ! ( fields[i].data || fields[i].len ) )
continue;
/* Build extension */
type = ~invtypes[i];
extension.type = &type;
extension.data = fields[i];
extension.next.len = 0;
if ( ( rc = tls_build ( tls_extension, TLS_VERSION_BASE,
&extension, subcursor ) ) != 0 ) {
return rc;
}
fields[i].len = extension.data.len;
DBGC2 ( map, "TLSFMT %s #%d extension %#04x len %zd\n",
tls_map_name ( map ), index, ntohs ( type ),
fields[i].len );
cursor->len += subcursor->len;
if ( cursor->data ) {
fields[i].data = extension.data.data;
DBGC2_HDA ( map, 0, fields[i].data, fields[i].len );
}
}
return 0;
}
/**
* Build TLS data structure
*
* @v map Data structure descriptor mapping
* @v version Protocol version
* @v desc Data structure descriptor
* @v cursor Cursor to contain TLS data structure
* @ret rc Return status code
*
* Build a TLS data structure at the cursor. The cursor's original
* length will be ignored and will be set to the overall length of the
* built data structure. The caller must ensure that sufficient space
* already exists (e.g. by calling tls_size() first to determine the
* required length).
*
* The overall length will be calculated based on the variable lengths
* within the descriptor. The output content will be be copied from
* any non-NULL pointers within the descriptor (with any missing
* content initialised to zero).
*
* Pointers within the descriptor will be updated to point to the
* appropriate location within the built data structure.
*
* The caller must therefore fill in any variable lengths within the
* descriptor beforehand, but may freely choose to either fill in
* pointers within the descriptor beforehand or to write through the
* updated pointers afterwards.
*
* A cursor with a NULL data pointer may be used to calculate the
* required length without copying in any data or updating any
* pointers within the descriptor.
*/
int tls_build_map ( const uint8_t *map, unsigned int version,
union tls_ptr_len *desc, struct tls_cursor *cursor ) {
struct tls_cursor *field;
void *data;
size_t len;
size_t max;
unsigned int count;
unsigned int index;
unsigned int next;
unsigned int byte;
unsigned int minimum;
unsigned int len_len;
int fixed;
int exts;
int rc;
/* Read initial cursor (may overlap output data structure) */
data = cursor->data;
len = 0;
/* Get mapping length */
count = map[0];
if ( ! count ) {
DBGC ( map, "TLSFMT %s mapping has no count\n",
tls_map_name ( map ) );
return -EINVAL;
}
/* Accumulate total length via mapping */
for ( index = 1 ; ( next = index ) < count ; index = next ) {
/* Prepare to read field description */
field = container_of ( &desc[ index - 1 ].data,
struct tls_cursor, data );
/* Interpret byte as `llllllvv` */
byte = map[next++];
minimum = TLS_MAP_MIN ( byte );
fixed = TLS_MAP_FIXED ( byte );
if ( fixed < 0 ) {
DBGC ( map, "TLSFMT %s #%d mapping missing\n",
tls_map_name ( map ), index );
return -EINVAL;
}
assert ( next <= count );
/* Handle fixed-length fields */
if ( fixed ) {
if ( version < minimum ) {
DBGC2 ( map, "TLSFMT %s #%d not in version "
"%d.%d\n", tls_map_name ( map ),
index, ( version >> 8 ),
( version & 0xff ) );
continue;
}
DBGC2 ( map, "TLSFMT %s #%d len %d\n",
tls_map_name ( map ), index, fixed );
len += fixed;
if ( data ) {
if ( field->data ) {
memcpy ( data, field->data, fixed );
} else {
memset ( data, 0, fixed );
}
field->data = data;
data += fixed;
DBGC2_HDA ( map, 0, field->data, fixed );
}
continue;
}
/* Interpret next byte as `xxxxxxnn` */
if ( next >= count ) {
DBGC ( map, "TLSFMT %s #%d mapping overrun\n",
tls_map_name ( map ), index );
return -EINVAL;
}
byte = map[next++];
len_len = TLS_MAP_LEN_LEN ( byte );
exts = TLS_MAP_EXTENSIONS ( byte );
if ( exts >= 0 )
next += ( exts * 2 );
if ( next > count ) {
DBGC ( map, "TLSFMT %s #%d mapping extensions "
"overrun\n", tls_map_name ( map ), index );
return -EINVAL;
}
if ( version < minimum ) {
DBGC2 ( map, "TLSFMT %s #%d not in version %d.%d\n",
tls_map_name ( map ), index, ( version >> 8 ),
( version & 0xff ) );
continue;
}
/* Handle variable-length fields */
max = ( len_len ? ( ( 1 << ( 8 * len_len ) ) - 1 ) :
( ( 1 << ( 8 * TLS_MAP_LEN_LEN_MAX ) ) - 1 ) );
if ( exts >= 0 ) {
field->data = ( data ? ( data + len_len ) : NULL );
if ( ( rc = tls_build_extensions ( map, index, field,
exts ) ) != 0 ) {
return rc;
}
}
if ( field->len > max ) {
DBGC ( map, "TLSFMT %s #%d len %zd too long\n",
tls_map_name ( map ), index, field->len );
return -ERANGE;
}
/* Allow for optional extensions fields */
if ( ( exts >= 0 ) && ( ! field->len ) &&
( version < TLS_VERSION_TLS_1_3 ) ) {
DBGC2 ( map, "TLSFMT %s #%d optional in version "
"%d.%d\n", tls_map_name ( map ), index,
( version >> 8 ), ( version & 0xff ) );
continue;
}
/* Build field */
DBGC2 ( map, "TLSFMT %s #%d len %zd\n",
tls_map_name ( map ), index, field->len );
len += ( len_len + field->len );
if ( data ) {
while ( len_len-- ) {
*( ( uint8_t * ) data++ ) =
( field->len >> ( 8 * len_len ) );
}
if ( exts < 0 ) {
if ( field->data ) {
memcpy ( data, field->data,
field->len );
} else {
memset ( data, 0, field->len );
}
}
field->data = data;
data += field->len;
DBGC2_HDA ( map, 0, field->data, field->len );
}
}
/* Update cursor (may overlap output data structure) */
cursor->len = len;
DBGC2 ( map, "TLSFMT %s built len %zd\n",
tls_map_name ( map ), cursor->len );
if ( data )
DBGC2_HDA ( map, 0, ( data - cursor->len ), cursor->len );
return 0;
}
/**
* Calculate length of TLS data structure
*
* @v type Descriptor structure name
* @v version Protocol version
* @v desc Data structure descriptor to fill in
* @v cursor Cursor to contain TLS data structure
* @ret rc Return status code
*
* The cursor size will be set to the overall length required to
* contain the TLS data structure, and the cursor data pointer will be
* set to NULL.
*
* If this function returns successfully, then a subsequent call to
* tls_build() with the exact same inputs is guaranteed to succeed and
* need not be checked for an error return status. The data structure
* descriptor must not be modified in any way that would affect its
* length before calling tls_build(): the easiest way to ensure this
* is to not modify the data structure descriptor at all.
*
* If this function fails, then the cursor length will be set to a
* value that is too large to be represented by a 24-bit length field.
* If the cursor itself lies within a containing data structure
* descriptor (e.g. if tls_size() is being used to calculate the size
* of an extension within a ClientHello descriptor), then this
* guarantees that a subsequent call to tls_size() on the containing
* descriptor will also fail. The caller therefore need only check
* the return status code from the call to tls_size() for the
* outermost descriptor.
*
* Note that this optimisation applies only when the result cursor
* lies within a containing data structure descriptor and so is
* guaranteed to be consumed by a subsequent call to calculate the
* length of that containing TLS data structure. If a caller is using
* the result from tls_size() in any other way (e.g. to add up the
* lengths of a sequence of CertificateEntry structures), then the
* caller must check the return status code in the normal way.
*/
int tls_size_map ( const uint8_t *map, unsigned int version,
union tls_ptr_len *desc, struct tls_cursor *cursor ) {
int rc;
/* Calculate length */
cursor->data = NULL;
if ( ( rc = tls_build_map ( map, version, desc, cursor ) ) != 0 ) {
/* Set an uncontainable length on error */
cursor->len = -1UL;
return rc;
}
return 0;
}
/** Certificate descriptor mapping */
TLS_DESCR_MAPPING ( tls_certificate ) = {
TLS_MAPSZ ( tls_certificate ),
TLS_VAR08 ( tls_certificate, TLS_VERSION_TLS_1_3, context ),
TLS_VAR24 ( tls_certificate, TLS_VERSION_BASE, list ),
};
/** CertificateEntry descriptor mapping */
TLS_DESCR_MAPPING ( tls_certificate_entry ) = {
TLS_MAPSZ ( tls_certificate_entry ),
TLS_VAR24 ( tls_certificate_entry, TLS_VERSION_BASE, cert ),
TLS_EXT16 ( tls_certificate_entry, TLS_VERSION_TLS_1_3, ext ),
TLS_EXTRA ( tls_certificate_entry, TLS_VERSION_BASE, next ),
};
/** ClientHello descriptor mapping */
TLS_DESCR_MAPPING ( tls_client_hello ) = {
TLS_MAPSZ ( tls_client_hello ),
TLS_FIXED ( tls_client_hello, TLS_VERSION_BASE, a ),
TLS_VAR08 ( tls_client_hello, TLS_VERSION_BASE, session_id ),
TLS_VAR16 ( tls_client_hello, TLS_VERSION_BASE, suites ),
TLS_VAR08 ( tls_client_hello, TLS_VERSION_BASE, compression ),
TLS_EXT16 ( tls_client_hello, TLS_VERSION_BASE, ext ),
TLS_EXTND ( tls_client_hello, TLS_COOKIE, ext.cookie ),
TLS_EXTND ( tls_client_hello, TLS_EXTENDED_MASTER_SECRET, ext.ems ),
TLS_EXTND ( tls_client_hello, TLS_MAX_FRAGMENT_LENGTH, ext.frag ),
TLS_EXTND ( tls_client_hello, TLS_NAMED_GROUP, ext.groups ),
TLS_EXTND ( tls_client_hello, TLS_KEY_SHARE, ext.keys ),
TLS_EXTND ( tls_client_hello, TLS_SERVER_NAME, ext.names ),
TLS_EXTND ( tls_client_hello, TLS_PSK_MODES, ext.pskmodes ),
TLS_EXTND ( tls_client_hello, TLS_RECORD_SIZE_LIMIT, ext.record ),
TLS_EXTND ( tls_client_hello, TLS_RENEGOTIATION_INFO, ext.reneg ),
TLS_EXTND ( tls_client_hello, TLS_SIGNATURE_ALGORITHMS, ext.sigs ),
TLS_EXTND ( tls_client_hello, TLS_SUPPORTED_VERSIONS, ext.supvers ),
TLS_EXTND ( tls_client_hello, TLS_SESSION_TICKET, ext.ticket ),
};
/** ClientKeyExchange descriptor mapping (for DHE) */
TLS_DESCR_MAPPING ( tls_client_key_exchange_dhe ) = {
TLS_MAPSZ ( tls_client_key_exchange_dhe ),
TLS_VAR16 ( tls_client_key_exchange_dhe, TLS_VERSION_BASE, dh_yc ),
};
/** ClientKeyExchange descriptor mapping (for ECDHE) */
TLS_DESCR_MAPPING ( tls_client_key_exchange_ecdhe ) = {
TLS_MAPSZ ( tls_client_key_exchange_ecdhe ),
TLS_VAR08 ( tls_client_key_exchange_ecdhe, TLS_VERSION_BASE, point ),
};
/** ClientKeyExchange descriptor mapping (for key transport) */
TLS_DESCR_MAPPING ( tls_client_key_exchange_pubkey ) = {
TLS_MAPSZ ( tls_client_key_exchange_pubkey ),
TLS_VAR16 ( tls_client_key_exchange_pubkey, TLS_VERSION_BASE, enc ),
};
/** DigitallySigned descriptor mapping */
TLS_DESCR_MAPPING ( tls_digitally_signed ) = {
TLS_MAPSZ ( tls_digitally_signed ),
TLS_FIXED ( tls_digitally_signed, TLS_VERSION_TLS_1_2, sig_hash ),
TLS_VAR16 ( tls_digitally_signed, TLS_VERSION_BASE, sig ),
};
/** Extension descriptor mapping */
TLS_DESCR_MAPPING ( tls_extension ) = {
TLS_MAPSZ ( tls_extension ),
TLS_FIXED ( tls_extension, TLS_VERSION_BASE, type ),
TLS_VAR16 ( tls_extension, TLS_VERSION_BASE, data ),
TLS_EXTRA ( tls_extension, TLS_VERSION_BASE, next ),
};
/** HelloRequest descriptor mapping */
TLS_DESCR_MAPPING ( tls_hello_request ) = {
TLS_MAPSZ ( tls_hello_request ),
};
/** KeyShareClientHello descriptor mapping */
TLS_DESCR_MAPPING ( tls_key_share_client_hello ) = {
TLS_MAPSZ ( tls_key_share_client_hello ),
TLS_VAR16 ( tls_key_share_client_hello, TLS_VERSION_BASE, list ),
};
/** KeyShareEntry descriptor mapping */
TLS_DESCR_MAPPING ( tls_key_share_entry ) = {
TLS_MAPSZ ( tls_key_share_entry ),
TLS_FIXED ( tls_key_share_entry, TLS_VERSION_BASE, group ),
TLS_VAR16 ( tls_key_share_entry, TLS_VERSION_BASE, public ),
TLS_EXTRA ( tls_key_share_entry, TLS_VERSION_BASE, next ),
};
/** KeyShareHelloRetryRequest descriptor mapping */
TLS_DESCR_MAPPING ( tls_key_share_hello_retry_request ) = {
TLS_MAPSZ ( tls_key_share_hello_retry_request ),
TLS_FIXED ( tls_key_share_hello_retry_request, TLS_VERSION_BASE,
group ),
};
/** KeyShareServerHello descriptor mapping */
TLS_DESCR_MAPPING ( tls_key_share_server_hello ) = {
TLS_MAPSZ ( tls_key_share_server_hello ),
TLS_FIXED ( tls_key_share_server_hello, TLS_VERSION_BASE, group ),
TLS_VAR16 ( tls_key_share_server_hello, TLS_VERSION_BASE, public ),
};
/** MaxFragmentLength descriptor mapping */
TLS_DESCR_MAPPING ( tls_max_fragment_length ) = {
TLS_MAPSZ ( tls_max_fragment_length ),
TLS_FIXED ( tls_max_fragment_length, TLS_VERSION_BASE, max ),
};
/** NamedGroupList descriptor mapping */
TLS_DESCR_MAPPING ( tls_named_group_list ) = {
TLS_MAPSZ ( tls_named_group_list ),
TLS_VAR16 ( tls_named_group_list, TLS_VERSION_BASE, list ),
};
/** NewSessionTicket descriptor mapping */
TLS_DESCR_MAPPING ( tls_new_session_ticket ) = {
TLS_MAPSZ ( tls_new_session_ticket ),
TLS_FIXED ( tls_new_session_ticket, TLS_VERSION_BASE, lifetime ),
TLS_FIXED ( tls_new_session_ticket, TLS_VERSION_TLS_1_3, age ),
TLS_VAR08 ( tls_new_session_ticket, TLS_VERSION_TLS_1_3, nonce ),
TLS_VAR16 ( tls_new_session_ticket, TLS_VERSION_BASE, ticket ),
TLS_EXT16 ( tls_new_session_ticket, TLS_VERSION_TLS_1_3, ext ),
};
/** PskKeyExchangeModes descriptor mapping */
TLS_DESCR_MAPPING ( tls_psk_key_exchange_modes ) = {
TLS_MAPSZ ( tls_psk_key_exchange_modes ),
TLS_VAR08 ( tls_psk_key_exchange_modes, TLS_VERSION_TLS_1_3, list ),
};
/** RenegotiationInfo descriptor mapping */
TLS_DESCR_MAPPING ( tls_renegotiation_info ) = {
TLS_MAPSZ ( tls_renegotiation_info ),
TLS_VAR08 ( tls_renegotiation_info, TLS_VERSION_BASE, verify ),
};
/** ServerHello descriptor mapping */
TLS_DESCR_MAPPING ( tls_server_hello ) = {
TLS_MAPSZ ( tls_server_hello ),
TLS_FIXED ( tls_server_hello, TLS_VERSION_BASE, a ),
TLS_VAR08 ( tls_server_hello, TLS_VERSION_BASE, session_id ),
TLS_FIXED ( tls_server_hello, TLS_VERSION_BASE, b ),
TLS_EXT16 ( tls_server_hello, TLS_VERSION_BASE, ext ),
TLS_EXTND ( tls_server_hello, TLS_RENEGOTIATION_INFO, ext.reneg ),
TLS_EXTND ( tls_server_hello, TLS_EXTENDED_MASTER_SECRET, ext.ems ),
TLS_EXTND ( tls_server_hello, TLS_SUPPORTED_VERSIONS, ext.supver ),
TLS_EXTND ( tls_server_hello, TLS_KEY_SHARE, ext.key ),
TLS_EXTND ( tls_server_hello, TLS_COOKIE, ext.cookie ),
};
/** ServerHello descriptor mapping */
TLS_DESCR_MAPPING ( tls_server_hello_done ) = {
TLS_MAPSZ ( tls_server_hello_done ),
};
/** ServerKeyExchange descriptor mapping (for DHE) */
TLS_DESCR_MAPPING ( tls_server_key_exchange_dhe ) = {
TLS_MAPSZ ( tls_server_key_exchange_dhe ),
TLS_VAR16 ( tls_server_key_exchange_dhe, TLS_VERSION_BASE, dh_p ),
TLS_VAR16 ( tls_server_key_exchange_dhe, TLS_VERSION_BASE, dh_g ),
TLS_VAR16 ( tls_server_key_exchange_dhe, TLS_VERSION_BASE, dh_ys ),
TLS_EXTRA ( tls_server_key_exchange_dhe, TLS_VERSION_BASE, dsig ),
};
/** ServerKeyExchange descriptor mapping (for ECDHE) */
TLS_DESCR_MAPPING ( tls_server_key_exchange_ecdhe ) = {
TLS_MAPSZ ( tls_server_key_exchange_ecdhe ),
TLS_FIXED ( tls_server_key_exchange_ecdhe, TLS_VERSION_BASE, curve ),
TLS_VAR08 ( tls_server_key_exchange_ecdhe, TLS_VERSION_BASE, point ),
TLS_EXTRA ( tls_server_key_exchange_ecdhe, TLS_VERSION_BASE, dsig ),
};
/** ServerName descriptor mapping */
TLS_DESCR_MAPPING ( tls_server_name ) = {
TLS_MAPSZ ( tls_server_name ),
TLS_FIXED ( tls_server_name, TLS_VERSION_BASE, type ),
TLS_VAR16 ( tls_server_name, TLS_VERSION_BASE, name ),
};
/** ServerNameList descriptor mapping */
TLS_DESCR_MAPPING ( tls_server_name_list ) = {
TLS_MAPSZ ( tls_server_name_list ),
TLS_VAR16 ( tls_server_name_list, TLS_VERSION_BASE, list ),
};
/** SignatureSchemeList descriptor mapping */
TLS_DESCR_MAPPING ( tls_signature_scheme_list ) = {
TLS_MAPSZ ( tls_signature_scheme_list ),
TLS_VAR16 ( tls_signature_scheme_list, TLS_VERSION_BASE, list ),
};
/** SupportedVersions descriptor mapping (in ServerHello) */
TLS_DESCR_MAPPING ( tls_supported_version ) = {
TLS_MAPSZ ( tls_supported_version ),
TLS_FIXED ( tls_supported_version, TLS_VERSION_BASE, selected ),
};
/** SupportedVersions descriptor mapping (in ClientHello) */
TLS_DESCR_MAPPING ( tls_supported_versions ) = {
TLS_MAPSZ ( tls_supported_versions ),
TLS_VAR08 ( tls_supported_versions, TLS_VERSION_BASE, list ),
};