3. Bootstrapping in TLS 1.3
TLS-POK uses certificate-based authentication with an EPSK. The EPSK is derived from the BSK public key and imported using RFC 9258. The client presents the BSK as a raw public key and authenticates with ECDSA.
3.1. EPSK Derivation
The EPSK tuple is Base Key, External Identity, and Hash. The Base Key is the DER-encoded ASN.1 SubjectPublicKeyInfo representation of the BSK public key. Zero-byte padding MUST NOT be added.
epskid = HKDF-Expand(HKDF-Extract(<>, Base Key),
"tls13-bspsk-identity", L)
where:
- epskid is the EPSK External Identity
- Base Key is the DER-encoded ASN.1 subjectPublicKeyInfo
representation of the BSK public key
- L equals 32, the length in octets of the SHA-256 output
- <> is a NULL salt, which is a string of L zeros
SHA-256 MUST be used.
struct {
opaque external_identity<1...2^16-1>;
opaque context<0..2^16-1>;
uint16 target_protocol;
uint16 target_kdf;
} ImportedIdentity;
The values are external_identity = epskid, context = "tls13-bsk", target_protocol = TLS1.3(0x0304), and target_kdf as specified by RFC 9258. The context value MUST be "tls13-bsk".
3.2. TLS 1.3 Handshake Details
The client includes "tls_cert_with_extern_psk" and "client_certificate_type" in ClientHello and specifies RawPublicKey. If the server finds no matching EPSK, it MUST terminate the handshake with an alert. The TLS 1.3 key schedule MUST include both the EPSK in Early Secret derivation and DHE/ECDHE in Handshake Secret derivation.
The server MUST send CertificateRequest. The client MUST authenticate with its BSK as a raw public key. The client MUST NOT share the BSK public key until after it processes ServerHello and verifies the TLS key schedule; if PSK verification fails, the BSK public key MUST NOT be shared. The server MUST ensure the Certificate public key is identical to the BSK public key used for the EPSK and ImportedIdentity.
Client Server
-------- --------
ClientHello
+ cert_with_extern_psk
+ client_cert_type=RawPublicKey
+ key_share
+ pre_shared_key -------->
ServerHello
+ cert_with_extern_psk
+ client_cert_type=RawPublicKey
+ key_share
+ pre_shared_key
{EncryptedExtensions}
{CertificateRequest}
{Certificate}
{CertificateVerify}
<-------- {Finished}
{Certificate}
{CertificateVerify}
{Finished} -------->