/src/nss/lib/softoken/sftkhmac.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /* This Source Code Form is subject to the terms of the Mozilla Public  | 
2  |  |  * License, v. 2.0. If a copy of the MPL was not distributed with this  | 
3  |  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */  | 
4  |  |  | 
5  |  | #include "seccomon.h"  | 
6  |  | #include "secerr.h"  | 
7  |  | #include "blapi.h"  | 
8  |  | #include "pkcs11i.h"  | 
9  |  | #include "softoken.h"  | 
10  |  | #include "hmacct.h"  | 
11  |  |  | 
12  |  | /* Wrappers to avoid undefined behavior calling functions through a pointer of incorrect type. */  | 
13  |  | static void  | 
14  |  | SFTKMAC_CMAC_Destroy(void *ctx, PRBool freeit)  | 
15  | 0  | { | 
16  | 0  |     CMACContext *cctx = ctx;  | 
17  | 0  |     CMAC_Destroy(cctx, freeit);  | 
18  | 0  | }  | 
19  |  |  | 
20  |  | static void  | 
21  |  | SFTKMAC_HMAC_Destroy(void *ctx, PRBool freeit)  | 
22  | 0  | { | 
23  | 0  |     HMACContext *hctx = ctx;  | 
24  | 0  |     HMAC_Destroy(hctx, freeit);  | 
25  | 0  | }  | 
26  |  |  | 
27  |  | /* sftk_HMACMechanismToHash converts a PKCS#11 MAC mechanism into a freebl hash  | 
28  |  |  * type. */  | 
29  |  | HASH_HashType  | 
30  |  | sftk_HMACMechanismToHash(CK_MECHANISM_TYPE mech)  | 
31  | 0  | { | 
32  | 0  |     switch (mech) { | 
33  | 0  |         case CKM_MD2_HMAC:  | 
34  | 0  |             return HASH_AlgMD2;  | 
35  | 0  |         case CKM_MD5_HMAC:  | 
36  | 0  |         case CKM_SSL3_MD5_MAC:  | 
37  | 0  |             return HASH_AlgMD5;  | 
38  | 0  |         case CKM_SHA_1_HMAC:  | 
39  | 0  |         case CKM_SSL3_SHA1_MAC:  | 
40  | 0  |             return HASH_AlgSHA1;  | 
41  | 0  |         case CKM_SHA224_HMAC:  | 
42  | 0  |             return HASH_AlgSHA224;  | 
43  | 0  |         case CKM_SHA256_HMAC:  | 
44  | 0  |             return HASH_AlgSHA256;  | 
45  | 0  |         case CKM_SHA384_HMAC:  | 
46  | 0  |             return HASH_AlgSHA384;  | 
47  | 0  |         case CKM_SHA512_HMAC:  | 
48  | 0  |             return HASH_AlgSHA512;  | 
49  | 0  |         case CKM_SHA3_224_HMAC:  | 
50  | 0  |             return HASH_AlgSHA3_224;  | 
51  | 0  |         case CKM_SHA3_256_HMAC:  | 
52  | 0  |             return HASH_AlgSHA3_256;  | 
53  | 0  |         case CKM_SHA3_384_HMAC:  | 
54  | 0  |             return HASH_AlgSHA3_384;  | 
55  | 0  |         case CKM_SHA3_512_HMAC:  | 
56  | 0  |             return HASH_AlgSHA3_512;  | 
57  | 0  |     }  | 
58  | 0  |     return HASH_AlgNULL;  | 
59  | 0  | }  | 
60  |  |  | 
61  |  | static sftk_MACConstantTimeCtx *  | 
62  |  | SetupMAC(CK_MECHANISM_PTR mech, SFTKObject *key)  | 
63  | 0  | { | 
64  | 0  |     CK_NSS_MAC_CONSTANT_TIME_PARAMS *params =  | 
65  | 0  |         (CK_NSS_MAC_CONSTANT_TIME_PARAMS *)mech->pParameter;  | 
66  | 0  |     sftk_MACConstantTimeCtx *ctx;  | 
67  | 0  |     HASH_HashType alg;  | 
68  | 0  |     SFTKAttribute *keyval;  | 
69  | 0  |     unsigned char secret[sizeof(ctx->secret)];  | 
70  | 0  |     unsigned int secretLength;  | 
71  |  | 
  | 
72  | 0  |     if (mech->ulParameterLen != sizeof(CK_NSS_MAC_CONSTANT_TIME_PARAMS)) { | 
73  | 0  |         return NULL;  | 
74  | 0  |     }  | 
75  |  |  | 
76  | 0  |     alg = sftk_HMACMechanismToHash(params->macAlg);  | 
77  | 0  |     if (alg == HASH_AlgNULL) { | 
78  | 0  |         return NULL;  | 
79  | 0  |     }  | 
80  |  |  | 
81  | 0  |     keyval = sftk_FindAttribute(key, CKA_VALUE);  | 
82  | 0  |     if (keyval == NULL) { | 
83  | 0  |         return NULL;  | 
84  | 0  |     }  | 
85  | 0  |     secretLength = keyval->attrib.ulValueLen;  | 
86  | 0  |     if (secretLength > sizeof(secret)) { | 
87  | 0  |         sftk_FreeAttribute(keyval);  | 
88  | 0  |         return NULL;  | 
89  | 0  |     }  | 
90  | 0  |     memcpy(secret, keyval->attrib.pValue, secretLength);  | 
91  | 0  |     sftk_FreeAttribute(keyval);  | 
92  |  | 
  | 
93  | 0  |     ctx = PORT_Alloc(sizeof(sftk_MACConstantTimeCtx));  | 
94  | 0  |     if (!ctx) { | 
95  | 0  |         PORT_Memset(secret, 0, secretLength);  | 
96  | 0  |         return NULL;  | 
97  | 0  |     }  | 
98  |  |  | 
99  | 0  |     memcpy(ctx->secret, secret, secretLength);  | 
100  | 0  |     ctx->secretLength = secretLength;  | 
101  | 0  |     ctx->hash = HASH_GetRawHashObject(alg);  | 
102  | 0  |     ctx->totalLength = params->ulBodyTotalLen;  | 
103  | 0  |     PORT_Memset(secret, 0, secretLength);  | 
104  |  | 
  | 
105  | 0  |     return ctx;  | 
106  | 0  | }  | 
107  |  |  | 
108  |  | sftk_MACConstantTimeCtx *  | 
109  |  | sftk_HMACConstantTime_New(CK_MECHANISM_PTR mech, SFTKObject *key)  | 
110  | 0  | { | 
111  | 0  |     CK_NSS_MAC_CONSTANT_TIME_PARAMS *params =  | 
112  | 0  |         (CK_NSS_MAC_CONSTANT_TIME_PARAMS *)mech->pParameter;  | 
113  | 0  |     sftk_MACConstantTimeCtx *ctx;  | 
114  |  | 
  | 
115  | 0  |     if (params->ulHeaderLen > sizeof(ctx->header)) { | 
116  | 0  |         return NULL;  | 
117  | 0  |     }  | 
118  | 0  |     ctx = SetupMAC(mech, key);  | 
119  | 0  |     if (!ctx) { | 
120  | 0  |         return NULL;  | 
121  | 0  |     }  | 
122  |  |  | 
123  | 0  |     ctx->headerLength = params->ulHeaderLen;  | 
124  | 0  |     memcpy(ctx->header, params->pHeader, params->ulHeaderLen);  | 
125  | 0  |     return ctx;  | 
126  | 0  | }  | 
127  |  |  | 
128  |  | sftk_MACConstantTimeCtx *  | 
129  |  | sftk_SSLv3MACConstantTime_New(CK_MECHANISM_PTR mech, SFTKObject *key)  | 
130  | 0  | { | 
131  | 0  |     CK_NSS_MAC_CONSTANT_TIME_PARAMS *params =  | 
132  | 0  |         (CK_NSS_MAC_CONSTANT_TIME_PARAMS *)mech->pParameter;  | 
133  | 0  |     unsigned int padLength = 40, j;  | 
134  | 0  |     sftk_MACConstantTimeCtx *ctx;  | 
135  |  | 
  | 
136  | 0  |     if (params->macAlg != CKM_SSL3_MD5_MAC &&  | 
137  | 0  |         params->macAlg != CKM_SSL3_SHA1_MAC) { | 
138  | 0  |         return NULL;  | 
139  | 0  |     }  | 
140  | 0  |     ctx = SetupMAC(mech, key);  | 
141  | 0  |     if (!ctx) { | 
142  | 0  |         return NULL;  | 
143  | 0  |     }  | 
144  |  |  | 
145  | 0  |     if (params->macAlg == CKM_SSL3_MD5_MAC) { | 
146  | 0  |         padLength = 48;  | 
147  | 0  |     }  | 
148  |  | 
  | 
149  | 0  |     ctx->headerLength =  | 
150  | 0  |         ctx->secretLength +  | 
151  | 0  |         padLength +  | 
152  | 0  |         params->ulHeaderLen;  | 
153  |  | 
  | 
154  | 0  |     if (ctx->headerLength > sizeof(ctx->header)) { | 
155  | 0  |         goto loser;  | 
156  | 0  |     }  | 
157  |  |  | 
158  | 0  |     j = 0;  | 
159  | 0  |     memcpy(&ctx->header[j], ctx->secret, ctx->secretLength);  | 
160  | 0  |     j += ctx->secretLength;  | 
161  | 0  |     memset(&ctx->header[j], 0x36, padLength);  | 
162  | 0  |     j += padLength;  | 
163  | 0  |     memcpy(&ctx->header[j], params->pHeader, params->ulHeaderLen);  | 
164  |  | 
  | 
165  | 0  |     return ctx;  | 
166  |  |  | 
167  | 0  | loser:  | 
168  | 0  |     PORT_Free(ctx);  | 
169  | 0  |     return NULL;  | 
170  | 0  | }  | 
171  |  |  | 
172  |  | void  | 
173  |  | sftk_HMACConstantTime_Update(void *pctx, const unsigned char *data, unsigned int len)  | 
174  | 0  | { | 
175  | 0  |     sftk_MACConstantTimeCtx *ctx = (sftk_MACConstantTimeCtx *)pctx;  | 
176  | 0  |     PORT_CheckSuccess(HMAC_ConstantTime(  | 
177  | 0  |         ctx->mac, NULL, sizeof(ctx->mac),  | 
178  | 0  |         ctx->hash,  | 
179  | 0  |         ctx->secret, ctx->secretLength,  | 
180  | 0  |         ctx->header, ctx->headerLength,  | 
181  | 0  |         data, len,  | 
182  | 0  |         ctx->totalLength));  | 
183  | 0  | }  | 
184  |  |  | 
185  |  | void  | 
186  |  | sftk_SSLv3MACConstantTime_Update(void *pctx, const unsigned char *data, unsigned int len)  | 
187  | 0  | { | 
188  | 0  |     sftk_MACConstantTimeCtx *ctx = (sftk_MACConstantTimeCtx *)pctx;  | 
189  | 0  |     PORT_CheckSuccess(SSLv3_MAC_ConstantTime(  | 
190  | 0  |         ctx->mac, NULL, sizeof(ctx->mac),  | 
191  | 0  |         ctx->hash,  | 
192  | 0  |         ctx->secret, ctx->secretLength,  | 
193  | 0  |         ctx->header, ctx->headerLength,  | 
194  | 0  |         data, len,  | 
195  | 0  |         ctx->totalLength));  | 
196  | 0  | }  | 
197  |  |  | 
198  |  | void  | 
199  |  | sftk_MACConstantTime_EndHash(void *pctx, unsigned char *out, unsigned int *outLength,  | 
200  |  |                              unsigned int maxLength)  | 
201  | 0  | { | 
202  | 0  |     const sftk_MACConstantTimeCtx *ctx = (sftk_MACConstantTimeCtx *)pctx;  | 
203  | 0  |     unsigned int toCopy = ctx->hash->length;  | 
204  | 0  |     if (toCopy > maxLength) { | 
205  | 0  |         toCopy = maxLength;  | 
206  | 0  |     }  | 
207  | 0  |     memcpy(out, ctx->mac, toCopy);  | 
208  | 0  |     if (outLength) { | 
209  | 0  |         *outLength = toCopy;  | 
210  | 0  |     }  | 
211  | 0  | }  | 
212  |  |  | 
213  |  | void  | 
214  |  | sftk_MACConstantTime_DestroyContext(void *pctx, PRBool free)  | 
215  | 0  | { | 
216  | 0  |     PORT_ZFree(pctx, sizeof(sftk_MACConstantTimeCtx));  | 
217  | 0  | }  | 
218  |  |  | 
219  |  | CK_RV  | 
220  |  | sftk_MAC_Create(CK_MECHANISM_TYPE mech, SFTKObject *key, sftk_MACCtx **ret_ctx)  | 
221  | 0  | { | 
222  | 0  |     CK_RV ret;  | 
223  |  | 
  | 
224  | 0  |     if (ret_ctx == NULL || key == NULL) { | 
225  | 0  |         return CKR_HOST_MEMORY;  | 
226  | 0  |     }  | 
227  |  |  | 
228  | 0  |     *ret_ctx = PORT_New(sftk_MACCtx);  | 
229  | 0  |     if (*ret_ctx == NULL) { | 
230  | 0  |         return CKR_HOST_MEMORY;  | 
231  | 0  |     }  | 
232  |  |  | 
233  | 0  |     ret = sftk_MAC_Init(*ret_ctx, mech, key);  | 
234  | 0  |     if (ret != CKR_OK) { | 
235  | 0  |         sftk_MAC_DestroyContext(*ret_ctx, PR_TRUE);  | 
236  | 0  |     }  | 
237  |  | 
  | 
238  | 0  |     return ret;  | 
239  | 0  | }  | 
240  |  |  | 
241  |  | CK_RV  | 
242  |  | sftk_MAC_Init(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, SFTKObject *key)  | 
243  | 0  | { | 
244  | 0  |     SFTKAttribute *keyval = NULL;  | 
245  | 0  |     PRBool isFIPS = sftk_isFIPS(key->slot->slotID);  | 
246  | 0  |     CK_RV ret = CKR_OK;  | 
247  |  |  | 
248  |  |     /* Find the actual value of the key. */  | 
249  | 0  |     keyval = sftk_FindAttribute(key, CKA_VALUE);  | 
250  | 0  |     if (keyval == NULL) { | 
251  | 0  |         ret = CKR_KEY_SIZE_RANGE;  | 
252  | 0  |         goto done;  | 
253  | 0  |     }  | 
254  |  |  | 
255  | 0  |     ret = sftk_MAC_InitRaw(ctx, mech,  | 
256  | 0  |                            (const unsigned char *)keyval->attrib.pValue,  | 
257  | 0  |                            keyval->attrib.ulValueLen, isFIPS);  | 
258  |  | 
  | 
259  | 0  | done:  | 
260  | 0  |     if (keyval) { | 
261  | 0  |         sftk_FreeAttribute(keyval);  | 
262  | 0  |     }  | 
263  | 0  |     return ret;  | 
264  | 0  | }  | 
265  |  |  | 
266  |  | CK_RV  | 
267  |  | sftk_MAC_InitRaw(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, const unsigned char *key, unsigned int key_len, PRBool isFIPS)  | 
268  | 0  | { | 
269  | 0  |     const SECHashObject *hashObj = NULL;  | 
270  | 0  |     CK_RV ret = CKR_OK;  | 
271  |  | 
  | 
272  | 0  |     if (ctx == NULL) { | 
273  | 0  |         return CKR_HOST_MEMORY;  | 
274  | 0  |     }  | 
275  |  |  | 
276  |  |     /* Clear the context before use. */  | 
277  | 0  |     PORT_Memset(ctx, 0, sizeof(*ctx));  | 
278  |  |  | 
279  |  |     /* Save the mech. */  | 
280  | 0  |     ctx->mech = mech;  | 
281  |  |  | 
282  |  |     /* Initialize the correct MAC context. */  | 
283  | 0  |     switch (mech) { | 
284  | 0  |         case CKM_MD2_HMAC:  | 
285  | 0  |         case CKM_MD5_HMAC:  | 
286  | 0  |         case CKM_SHA_1_HMAC:  | 
287  | 0  |         case CKM_SHA224_HMAC:  | 
288  | 0  |         case CKM_SHA256_HMAC:  | 
289  | 0  |         case CKM_SHA384_HMAC:  | 
290  | 0  |         case CKM_SHA512_HMAC:  | 
291  | 0  |         case CKM_SHA3_224_HMAC:  | 
292  | 0  |         case CKM_SHA3_256_HMAC:  | 
293  | 0  |         case CKM_SHA3_384_HMAC:  | 
294  | 0  |         case CKM_SHA3_512_HMAC:  | 
295  | 0  |             hashObj = HASH_GetRawHashObject(sftk_HMACMechanismToHash(mech));  | 
296  |  |  | 
297  |  |             /* Because we condition above only on hashes we know to be valid,  | 
298  |  |              * hashObj should never be NULL. This assert is only useful when  | 
299  |  |              * adding a new hash function (for which only partial support has  | 
300  |  |              * been added); thus there is no need to turn it into an if and  | 
301  |  |              * avoid the NULL dereference on the following line. */  | 
302  | 0  |             PR_ASSERT(hashObj != NULL);  | 
303  | 0  |             ctx->mac_size = hashObj->length;  | 
304  |  | 
  | 
305  | 0  |             goto hmac;  | 
306  | 0  |         case CKM_AES_CMAC:  | 
307  | 0  |             ctx->mac.cmac = CMAC_Create(CMAC_AES, key, key_len);  | 
308  | 0  |             ctx->destroy_func = SFTKMAC_CMAC_Destroy;  | 
309  |  |  | 
310  |  |             /* Copy the behavior of sftk_doCMACInit here. */  | 
311  | 0  |             if (ctx->mac.cmac == NULL) { | 
312  | 0  |                 if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) { | 
313  | 0  |                     ret = CKR_KEY_SIZE_RANGE;  | 
314  | 0  |                     goto done;  | 
315  | 0  |                 }  | 
316  |  |  | 
317  | 0  |                 ret = CKR_HOST_MEMORY;  | 
318  | 0  |                 goto done;  | 
319  | 0  |             }  | 
320  |  |  | 
321  | 0  |             ctx->mac_size = AES_BLOCK_SIZE;  | 
322  |  | 
  | 
323  | 0  |             goto done;  | 
324  | 0  |         default:  | 
325  | 0  |             ret = CKR_MECHANISM_PARAM_INVALID;  | 
326  | 0  |             goto done;  | 
327  | 0  |     }  | 
328  |  |  | 
329  | 0  | hmac:  | 
330  | 0  |     ctx->mac.hmac = HMAC_Create(hashObj, key, key_len, isFIPS);  | 
331  | 0  |     ctx->destroy_func = SFTKMAC_HMAC_Destroy;  | 
332  |  |  | 
333  |  |     /* Copy the behavior of sftk_doHMACInit here. */  | 
334  | 0  |     if (ctx->mac.hmac == NULL) { | 
335  | 0  |         if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) { | 
336  | 0  |             ret = CKR_KEY_SIZE_RANGE;  | 
337  | 0  |             goto done;  | 
338  | 0  |         }  | 
339  | 0  |         ret = CKR_HOST_MEMORY;  | 
340  | 0  |         goto done;  | 
341  | 0  |     }  | 
342  |  |  | 
343  |  |     /* Semantics: HMAC and CMAC should behave the same. Begin HMAC now. */  | 
344  | 0  |     HMAC_Begin(ctx->mac.hmac);  | 
345  |  | 
  | 
