Crypt-Bear
view release on metacpan or search on metacpan
src/ssl/ssl_hs_common.t0 view on Meta::CPAN
\ Scan the list of supported cipher suites for a given value. If found,
\ then the list index at which it was found is returned; otherwise, -1
\ is returned.
: scan-suite ( suite -- index )
{ suite }
addr-suites_num get8 { num }
0
begin dup num < while
dup 1 << addr-suites_buf + get16 suite = if ret then
1+
repeat
drop -1 ;
\ =======================================================================
\ Generate random bytes into buffer (address is offset in context).
cc: mkrand ( addr len -- ) {
size_t len = (size_t)T0_POP();
void *addr = (unsigned char *)ENG + (size_t)T0_POP();
br_hmac_drbg_generate(&ENG->rng, addr, len);
}
\ Read a handshake message header: type and length. These are returned
\ in reverse order (type is TOS, length is below it).
: read-handshake-header-core ( -- lim type )
read8-nc 3 read24 swap drop swap ;
\ Read a handshake message header: type and length. If the header is for
\ a HelloRequest message, then it is discarded and a new header is read
\ (repeatedly if necessary).
: read-handshake-header ( -- lim type )
begin
read-handshake-header-core dup 0= while
drop if ERR_BAD_HANDSHAKE fail then
repeat ;
\ =======================================================================
\ Cipher suite processing.
\
\ Unfortunately, cipher suite identifiers are attributed mostly arbitrary,
\ so we have to map the cipher suite numbers we support into aggregate
\ words that encode the information we need. Table below is organized
\ as a sequence of pairs of 16-bit words, the first being the cipher suite
\ identifier, the second encoding the algorithm elements. The suites are
\ ordered by increasing cipher suite ID, so that fast lookups may be
\ performed with a binary search (not implemented for the moment, since it
\ does not appear to matter much in practice).
\
\ Algorithm elements are encoded over 4 bits each, in the following order
\ (most significant to least significant):
\
\ -- Server key type:
\ 0 RSA (RSA key exchange)
\ 1 ECDHE-RSA (ECDHE key exchange, RSA signature)
\ 2 ECDHE-ECDSA (ECDHE key exchange, ECDSA signature)
\ 3 ECDH-RSA (ECDH key exchange, certificate is RSA-signed)
\ 4 ECDH-ECDSA (ECDH key exchange, certificate is ECDSA-signed)
\ -- Encryption algorithm:
\ 0 3DES/CBC
\ 1 AES-128/CBC
\ 2 AES-256/CBC
\ 3 AES-128/GCM
\ 4 AES-256/GCM
\ 5 ChaCha20/Poly1305
\ 6 AES-128/CCM
\ 7 AES-256/CCM
\ 8 AES-128/CCM8
\ 9 AES-256/CCM8
\ -- MAC algorithm:
\ 0 none (for suites with AEAD encryption)
\ 2 HMAC/SHA-1
\ 4 HMAC/SHA-256
\ 5 HMAC/SHA-384
\ -- PRF for TLS-1.2:
\ 4 with SHA-256
\ 5 with SHA-384
\
\ WARNING: if adding a new cipher suite that does not use SHA-256 for the
\ PRF (with TLS 1.2), be sure to check the suites_sha384[] array defined
\ in ssl/ssl_keyexport.c
data: cipher-suite-def
hexb| 000A 0024 | \ TLS_RSA_WITH_3DES_EDE_CBC_SHA
hexb| 002F 0124 | \ TLS_RSA_WITH_AES_128_CBC_SHA
hexb| 0035 0224 | \ TLS_RSA_WITH_AES_256_CBC_SHA
hexb| 003C 0144 | \ TLS_RSA_WITH_AES_128_CBC_SHA256
hexb| 003D 0244 | \ TLS_RSA_WITH_AES_256_CBC_SHA256
hexb| 009C 0304 | \ TLS_RSA_WITH_AES_128_GCM_SHA256
hexb| 009D 0405 | \ TLS_RSA_WITH_AES_256_GCM_SHA384
hexb| C003 4024 | \ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
hexb| C004 4124 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
hexb| C005 4224 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
hexb| C008 2024 | \ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
hexb| C009 2124 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
hexb| C00A 2224 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
hexb| C00D 3024 | \ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
hexb| C00E 3124 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
hexb| C00F 3224 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
hexb| C012 1024 | \ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
hexb| C013 1124 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
hexb| C014 1224 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
hexb| C023 2144 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
hexb| C024 2255 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
hexb| C025 4144 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
hexb| C026 4255 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
hexb| C027 1144 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
hexb| C028 1255 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
hexb| C029 3144 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
hexb| C02A 3255 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
hexb| C02B 2304 | \ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
hexb| C02C 2405 | \ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
hexb| C02D 4304 | \ TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
hexb| C02E 4405 | \ TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
hexb| C02F 1304 | \ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
hexb| C030 1405 | \ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
hexb| C031 3304 | \ TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
hexb| C032 3405 | \ TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
hexb| C09C 0604 | \ TLS_RSA_WITH_AES_128_CCM
hexb| C09D 0704 | \ TLS_RSA_WITH_AES_256_CCM
hexb| C0A0 0804 | \ TLS_RSA_WITH_AES_128_CCM_8
hexb| C0A1 0904 | \ TLS_RSA_WITH_AES_256_CCM_8
hexb| C0AC 2604 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM
hexb| C0AD 2704 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM
hexb| C0AE 2804 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
hexb| C0AF 2904 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
hexb| CCA8 1504 | \ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
hexb| CCA9 2504 | \ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
hexb| 0000 | \ List terminator.
\ Convert cipher suite identifier to element words. This returns 0 if
\ the cipher suite is not known.
: cipher-suite-to-elements ( suite -- elts )
{ id }
cipher-suite-def
begin
dup 2+ swap data-get16
dup ifnot 2drop 0 ret then
id = if data-get16 ret then
2+
again ;
\ Check that a given cipher suite is supported. Note that this also
\ returns true (-1) for the TLS_FALLBACK_SCSV pseudo-ciphersuite.
: suite-supported? ( suite -- bool )
dup 0x5600 = if drop -1 ret then
cipher-suite-to-elements 0<> ;
\ Get expected key type for cipher suite. The key type is one of
\ BR_KEYTYPE_RSA or BR_KEYTYPE_EC, combined with either BR_KEYTYPE_KEYX
\ (RSA encryption or static ECDH) or BR_KEYTYPE_SIGN (RSA or ECDSA
\ signature, for ECDHE cipher suites).
: expected-key-type ( suite -- key-type )
cipher-suite-to-elements 12 >>
case
0 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX } endof
1 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN } endof
2 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_SIGN } endof
3 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof
4 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof
0 swap
endcase ;
\ Test whether the cipher suite uses RSA key exchange.
: use-rsa-keyx? ( suite -- bool )
cipher-suite-to-elements 12 >> 0= ;
\ Test whether the cipher suite uses ECDHE key exchange, signed with RSA.
: use-rsa-ecdhe? ( suite -- bool )
cipher-suite-to-elements 12 >> 1 = ;
\ Test whether the cipher suite uses ECDHE key exchange, signed with ECDSA.
: use-ecdsa-ecdhe? ( suite -- bool )
cipher-suite-to-elements 12 >> 2 = ;
\ Test whether the cipher suite uses ECDHE key exchange (with RSA or ECDSA).
: use-ecdhe? ( suite -- bool )
cipher-suite-to-elements 12 >> dup 0> swap 3 < and ;
\ Test whether the cipher suite uses ECDH (static) key exchange.
: use-ecdh? ( suite -- bool )
cipher-suite-to-elements 12 >> 2 > ;
\ Get identifier for the PRF (TLS 1.2).
: prf-id ( suite -- id )
cipher-suite-to-elements 15 and ;
\ Test whether a cipher suite is only for TLS-1.2. Cipher suites that
\ can be used with TLS-1.0 or 1.1 use HMAC/SHA-1. RFC do not formally
\ forbid using a CBC-based TLS-1.2 cipher suite, e.g. based on HMAC/SHA-256,
\ with older protocol versions; however, servers should not do that, since
\ it may confuse clients. Since the server code does not try such games,
\ for consistency, the client should reject it as well (normal servers
\ don't do that, so any attempt is a sign of foul play).
: use-tls12? ( suite -- bool )
cipher-suite-to-elements 0xF0 and 0x20 <> ;
\ Switch to negotiated security parameters for input or output.
: switch-encryption ( is-client for-input -- )
{ for-input }
addr-cipher_suite get16 cipher-suite-to-elements { elts }
\ prf_id
elts 15 and
\ mac_id
elts 4 >> 15 and
\ cipher type and key length
elts 8 >> 15 and case
\ 3DES/CBC
0 of 0 24
for-input if
switch-cbc-in
else
switch-cbc-out
then
endof
\ AES-128/CBC
1 of 1 16
for-input if
switch-cbc-in
else
switch-cbc-out
then
endof
\ AES-256/CBC
2 of 1 32
for-input if
switch-cbc-in
else
switch-cbc-out
then
endof
\ AES-128/GCM
3 of drop 16
for-input if
switch-aesgcm-in
else
switch-aesgcm-out
then
endof
\ AES-256/GCM
4 of drop 32
for-input if
switch-aesgcm-in
else
switch-aesgcm-out
then
endof
\ ChaCha20+Poly1305
5 of drop
for-input if
switch-chapol-in
else
switch-chapol-out
then
endof
\ Now we only have AES/CCM suites (6 to 9). Since the
\ input is between 0 and 15, and we checked values 0 to 5,
\ we only need to reject values larger than 9.
dup 9 > if
ERR_BAD_PARAM fail
then
\ Stack: is_client prf_id mac_id cipher_id
\ We want to remove the mac_id (it is zero for CCM suites)
\ and replace the cipher_id with the key and tag lengths.
\ The following table applies:
\ id key length tag length
\ 6 16 16
\ 7 32 16
\ 8 16 8
\ 9 32 8
swap drop
dup 1 and 4 << 16 + swap
8 and 16 swap -
for-input if
switch-aesccm-in
else
switch-aesccm-out
then
ret
( run in 0.474 second using v1.01-cache-2.11-cpan-e1769b4cff6 )