Network Working Group | J. Schaad |
Internet-Draft | March 5, 2019 |
Intended status: Experimental | |
Expires: September 6, 2019 |
TLS Handshake in CBOR
draft-schaad-ace-tls-cbor-handshake-00
None
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."
This Internet-Draft will expire on September 6, 2019.
Copyright (c) 2019 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.
There are two measures that can be looked at when measuring how good the different options presented below are going to be.
Summary of message sizes in bytes.
TLS | TLS | TLS-C | TLS-C | TLS-S | TLS-S | |
---|---|---|---|---|---|---|
RPK | PSK | RPK | PSK | RPK | PSK | |
Message #1 | 122 | 164 | 97 | 134 | 47 | 64 |
Message #2 | 306 | 163 | 262 | 143 | 145 | 66 |
Message #3 | 205 | 72 | 175 | 54 | 101 | 21 |
Total | 633 | 399 | 534 | 331 | 293 | 151 |
Summary of message sizes in estimated number of messages.
TLS | TLS | TLS-C | TLS-C | TLS-S | TLS-S | |
---|---|---|---|---|---|---|
RPK | PSK | RPK | PSK | RPK | PSK | |
Message #1 | 2 | 3 | 2 | 3 | 1 | 1 |
Message #2 | 5 | 3 | 5 | 3 | 3 | 1 |
Message #3 | 4 | 1 | 3 | 1 | 2 | 1 |
Total | 11 | 7 | 10 | 7 | 6 | 3 |
The TLS Handshake message is:
struct { HandshakeType msg_type; /* handshake type */ uint24 length; /* remaining bytes in message */ select (Handshake.msg_type) { case client_hello: ClientHello; case server_hello: ServerHello; case end_of_early_data: EndOfEarlyData; case encrypted_extensions: EncryptedExtensions; case certificate_request: CertificateRequest; case certificate: Certificate; case certificate_verify: CertificateVerify; case finished: Finished; case new_session_ticket: NewSessionTicket; case key_update: KeyUpdate; }; } Handshake;
For the CBOR encoding make the following changes:
Handshake = handshakeMessage handshakeMessage = { 1 : ClientHello, 2 : ServerHello, 3 : EndOfEarlyData, 4 : EncryptedExtensions, 5 : CertificateRequest, 6 : Certificate, 7 : CertificateVerify, 8 : Finished, 9 : NewSessionTicket, 10 : KeyUpdate }
Expected space savings:
The TLS Client Hello structure is:
uint16 ProtocolVersion; opaque Random[32]; uint8 CipherSuite[2]; /* Cryptographic suite selector */ struct { ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */ Random random; opaque legacy_session_id<0..32>; CipherSuite cipher_suites<2..2^16-2>; opaque legacy_compression_methods<1..2^8-1>; Extension extensions<8..2^16-1>; } ClientHello;
For the CBOR encoding make the following changes:
ClientHello = [ random : bstr .len 32, cipher_suites : [+ int . len 1], // max 2^8-1 extensions : [ + Extension ] ]
The TLS Server Hello structure is:
struct { ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */ Random random; opaque legacy_session_id_echo<0..32>; CipherSuite cipher_suite; uint8 legacy_compression_method = 0; Extension extensions<6..2^16-1>; } ServerHello;
For the CBOR encoding make the following changes:
ServerHello = [ random : bstr .len 32 cipher_suite : int, extensions : [ + Extension ] ]
The TLS Extenions field is:
struct { ExtensionType extension_type; opaque extension_data<0..2^16-1>; } Extension; enum { server_name(0), /* RFC 6066 */ max_fragment_length(1), /* RFC 6066 */ status_request(5), /* RFC 6066 */ supported_groups(10), /* RFC 8422, 7919 */ signature_algorithms(13), /* RFC 8446 */ use_srtp(14), /* RFC 5764 */ heartbeat(15), /* RFC 6520 */ application_layer_protocol_negotiation(16), /* RFC 7301 */ signed_certificate_timestamp(18), /* RFC 6962 */ client_certificate_type(19), /* RFC 7250 */ server_certificate_type(20), /* RFC 7250 */ padding(21), /* RFC 7685 */ pre_shared_key(41), /* RFC 8446 */ early_data(42), /* RFC 8446 */ supported_versions(43), /* RFC 8446 */ cookie(44), /* RFC 8446 */ psk_key_exchange_modes(45), /* RFC 8446 */ certificate_authorities(47), /* RFC 8446 */ oid_filters(48), /* RFC 8446 */ post_handshake_auth(49), /* RFC 8446 */ signature_algorithms_cert(50), /* RFC 8446 */ key_share(51), /* RFC 8446 */ (65535) } ExtensionType;
For the CBOR encoding make the following changes:
ExtensionType = ( // 0 : ServerName, // 1 : max_fragment_length, // 5 : status_request, 10 : supported_groups, 13 : signature_algorithms, // 14 : use_srtp, // 15 : heartbeat, // 16 : application_layer_protocol_negoiation, // 18 : signed_certificate_timestamp, // 19 : client_certificate_type, // 20 : server_certificate_type, // 21 : padding, 41 : pre_shared_key, // 42 : early_data, // 43 : supported_versions, // 44 : cookie, 45 : psk_key_exchange_modes, // 47 : certificate_authorities, // 48 : oid_filters, // 49 : post_handshake_auth, // 50 : signature_algoirthms_cert, 51 : key_share ) Extension = ( int, any )
Not currently used as we only have one version. If absent it will be assumed to be this version.
There is no reason for this extension to be used in CoRE. For the same functionality use [I-D.ietf-core-echo-request-tag].
The TLS signature algorithm structures are:
enum { /* RSASSA-PKCS1-v1_5 algorithms */ rsa_pkcs1_sha256(0x0401), rsa_pkcs1_sha384(0x0501), rsa_pkcs1_sha512(0x0601), /* ECDSA algorithms */ ecdsa_secp256r1_sha256(0x0403), ecdsa_secp384r1_sha384(0x0503), ecdsa_secp521r1_sha512(0x0603), /* RSASSA-PSS algorithms with public key OID rsaEncryption */ rsa_pss_rsae_sha256(0x0804), rsa_pss_rsae_sha384(0x0805), rsa_pss_rsae_sha512(0x0806), /* EdDSA algorithms */ ed25519(0x0807), ed448(0x0808), /* RSASSA-PSS algorithms with public key OID RSASSA-PSS */ rsa_pss_pss_sha256(0x0809), rsa_pss_pss_sha384(0x080a), rsa_pss_pss_sha512(0x080b), /* Legacy algorithms */ rsa_pkcs1_sha1(0x0201), ecdsa_sha1(0x0203), /* Reserved Code Points */ private_use(0xFE00..0xFFFF), (0xFFFF) } SignatureScheme; struct { SignatureScheme supported_signature_algorithms<2..2^16-2>; } SignatureSchemeList;
One of the differences that may need to be dealt with at this point is the question of keeping the same enumeration as TLS uses or if the enumeration should be changed. For this document the same enumeration is being kept. TLS uses the current two byte format because it separates the hash algorithm from the public key algorithms. For a single algorithm this ends up being 3 bytes for CBOR and 4 bytes for TLS. Each additional algorithm adds 2 bytes until you get to 12 algorithms. If one switched to using integer values from the COSE tables, then one ends up with the same byte count.
For the CBOR encoding make the following changes:
signature_algorithms = bstr
Not used.
Not used.
Not used.
The TLS structure is:
enum { /* Elliptic Curve Groups (ECDHE) */ secp256r1(0x0017), secp384r1(0x0018), secp521r1(0x0019), x25519(0x001D), x448(0x001E), /* Finite Field Groups (DHE) */ ffdhe2048(0x0100), ffdhe3072(0x0101), ffdhe4096(0x0102), ffdhe6144(0x0103), ffdhe8192(0x0104), /* Reserved Code Points */ ffdhe_private_use(0x01FC..0x01FF), ecdhe_private_use(0xFE00..0xFEFF), (0xFFFF) } NamedGroup; struct { NamedGroup named_group_list<2..2^16-1>; } NamedGroupList;
It makes more sense to change the enumeration from that used by TLS to the COSE EC curve registry as those values are only single byte values and are small. One implication is that all of the Finite Field Groups are dropped, but this should not be a problem. This means a 2 byte value for a single curve in the CBOR version rather than a 4 byte encoding for TLS. Adding a second curve adds one byte for CBOR and 2 bytes for TLS.
For the CBOR encoding make the following changes:
NamedGroup = { secp256r1: 1, secp384r1: 2, secp521r1: 3, x25519: 4, x448:5 } supported_groups = [ + NamedGroup ]
The TLS structure for key share is:
struct { NamedGroup group; opaque key_exchange<1..2^16-1>; } KeyShareEntry; struct { KeyShareEntry client_shares<0..2^16-1>; } KeyShareClientHello; struct { NamedGroup selected_group; } KeyShareHelloRetryRequest; struct { KeyShareEntry server_share; } KeyShareServerHello;
For the CBOR encoding make the following changes:
keyShareEntry = { secp256r1 : CompressedPointRepresentation, secp384r1 : CompressedPointRepresentation, secp521r1 : CompressedPointRepresentation, x25519 : bstr, x448 : bstr, * NamedGroup : any } key_share = KeyShare_ClientHello | KeyShare_HelloRetryRequest | KeyShare_ServerHello KeyShare_ClientHello = [ *keyShareEntry] KeyShare_HelloRetryRequest = NamedGroup KeyShare_ServerHello = keyShareEntry
The TLS structure is:
struct { uint8 legacy_form = 4; opaque X[coordinate_length]; opaque Y[coordinate_length]; } UncompressedPointRepresentation;
For the CBOR encoding make the following changes:
CompressedPointReprentation = [ x : bstr, y : bool ]
The TLS structure is:
enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode; struct { PskKeyExchangeMode ke_modes<1..255>; } PskKeyExchangeModes;
Changes for CBOR:
pskKeyExchangeMode = ( psk_key: 0, psk_dhe_ke:1 } psk_key_exchange_modes = [ + pskKeyExchangeMode]
Not used.
The TLS structure is:
struct { opaque identity<1..2^16-1>; uint32 obfuscated_ticket_age; } PskIdentity; opaque PskBinderEntry<32..255>; struct { PskIdentity identities<7..2^16-1>; PskBinderEntry binders<33..2^16-1>; } OfferedPsks; struct { select (Handshake.msg_type) { case client_hello: OfferedPsks; case server_hello: uint16 selected_identity; }; } PreSharedKeyExtension;
The changes for CBOR are:
pre_shared_key = clientHello_PSK | serverHello_PSK clientHello_PSK = OfferedPsks serverHello_PSK = int OfferedPsks = [ identities : [ +PskIdentity ], binders : bstr ] PskIdentity = ( identity : bstr, ? obfuscated_ticket_age : int )
TLS
struct { select(ClientOrServerExtension) { case client: CertificateType client_certificate_types<1..2^8-1>; case server: CertificateType client_certificate_type; } } ClientCertTypeExtension; struct { select(ClientOrServerExtension) { case client: CertificateType server_certificate_types<1..2^8-1>; case server: CertificateType server_certificate_type; } } ServerCertTypeExtension;
CBOR
clientCertType = certTypeRequest | certTypeResponse serverCertType = certTypeRequest | certTypeResponse certTypeRequest = [+ cerType] certTypeResponse = certType certType = (x509:0, rawPublicKey:1 }
The TLS structure is:
struct { Extension extensions<0..2^16-1>; } EncryptedExtensions;
For CBOR:
EncryptedExtensions = [ * Extension ]
Not Used
TLS
enum { X509(0), RawPublicKey(2), (255) } CertificateType; struct { select (certificate_type) { case RawPublicKey: /* From RFC 7250 ASN.1_subjectPublicKeyInfo */ opaque ASN1_subjectPublicKeyInfo<1..2^24-1>; case X509: opaque cert_data<1..2^24-1>; }; Extension extensions<0..2^16-1>; } CertificateEntry; struct { opaque certificate_request_context<0..2^8-1>; CertificateEntry certificate_list<0..2^24-1>; } Certificate;
certificate = [ ? certificate_request_context : bstr, certificate_list : [* CertificateEntry] ] CertificateEntry = [ certificate : { 0 : bstr, // cert_data, 1 : bstr // ASN1_subjectPublicKeyInfo }, extensions : [* Extension] ]
TLS
struct { SignatureScheme algorithm; opaque signature<0..2^16-1>; } CertificateVerify;
CBOR
CertificateVerify = [ algorithm : SignatureScheme, signature : bstr ]
TLS
struct { opaque verify_data[Hash.length]; } Finished;
CBOR
Finished = bstr
TLS
enum { invalid(0), change_cipher_spec(20), alert(21), handshake(22), application_data(23), (255) } ContentType; struct { ContentType type; ProtocolVersion legacy_record_version; uint16 length; opaque fragment[TLSPlaintext.length]; } TLSPlaintext;
CBOR
contentType = ( invalid: 0, change_cipher_spec: 20, alert:21, handshake:22, application_data:23 ) TLSPlaintext = ( type : contentType, fragment : bstr )
TLS
struct { opaque content[TLSPlaintext.length]; ContentType type; uint8 zeros[length_of_padding]; } TLSInnerPlaintext; struct { ContentType opaque_type = application_data; /* 23 */ ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */ uint16 length; opaque encrypted_record[TLSCiphertext.length]; } TLSCiphertext;
CBOR
TLSCiphertext = ( type : application_data, encrypted_record : bstr )
There are many things that the EDHOC system did that slashed down size that has not been done for the previous version of TLS. If these changes are made then a non-trivial amount of savings can be done that might or might not be considered acceptable in this situation.
For the puspose of making things even small we are making the following assumptions:
Transporting the messages w/ CoAP is fairly simple:
[I-D.ietf-core-echo-request-tag] | Amsuess, C., Mattsson, J. and G. Selander, "Echo and Request-Tag", Internet-Draft draft-ietf-core-echo-request-tag-03, October 2018. |
The size of messge #1 is 97 bytes
22, << 1, [ h'0011223344556677889900112233445566778899001122334455 667788990011', / random / [ h'1304' / TLS_AES_128_CCM_SHA256 ], / cipher suites / [ 51, [ 4 / x25519 /, h'00112233445566778899001122334455 66778899001122334455667788990011' ], 13, [ h'0807' / Ed2215 / ], / signature algorithms / 10, [ 4 / secp256r1 / ], 19, [ 1 ] / client_cert_type /, 20, [ 1 ] / server_cert_type /, ] ] >>
Message #1
The size of message #2 is 262 bytes. If you directly encode what is below it will be 16 bytes short as there is no provision in the CDDL for the 16 bytes of the MAC appended to the end of the encrypted data.
22, << 2, [ h'00112233445566778899001122334455667788990011223344 55667788990011', / random / h'1304', / cipher suite / [ 51, [ 4 / x25519 /, h'001122334455667788990011223344 5566778899001122334455667788990011' ] / key share / ] ] >>, 23, << 4, [ 19, 1, / client_cert_type / 20, 1 / server_cert_type / ], 11, [ [ 1 / rpk /, h'1122334455667788990011223344556677889900112233445566 778899001122334455667788990011223344' ] ], 12, [ h'0807', h'1122334455667788990011223344556677889900112233445566 778899001122334455667788990011223344556677889900112233 4455667788990011223344' ], 13, h'1122334455667788990011223344556677889900112233445566 778899001122' >>
Message #2
Size of message #3 is 175 bytes
23, << 11, [ [ 1 / rpk /, h'11223344556677889900112233445566778899001122334455 66778899001122334455667788990011223344' ] ], 12, [ h'0807', h'112233445566778899001122334455667788990011223344 55667788990011223344556677889900112233445566778899 001122334455667788990011223344' ], 13, h'1122334455667788990011223344556677889900112233445566 778899001122' >>
Message #3
The size of messge #1 is 97 bytes
22, << 1, [ h'001122334455667788990011223344556677889 9001122334455667788990011', / random / [ h'1304' / TLS_AES_128_CCM_SHA256 ], / cipher suites / [ 51, [ 4 / x25519 /, h'0011223344556677889900112233445 566778899001122334455667788990011' ], 13, [ h'0807' / Ed2215 / ], / signature algorithms / 10, [ 4 / secp256r1 / ], 19, [ 1 ] / client_cert_type /, 20, [ 1 ] / server_cert_type /, ] ] >>
Message #1
The size of message #2 is 262 bytes. If you directly encode what is below it will be 16 bytes short as there is no provision in the CDDL for the 16 bytes of the MAC appended to the end of the encrypted data.
22, << 2, [ h'001122334455667788990011223344556677889900112233445 5667788990011', / random / h'1304', / cipher suite / [ 51, [ 4 / x25519 /, h'00112233445566778899001122 33445566778899001122334455667788990011' ] / key share / ] ] >>, 23, << 4, [ 19, 1, / client_cert_type / 20, 1 / server_cert_type / ], 11, [ [ 1 / rpk /, h'1122334455667788990011223344556677889900112233445566 778899001122334455667788990011223344' ] ], 12, [ h'0807', h'1122334455667788990011223344556677889900112233445566 7788990011223344556677889900112233445566778899001122 334455667788990011223344' ], 13, h'112233445566778899001122334455667788990011223344556677 8899001122' >>
Message #2
Size of message #3 is 175 bytes
23, << 11, [ [ 1 / rpk /, h'11223344556677889900112233445566778899001122334455 66778899001122334455667788990011223344' ] ], 12, [ h'0807', h'1122334455667788990011223344556677889900112233445566 77889900112233445566778899001122334455667788990011223 34455667788990011223344' ], 13, h'1122334455667788990011223344556677889900112233445566778 899001122' >>
Message #3
The size of messge #1 is 47 bytes
22, << 1, [ 1 / TLS_AES_128_CCM_SHA256_64 /, / cipher suites / [ 1, [ 4 / x25519 /, h'00112233445566778899001122334455 66778899001122334455667788990011' ], 2, 99 / Ed2215 / / signature algorithms / ] ] >>
Message #1
The size of message #2 is 146 bytes. The encryption authentication code is added as a separate at the end of the encrypted handshake block.
22, << 2, [ 1 / TLS_AES_128_CCM_SHA256_64 /, / cipher suite / [ 1, [ 4 / x25519 /, h'001122334455667788990011223344 5566778899001122334455667788990011' ] / key share / ] ] >>, 23, << 11, [ [ 9 / reference /, h'1122334455' ] / certificate / ], 12, [ 99, h'11223344556677889900112233445566778899001122 3344556677889900112233445566778899001122334455 66778899001122334455667788990011223344' / signature / ], / certificate verify / 13, h'1122334455667788', / finish / h'11223344556677' / encryption authentication code / >>
Message #2
Size of message #3 is 102 bytes
23, << 11, [ [ 9 / reference /, h'1122334455' ] ], / certificate / 12, [ 99, h'11223344556677889900112233445566778899001122 33445566778899001122334455667788990011223344 5566778899001122334455667788990011223344' ], / certificate verify / 13, h'1122334455667788', / finish / h'1122334455667788' / encryption authentication code / >>
Message #3
The size of messge #1 is 65 bytes
22, << 1, [ 1, / cipher suites / [ 1, [ 4 / x25519 /, h'001122334455667788990011 2233445566778899001122334455667788990011' ], 2, 99, / signature algorithms / 6, [ h'0102030405', h'0102030405060708' ] ] ] >>
Message #1
The size of message #2 is 59 bytes. If you directly encode what is below it will be 16 bytes short as there is no provision in the CDDL for the 16 bytes of the MAC appended to the end of the encrypted data.
22, << 2, [ 1, / cipher suite / [ 1, [ 4 / x25519 /, h'0011223344556677889900112233445 566778899001122334455667788990011' ], / key share / 6, 1 ] ] >>, 23, << 13, h'1122334455667788' >>
Message #2
Size of message #3 is 12 bytes
23, << 13, h'1122334455667788' >>
Message #3
The following things can still be considered for shrinking things:
I still need to actually read the current document. From a quick glance through I have the following issues: