1 /*
2 * aes_gcm_nss.c
3 *
4 * AES Galois Counter Mode
5 *
6 * Richard L. Barnes
7 * Cisco Systems, Inc.
8 *
9 */
10
11 /*
12 *
13 * Copyright (c) 2013-2017, Cisco Systems, Inc.
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 *
23 * Redistributions in binary form must reproduce the above
24 * copyright notice, this list of conditions and the following
25 * disclaimer in the documentation and/or other materials provided
26 * with the distribution.
27 *
28 * Neither the name of the Cisco Systems, Inc. nor the names of its
29 * contributors may be used to endorse or promote products derived
30 * from this software without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
36 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43 * OF THE POSSIBILITY OF SUCH DAMAGE.
44 *
45 */
46
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif
50
51 #include "aes_gcm.h"
52 #include "alloc.h"
53 #include "err.h" /* for srtp_debug */
54 #include "crypto_types.h"
55 #include "cipher_types.h"
56 #include "cipher_test_cases.h"
57 #include <secerr.h>
58 #include <nspr.h>
59
60 srtp_debug_module_t srtp_mod_aes_gcm = {
61 0, /* debugging is off by default */
62 "aes gcm nss" /* printable module name */
63 };
64
65 /*
66 * For now we only support 8 and 16 octet tags. The spec allows for
67 * optional 12 byte tag, which may be supported in the future.
68 */
69 #define GCM_IV_LEN 12
70 #define GCM_AUTH_TAG_LEN 16
71 #define GCM_AUTH_TAG_LEN_8 8
72
73 /*
74 * This function allocates a new instance of this crypto engine.
75 * The key_len parameter should be one of 28 or 44 for
76 * AES-128-GCM or AES-256-GCM respectively. Note that the
77 * key length includes the 14 byte salt value that is used when
78 * initializing the KDF.
79 */
srtp_aes_gcm_nss_alloc(srtp_cipher_t ** c,int key_len,int tlen)80 static srtp_err_status_t srtp_aes_gcm_nss_alloc(srtp_cipher_t **c,
81 int key_len,
82 int tlen)
83 {
84 srtp_aes_gcm_ctx_t *gcm;
85 NSSInitContext *nss;
86
87 debug_print(srtp_mod_aes_gcm, "allocating cipher with key length %d",
88 key_len);
89 debug_print(srtp_mod_aes_gcm, "allocating cipher with tag length %d", tlen);
90
91 /*
92 * Verify the key_len is valid for one of: AES-128/256
93 */
94 if (key_len != SRTP_AES_GCM_128_KEY_LEN_WSALT &&
95 key_len != SRTP_AES_GCM_256_KEY_LEN_WSALT) {
96 return (srtp_err_status_bad_param);
97 }
98
99 if (tlen != GCM_AUTH_TAG_LEN && tlen != GCM_AUTH_TAG_LEN_8) {
100 return (srtp_err_status_bad_param);
101 }
102
103 /* Initialize NSS equiv of NSS_NoDB_Init(NULL) */
104 nss = NSS_InitContext("", "", "", "", NULL,
105 NSS_INIT_READONLY | NSS_INIT_NOCERTDB |
106 NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN |
107 NSS_INIT_OPTIMIZESPACE);
108 if (!nss) {
109 return (srtp_err_status_cipher_fail);
110 }
111
112 /* allocate memory a cipher of type aes_gcm */
113 *c = (srtp_cipher_t *)srtp_crypto_alloc(sizeof(srtp_cipher_t));
114 if (*c == NULL) {
115 NSS_ShutdownContext(nss);
116 return (srtp_err_status_alloc_fail);
117 }
118
119 gcm = (srtp_aes_gcm_ctx_t *)srtp_crypto_alloc(sizeof(srtp_aes_gcm_ctx_t));
120 if (gcm == NULL) {
121 NSS_ShutdownContext(nss);
122 srtp_crypto_free(*c);
123 *c = NULL;
124 return (srtp_err_status_alloc_fail);
125 }
126
127 gcm->nss = nss;
128
129 /* set pointers */
130 (*c)->state = gcm;
131
132 /* setup cipher attributes */
133 switch (key_len) {
134 case SRTP_AES_GCM_128_KEY_LEN_WSALT:
135 (*c)->type = &srtp_aes_gcm_128;
136 (*c)->algorithm = SRTP_AES_GCM_128;
137 gcm->key_size = SRTP_AES_128_KEY_LEN;
138 gcm->tag_size = tlen;
139 gcm->params.ulTagBits = 8 * tlen;
140 break;
141 case SRTP_AES_GCM_256_KEY_LEN_WSALT:
142 (*c)->type = &srtp_aes_gcm_256;
143 (*c)->algorithm = SRTP_AES_GCM_256;
144 gcm->key_size = SRTP_AES_256_KEY_LEN;
145 gcm->tag_size = tlen;
146 gcm->params.ulTagBits = 8 * tlen;
147 break;
148 default:
149 /* this should never hit, but to be sure... */
150 return (srtp_err_status_bad_param);
151 }
152
153 /* set key size and tag size*/
154 (*c)->key_len = key_len;
155
156 return (srtp_err_status_ok);
157 }
158
159 /*
160 * This function deallocates a GCM session
161 */
srtp_aes_gcm_nss_dealloc(srtp_cipher_t * c)162 static srtp_err_status_t srtp_aes_gcm_nss_dealloc(srtp_cipher_t *c)
163 {
164 srtp_aes_gcm_ctx_t *ctx;
165
166 ctx = (srtp_aes_gcm_ctx_t *)c->state;
167 if (ctx) {
168 /* release NSS resources */
169 if (ctx->key) {
170 PK11_FreeSymKey(ctx->key);
171 }
172
173 if (ctx->nss) {
174 NSS_ShutdownContext(ctx->nss);
175 ctx->nss = NULL;
176 }
177
178 /* zeroize the key material */
179 octet_string_set_to_zero(ctx, sizeof(srtp_aes_gcm_ctx_t));
180 srtp_crypto_free(ctx);
181 }
182
183 /* free memory */
184 srtp_crypto_free(c);
185
186 return (srtp_err_status_ok);
187 }
188
189 /*
190 * aes_gcm_nss_context_init(...) initializes the aes_gcm_context
191 * using the value in key[].
192 *
193 * the key is the secret key
194 */
srtp_aes_gcm_nss_context_init(void * cv,const uint8_t * key)195 static srtp_err_status_t srtp_aes_gcm_nss_context_init(void *cv,
196 const uint8_t *key)
197 {
198 srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv;
199
200 c->dir = srtp_direction_any;
201
202 debug_print(srtp_mod_aes_gcm, "key: %s",
203 srtp_octet_string_hex_string(key, c->key_size));
204
205 if (c->key) {
206 PK11_FreeSymKey(c->key);
207 c->key = NULL;
208 }
209
210 PK11SlotInfo *slot = PK11_GetBestSlot(CKM_AES_GCM, NULL);
211 if (!slot) {
212 return (srtp_err_status_cipher_fail);
213 }
214
215 SECItem key_item = { siBuffer, (unsigned char *)key, c->key_size };
216 c->key = PK11_ImportSymKey(slot, CKM_AES_GCM, PK11_OriginUnwrap,
217 CKA_ENCRYPT, &key_item, NULL);
218 PK11_FreeSlot(slot);
219
220 if (!c->key) {
221 return (srtp_err_status_cipher_fail);
222 }
223
224 return (srtp_err_status_ok);
225 }
226
227 /*
228 * aes_gcm_nss_set_iv(c, iv) sets the counter value to the exor of iv with
229 * the offset
230 */
srtp_aes_gcm_nss_set_iv(void * cv,uint8_t * iv,srtp_cipher_direction_t direction)231 static srtp_err_status_t srtp_aes_gcm_nss_set_iv(
232 void *cv,
233 uint8_t *iv,
234 srtp_cipher_direction_t direction)
235 {
236 srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv;
237
238 if (direction != srtp_direction_encrypt &&
239 direction != srtp_direction_decrypt) {
240 return (srtp_err_status_bad_param);
241 }
242 c->dir = direction;
243
244 debug_print(srtp_mod_aes_gcm, "setting iv: %s",
245 srtp_octet_string_hex_string(iv, GCM_IV_LEN));
246
247 memcpy(c->iv, iv, GCM_IV_LEN);
248
249 return (srtp_err_status_ok);
250 }
251
252 /*
253 * This function processes the AAD
254 *
255 * Parameters:
256 * c Crypto context
257 * aad Additional data to process for AEAD cipher suites
258 * aad_len length of aad buffer
259 */
srtp_aes_gcm_nss_set_aad(void * cv,const uint8_t * aad,uint32_t aad_len)260 static srtp_err_status_t srtp_aes_gcm_nss_set_aad(void *cv,
261 const uint8_t *aad,
262 uint32_t aad_len)
263 {
264 srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv;
265
266 debug_print(srtp_mod_aes_gcm, "setting AAD: %s",
267 srtp_octet_string_hex_string(aad, aad_len));
268
269 if (aad_len + c->aad_size > MAX_AD_SIZE) {
270 return srtp_err_status_bad_param;
271 }
272
273 memcpy(c->aad + c->aad_size, aad, aad_len);
274 c->aad_size += aad_len;
275
276 return (srtp_err_status_ok);
277 }
278
srtp_aes_gcm_nss_do_crypto(void * cv,int encrypt,unsigned char * buf,unsigned int * enc_len)279 static srtp_err_status_t srtp_aes_gcm_nss_do_crypto(void *cv,
280 int encrypt,
281 unsigned char *buf,
282 unsigned int *enc_len)
283 {
284 srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv;
285
286 c->params.pIv = c->iv;
287 c->params.ulIvLen = GCM_IV_LEN;
288 c->params.pAAD = c->aad;
289 c->params.ulAADLen = c->aad_size;
290
291 // Reset AAD
292 c->aad_size = 0;
293
294 int rv;
295 SECItem param = { siBuffer, (unsigned char *)&c->params,
296 sizeof(CK_GCM_PARAMS) };
297 if (encrypt) {
298 rv = PK11_Encrypt(c->key, CKM_AES_GCM, ¶m, buf, enc_len,
299 *enc_len + 16, buf, *enc_len);
300 } else {
301 rv = PK11_Decrypt(c->key, CKM_AES_GCM, ¶m, buf, enc_len, *enc_len,
302 buf, *enc_len);
303 }
304
305 srtp_err_status_t status = (srtp_err_status_ok);
306 if (rv != SECSuccess) {
307 status = (srtp_err_status_cipher_fail);
308 }
309
310 return status;
311 }
312
313 /*
314 * This function encrypts a buffer using AES GCM mode
315 *
316 * XXX(rlb@ipv.sx): We're required to break off and cache the tag
317 * here, because the get_tag() method is separate and the tests expect
318 * encrypt() not to change the size of the plaintext. It might be
319 * good to update the calling API so that this is cleaner.
320 *
321 * Parameters:
322 * c Crypto context
323 * buf data to encrypt
324 * enc_len length of encrypt buffer
325 */
srtp_aes_gcm_nss_encrypt(void * cv,unsigned char * buf,unsigned int * enc_len)326 static srtp_err_status_t srtp_aes_gcm_nss_encrypt(void *cv,
327 unsigned char *buf,
328 unsigned int *enc_len)
329 {
330 srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv;
331
332 // When we get a non-NULL buffer, we know that the caller is
333 // prepared to also take the tag. When we get a NULL buffer,
334 // even though there's no data, we need to give NSS a buffer
335 // where it can write the tag. We can't just use c->tag because
336 // memcpy has undefined behavior on overlapping ranges.
337 unsigned char tagbuf[16];
338 unsigned char *non_null_buf = buf;
339 if (!non_null_buf && (*enc_len == 0)) {
340 non_null_buf = tagbuf;
341 } else if (!non_null_buf) {
342 return srtp_err_status_bad_param;
343 }
344
345 srtp_err_status_t status =
346 srtp_aes_gcm_nss_do_crypto(cv, 1, non_null_buf, enc_len);
347 if (status != srtp_err_status_ok) {
348 return status;
349 }
350
351 memcpy(c->tag, non_null_buf + (*enc_len - c->tag_size), c->tag_size);
352 *enc_len -= c->tag_size;
353 return srtp_err_status_ok;
354 }
355
356 /*
357 * This function calculates and returns the GCM tag for a given context.
358 * This should be called after encrypting the data. The *len value
359 * is increased by the tag size. The caller must ensure that *buf has
360 * enough room to accept the appended tag.
361 *
362 * Parameters:
363 * c Crypto context
364 * buf data to encrypt
365 * len length of encrypt buffer
366 */
srtp_aes_gcm_nss_get_tag(void * cv,uint8_t * buf,uint32_t * len)367 static srtp_err_status_t srtp_aes_gcm_nss_get_tag(void *cv,
368 uint8_t *buf,
369 uint32_t *len)
370 {
371 srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv;
372 *len = c->tag_size;
373 memcpy(buf, c->tag, c->tag_size);
374 return (srtp_err_status_ok);
375 }
376
377 /*
378 * This function decrypts a buffer using AES GCM mode
379 *
380 * Parameters:
381 * c Crypto context
382 * buf data to encrypt
383 * enc_len length of encrypt buffer
384 */
srtp_aes_gcm_nss_decrypt(void * cv,unsigned char * buf,unsigned int * enc_len)385 static srtp_err_status_t srtp_aes_gcm_nss_decrypt(void *cv,
386 unsigned char *buf,
387 unsigned int *enc_len)
388 {
389 srtp_err_status_t status = srtp_aes_gcm_nss_do_crypto(cv, 0, buf, enc_len);
390 if (status != srtp_err_status_ok) {
391 int err = PR_GetError();
392 if (err == SEC_ERROR_BAD_DATA) {
393 status = srtp_err_status_auth_fail;
394 }
395 }
396
397 return status;
398 }
399
400 /*
401 * Name of this crypto engine
402 */
403 static const char srtp_aes_gcm_128_nss_description[] = "AES-128 GCM using NSS";
404 static const char srtp_aes_gcm_256_nss_description[] = "AES-256 GCM using NSS";
405
406 /*
407 * This is the vector function table for this crypto engine.
408 */
409 /* clang-format off */
410 const srtp_cipher_type_t srtp_aes_gcm_128 = {
411 srtp_aes_gcm_nss_alloc,
412 srtp_aes_gcm_nss_dealloc,
413 srtp_aes_gcm_nss_context_init,
414 srtp_aes_gcm_nss_set_aad,
415 srtp_aes_gcm_nss_encrypt,
416 srtp_aes_gcm_nss_decrypt,
417 srtp_aes_gcm_nss_set_iv,
418 srtp_aes_gcm_nss_get_tag,
419 srtp_aes_gcm_128_nss_description,
420 &srtp_aes_gcm_128_test_case_0,
421 SRTP_AES_GCM_128
422 };
423 /* clang-format on */
424
425 /*
426 * This is the vector function table for this crypto engine.
427 */
428 /* clang-format off */
429 const srtp_cipher_type_t srtp_aes_gcm_256 = {
430 srtp_aes_gcm_nss_alloc,
431 srtp_aes_gcm_nss_dealloc,
432 srtp_aes_gcm_nss_context_init,
433 srtp_aes_gcm_nss_set_aad,
434 srtp_aes_gcm_nss_encrypt,
435 srtp_aes_gcm_nss_decrypt,
436 srtp_aes_gcm_nss_set_iv,
437 srtp_aes_gcm_nss_get_tag,
438 srtp_aes_gcm_256_nss_description,
439 &srtp_aes_gcm_256_test_case_0,
440 SRTP_AES_GCM_256
441 };
442 /* clang-format on */
443