/src/nss/lib/ssl/selfencrypt.c
Line | Count | Source |
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 | 497 | { |
22 | 497 | PK11Context *ctx; |
23 | 497 | SECItem macParam = { 0, NULL, 0 }; |
24 | 497 | unsigned int computedLen; |
25 | 497 | SECStatus rv; |
26 | | |
27 | 497 | ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam); |
28 | 497 | if (!ctx) { |
29 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
30 | 0 | return SECFailure; |
31 | 0 | } |
32 | | |
33 | 497 | rv = PK11_DigestBegin(ctx); |
34 | 497 | if (rv != SECSuccess) { |
35 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
36 | 0 | goto loser; |
37 | 0 | } |
38 | | |
39 | 497 | rv = PK11_DigestOp(ctx, in, len); |
40 | 497 | if (rv != SECSuccess) { |
41 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
42 | 0 | goto loser; |
43 | 0 | } |
44 | | |
45 | 497 | rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen); |
46 | 497 | if (rv != SECSuccess) { |
47 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
48 | 0 | goto loser; |
49 | 0 | } |
50 | | |
51 | 497 | *macLen = maxMacLen; |
52 | 497 | PK11_DestroyContext(ctx, PR_TRUE); |
53 | 497 | return SECSuccess; |
54 | | |
55 | 0 | loser: |
56 | 0 | PK11_DestroyContext(ctx, PR_TRUE); |
57 | 0 | return SECFailure; |
58 | 497 | } Unexecuted instantiation: selfencrypt.c:ssl_MacBuffer selfencrypt.c:ssl_MacBuffer Line | Count | Source | 21 | 497 | { | 22 | 497 | PK11Context *ctx; | 23 | 497 | SECItem macParam = { 0, NULL, 0 }; | 24 | 497 | unsigned int computedLen; | 25 | 497 | SECStatus rv; | 26 | | | 27 | 497 | ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam); | 28 | 497 | if (!ctx) { | 29 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | 30 | 0 | return SECFailure; | 31 | 0 | } | 32 | | | 33 | 497 | rv = PK11_DigestBegin(ctx); | 34 | 497 | if (rv != SECSuccess) { | 35 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | 36 | 0 | goto loser; | 37 | 0 | } | 38 | | | 39 | 497 | rv = PK11_DigestOp(ctx, in, len); | 40 | 497 | if (rv != SECSuccess) { | 41 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | 42 | 0 | goto loser; | 43 | 0 | } | 44 | | | 45 | 497 | rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen); | 46 | 497 | if (rv != SECSuccess) { | 47 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | 48 | 0 | goto loser; | 49 | 0 | } | 50 | | | 51 | 497 | *macLen = maxMacLen; | 52 | 497 | PK11_DestroyContext(ctx, PR_TRUE); | 53 | 497 | return SECSuccess; | 54 | | | 55 | 0 | loser: | 56 | 0 | PK11_DestroyContext(ctx, PR_TRUE); | 57 | 0 | return SECFailure; | 58 | 497 | } |
|
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 | 4.37k | { |
68 | 4.37k | if (inLen > maxOutLen) { |
69 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
70 | 0 | return SECFailure; |
71 | 0 | } |
72 | | |
73 | 4.37k | PORT_Memcpy(out, in, inLen); |
74 | 4.37k | *outLen = inLen; |
75 | | |
76 | 4.37k | return 0; |
77 | 4.37k | } |
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 | 1.25k | { |
85 | 1.25k | if (inLen > maxOutLen) { |
86 | 5 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
87 | 5 | return SECFailure; |
88 | 5 | } |
89 | | |
90 | 1.24k | PORT_Memcpy(out, in, inLen); |
91 | 1.24k | *outLen = inLen; |
92 | | |
93 | 1.24k | return 0; |
94 | 1.25k | } |
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 | 483 | { |
122 | 483 | unsigned int len; |
123 | 483 | unsigned int lenOffset; |
124 | 483 | unsigned char iv[AES_BLOCK_SIZE]; |
125 | 483 | SECItem ivItem = { siBuffer, iv, sizeof(iv) }; |
126 | | /* Write directly to out. */ |
127 | 483 | sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen); |
128 | 483 | SECStatus rv; |
129 | | |
130 | | /* Generate a random IV */ |
131 | 483 | rv = PK11_GenerateRandom(iv, sizeof(iv)); |
132 | 483 | if (rv != SECSuccess) { |
133 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
134 | 0 | return SECFailure; |
135 | 0 | } |
136 | | |
137 | | /* Add header. */ |
138 | 483 | rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN); |
139 | 483 | if (rv != SECSuccess) { |
140 | 0 | return SECFailure; |
141 | 0 | } |
142 | 483 | rv = sslBuffer_Append(&buf, iv, sizeof(iv)); |
143 | 483 | if (rv != SECSuccess) { |
144 | 0 | return SECFailure; |
145 | 0 | } |
146 | | |
147 | | /* Leave space for the length of the ciphertext. */ |
148 | 483 | rv = sslBuffer_Skip(&buf, 2, &lenOffset); |
149 | 483 | if (rv != SECSuccess) { |
150 | 0 | return SECFailure; |
151 | 0 | } |
152 | | |
153 | | /* Encode the ciphertext in place. */ |
154 | 483 | rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem, |
155 | 483 | SSL_BUFFER_NEXT(&buf), &len, |
156 | 483 | SSL_BUFFER_SPACE(&buf), in, inLen); |
157 | 483 | if (rv != SECSuccess) { |
158 | 0 | return SECFailure; |
159 | 0 | } |
160 | 483 | rv = sslBuffer_Skip(&buf, len, NULL); |
161 | 483 | if (rv != SECSuccess) { |
162 | 0 | return SECFailure; |
163 | 0 | } |
164 | | |
165 | 483 | rv = sslBuffer_InsertLength(&buf, lenOffset, 2); |
166 | 483 | if (rv != SECSuccess) { |
167 | 0 | return SECFailure; |
168 | 0 | } |
169 | | |
170 | | /* MAC the entire output buffer into the output. */ |
171 | 483 | PORT_Assert(buf.space - buf.len >= SHA256_LENGTH); |
172 | 483 | rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, |
173 | 483 | SSL_BUFFER_BASE(&buf), /* input */ |
174 | 483 | SSL_BUFFER_LEN(&buf), |
175 | 483 | SSL_BUFFER_NEXT(&buf), &len, /* output */ |
176 | 483 | SHA256_LENGTH); |
177 | 483 | if (rv != SECSuccess) { |
178 | 0 | return SECFailure; |
179 | 0 | } |
180 | 483 | rv = sslBuffer_Skip(&buf, len, NULL); |
181 | 483 | if (rv != SECSuccess) { |
182 | 0 | return SECFailure; |
183 | 0 | } |
184 | | |
185 | 483 | *outLen = SSL_BUFFER_LEN(&buf); |
186 | 483 | return SECSuccess; |
187 | 483 | } |
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 | 331 | { |
195 | 331 | sslReader reader = SSL_READER(in, inLen); |
196 | | |
197 | 331 | sslReadBuffer encodedKeyNameBuffer = { 0 }; |
198 | 331 | SECStatus rv = sslRead_Read(&reader, SELF_ENCRYPT_KEY_NAME_LEN, |
199 | 331 | &encodedKeyNameBuffer); |
200 | 331 | if (rv != SECSuccess) { |
201 | 150 | return SECFailure; |
202 | 150 | } |
203 | | |
204 | 181 | sslReadBuffer ivBuffer = { 0 }; |
205 | 181 | rv = sslRead_Read(&reader, AES_BLOCK_SIZE, &ivBuffer); |
206 | 181 | if (rv != SECSuccess) { |
207 | 69 | return SECFailure; |
208 | 69 | } |
209 | | |
210 | 112 | PRUint64 cipherTextLen = 0; |
211 | 112 | rv = sslRead_ReadNumber(&reader, 2, &cipherTextLen); |
212 | 112 | if (rv != SECSuccess) { |
213 | 4 | return SECFailure; |
214 | 4 | } |
215 | | |
216 | 108 | sslReadBuffer cipherTextBuffer = { 0 }; |
217 | 108 | rv = sslRead_Read(&reader, (unsigned int)cipherTextLen, &cipherTextBuffer); |
218 | 108 | if (rv != SECSuccess) { |
219 | 40 | return SECFailure; |
220 | 40 | } |
221 | 68 | unsigned int bytesToMac = reader.offset; |
222 | | |
223 | 68 | sslReadBuffer encodedMacBuffer = { 0 }; |
224 | 68 | rv = sslRead_Read(&reader, SHA256_LENGTH, &encodedMacBuffer); |
225 | 68 | if (rv != SECSuccess) { |
226 | 10 | return SECFailure; |
227 | 10 | } |
228 | | |
229 | | /* Make sure we're at the end of the block. */ |
230 | 58 | if (reader.offset != reader.buf.len) { |
231 | 15 | PORT_SetError(SEC_ERROR_BAD_DATA); |
232 | 15 | return SECFailure; |
233 | 15 | } |
234 | | |
235 | | /* Now that everything is decoded, we can make progress. */ |
236 | | /* 1. Check that we have the right key. */ |
237 | 43 | if (PORT_Memcmp(keyName, encodedKeyNameBuffer.buf, SELF_ENCRYPT_KEY_NAME_LEN)) { |
238 | 29 | PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT); |
239 | 29 | return SECFailure; |
240 | 29 | } |
241 | | |
242 | | /* 2. Check the MAC */ |
243 | 14 | unsigned char computedMac[SHA256_LENGTH]; |
244 | 14 | unsigned int computedMacLen = 0; |
245 | 14 | rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac, |
246 | 14 | computedMac, &computedMacLen, sizeof(computedMac)); |
247 | 14 | if (rv != SECSuccess) { |
248 | 0 | return SECFailure; |
249 | 0 | } |
250 | 14 | PORT_Assert(computedMacLen == SHA256_LENGTH); |
251 | 14 | if (NSS_SecureMemcmp(computedMac, encodedMacBuffer.buf, computedMacLen) != 0) { |
252 | 14 | PORT_SetError(SEC_ERROR_BAD_DATA); |
253 | 14 | return SECFailure; |
254 | 14 | } |
255 | | |
256 | | /* 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 | | |
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 | 3.88k | { |
272 | 3.88k | return SELF_ENCRYPT_KEY_NAME_LEN + |
273 | 3.88k | AES_BLOCK_SIZE + |
274 | 3.88k | 2 + |
275 | 3.88k | ((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */ |
276 | 3.88k | SHA256_LENGTH; |
277 | 3.88k | } |
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 | 4.86k | { |
284 | 4.86k | PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; |
285 | 4.86k | PK11SymKey *encKey; |
286 | 4.86k | PK11SymKey *macKey; |
287 | 4.86k | SECStatus rv; |
288 | | |
289 | | /* Get session ticket keys. */ |
290 | 4.86k | rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey); |
291 | 4.86k | 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 | | |
297 | 4.86k | return ssl_SelfEncryptProtectInt(encKey, macKey, keyName, |
298 | 4.86k | in, inLen, out, outLen, maxOutLen); |
299 | 4.86k | } |
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 | 1.58k | { |
306 | 1.58k | PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; |
307 | 1.58k | PK11SymKey *encKey; |
308 | 1.58k | PK11SymKey *macKey; |
309 | 1.58k | SECStatus rv; |
310 | | |
311 | | /* Get session ticket keys. */ |
312 | 1.58k | rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey); |
313 | 1.58k | 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 | | |
319 | 1.58k | return ssl_SelfEncryptUnprotectInt(encKey, macKey, keyName, |
320 | 1.58k | in, inLen, out, outLen, maxOutLen); |
321 | 1.58k | } |