hmac_nss.c (8539B)
1 /* 2 * 3 * Copyright(c) 2013-2017, Cisco Systems, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * Neither the name of the Cisco Systems, Inc. nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 33 * OF THE POSSIBILITY OF SUCH DAMAGE. 34 * 35 */ 36 37 #ifdef HAVE_CONFIG_H 38 #include <config.h> 39 #endif 40 41 #include "auth.h" 42 #include "alloc.h" 43 #include "err.h" /* for srtp_debug */ 44 #include "auth_test_cases.h" 45 46 #define NSS_PKCS11_2_0_COMPAT 1 47 48 #include <nss.h> 49 #include <pk11pub.h> 50 51 #define SHA1_DIGEST_SIZE 20 52 53 /* the debug module for authentiation */ 54 55 srtp_debug_module_t srtp_mod_hmac = { 56 0, /* debugging is off by default */ 57 "hmac sha-1 nss" /* printable name for module */ 58 }; 59 60 typedef struct { 61 NSSInitContext *nss; 62 PK11SymKey *key; 63 PK11Context *ctx; 64 } srtp_hmac_nss_ctx_t; 65 66 static srtp_err_status_t srtp_hmac_alloc(srtp_auth_t **a, 67 int key_len, 68 int out_len) 69 { 70 extern const srtp_auth_type_t srtp_hmac; 71 srtp_hmac_nss_ctx_t *hmac; 72 NSSInitContext *nss; 73 74 debug_print(srtp_mod_hmac, "allocating auth func with key length %d", 75 key_len); 76 debug_print(srtp_mod_hmac, " tag length %d", 77 out_len); 78 79 /* check output length - should be less than 20 bytes */ 80 if (out_len > SHA1_DIGEST_SIZE) { 81 return srtp_err_status_bad_param; 82 } 83 84 /* Initialize NSS equiv of NSS_NoDB_Init(NULL) */ 85 nss = NSS_InitContext("", "", "", "", NULL, 86 NSS_INIT_READONLY | NSS_INIT_NOCERTDB | 87 NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN | 88 NSS_INIT_OPTIMIZESPACE); 89 if (!nss) { 90 return srtp_err_status_auth_fail; 91 } 92 93 *a = (srtp_auth_t *)srtp_crypto_alloc(sizeof(srtp_auth_t)); 94 if (*a == NULL) { 95 NSS_ShutdownContext(nss); 96 return srtp_err_status_alloc_fail; 97 } 98 99 hmac = 100 (srtp_hmac_nss_ctx_t *)srtp_crypto_alloc(sizeof(srtp_hmac_nss_ctx_t)); 101 if (hmac == NULL) { 102 NSS_ShutdownContext(nss); 103 srtp_crypto_free(*a); 104 *a = NULL; 105 return srtp_err_status_alloc_fail; 106 } 107 108 hmac->nss = nss; 109 hmac->key = NULL; 110 hmac->ctx = NULL; 111 112 /* set pointers */ 113 (*a)->state = hmac; 114 (*a)->type = &srtp_hmac; 115 (*a)->out_len = out_len; 116 (*a)->key_len = key_len; 117 (*a)->prefix_len = 0; 118 119 return srtp_err_status_ok; 120 } 121 122 static srtp_err_status_t srtp_hmac_dealloc(srtp_auth_t *a) 123 { 124 srtp_hmac_nss_ctx_t *hmac; 125 126 hmac = (srtp_hmac_nss_ctx_t *)a->state; 127 if (hmac) { 128 /* free any PK11 values that have been created */ 129 if (hmac->key) { 130 PK11_FreeSymKey(hmac->key); 131 hmac->key = NULL; 132 } 133 134 if (hmac->ctx) { 135 PK11_DestroyContext(hmac->ctx, PR_TRUE); 136 hmac->ctx = NULL; 137 } 138 139 if (hmac->nss) { 140 NSS_ShutdownContext(hmac->nss); 141 hmac->nss = NULL; 142 } 143 144 /* zeroize everything */ 145 octet_string_set_to_zero(hmac, sizeof(srtp_hmac_nss_ctx_t)); 146 srtp_crypto_free(hmac); 147 } 148 149 /* free memory */ 150 srtp_crypto_free(a); 151 152 return srtp_err_status_ok; 153 } 154 155 static srtp_err_status_t srtp_hmac_start(void *statev) 156 { 157 srtp_hmac_nss_ctx_t *hmac; 158 hmac = (srtp_hmac_nss_ctx_t *)statev; 159 160 if (PK11_DigestBegin(hmac->ctx) != SECSuccess) { 161 return srtp_err_status_auth_fail; 162 } 163 return srtp_err_status_ok; 164 } 165 166 static srtp_err_status_t srtp_hmac_init(void *statev, 167 const uint8_t *key, 168 int key_len) 169 { 170 srtp_hmac_nss_ctx_t *hmac; 171 hmac = (srtp_hmac_nss_ctx_t *)statev; 172 PK11SymKey *sym_key; 173 PK11Context *ctx; 174 175 if (hmac->ctx) { 176 PK11_DestroyContext(hmac->ctx, PR_TRUE); 177 hmac->ctx = NULL; 178 } 179 180 if (hmac->key) { 181 PK11_FreeSymKey(hmac->key); 182 hmac->key = NULL; 183 } 184 185 PK11SlotInfo *slot = PK11_GetBestSlot(CKM_SHA_1_HMAC, NULL); 186 if (!slot) { 187 return srtp_err_status_bad_param; 188 } 189 190 /* explicitly cast away const of key */ 191 SECItem key_item = { siBuffer, (unsigned char *)(uintptr_t)key, key_len }; 192 sym_key = PK11_ImportSymKey(slot, CKM_SHA_1_HMAC, PK11_OriginUnwrap, 193 CKA_SIGN, &key_item, NULL); 194 PK11_FreeSlot(slot); 195 196 if (!sym_key) { 197 return srtp_err_status_auth_fail; 198 } 199 200 SECItem param_item = { siBuffer, NULL, 0 }; 201 ctx = PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, CKA_SIGN, sym_key, 202 ¶m_item); 203 if (!ctx) { 204 PK11_FreeSymKey(sym_key); 205 return srtp_err_status_auth_fail; 206 } 207 208 hmac->key = sym_key; 209 hmac->ctx = ctx; 210 211 return srtp_err_status_ok; 212 } 213 214 static srtp_err_status_t srtp_hmac_update(void *statev, 215 const uint8_t *message, 216 int msg_octets) 217 { 218 srtp_hmac_nss_ctx_t *hmac; 219 hmac = (srtp_hmac_nss_ctx_t *)statev; 220 221 debug_print(srtp_mod_hmac, "input: %s", 222 srtp_octet_string_hex_string(message, msg_octets)); 223 224 if (PK11_DigestOp(hmac->ctx, message, msg_octets) != SECSuccess) { 225 return srtp_err_status_auth_fail; 226 } 227 228 return srtp_err_status_ok; 229 } 230 231 static srtp_err_status_t srtp_hmac_compute(void *statev, 232 const uint8_t *message, 233 int msg_octets, 234 int tag_len, 235 uint8_t *result) 236 { 237 srtp_hmac_nss_ctx_t *hmac; 238 hmac = (srtp_hmac_nss_ctx_t *)statev; 239 uint8_t hash_value[SHA1_DIGEST_SIZE]; 240 int i; 241 unsigned int len; 242 243 debug_print(srtp_mod_hmac, "input: %s", 244 srtp_octet_string_hex_string(message, msg_octets)); 245 246 /* check tag length, return error if we can't provide the value expected */ 247 if (tag_len > SHA1_DIGEST_SIZE) { 248 return srtp_err_status_bad_param; 249 } 250 251 if (PK11_DigestOp(hmac->ctx, message, msg_octets) != SECSuccess) { 252 return srtp_err_status_auth_fail; 253 } 254 255 if (PK11_DigestFinal(hmac->ctx, hash_value, &len, SHA1_DIGEST_SIZE) != 256 SECSuccess) { 257 return srtp_err_status_auth_fail; 258 } 259 260 if (tag_len < 0 || len < (unsigned int)tag_len) 261 return srtp_err_status_auth_fail; 262 263 /* copy hash_value to *result */ 264 for (i = 0; i < tag_len; i++) { 265 result[i] = hash_value[i]; 266 } 267 268 debug_print(srtp_mod_hmac, "output: %s", 269 srtp_octet_string_hex_string(hash_value, tag_len)); 270 271 return srtp_err_status_ok; 272 } 273 274 static const char srtp_hmac_description[] = 275 "hmac sha-1 authentication function"; 276 277 /* 278 * srtp_auth_type_t hmac is the hmac metaobject 279 */ 280 281 const srtp_auth_type_t srtp_hmac = { 282 srtp_hmac_alloc, /* */ 283 srtp_hmac_dealloc, /* */ 284 srtp_hmac_init, /* */ 285 srtp_hmac_compute, /* */ 286 srtp_hmac_update, /* */ 287 srtp_hmac_start, /* */ 288 srtp_hmac_description, /* */ 289 &srtp_hmac_test_case_0, /* */ 290 SRTP_HMAC_SHA1 /* */ 291 };