tor-browser

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

sslprimitive.c (17030B)


      1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /*
      3 * SSL Primitives: Public HKDF and AEAD Functions
      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 "blapit.h"
     10 #include "keyhi.h"
     11 #include "pk11pub.h"
     12 #include "sechash.h"
     13 #include "ssl.h"
     14 #include "sslexp.h"
     15 #include "sslerr.h"
     16 #include "sslproto.h"
     17 
     18 #include "sslimpl.h"
     19 #include "tls13con.h"
     20 #include "tls13hkdf.h"
     21 
     22 struct SSLAeadContextStr {
     23    /* sigh, the API creates a single context, but then uses either encrypt
     24     * and decrypt on that context. We should take an encrypt/decrypt
     25     * variable here, but for now create two contexts. */
     26    PK11Context *encryptContext;
     27    PK11Context *decryptContext;
     28    int tagLen;
     29    int ivLen;
     30    unsigned char iv[MAX_IV_LENGTH];
     31 };
     32 
     33 SECStatus
     34 SSLExp_MakeVariantAead(PRUint16 version, PRUint16 cipherSuite, SSLProtocolVariant variant,
     35                       PK11SymKey *secret, const char *labelPrefix,
     36                       unsigned int labelPrefixLen, SSLAeadContext **ctx)
     37 {
     38    SSLAeadContext *out = NULL;
     39    char label[255]; // Maximum length label.
     40    static const char *const keySuffix = "key";
     41    static const char *const ivSuffix = "iv";
     42    CK_MECHANISM_TYPE mech;
     43    SECItem nullParams = { siBuffer, NULL, 0 };
     44    PK11SymKey *key = NULL;
     45 
     46    PORT_Assert(strlen(keySuffix) >= strlen(ivSuffix));
     47    if (secret == NULL || ctx == NULL ||
     48        (labelPrefix == NULL && labelPrefixLen > 0) ||
     49        labelPrefixLen + strlen(keySuffix) > sizeof(label)) {
     50        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     51        goto loser;
     52    }
     53 
     54    SSLHashType hash;
     55    const ssl3BulkCipherDef *cipher;
     56    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
     57                                          &hash, &cipher);
     58    if (rv != SECSuccess) {
     59        goto loser; /* Code already set. */
     60    }
     61 
     62    out = PORT_ZNew(SSLAeadContext);
     63    if (out == NULL) {
     64        goto loser;
     65    }
     66    mech = ssl3_Alg2Mech(cipher->calg);
     67    out->ivLen = cipher->iv_size + cipher->explicit_nonce_size;
     68    out->tagLen = cipher->tag_size;
     69 
     70    if (labelPrefixLen > 0) {
     71        memcpy(label, labelPrefix, labelPrefixLen);
     72    }
     73    memcpy(label + labelPrefixLen, ivSuffix, strlen(ivSuffix));
     74    unsigned int labelLen = labelPrefixLen + strlen(ivSuffix);
     75    unsigned int ivLen = cipher->iv_size + cipher->explicit_nonce_size;
     76    rv = tls13_HkdfExpandLabelRaw(secret, hash,
     77                                  NULL, 0, // Handshake hash.
     78                                  label, labelLen, variant,
     79                                  out->iv, ivLen);
     80    if (rv != SECSuccess) {
     81        goto loser;
     82    }
     83 
     84    memcpy(label + labelPrefixLen, keySuffix, strlen(keySuffix));
     85    labelLen = labelPrefixLen + strlen(keySuffix);
     86    rv = tls13_HkdfExpandLabel(secret, hash,
     87                               NULL, 0, // Handshake hash.
     88                               label, labelLen, mech, cipher->key_size,
     89                               variant, &key);
     90    if (rv != SECSuccess) {
     91        goto loser;
     92    }
     93 
     94    /* We really need to change the API to Create a context for each
     95     * encrypt and decrypt rather than a single call that does both. it's
     96     * almost certain that the underlying application tries to use the same
     97     * context for both. */
     98    out->encryptContext = PK11_CreateContextBySymKey(mech,
     99                                                     CKA_NSS_MESSAGE | CKA_ENCRYPT,
    100                                                     key, &nullParams);
    101    if (out->encryptContext == NULL) {
    102        goto loser;
    103    }
    104 
    105    out->decryptContext = PK11_CreateContextBySymKey(mech,
    106                                                     CKA_NSS_MESSAGE | CKA_DECRYPT,
    107                                                     key, &nullParams);
    108    if (out->decryptContext == NULL) {
    109        goto loser;
    110    }
    111 
    112    PK11_FreeSymKey(key);
    113    *ctx = out;
    114    return SECSuccess;
    115 
    116 loser:
    117    PK11_FreeSymKey(key);
    118    SSLExp_DestroyAead(out);
    119    return SECFailure;
    120 }
    121 
    122 SECStatus
    123 SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
    124                const char *labelPrefix, unsigned int labelPrefixLen, SSLAeadContext **ctx)
    125 {
    126    return SSLExp_MakeVariantAead(version, cipherSuite, ssl_variant_stream, secret,
    127                                  labelPrefix, labelPrefixLen, ctx);
    128 }
    129 
    130 SECStatus
    131 SSLExp_DestroyAead(SSLAeadContext *ctx)
    132 {
    133    if (!ctx) {
    134        return SECSuccess;
    135    }
    136    if (ctx->encryptContext) {
    137        PK11_DestroyContext(ctx->encryptContext, PR_TRUE);
    138    }
    139    if (ctx->decryptContext) {
    140        PK11_DestroyContext(ctx->decryptContext, PR_TRUE);
    141    }
    142 
    143    PORT_ZFree(ctx, sizeof(*ctx));
    144    return SECSuccess;
    145 }
    146 
    147 /* Bug 1529440 exists to refactor this and the other AEAD uses. */
    148 static SECStatus
    149 ssl_AeadInner(const SSLAeadContext *ctx, PK11Context *context,
    150              PRBool decrypt, PRUint64 counter,
    151              const PRUint8 *aad, unsigned int aadLen,
    152              const PRUint8 *in, unsigned int inLen,
    153              PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
    154 {
    155    if (ctx == NULL || (aad == NULL && aadLen > 0) || in == NULL ||
    156        out == NULL || outLen == NULL) {
    157        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    158        return SECFailure;
    159    }
    160 
    161    // Setup the nonce.
    162    PRUint8 nonce[sizeof(counter)] = { 0 };
    163    sslBuffer nonceBuf = SSL_BUFFER_FIXED(nonce, sizeof(counter));
    164    SECStatus rv = sslBuffer_AppendNumber(&nonceBuf, counter, sizeof(counter));
    165    if (rv != SECSuccess) {
    166        PORT_Assert(0);
    167        return SECFailure;
    168    }
    169    /* at least on encrypt, we should not be using CKG_NO_GENERATE, but
    170     * the current experimental API has the application tracking the counter
    171     * rather than token. We should look at the QUIC code and see if the
    172     * counter can be moved internally where it belongs. That would
    173     * also get rid of the  formatting code above and have the API
    174     * call tls13_AEAD directly in SSLExp_Aead* */
    175    return tls13_AEAD(context, decrypt, CKG_NO_GENERATE, 0, ctx->iv, NULL,
    176                      ctx->ivLen, nonce, sizeof(counter), aad, aadLen,
    177                      out, outLen, maxOut, ctx->tagLen, in, inLen);
    178 }
    179 
    180 SECStatus
    181 SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter,
    182                   const PRUint8 *aad, unsigned int aadLen,
    183                   const PRUint8 *plaintext, unsigned int plaintextLen,
    184                   PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
    185 {
    186    // false == encrypt
    187    return ssl_AeadInner(ctx, ctx->encryptContext, PR_FALSE, counter,
    188                         aad, aadLen, plaintext, plaintextLen,
    189                         out, outLen, maxOut);
    190 }
    191 
    192 SECStatus
    193 SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter,
    194                   const PRUint8 *aad, unsigned int aadLen,
    195                   const PRUint8 *ciphertext, unsigned int ciphertextLen,
    196                   PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
    197 {
    198    // true == decrypt
    199    return ssl_AeadInner(ctx, ctx->decryptContext, PR_TRUE, counter,
    200                         aad, aadLen, ciphertext, ciphertextLen,
    201                         out, outLen, maxOut);
    202 }
    203 
    204 SECStatus
    205 SSLExp_HkdfExtract(PRUint16 version, PRUint16 cipherSuite,
    206                   PK11SymKey *salt, PK11SymKey *ikm, PK11SymKey **keyp)
    207 {
    208    if (keyp == NULL) {
    209        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    210        return SECFailure;
    211    }
    212 
    213    SSLHashType hash;
    214    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
    215                                          &hash, NULL);
    216    if (rv != SECSuccess) {
    217        return SECFailure; /* Code already set. */
    218    }
    219    return tls13_HkdfExtract(salt, ikm, hash, keyp);
    220 }
    221 
    222 SECStatus
    223 SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
    224                       const PRUint8 *hsHash, unsigned int hsHashLen,
    225                       const char *label, unsigned int labelLen, PK11SymKey **keyp)
    226 {
    227    return SSLExp_HkdfVariantExpandLabel(version, cipherSuite, prk, hsHash, hsHashLen,
    228                                         label, labelLen, ssl_variant_stream, keyp);
    229 }
    230 
    231 SECStatus
    232 SSLExp_HkdfVariantExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
    233                              const PRUint8 *hsHash, unsigned int hsHashLen,
    234                              const char *label, unsigned int labelLen,
    235                              SSLProtocolVariant variant, PK11SymKey **keyp)
    236 {
    237    if (prk == NULL || keyp == NULL ||
    238        label == NULL || labelLen == 0) {
    239        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    240        return SECFailure;
    241    }
    242 
    243    SSLHashType hash;
    244    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
    245                                          &hash, NULL);
    246    if (rv != SECSuccess) {
    247        return SECFailure; /* Code already set. */
    248    }
    249    return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen,
    250                                 CKM_HKDF_DERIVE,
    251                                 tls13_GetHashSizeForHash(hash), variant, keyp);
    252 }
    253 
    254 SECStatus
    255 SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
    256                               const PRUint8 *hsHash, unsigned int hsHashLen,
    257                               const char *label, unsigned int labelLen,
    258                               CK_MECHANISM_TYPE mech, unsigned int keySize,
    259                               PK11SymKey **keyp)
    260 {
    261    return SSLExp_HkdfVariantExpandLabelWithMech(version, cipherSuite, prk, hsHash, hsHashLen,
    262                                                 label, labelLen, mech, keySize,
    263                                                 ssl_variant_stream, keyp);
    264 }
    265 
    266 SECStatus
    267 SSLExp_HkdfVariantExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
    268                                      const PRUint8 *hsHash, unsigned int hsHashLen,
    269                                      const char *label, unsigned int labelLen,
    270                                      CK_MECHANISM_TYPE mech, unsigned int keySize,
    271                                      SSLProtocolVariant variant, PK11SymKey **keyp)
    272 {
    273    if (prk == NULL || keyp == NULL ||
    274        label == NULL || labelLen == 0 ||
    275        mech == CKM_INVALID_MECHANISM || keySize == 0) {
    276        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    277        return SECFailure;
    278    }
    279 
    280    SSLHashType hash;
    281    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
    282                                          &hash, NULL);
    283    if (rv != SECSuccess) {
    284        return SECFailure; /* Code already set. */
    285    }
    286    return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen,
    287                                 mech, keySize, variant, keyp);
    288 }
    289 
    290 SECStatus
    291 ssl_CreateMaskingContextInner(PRUint16 version, PRUint16 cipherSuite,
    292                              SSLProtocolVariant variant,
    293                              PK11SymKey *secret,
    294                              const char *label,
    295                              unsigned int labelLen,
    296                              SSLMaskingContext **ctx)
    297 {
    298    if (!secret || !ctx || (!label && labelLen)) {
    299        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    300        return SECFailure;
    301    }
    302 
    303    SSLMaskingContext *out = PORT_ZNew(SSLMaskingContext);
    304    if (out == NULL) {
    305        goto loser;
    306    }
    307 
    308    SSLHashType hash;
    309    const ssl3BulkCipherDef *cipher;
    310    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
    311                                          &hash, &cipher);
    312    if (rv != SECSuccess) {
    313        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    314        goto loser; /* Code already set. */
    315    }
    316 
    317    out->mech = tls13_SequenceNumberEncryptionMechanism(cipher->calg);
    318    if (out->mech == CKM_INVALID_MECHANISM) {
    319        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    320        goto loser;
    321    }
    322 
    323    // Derive the masking key
    324    rv = tls13_HkdfExpandLabel(secret, hash,
    325                               NULL, 0, // Handshake hash.
    326                               label, labelLen,
    327                               out->mech,
    328                               cipher->key_size, variant,
    329                               &out->secret);
    330    if (rv != SECSuccess) {
    331        goto loser;
    332    }
    333 
    334    out->version = version;
    335    out->cipherSuite = cipherSuite;
    336 
    337    *ctx = out;
    338    return SECSuccess;
    339 loser:
    340    SSLExp_DestroyMaskingContext(out);
    341    return SECFailure;
    342 }
    343 
    344 SECStatus
    345 ssl_CreateMaskInner(SSLMaskingContext *ctx, const PRUint8 *sample,
    346                    unsigned int sampleLen, PRUint8 *outMask,
    347                    unsigned int maskLen)
    348 {
    349    if (!ctx || !sample || !sampleLen || !outMask || !maskLen) {
    350        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    351        return SECFailure;
    352    }
    353 
    354    if (ctx->secret == NULL) {
    355        PORT_SetError(SEC_ERROR_NO_KEY);
    356        return SECFailure;
    357    }
    358 
    359    SECStatus rv = SECFailure;
    360    unsigned int outMaskLen = 0;
    361    int paramLen = 0;
    362 
    363    /* Internal output len/buf, for use if the caller allocated and requested
    364     * less than one block of output. |oneBlock| should have size equal to the
    365     * largest block size supported below. */
    366    PRUint8 oneBlock[AES_BLOCK_SIZE];
    367    PRUint8 *outMask_ = outMask;
    368    unsigned int maskLen_ = maskLen;
    369 
    370    switch (ctx->mech) {
    371        case CKM_AES_ECB:
    372            if (sampleLen < AES_BLOCK_SIZE) {
    373                PORT_SetError(SEC_ERROR_INVALID_ARGS);
    374                return SECFailure;
    375            }
    376            if (maskLen_ < AES_BLOCK_SIZE) {
    377                outMask_ = oneBlock;
    378                maskLen_ = sizeof(oneBlock);
    379            }
    380            rv = PK11_Encrypt(ctx->secret,
    381                              ctx->mech,
    382                              NULL,
    383                              outMask_, &outMaskLen, maskLen_,
    384                              sample, AES_BLOCK_SIZE);
    385            if (rv == SECSuccess &&
    386                maskLen < AES_BLOCK_SIZE) {
    387                memcpy(outMask, outMask_, maskLen);
    388            }
    389            break;
    390        case CKM_NSS_CHACHA20_CTR:
    391            paramLen = 16;
    392        /* fall through */
    393        case CKM_CHACHA20:
    394            paramLen = (paramLen) ? paramLen : sizeof(CK_CHACHA20_PARAMS);
    395            if (sampleLen < paramLen) {
    396                PORT_SetError(SEC_ERROR_INVALID_ARGS);
    397                return SECFailure;
    398            }
    399 
    400            SECItem param;
    401            param.type = siBuffer;
    402            param.len = paramLen;
    403            param.data = (PRUint8 *)sample; // const-cast :(
    404            unsigned char zeros[128] = { 0 };
    405 
    406            if (maskLen > sizeof(zeros)) {
    407                PORT_SetError(SEC_ERROR_OUTPUT_LEN);
    408                return SECFailure;
    409            }
    410 
    411            rv = PK11_Encrypt(ctx->secret,
    412                              ctx->mech,
    413                              &param,
    414                              outMask, &outMaskLen,
    415                              maskLen,
    416                              zeros, maskLen);
    417            break;
    418        default:
    419            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    420            return SECFailure;
    421    }
    422 
    423    if (rv != SECSuccess) {
    424        PORT_SetError(SEC_ERROR_PKCS11_FUNCTION_FAILED);
    425        return SECFailure;
    426    }
    427 
    428    // Ensure we produced at least as much material as requested.
    429    if (outMaskLen < maskLen) {
    430        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
    431        return SECFailure;
    432    }
    433 
    434    return SECSuccess;
    435 }
    436 
    437 SECStatus
    438 ssl_DestroyMaskingContextInner(SSLMaskingContext *ctx)
    439 {
    440    if (!ctx) {
    441        return SECSuccess;
    442    }
    443 
    444    PK11_FreeSymKey(ctx->secret);
    445    PORT_ZFree(ctx, sizeof(*ctx));
    446    return SECSuccess;
    447 }
    448 
    449 SECStatus
    450 SSLExp_CreateMask(SSLMaskingContext *ctx, const PRUint8 *sample,
    451                  unsigned int sampleLen, PRUint8 *outMask,
    452                  unsigned int maskLen)
    453 {
    454    return ssl_CreateMaskInner(ctx, sample, sampleLen, outMask, maskLen);
    455 }
    456 
    457 SECStatus
    458 SSLExp_CreateMaskingContext(PRUint16 version, PRUint16 cipherSuite,
    459                            PK11SymKey *secret,
    460                            const char *label,
    461                            unsigned int labelLen,
    462                            SSLMaskingContext **ctx)
    463 {
    464    return ssl_CreateMaskingContextInner(version, cipherSuite, ssl_variant_stream, secret,
    465                                         label, labelLen, ctx);
    466 }
    467 
    468 SECStatus
    469 SSLExp_CreateVariantMaskingContext(PRUint16 version, PRUint16 cipherSuite,
    470                                   SSLProtocolVariant variant,
    471                                   PK11SymKey *secret,
    472                                   const char *label,
    473                                   unsigned int labelLen,
    474                                   SSLMaskingContext **ctx)
    475 {
    476    return ssl_CreateMaskingContextInner(version, cipherSuite, variant, secret,
    477                                         label, labelLen, ctx);
    478 }
    479 
    480 SECStatus
    481 SSLExp_DestroyMaskingContext(SSLMaskingContext *ctx)
    482 {
    483    return ssl_DestroyMaskingContextInner(ctx);
    484 }