tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

tls13hkdf.c (10419B)


      1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /*
      3 * TLS 1.3 Protocol
      4 *
      5 * This Source Code Form is subject to the terms of the Mozilla Public
      6 * License, v. 2.0. If a copy of the MPL was not distributed with this
      7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      8 
      9 #include "keyhi.h"
     10 #include "pk11func.h"
     11 #include "secitem.h"
     12 #include "ssl.h"
     13 #include "sslt.h"
     14 #include "sslerr.h"
     15 #include "sslimpl.h"
     16 
     17 /* This table contains the mapping between TLS hash identifiers and the
     18 * PKCS#11 identifiers */
     19 static const struct {
     20    SSLHashType hash;
     21    CK_MECHANISM_TYPE pkcs11Mech;
     22    unsigned int hashSize;
     23 } kTlsHkdfInfo[] = {
     24    { ssl_hash_none, 0, 0 },
     25    { ssl_hash_md5, 0, 0 },
     26    { ssl_hash_sha1, 0, 0 },
     27    { ssl_hash_sha224, 0 },
     28    { ssl_hash_sha256, CKM_SHA256, 32 },
     29    { ssl_hash_sha384, CKM_SHA384, 48 },
     30    { ssl_hash_sha512, CKM_SHA512, 64 }
     31 };
     32 
     33 SECStatus
     34 tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash,
     35                  PK11SymKey **prkp)
     36 {
     37    CK_HKDF_PARAMS params;
     38    SECItem paramsi;
     39    PK11SymKey *prk;
     40    static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX];
     41    SECItem zeroKeyItem = { siBuffer, CONST_CAST(PRUint8, zeroKeyBuf), kTlsHkdfInfo[baseHash].hashSize };
     42    PK11SlotInfo *slot = NULL;
     43    PK11SymKey *newIkm2 = NULL;
     44    PK11SymKey *newIkm1 = NULL;
     45    SECStatus rv;
     46 
     47    params.bExtract = CK_TRUE;
     48    params.bExpand = CK_FALSE;
     49    params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
     50    params.pInfo = NULL;
     51    params.ulInfoLen = 0UL;
     52    params.pSalt = NULL;
     53    params.ulSaltLen = 0UL;
     54    params.hSaltKey = CK_INVALID_HANDLE;
     55 
     56    if (!ikm1) {
     57        /* PKCS #11 v3.0 has and explict NULL value, which equates to
     58         * a sequence of zeros equal in length to the HMAC. */
     59        params.ulSaltType = CKF_HKDF_SALT_NULL;
     60    } else {
     61        /* PKCS #11 v3.0 can take the salt as a key handle */
     62        params.hSaltKey = PK11_GetSymKeyHandle(ikm1);
     63        params.ulSaltType = CKF_HKDF_SALT_KEY;
     64 
     65        /* if we have both keys, make sure they are in the same slot */
     66        if (ikm2) {
     67            rv = PK11_SymKeysToSameSlot(CKM_HKDF_DERIVE,
     68                                        CKA_DERIVE, CKA_DERIVE,
     69                                        ikm2, ikm1, &newIkm2, &newIkm1);
     70            if (rv != SECSuccess) {
     71                SECItem *salt;
     72                /* couldn't move the keys, try extracting the salt */
     73                rv = PK11_ExtractKeyValue(ikm1);
     74                if (rv != SECSuccess)
     75                    return rv;
     76                salt = PK11_GetKeyData(ikm1);
     77                if (!salt)
     78                    return SECFailure;
     79                PORT_Assert(salt->len > 0);
     80                /* Set up for Salt as Data instead of Salt as key */
     81                params.pSalt = salt->data;
     82                params.ulSaltLen = salt->len;
     83                params.ulSaltType = CKF_HKDF_SALT_DATA;
     84            }
     85            /* use the new keys */
     86            if (newIkm1) {
     87                /* we've moved the key, get the handle for the new key */
     88                params.hSaltKey = PK11_GetSymKeyHandle(newIkm1);
     89                /* we don't use ikm1 after this, so don't bother setting it */
     90            }
     91            if (newIkm2) {
     92                /* new ikm2 key, use the new key */
     93                ikm2 = newIkm2;
     94            }
     95        }
     96    }
     97    paramsi.data = (unsigned char *)&params;
     98    paramsi.len = sizeof(params);
     99 
    100    PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech);
    101    PORT_Assert(kTlsHkdfInfo[baseHash].hashSize);
    102    PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash);
    103 
    104    /* A zero ikm2 is a key of hash-length 0s. */
    105    if (!ikm2) {
    106        /* if we have ikm1, put the zero key in the same slot */
    107        slot = ikm1 ? PK11_GetSlotFromKey(ikm1) : PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
    108        if (!slot) {
    109            return SECFailure;
    110        }
    111 
    112        newIkm2 = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap,
    113                                     CKA_DERIVE, &zeroKeyItem, NULL);
    114        if (!newIkm2) {
    115            return SECFailure;
    116        }
    117        ikm2 = newIkm2;
    118    }
    119    PORT_Assert(ikm2);
    120 
    121    PRINT_BUF(50, (NULL, "HKDF Extract: IKM1/Salt", params.pSalt, params.ulSaltLen));
    122    PRINT_KEY(50, (NULL, "HKDF Extract: IKM2", ikm2));
    123 
    124    prk = PK11_Derive(ikm2, CKM_HKDF_DERIVE, &paramsi, CKM_HKDF_DERIVE,
    125                      CKA_DERIVE, 0);
    126    PK11_FreeSymKey(newIkm2);
    127    PK11_FreeSymKey(newIkm1);
    128    if (slot)
    129        PK11_FreeSlot(slot);
    130    if (!prk) {
    131        return SECFailure;
    132    }
    133 
    134    PRINT_KEY(50, (NULL, "HKDF Extract", prk));
    135    *prkp = prk;
    136 
    137    return SECSuccess;
    138 }
    139 
    140 SECStatus
    141 tls13_HkdfExpandLabelGeneral(CK_MECHANISM_TYPE deriveMech, PK11SymKey *prk,
    142                             SSLHashType baseHash,
    143                             const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
    144                             const char *label, unsigned int labelLen,
    145                             CK_MECHANISM_TYPE algorithm, unsigned int keySize,
    146                             SSLProtocolVariant variant, PK11SymKey **keyp)
    147 {
    148    CK_HKDF_PARAMS params;
    149    SECItem paramsi = { siBuffer, NULL, 0 };
    150    /* Size of info array needs to be big enough to hold the maximum Prefix,
    151     * Label, plus HandshakeHash. If it's ever to small, the code will abort.
    152     */
    153    PRUint8 info[256];
    154    sslBuffer infoBuf = SSL_BUFFER(info);
    155    PK11SymKey *derived;
    156    SECStatus rv;
    157    const char *kLabelPrefixTls = "tls13 ";
    158    const char *kLabelPrefixDtls = "dtls13";
    159    const unsigned int kLabelPrefixLen =
    160        (variant == ssl_variant_stream) ? strlen(kLabelPrefixTls) : strlen(kLabelPrefixDtls);
    161    const char *kLabelPrefix =
    162        (variant == ssl_variant_stream) ? kLabelPrefixTls : kLabelPrefixDtls;
    163 
    164    PORT_Assert(prk);
    165    PORT_Assert(keyp);
    166    if ((handshakeHashLen > 255) ||
    167        (handshakeHash == NULL && handshakeHashLen > 0) ||
    168        (labelLen + kLabelPrefixLen > 255)) {
    169        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    170        return SECFailure;
    171    }
    172 
    173    /*
    174     *  [draft-ietf-tls-tls13-11] Section 7.1:
    175     *
    176     *  HKDF-Expand-Label(Secret, Label, HashValue, Length) =
    177     *       HKDF-Expand(Secret, HkdfLabel, Length)
    178     *
    179     *  Where HkdfLabel is specified as:
    180     *
    181     *  struct HkdfLabel {
    182     *    uint16 length;
    183     *    opaque label<9..255>;
    184     *    opaque hash_value<0..255>;
    185     *  };
    186     *
    187     *  Where:
    188     *  - HkdfLabel.length is Length
    189     *  - HkdfLabel.hash_value is HashValue.
    190     *  - HkdfLabel.label is "TLS 1.3, " + Label
    191     *
    192     */
    193    rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2);
    194    if (rv != SECSuccess) {
    195        return SECFailure;
    196    }
    197    rv = sslBuffer_AppendNumber(&infoBuf, labelLen + kLabelPrefixLen, 1);
    198    if (rv != SECSuccess) {
    199        return SECFailure;
    200    }
    201    rv = sslBuffer_Append(&infoBuf, kLabelPrefix, kLabelPrefixLen);
    202    if (rv != SECSuccess) {
    203        return SECFailure;
    204    }
    205    rv = sslBuffer_Append(&infoBuf, label, labelLen);
    206    if (rv != SECSuccess) {
    207        return SECFailure;
    208    }
    209    rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1);
    210    if (rv != SECSuccess) {
    211        return SECFailure;
    212    }
    213 
    214    params.bExtract = CK_FALSE;
    215    params.bExpand = CK_TRUE;
    216    params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
    217    params.pInfo = SSL_BUFFER_BASE(&infoBuf);
    218    params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf);
    219    paramsi.data = (unsigned char *)&params;
    220    paramsi.len = sizeof(params);
    221    derived = PK11_DeriveWithFlags(prk, deriveMech,
    222                                   &paramsi, algorithm,
    223                                   CKA_DERIVE, keySize,
    224                                   CKF_SIGN | CKF_VERIFY);
    225    if (!derived) {
    226        return SECFailure;
    227    }
    228 
    229    *keyp = derived;
    230 
    231 #ifdef TRACE
    232    if (ssl_trace >= 50) {
    233        /* Make sure the label is null terminated. */
    234        char labelStr[100];
    235        PORT_Memcpy(labelStr, label, labelLen);
    236        labelStr[labelLen] = 0;
    237        SSL_TRC(50, ("HKDF Expand: label='tls13 %s',requested length=%d",
    238                     labelStr, keySize));
    239    }
    240    PRINT_KEY(50, (NULL, "PRK", prk));
    241    PRINT_BUF(50, (NULL, "Hash", handshakeHash, handshakeHashLen));
    242    PRINT_BUF(50, (NULL, "Info", SSL_BUFFER_BASE(&infoBuf),
    243                   SSL_BUFFER_LEN(&infoBuf)));
    244    PRINT_KEY(50, (NULL, "Derived key", derived));
    245 #endif
    246 
    247    return SECSuccess;
    248 }
    249 
    250 SECStatus
    251 tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
    252                      const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
    253                      const char *label, unsigned int labelLen,
    254                      CK_MECHANISM_TYPE algorithm, unsigned int keySize,
    255                      SSLProtocolVariant variant, PK11SymKey **keyp)
    256 {
    257    return tls13_HkdfExpandLabelGeneral(CKM_HKDF_DERIVE, prk, baseHash,
    258                                        handshakeHash, handshakeHashLen,
    259                                        label, labelLen, algorithm, keySize,
    260                                        variant, keyp);
    261 }
    262 
    263 SECStatus
    264 tls13_HkdfExpandLabelRaw(PK11SymKey *prk, SSLHashType baseHash,
    265                         const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
    266                         const char *label, unsigned int labelLen,
    267                         SSLProtocolVariant variant, unsigned char *output,
    268                         unsigned int outputLen)
    269 {
    270    PK11SymKey *derived = NULL;
    271    SECItem *rawkey;
    272    SECStatus rv;
    273 
    274    /* the result is not really a key, it's a data object */
    275    rv = tls13_HkdfExpandLabelGeneral(CKM_HKDF_DATA, prk, baseHash,
    276                                      handshakeHash, handshakeHashLen,
    277                                      label, labelLen, CKM_HKDF_DERIVE, outputLen,
    278                                      variant, &derived);
    279    if (rv != SECSuccess || !derived) {
    280        goto abort;
    281    }
    282 
    283    rv = PK11_ExtractKeyValue(derived);
    284    if (rv != SECSuccess) {
    285        goto abort;
    286    }
    287 
    288    rawkey = PK11_GetKeyData(derived);
    289    if (!rawkey) {
    290        goto abort;
    291    }
    292 
    293    PORT_Assert(rawkey->len == outputLen);
    294    memcpy(output, rawkey->data, outputLen);
    295    PK11_FreeSymKey(derived);
    296 
    297    return SECSuccess;
    298 
    299 abort:
    300    if (derived) {
    301        PK11_FreeSymKey(derived);
    302    }
    303    PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
    304    return SECFailure;
    305 }