1/* 2 * Copyright (c) 2002,2005-2008,2010-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * tls_hmac.c - HMAC routines used by TLS 26 */ 27 28/* THIS FILE CONTAINS KERNEL CODE */ 29 30#include "tls_hmac.h" 31#include "tls_digest.h" 32#include "sslMemory.h" 33#include "sslDebug.h" 34#include <string.h> 35#include <AssertMacros.h> 36 37 38/* Per-session state, opaque to callers; all fields set at alloc time */ 39struct HMACContext { 40 const HashReference *digest; 41 SSLBuffer outerHashCtx; 42 SSLBuffer innerHashCtx; 43 SSLBuffer currentHashCtx; 44}; 45 46// MARK: - 47// MARK: Common HMAC routines 48 49/* Create an HMAC session */ 50static int HMAC_Alloc( 51 const struct HMACReference *hmac, 52 const void *keyPtr, 53 size_t keyLen, 54 HMACContextRef *hmacCtx) // RETURNED 55{ 56 const HashReference *digest; 57 HMACContextRef href; 58 size_t ix; 59 uint8_t *context; 60 const uint8_t *key; 61 size_t digest_block_size; 62 63 switch(hmac->alg) { 64 case HA_SHA384: 65 digest = &SSLHashSHA384; 66 digest_block_size = 128; 67 break; 68 case HA_SHA256: 69 digest = &SSLHashSHA256; 70 digest_block_size = 64; 71 break; 72 case HA_SHA1: 73 digest = &SSLHashSHA1; 74 digest_block_size = 64; 75 break; 76 case HA_MD5: 77 digest = &SSLHashMD5; 78 digest_block_size = 64; 79 break; 80 default: 81 check(0); 82 return -1; 83 } 84 85 context = (uint8_t *)sslMalloc(sizeof(struct HMACContext) + 86 3 * digest->contextSize); 87 if(context == NULL) { 88 check(0); 89 return -1; 90 } 91 href = (HMACContextRef)context; 92 href->digest = digest; 93 href->outerHashCtx.data = context + sizeof(*href); 94 href->outerHashCtx.length = digest->contextSize; 95 href->innerHashCtx.data = href->outerHashCtx.data + digest->contextSize; 96 href->innerHashCtx.length = digest->contextSize; 97 href->currentHashCtx.data = href->innerHashCtx.data + digest->contextSize; 98 href->currentHashCtx.length = digest->contextSize; 99 100 digest->init(&href->outerHashCtx); 101 digest->init(&href->innerHashCtx); 102 103 uint8_t tmpkey[digest->digestSize]; 104 uint8_t pad[digest_block_size]; 105 SSLBuffer kpad = { digest_block_size, pad }; 106 107 /* If the key is longer than digest_block_size, reset it to key=digest(key) */ 108 if (keyLen <= digest_block_size) { 109 key = (const uint8_t *)keyPtr; 110 } else { 111 SSLBuffer keyBuffer = { keyLen, (uint8_t *)keyPtr }; 112 SSLBuffer outBuffer = { digest->digestSize, tmpkey }; 113 digest->update(&href->innerHashCtx, &keyBuffer); 114 digest->final(&href->innerHashCtx, &outBuffer); 115 key = outBuffer.data; 116 keyLen = outBuffer.length; 117 /* Re-initialize the inner context. */ 118 digest->init(&href->innerHashCtx); 119 } 120 121 /* Copy the key into k_opad while doing the XOR. */ 122 for (ix = 0; ix < keyLen; ++ix) 123 pad[ix] = key[ix] ^ 0x5c; 124 memset(pad + keyLen, 0x5c, digest_block_size - keyLen); 125 digest->update(&href->outerHashCtx, &kpad); 126 127 /* Copy the key into k_ipad while doing the XOR. */ 128 for (ix = 0; ix < keyLen; ++ix) 129 pad[ix] = key[ix] ^ 0x36; 130 memset(pad + keyLen, 0x36, digest_block_size - keyLen); 131 digest->update(&href->innerHashCtx, &kpad); 132 133 /* Clear out the key bits in pad. */ 134 bzero(pad, keyLen); 135 136 /* Now clone the inner digest so we are ready to receive an update. */ 137 /* @@@ If init is always called before update we could skip this step. */ 138 digest->clone(&href->innerHashCtx, &href->currentHashCtx); 139 140 /* success */ 141 *hmacCtx = href; 142 return 0; 143} 144 145/* free a session */ 146static int HMAC_Free( 147 HMACContextRef hmacCtx) 148{ 149 if(hmacCtx != NULL) { 150 hmacCtx->digest->close(&hmacCtx->outerHashCtx); 151 hmacCtx->digest->close(&hmacCtx->innerHashCtx); 152 hmacCtx->digest->close(&hmacCtx->currentHashCtx); 153 154 /* Clear out any key material left in the digest contexts. */ 155 bzero(hmacCtx->outerHashCtx.data, hmacCtx->outerHashCtx.length); 156 bzero(hmacCtx->innerHashCtx.data, hmacCtx->innerHashCtx.length); 157 bzero(hmacCtx->currentHashCtx.data, hmacCtx->currentHashCtx.length); 158 159 sslFree(hmacCtx); 160 } 161 return 0; 162} 163 164/* Reusable init */ 165static int HMAC_Init( 166 HMACContextRef hmacCtx) 167{ 168 if(hmacCtx == NULL) { 169 check(0); 170 return -1; 171 } 172 173 check(hmacCtx->digest != NULL); 174 175 hmacCtx->digest->close(&hmacCtx->currentHashCtx); 176 hmacCtx->digest->clone(&hmacCtx->innerHashCtx, &hmacCtx->currentHashCtx); 177 178 return 0; 179} 180 181/* normal crypt ops */ 182static int HMAC_Update( 183 HMACContextRef hmacCtx, 184 const void *data, 185 size_t dataLen) 186{ 187 SSLBuffer cdata = { dataLen, (uint8_t *)data }; 188 if(hmacCtx == NULL) { 189 check(0); 190 return -1; 191 } 192 193 check(hmacCtx->digest != NULL); 194 195 hmacCtx->digest->update(&hmacCtx->currentHashCtx, &cdata); 196 197 return 0; 198} 199 200static int HMAC_Final( 201 HMACContextRef hmacCtx, 202 void *hmac, // mallocd by caller 203 size_t *hmacLen) // IN/OUT 204{ 205 uint8_t bytes[TLS_HMAC_MAX_SIZE]; 206 SSLBuffer digest = { TLS_HMAC_MAX_SIZE, bytes }; 207 SSLBuffer cdata; 208 209 if(hmacCtx == NULL) { 210 check(0); 211 return -1; 212 } 213 if((hmac == NULL) || (hmacLen == NULL)) { 214 check(0); 215 return -1; 216 } 217 check(hmacCtx->digest != NULL); 218 check(*hmacLen >= hmacCtx->digest->digestSize); 219 220 cdata.length = *hmacLen; 221 cdata.data = (uint8_t *)hmac; 222 223 hmacCtx->digest->final(&hmacCtx->currentHashCtx, &digest); 224 hmacCtx->digest->clone(&hmacCtx->outerHashCtx, &hmacCtx->currentHashCtx); 225 hmacCtx->digest->update(&hmacCtx->currentHashCtx, &digest); 226 bzero(bytes, hmacCtx->digest->digestSize); 227 hmacCtx->digest->final(&hmacCtx->currentHashCtx, &cdata); 228 *hmacLen = hmacCtx->digest->digestSize; 229 230 return 0; 231} 232 233/* one-shot */ 234static int HMAC_Hmac ( 235 HMACContextRef hmacCtx, 236 const void *data, 237 size_t dataLen, 238 void *hmac, // mallocd by caller 239 size_t *hmacLen) // IN/OUT 240{ 241 int serr; 242 243 if(hmacCtx == NULL) { 244 check(0); 245 return -1; 246 } 247 serr = HMAC_Init(hmacCtx); 248 if(serr) { 249 return serr; 250 } 251 serr = HMAC_Update(hmacCtx, data, dataLen); 252 if(serr) { 253 return serr; 254 } 255 return HMAC_Final(hmacCtx, hmac, hmacLen); 256} 257 258 259// MARK: - 260// MARK: Null HMAC 261 262static int HMAC_AllocNull( 263 const struct HMACReference *hmac, 264 const void *keyPtr, 265 size_t keyLen, 266 HMACContextRef *hmacCtx) // RETURNED 267{ 268 *hmacCtx = NULL; 269 return 0; 270} 271 272static int HMAC_FreeNull( 273 HMACContextRef hmacCtx) 274{ 275 return 0; 276} 277 278static int HMAC_InitNull( 279 HMACContextRef hmacCtx) 280 { 281 return 0; 282} 283 284static int HMAC_UpdateNull( 285 HMACContextRef hmacCtx, 286 const void *data, 287 size_t dataLen) 288{ 289 return 0; 290} 291 292static int HMAC_FinalNull( 293 HMACContextRef hmacCtx, 294 void *hmac, // mallocd by caller 295 size_t *hmacLen) // IN/OUT 296{ 297 return 0; 298} 299 300static int HMAC_HmacNull ( 301 HMACContextRef hmacCtx, 302 const void *data, 303 size_t dataLen, 304 void *hmac, // mallocd by caller 305 size_t *hmacLen) 306{ 307 return 0; 308} 309 310const HMACReference TlsHmacNull = { 311 0, 312 HA_Null, 313 HMAC_AllocNull, 314 HMAC_FreeNull, 315 HMAC_InitNull, 316 HMAC_UpdateNull, 317 HMAC_FinalNull, 318 HMAC_HmacNull 319}; 320 321const HMACReference TlsHmacMD5 = { 322 16, 323 HA_MD5, 324 HMAC_Alloc, 325 HMAC_Free, 326 HMAC_Init, 327 HMAC_Update, 328 HMAC_Final, 329 HMAC_Hmac 330}; 331 332const HMACReference TlsHmacSHA1 = { 333 20, 334 HA_SHA1, 335 HMAC_Alloc, 336 HMAC_Free, 337 HMAC_Init, 338 HMAC_Update, 339 HMAC_Final, 340 HMAC_Hmac 341}; 342 343const HMACReference TlsHmacSHA256 = { 344 32, 345 HA_SHA256, 346 HMAC_Alloc, 347 HMAC_Free, 348 HMAC_Init, 349 HMAC_Update, 350 HMAC_Final, 351 HMAC_Hmac 352}; 353 354const HMACReference TlsHmacSHA384 = { 355 48, 356 HA_SHA384, 357 HMAC_Alloc, 358 HMAC_Free, 359 HMAC_Init, 360 HMAC_Update, 361 HMAC_Final, 362 HMAC_Hmac 363}; 364