346  | 0  | done:  | 
347  |  |     /* Handle a failure: ctx->mac.raw should be NULL, but make sure  | 
348  |  |      * destroy_func isn't set. */  | 
349  | 0  |     if (ret != CKR_OK) { | 
350  | 0  |         ctx->destroy_func = NULL;  | 
351  | 0  |     }  | 
352  |  | 
  | 
353  | 0  |     return ret;  | 
354  | 0  | }  | 
355  |  |  | 
356  |  | CK_RV  | 
357  |  | sftk_MAC_Reset(sftk_MACCtx *ctx)  | 
358  | 0  | { | 
359  |  |     /* Useful for resetting the state of MAC prior to calling update again  | 
360  |  |      *  | 
361  |  |      * This lets the caller keep a single MAC instance and re-use it as long  | 
362  |  |      * as the key stays the same. */  | 
363  | 0  |     switch (ctx->mech) { | 
364  | 0  |         case CKM_MD2_HMAC:  | 
365  | 0  |         case CKM_MD5_HMAC:  | 
366  | 0  |         case CKM_SHA_1_HMAC:  | 
367  | 0  |         case CKM_SHA224_HMAC:  | 
368  | 0  |         case CKM_SHA256_HMAC:  | 
369  | 0  |         case CKM_SHA384_HMAC:  | 
370  | 0  |         case CKM_SHA512_HMAC:  | 
371  | 0  |         case CKM_SHA3_224_HMAC:  | 
372  | 0  |         case CKM_SHA3_256_HMAC:  | 
373  | 0  |         case CKM_SHA3_384_HMAC:  | 
374  | 0  |         case CKM_SHA3_512_HMAC:  | 
375  | 0  |             HMAC_Begin(ctx->mac.hmac);  | 
376  | 0  |             break;  | 
377  | 0  |         case CKM_AES_CMAC:  | 
378  | 0  |             if (CMAC_Begin(ctx->mac.cmac) != SECSuccess) { | 
379  | 0  |                 return CKR_FUNCTION_FAILED;  | 
380  | 0  |             }  | 
381  | 0  |             break;  | 
382  | 0  |         default:  | 
383  |  |             /* This shouldn't happen -- asserting indicates partial support  | 
384  |  |              * for a new MAC type. */  | 
385  | 0  |             PR_ASSERT(PR_FALSE);  | 
386  | 0  |             return CKR_FUNCTION_FAILED;  | 
387  | 0  |     }  | 
388  |  |  | 
389  | 0  |     return CKR_OK;  | 
390  | 0  | }  | 
391  |  |  | 
392  |  | CK_RV  | 
393  |  | sftk_MAC_Update(sftk_MACCtx *ctx, const CK_BYTE *data, unsigned int data_len)  | 
394  | 0  | { | 
395  | 0  |     switch (ctx->mech) { | 
396  | 0  |         case CKM_MD2_HMAC:  | 
397  | 0  |         case CKM_MD5_HMAC:  | 
398  | 0  |         case CKM_SHA_1_HMAC:  | 
399  | 0  |         case CKM_SHA224_HMAC:  | 
400  | 0  |         case CKM_SHA256_HMAC:  | 
401  | 0  |         case CKM_SHA384_HMAC:  | 
402  | 0  |         case CKM_SHA512_HMAC:  | 
403  | 0  |         case CKM_SHA3_224_HMAC:  | 
404  | 0  |         case CKM_SHA3_256_HMAC:  | 
405  | 0  |         case CKM_SHA3_384_HMAC:  | 
406  | 0  |         case CKM_SHA3_512_HMAC:  | 
407  |  |             /* HMAC doesn't indicate failure in the return code. */  | 
408  | 0  |             HMAC_Update(ctx->mac.hmac, data, data_len);  | 
409  | 0  |             break;  | 
410  | 0  |         case CKM_AES_CMAC:  | 
411  |  |             /* CMAC indicates failure in the return code, however this is  | 
412  |  |              * unlikely to occur. */  | 
413  | 0  |             if (CMAC_Update(ctx->mac.cmac, data, data_len) != SECSuccess) { | 
414  | 0  |                 return CKR_FUNCTION_FAILED;  | 
415  | 0  |             }  | 
416  | 0  |             break;  | 
417  | 0  |         default:  | 
418  |  |             /* This shouldn't happen -- asserting indicates partial support  | 
419  |  |              * for a new MAC type. */  | 
420  | 0  |             PR_ASSERT(PR_FALSE);  | 
421  | 0  |             return CKR_FUNCTION_FAILED;  | 
422  | 0  |     }  | 
423  | 0  |     return CKR_OK;  | 
424  | 0  | }  | 
425  |  |  | 
426  |  | CK_RV  | 
427  |  | sftk_MAC_End(sftk_MACCtx *ctx, CK_BYTE_PTR result, unsigned int *result_len, unsigned int max_result_len)  | 
428  | 0  | { | 
429  | 0  |     unsigned int actual_result_len;  | 
430  |  | 
  | 
431  | 0  |     switch (ctx->mech) { | 
432  | 0  |         case CKM_MD2_HMAC:  | 
433  | 0  |         case CKM_MD5_HMAC:  | 
434  | 0  |         case CKM_SHA_1_HMAC:  | 
435  | 0  |         case CKM_SHA224_HMAC:  | 
436  | 0  |         case CKM_SHA256_HMAC:  | 
437  | 0  |         case CKM_SHA384_HMAC:  | 
438  | 0  |         case CKM_SHA512_HMAC:  | 
439  | 0  |         case CKM_SHA3_224_HMAC:  | 
440  | 0  |         case CKM_SHA3_256_HMAC:  | 
441  | 0  |         case CKM_SHA3_384_HMAC:  | 
442  | 0  |         case CKM_SHA3_512_HMAC:  | 
443  |  |             /* HMAC doesn't indicate failure in the return code. Additionally,  | 
444  |  |              * unlike CMAC, it doesn't support partial results. This means that we  | 
445  |  |              * need to allocate a buffer if max_result_len < ctx->mac_size. */  | 
446  | 0  |             if (max_result_len >= ctx->mac_size) { | 
447  |  |                 /* Split this into two calls to avoid an unnecessary stack  | 
448  |  |                  * allocation and memcpy when possible. */  | 
449  | 0  |                 HMAC_Finish(ctx->mac.hmac, result, &actual_result_len, max_result_len);  | 
450  | 0  |             } else { | 
451  | 0  |                 uint8_t tmp_buffer[SFTK_MAX_MAC_LENGTH];  | 
452  |  |  | 
453  |  |                 /* Assumption: buffer is large enough to hold this HMAC's  | 
454  |  |                  * output. */  | 
455  | 0  |                 PR_ASSERT(SFTK_MAX_MAC_LENGTH >= ctx->mac_size);  | 
456  |  | 
  | 
457  | 0  |                 HMAC_Finish(ctx->mac.hmac, tmp_buffer, &actual_result_len, SFTK_MAX_MAC_LENGTH);  | 
458  |  | 
  | 
459  | 0  |                 if (actual_result_len > max_result_len) { | 
460  |  |                     /* This should always be true since:  | 
461  |  |                      *  | 
462  |  |                      *   (SFTK_MAX_MAC_LENGTH >= ctx->mac_size =  | 
463  |  |                      *       actual_result_len) > max_result_len,  | 
464  |  |                      *  | 
465  |  |                      * but guard this truncation just in case. */  | 
466  | 0  |                     actual_result_len = max_result_len;  | 
467  | 0  |                 }  | 
468  |  | 
  | 
469  | 0  |                 PORT_Memcpy(result, tmp_buffer, actual_result_len);  | 
470  | 0  |             }  | 
471  | 0  |             break;  | 
472  | 0  |         case CKM_AES_CMAC:  | 
473  |  |             /* CMAC indicates failure in the return code, however this is  | 
474  |  |              * unlikely to occur. */  | 
475  | 0  |             if (CMAC_Finish(ctx->mac.cmac, result, &actual_result_len, max_result_len) != SECSuccess) { | 
476  | 0  |                 return CKR_FUNCTION_FAILED;  | 
477  | 0  |             }  | 
478  | 0  |             break;  | 
479  | 0  |         default:  | 
480  |  |             /* This shouldn't happen -- asserting indicates partial support  | 
481  |  |              * for a new MAC type. */  | 
482  | 0  |             PR_ASSERT(PR_FALSE);  | 
483  | 0  |             return CKR_FUNCTION_FAILED;  | 
484  | 0  |     }  | 
485  |  |  | 
486  | 0  |     if (result_len) { | 
487  |  |         /* When result length is passed, inform the caller of its value. */  | 
488  | 0  |         *result_len = actual_result_len;  | 
489  | 0  |     } else if (max_result_len == ctx->mac_size) { | 
490  |  |         /* Validate that the amount requested was what was actually given; the  | 
491  |  |          * caller assumes that what they passed was the output size of the  | 
492  |  |          * underlying MAC and that they got all the bytes the asked for. */  | 
493  | 0  |         PR_ASSERT(actual_result_len == max_result_len);  | 
494  | 0  |     }  | 
495  |  | 
  | 
496  | 0  |     return CKR_OK;  | 
497  | 0  | }  | 
498  |  |  | 
499  |  | void  | 
500  |  | sftk_MAC_DestroyContext(sftk_MACCtx *ctx, PRBool free_it)  | 
501  | 0  | { | 
502  | 0  |     if (ctx == NULL) { | 
503  | 0  |         return;  | 
504  | 0  |     }  | 
505  |  |  | 
506  | 0  |     if (ctx->mac.raw != NULL && ctx->destroy_func != NULL) { | 
507  | 0  |         ctx->destroy_func(ctx->mac.raw, PR_TRUE);  | 
508  | 0  |     }  | 
509  |  |  | 
510  |  |     /* Clean up the struct so we don't double free accidentally. */  | 
511  | 0  |     PORT_Memset(ctx, 0, sizeof(sftk_MACCtx));  | 
512  |  | 
  | 
513  | 0  |     if (free_it == PR_TRUE) { | 
514  | 0  |         PORT_Free(ctx);  | 
515  | 0  |     }  | 
516  | 0  | }  |