tor-browser

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

selfencrypt.c (9284B)


      1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /*
      3 * This file is PRIVATE to SSL.
      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 "nss.h"
     10 #include "blapit.h"
     11 #include "pk11func.h"
     12 #include "ssl.h"
     13 #include "sslt.h"
     14 #include "sslimpl.h"
     15 #include "selfencrypt.h"
     16 
     17 static SECStatus
     18 ssl_MacBuffer(PK11SymKey *key, CK_MECHANISM_TYPE mech,
     19              const unsigned char *in, unsigned int len,
     20              unsigned char *mac, unsigned int *macLen, unsigned int maxMacLen)
     21 {
     22    PK11Context *ctx;
     23    SECItem macParam = { 0, NULL, 0 };
     24    unsigned int computedLen;
     25    SECStatus rv;
     26 
     27    ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam);
     28    if (!ctx) {
     29        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
     30        return SECFailure;
     31    }
     32 
     33    rv = PK11_DigestBegin(ctx);
     34    if (rv != SECSuccess) {
     35        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
     36        goto loser;
     37    }
     38 
     39    rv = PK11_DigestOp(ctx, in, len);
     40    if (rv != SECSuccess) {
     41        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
     42        goto loser;
     43    }
     44 
     45    rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen);
     46    if (rv != SECSuccess) {
     47        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
     48        goto loser;
     49    }
     50 
     51    *macLen = maxMacLen;
     52    PK11_DestroyContext(ctx, PR_TRUE);
     53    return SECSuccess;
     54 
     55 loser:
     56    PK11_DestroyContext(ctx, PR_TRUE);
     57    return SECFailure;
     58 }
     59 
     60 #ifdef UNSAFE_FUZZER_MODE
     61 SECStatus
     62 ssl_SelfEncryptProtectInt(
     63    PK11SymKey *encKey, PK11SymKey *macKey,
     64    const unsigned char *keyName,
     65    const PRUint8 *in, unsigned int inLen,
     66    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
     67 {
     68    if (inLen > maxOutLen) {
     69        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     70        return SECFailure;
     71    }
     72 
     73    PORT_Memcpy(out, in, inLen);
     74    *outLen = inLen;
     75 
     76    return 0;
     77 }
     78 
     79 SECStatus
     80 ssl_SelfEncryptUnprotectInt(
     81    PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName,
     82    const PRUint8 *in, unsigned int inLen,
     83    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
     84 {
     85    if (inLen > maxOutLen) {
     86        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     87        return SECFailure;
     88    }
     89 
     90    PORT_Memcpy(out, in, inLen);
     91    *outLen = inLen;
     92 
     93    return 0;
     94 }
     95 
     96 #else
     97 /*
     98 * Structure is.
     99 *
    100 * struct {
    101 *   opaque keyName[16];
    102 *   opaque iv[16];
    103 *   opaque ciphertext<16..2^16-1>;
    104 *   opaque mac[32];
    105 * } SelfEncrypted;
    106 *
    107 * We are using AES-CBC + HMAC-SHA256 in Encrypt-then-MAC mode for
    108 * two reasons:
    109 *
    110 * 1. It's what we already used for tickets.
    111 * 2. We don't have to worry about nonce collisions as much
    112 *    (the chance is lower because we have a random 128-bit nonce
    113 *    and they are less serious than with AES-GCM).
    114 */
    115 SECStatus
    116 ssl_SelfEncryptProtectInt(
    117    PK11SymKey *encKey, PK11SymKey *macKey,
    118    const unsigned char *keyName,
    119    const PRUint8 *in, unsigned int inLen,
    120    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
    121 {
    122    unsigned int len;
    123    unsigned int lenOffset;
    124    unsigned char iv[AES_BLOCK_SIZE];
    125    SECItem ivItem = { siBuffer, iv, sizeof(iv) };
    126    /* Write directly to out. */
    127    sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen);
    128    SECStatus rv;
    129 
    130    /* Generate a random IV */
    131    rv = PK11_GenerateRandom(iv, sizeof(iv));
    132    if (rv != SECSuccess) {
    133        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    134        return SECFailure;
    135    }
    136 
    137    /* Add header. */
    138    rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN);
    139    if (rv != SECSuccess) {
    140        return SECFailure;
    141    }
    142    rv = sslBuffer_Append(&buf, iv, sizeof(iv));
    143    if (rv != SECSuccess) {
    144        return SECFailure;
    145    }
    146 
    147    /* Leave space for the length of the ciphertext. */
    148    rv = sslBuffer_Skip(&buf, 2, &lenOffset);
    149    if (rv != SECSuccess) {
    150        return SECFailure;
    151    }
    152 
    153    /* Encode the ciphertext in place. */
    154    rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
    155                      SSL_BUFFER_NEXT(&buf), &len,
    156                      SSL_BUFFER_SPACE(&buf), in, inLen);
    157    if (rv != SECSuccess) {
    158        return SECFailure;
    159    }
    160    rv = sslBuffer_Skip(&buf, len, NULL);
    161    if (rv != SECSuccess) {
    162        return SECFailure;
    163    }
    164 
    165    rv = sslBuffer_InsertLength(&buf, lenOffset, 2);
    166    if (rv != SECSuccess) {
    167        return SECFailure;
    168    }
    169 
    170    /* MAC the entire output buffer into the output. */
    171    PORT_Assert(buf.space - buf.len >= SHA256_LENGTH);
    172    rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC,
    173                       SSL_BUFFER_BASE(&buf), /* input */
    174                       SSL_BUFFER_LEN(&buf),
    175                       SSL_BUFFER_NEXT(&buf), &len, /* output */
    176                       SHA256_LENGTH);
    177    if (rv != SECSuccess) {
    178        return SECFailure;
    179    }
    180    rv = sslBuffer_Skip(&buf, len, NULL);
    181    if (rv != SECSuccess) {
    182        return SECFailure;
    183    }
    184 
    185    *outLen = SSL_BUFFER_LEN(&buf);
    186    return SECSuccess;
    187 }
    188 
    189 SECStatus
    190 ssl_SelfEncryptUnprotectInt(
    191    PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName,
    192    const PRUint8 *in, unsigned int inLen,
    193    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
    194 {
    195    sslReader reader = SSL_READER(in, inLen);
    196 
    197    sslReadBuffer encodedKeyNameBuffer = { 0 };
    198    SECStatus rv = sslRead_Read(&reader, SELF_ENCRYPT_KEY_NAME_LEN,
    199                                &encodedKeyNameBuffer);
    200    if (rv != SECSuccess) {
    201        return SECFailure;
    202    }
    203 
    204    sslReadBuffer ivBuffer = { 0 };
    205    rv = sslRead_Read(&reader, AES_BLOCK_SIZE, &ivBuffer);
    206    if (rv != SECSuccess) {
    207        return SECFailure;
    208    }
    209 
    210    PRUint64 cipherTextLen = 0;
    211    rv = sslRead_ReadNumber(&reader, 2, &cipherTextLen);
    212    if (rv != SECSuccess) {
    213        return SECFailure;
    214    }
    215 
    216    sslReadBuffer cipherTextBuffer = { 0 };
    217    rv = sslRead_Read(&reader, (unsigned int)cipherTextLen, &cipherTextBuffer);
    218    if (rv != SECSuccess) {
    219        return SECFailure;
    220    }
    221    unsigned int bytesToMac = reader.offset;
    222 
    223    sslReadBuffer encodedMacBuffer = { 0 };
    224    rv = sslRead_Read(&reader, SHA256_LENGTH, &encodedMacBuffer);
    225    if (rv != SECSuccess) {
    226        return SECFailure;
    227    }
    228 
    229    /* Make sure we're at the end of the block. */
    230    if (reader.offset != reader.buf.len) {
    231        PORT_SetError(SEC_ERROR_BAD_DATA);
    232        return SECFailure;
    233    }
    234 
    235    /* Now that everything is decoded, we can make progress. */
    236    /* 1. Check that we have the right key. */
    237    if (PORT_Memcmp(keyName, encodedKeyNameBuffer.buf, SELF_ENCRYPT_KEY_NAME_LEN)) {
    238        PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
    239        return SECFailure;
    240    }
    241 
    242    /* 2. Check the MAC */
    243    unsigned char computedMac[SHA256_LENGTH];
    244    unsigned int computedMacLen = 0;
    245    rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac,
    246                       computedMac, &computedMacLen, sizeof(computedMac));
    247    if (rv != SECSuccess) {
    248        return SECFailure;
    249    }
    250    PORT_Assert(computedMacLen == SHA256_LENGTH);
    251    if (NSS_SecureMemcmp(computedMac, encodedMacBuffer.buf, computedMacLen) != 0) {
    252        PORT_SetError(SEC_ERROR_BAD_DATA);
    253        return SECFailure;
    254    }
    255 
    256    /* 3. OK, it verifies, now decrypt. */
    257    SECItem ivItem = { siBuffer, (unsigned char *)ivBuffer.buf, AES_BLOCK_SIZE };
    258    rv = PK11_Decrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
    259                      out, outLen, maxOutLen, cipherTextBuffer.buf, cipherTextLen);
    260    if (rv != SECSuccess) {
    261        return SECFailure;
    262    }
    263 
    264    return SECSuccess;
    265 }
    266 #endif
    267 
    268 /* Predict the size of the encrypted data, including padding */
    269 unsigned int
    270 ssl_SelfEncryptGetProtectedSize(unsigned int inLen)
    271 {
    272    return SELF_ENCRYPT_KEY_NAME_LEN +
    273           AES_BLOCK_SIZE +
    274           2 +
    275           ((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */
    276           SHA256_LENGTH;
    277 }
    278 
    279 SECStatus
    280 ssl_SelfEncryptProtect(
    281    sslSocket *ss, const PRUint8 *in, unsigned int inLen,
    282    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
    283 {
    284    PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN];
    285    PK11SymKey *encKey;
    286    PK11SymKey *macKey;
    287    SECStatus rv;
    288 
    289    /* Get session ticket keys. */
    290    rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey);
    291    if (rv != SECSuccess) {
    292        SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.",
    293                 SSL_GETPID(), ss->fd));
    294        return SECFailure;
    295    }
    296 
    297    return ssl_SelfEncryptProtectInt(encKey, macKey, keyName,
    298                                     in, inLen, out, outLen, maxOutLen);
    299 }
    300 
    301 SECStatus
    302 ssl_SelfEncryptUnprotect(
    303    sslSocket *ss, const PRUint8 *in, unsigned int inLen,
    304    PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
    305 {
    306    PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN];
    307    PK11SymKey *encKey;
    308    PK11SymKey *macKey;
    309    SECStatus rv;
    310 
    311    /* Get session ticket keys. */
    312    rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey);
    313    if (rv != SECSuccess) {
    314        SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.",
    315                 SSL_GETPID(), ss->fd));
    316        return SECFailure;
    317    }
    318 
    319    return ssl_SelfEncryptUnprotectInt(encKey, macKey, keyName,
    320                                       in, inLen, out, outLen, maxOutLen);
    321 }