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, &param, buf, enc_len,
299                           *enc_len + 16, buf, *enc_len);
300     } else {
301         rv = PK11_Decrypt(c->key, CKM_AES_GCM, &param, 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