/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 | } |