Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/nss/lib/ssl/selfencrypt.c
Line
Count
Source (jump to first uncovered line)
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
0
{
22
0
    PK11Context *ctx;
23
0
    SECItem macParam = { 0, NULL, 0 };
24
0
    unsigned int computedLen;
25
0
    SECStatus rv;
26
0
27
0
    ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam);
28
0
    if (!ctx) {
29
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
30
0
        return SECFailure;
31
0
    }
32
0
33
0
    rv = PK11_DigestBegin(ctx);
34
0
    if (rv != SECSuccess) {
35
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
36
0
        goto loser;
37
0
    }
38
0
39
0
    rv = PK11_DigestOp(ctx, in, len);
40
0
    if (rv != SECSuccess) {
41
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
42
0
        goto loser;
43
0
    }
44
0
45
0
    rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen);
46
0
    if (rv != SECSuccess) {
47
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
48
0
        goto loser;
49
0
    }
50
0
51
0
    *macLen = maxMacLen;
52
0
    PK11_DestroyContext(ctx, PR_TRUE);
53
0
    return SECSuccess;
54
0
55
0
loser:
56
0
    PK11_DestroyContext(ctx, PR_TRUE);
57
0
    return SECFailure;
58
0
}
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
0
{
122
0
    unsigned int len;
123
0
    unsigned int lenOffset;
124
0
    unsigned char iv[AES_BLOCK_SIZE];
125
0
    SECItem ivItem = { siBuffer, iv, sizeof(iv) };
126
0
    /* Write directly to out. */
127
0
    sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen);
128
0
    SECStatus rv;
129
0
130
0
    /* Generate a random IV */
131
0
    rv = PK11_GenerateRandom(iv, sizeof(iv));
132
0
    if (rv != SECSuccess) {
133
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
134
0
        return SECFailure;
135
0
    }
136
0
137
0
    /* Add header. */
138
0
    rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN);
139
0
    if (rv != SECSuccess) {
140
0
        return SECFailure;
141
0
    }
142
0
    rv = sslBuffer_Append(&buf, iv, sizeof(iv));
143
0
    if (rv != SECSuccess) {
144
0
        return SECFailure;
145
0
    }
146
0
147
0
    /* Leave space for the length of the ciphertext. */
148
0
    rv = sslBuffer_Skip(&buf, 2, &lenOffset);
149
0
    if (rv != SECSuccess) {
150
0
        return SECFailure;
151
0
    }
152
0
153
0
    /* Encode the ciphertext in place. */
154
0
    rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
155
0
                      SSL_BUFFER_NEXT(&buf), &len,
156
0
                      SSL_BUFFER_SPACE(&buf), in, inLen);
157
0
    if (rv != SECSuccess) {
158
0
        return SECFailure;
159
0
    }
160
0
    rv = sslBuffer_Skip(&buf, len, NULL);
161
0
    if (rv != SECSuccess) {
162
0
        return SECFailure;
163
0
    }
164
0
165
0
    rv = sslBuffer_InsertLength(&buf, lenOffset, 2);
166
0
    if (rv != SECSuccess) {
167
0
        return SECFailure;
168
0
    }
169
0
170
0
    /* MAC the entire output buffer into the output. */
171
0
    PORT_Assert(buf.space - buf.len >= SHA256_LENGTH);
172
0
    rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC,
173
0
                       SSL_BUFFER_BASE(&buf), /* input */
174
0
                       SSL_BUFFER_LEN(&buf),
175
0
                       SSL_BUFFER_NEXT(&buf), &len, /* output */
176
0
                       SHA256_LENGTH);
177
0
    if (rv != SECSuccess) {
178
0
        return SECFailure;
179
0
    }
180
0
    rv = sslBuffer_Skip(&buf, len, NULL);
181
0
    if (rv != SECSuccess) {
182
0
        return SECFailure;
183
0
    }
184
0
185
0
    *outLen = SSL_BUFFER_LEN(&buf);
186
0
    return SECSuccess;
187
0
}
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
0
{
195
0
    sslReader reader = SSL_READER(in, inLen);
196
0
197
0
    sslReadBuffer encodedKeyNameBuffer = { 0 };
198
0
    SECStatus rv = sslRead_Read(&reader, SELF_ENCRYPT_KEY_NAME_LEN,
199
0
                                &encodedKeyNameBuffer);
200
0
    if (rv != SECSuccess) {
201
0
        return SECFailure;
202
0
    }
203
0
204
0
    sslReadBuffer ivBuffer = { 0 };
205
0
    rv = sslRead_Read(&reader, AES_BLOCK_SIZE, &ivBuffer);
206
0
    if (rv != SECSuccess) {
207
0
        return SECFailure;
208
0
    }
209
0
210
0
    PRUint64 cipherTextLen = 0;
211
0
    rv = sslRead_ReadNumber(&reader, 2, &cipherTextLen);
212
0
    if (rv != SECSuccess) {
213
0
        return SECFailure;
214
0
    }
215
0
216
0
    sslReadBuffer cipherTextBuffer = { 0 };
217
0
    rv = sslRead_Read(&reader, (unsigned int)cipherTextLen, &cipherTextBuffer);
218
0
    if (rv != SECSuccess) {
219
0
        return SECFailure;
220
0
    }
221
0
    unsigned int bytesToMac = reader.offset;
222
0
223
0
    sslReadBuffer encodedMacBuffer = { 0 };
224
0
    rv = sslRead_Read(&reader, SHA256_LENGTH, &encodedMacBuffer);
225
0
    if (rv != SECSuccess) {
226
0
        return SECFailure;
227
0
    }
228
0
229
0
    /* Make sure we're at the end of the block. */
230
0
    if (reader.offset != reader.buf.len) {
231
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
232
0
        return SECFailure;
233
0
    }
234
0
235
0
    /* Now that everything is decoded, we can make progress. */
236
0
    /* 1. Check that we have the right key. */
237
0
    if (PORT_Memcmp(keyName, encodedKeyNameBuffer.buf, SELF_ENCRYPT_KEY_NAME_LEN)) {
238
0
        PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
239
0
        return SECFailure;
240
0
    }
241
0
242
0
    /* 2. Check the MAC */
243
0
    unsigned char computedMac[SHA256_LENGTH];
244
0
    unsigned int computedMacLen = 0;
245
0
    rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac,
246
0
                       computedMac, &computedMacLen, sizeof(computedMac));
247
0
    if (rv != SECSuccess) {
248
0
        return SECFailure;
249
0
    }
250
0
    PORT_Assert(computedMacLen == SHA256_LENGTH);
251
0
    if (NSS_SecureMemcmp(computedMac, encodedMacBuffer.buf, computedMacLen) != 0) {
252
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
253
0
        return SECFailure;
254
0
    }
255
0
256
0
    /* 3. OK, it verifies, now decrypt. */
257
0
    SECItem ivItem = { siBuffer, (unsigned char *)ivBuffer.buf, AES_BLOCK_SIZE };
258
0
    rv = PK11_Decrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
259
0
                      out, outLen, maxOutLen, cipherTextBuffer.buf, cipherTextLen);
260
0
    if (rv != SECSuccess) {
261
0
        return SECFailure;
262
0
    }
263
0
264
0
    return SECSuccess;
265
0
}
266
#endif
267
268
/* Predict the size of the encrypted data, including padding */
269
unsigned int
270
ssl_SelfEncryptGetProtectedSize(unsigned int inLen)
271
0
{
272
0
    return SELF_ENCRYPT_KEY_NAME_LEN +
273
0
           AES_BLOCK_SIZE +
274
0
           2 +
275
0
           ((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */
276
0
           SHA256_LENGTH;
277
0
}
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
0
{
284
0
    PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN];
285
0
    PK11SymKey *encKey;
286
0
    PK11SymKey *macKey;
287
0
    SECStatus rv;
288
0
289
0
    /* Get session ticket keys. */
290
0
    rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey);
291
0
    if (rv != SECSuccess) {
292
0
        SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.",
293
0
                 SSL_GETPID(), ss->fd));
294
0
        return SECFailure;
295
0
    }
296
0
297
0
    return ssl_SelfEncryptProtectInt(encKey, macKey, keyName,
298
0
                                     in, inLen, out, outLen, maxOutLen);
299
0
}
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
0
{
306
0
    PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN];
307
0
    PK11SymKey *encKey;
308
0
    PK11SymKey *macKey;
309
0
    SECStatus rv;
310
0
311
0
    /* Get session ticket keys. */
312
0
    rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey);
313
0
    if (rv != SECSuccess) {
314
0
        SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.",
315
0
                 SSL_GETPID(), ss->fd));
316
0
        return SECFailure;
317
0
    }
318
0
319
0
    return ssl_SelfEncryptUnprotectInt(encKey, macKey, keyName,
320
0
                                       in, inLen, out, outLen, maxOutLen);
321
0
}