X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_ssl/lib/tls_hmac.c?ds=inline diff --git a/Security/libsecurity_ssl/lib/tls_hmac.c b/Security/libsecurity_ssl/lib/tls_hmac.c new file mode 100644 index 00000000..11662d8d --- /dev/null +++ b/Security/libsecurity_ssl/lib/tls_hmac.c @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2002,2005-2008,2010-2012,2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * tls_hmac.c - HMAC routines used by TLS + */ + +/* THIS FILE CONTAINS KERNEL CODE */ + +#include "tls_hmac.h" +#include "tls_digest.h" +#include "sslMemory.h" +#include "sslDebug.h" +#include +#include + + +/* Per-session state, opaque to callers; all fields set at alloc time */ +struct HMACContext { + const HashReference *digest; + SSLBuffer outerHashCtx; + SSLBuffer innerHashCtx; + SSLBuffer currentHashCtx; +}; + +// MARK: - +// MARK: Common HMAC routines + +/* Create an HMAC session */ +static int HMAC_Alloc( + const struct HMACReference *hmac, + const void *keyPtr, + size_t keyLen, + HMACContextRef *hmacCtx) // RETURNED +{ + const HashReference *digest; + HMACContextRef href; + size_t ix; + uint8_t *context; + const uint8_t *key; + size_t digest_block_size; + + switch(hmac->alg) { + case HA_SHA384: + digest = &SSLHashSHA384; + digest_block_size = 128; + break; + case HA_SHA256: + digest = &SSLHashSHA256; + digest_block_size = 64; + break; + case HA_SHA1: + digest = &SSLHashSHA1; + digest_block_size = 64; + break; + case HA_MD5: + digest = &SSLHashMD5; + digest_block_size = 64; + break; + default: + check(0); + return -1; + } + + context = (uint8_t *)sslMalloc(sizeof(struct HMACContext) + + 3 * digest->contextSize); + if(context == NULL) { + check(0); + return -1; + } + href = (HMACContextRef)context; + href->digest = digest; + href->outerHashCtx.data = context + sizeof(*href); + href->outerHashCtx.length = digest->contextSize; + href->innerHashCtx.data = href->outerHashCtx.data + digest->contextSize; + href->innerHashCtx.length = digest->contextSize; + href->currentHashCtx.data = href->innerHashCtx.data + digest->contextSize; + href->currentHashCtx.length = digest->contextSize; + + digest->init(&href->outerHashCtx); + digest->init(&href->innerHashCtx); + + uint8_t tmpkey[digest->digestSize]; + uint8_t pad[digest_block_size]; + SSLBuffer kpad = { digest_block_size, pad }; + + /* If the key is longer than digest_block_size, reset it to key=digest(key) */ + if (keyLen <= digest_block_size) { + key = (const uint8_t *)keyPtr; + } else { + SSLBuffer keyBuffer = { keyLen, (uint8_t *)keyPtr }; + SSLBuffer outBuffer = { digest->digestSize, tmpkey }; + digest->update(&href->innerHashCtx, &keyBuffer); + digest->final(&href->innerHashCtx, &outBuffer); + key = outBuffer.data; + keyLen = outBuffer.length; + /* Re-initialize the inner context. */ + digest->init(&href->innerHashCtx); + } + + /* Copy the key into k_opad while doing the XOR. */ + for (ix = 0; ix < keyLen; ++ix) + pad[ix] = key[ix] ^ 0x5c; + memset(pad + keyLen, 0x5c, digest_block_size - keyLen); + digest->update(&href->outerHashCtx, &kpad); + + /* Copy the key into k_ipad while doing the XOR. */ + for (ix = 0; ix < keyLen; ++ix) + pad[ix] = key[ix] ^ 0x36; + memset(pad + keyLen, 0x36, digest_block_size - keyLen); + digest->update(&href->innerHashCtx, &kpad); + + /* Clear out the key bits in pad. */ + bzero(pad, keyLen); + + /* Now clone the inner digest so we are ready to receive an update. */ + /* @@@ If init is always called before update we could skip this step. */ + digest->clone(&href->innerHashCtx, &href->currentHashCtx); + + /* success */ + *hmacCtx = href; + return 0; +} + +/* free a session */ +static int HMAC_Free( + HMACContextRef hmacCtx) +{ + if(hmacCtx != NULL) { + hmacCtx->digest->close(&hmacCtx->outerHashCtx); + hmacCtx->digest->close(&hmacCtx->innerHashCtx); + hmacCtx->digest->close(&hmacCtx->currentHashCtx); + + /* Clear out any key material left in the digest contexts. */ + bzero(hmacCtx->outerHashCtx.data, hmacCtx->outerHashCtx.length); + bzero(hmacCtx->innerHashCtx.data, hmacCtx->innerHashCtx.length); + bzero(hmacCtx->currentHashCtx.data, hmacCtx->currentHashCtx.length); + + sslFree(hmacCtx); + } + return 0; +} + +/* Reusable init */ +static int HMAC_Init( + HMACContextRef hmacCtx) +{ + if(hmacCtx == NULL) { + check(0); + return -1; + } + + check(hmacCtx->digest != NULL); + + hmacCtx->digest->close(&hmacCtx->currentHashCtx); + hmacCtx->digest->clone(&hmacCtx->innerHashCtx, &hmacCtx->currentHashCtx); + + return 0; +} + +/* normal crypt ops */ +static int HMAC_Update( + HMACContextRef hmacCtx, + const void *data, + size_t dataLen) +{ + SSLBuffer cdata = { dataLen, (uint8_t *)data }; + if(hmacCtx == NULL) { + check(0); + return -1; + } + + check(hmacCtx->digest != NULL); + + hmacCtx->digest->update(&hmacCtx->currentHashCtx, &cdata); + + return 0; +} + +static int HMAC_Final( + HMACContextRef hmacCtx, + void *hmac, // mallocd by caller + size_t *hmacLen) // IN/OUT +{ + uint8_t bytes[TLS_HMAC_MAX_SIZE]; + SSLBuffer digest = { TLS_HMAC_MAX_SIZE, bytes }; + SSLBuffer cdata; + + if(hmacCtx == NULL) { + check(0); + return -1; + } + if((hmac == NULL) || (hmacLen == NULL)) { + check(0); + return -1; + } + check(hmacCtx->digest != NULL); + check(*hmacLen >= hmacCtx->digest->digestSize); + + cdata.length = *hmacLen; + cdata.data = (uint8_t *)hmac; + + hmacCtx->digest->final(&hmacCtx->currentHashCtx, &digest); + hmacCtx->digest->clone(&hmacCtx->outerHashCtx, &hmacCtx->currentHashCtx); + hmacCtx->digest->update(&hmacCtx->currentHashCtx, &digest); + bzero(bytes, hmacCtx->digest->digestSize); + hmacCtx->digest->final(&hmacCtx->currentHashCtx, &cdata); + *hmacLen = hmacCtx->digest->digestSize; + + return 0; +} + +/* one-shot */ +static int HMAC_Hmac ( + HMACContextRef hmacCtx, + const void *data, + size_t dataLen, + void *hmac, // mallocd by caller + size_t *hmacLen) // IN/OUT +{ + int serr; + + if(hmacCtx == NULL) { + check(0); + return -1; + } + serr = HMAC_Init(hmacCtx); + if(serr) { + return serr; + } + serr = HMAC_Update(hmacCtx, data, dataLen); + if(serr) { + return serr; + } + return HMAC_Final(hmacCtx, hmac, hmacLen); +} + + +// MARK: - +// MARK: Null HMAC + +static int HMAC_AllocNull( + const struct HMACReference *hmac, + const void *keyPtr, + size_t keyLen, + HMACContextRef *hmacCtx) // RETURNED +{ + *hmacCtx = NULL; + return 0; +} + +static int HMAC_FreeNull( + HMACContextRef hmacCtx) +{ + return 0; +} + +static int HMAC_InitNull( + HMACContextRef hmacCtx) + { + return 0; +} + +static int HMAC_UpdateNull( + HMACContextRef hmacCtx, + const void *data, + size_t dataLen) +{ + return 0; +} + +static int HMAC_FinalNull( + HMACContextRef hmacCtx, + void *hmac, // mallocd by caller + size_t *hmacLen) // IN/OUT +{ + return 0; +} + +static int HMAC_HmacNull ( + HMACContextRef hmacCtx, + const void *data, + size_t dataLen, + void *hmac, // mallocd by caller + size_t *hmacLen) +{ + return 0; +} + +const HMACReference TlsHmacNull = { + 0, + HA_Null, + HMAC_AllocNull, + HMAC_FreeNull, + HMAC_InitNull, + HMAC_UpdateNull, + HMAC_FinalNull, + HMAC_HmacNull +}; + +const HMACReference TlsHmacMD5 = { + 16, + HA_MD5, + HMAC_Alloc, + HMAC_Free, + HMAC_Init, + HMAC_Update, + HMAC_Final, + HMAC_Hmac +}; + +const HMACReference TlsHmacSHA1 = { + 20, + HA_SHA1, + HMAC_Alloc, + HMAC_Free, + HMAC_Init, + HMAC_Update, + HMAC_Final, + HMAC_Hmac +}; + +const HMACReference TlsHmacSHA256 = { + 32, + HA_SHA256, + HMAC_Alloc, + HMAC_Free, + HMAC_Init, + HMAC_Update, + HMAC_Final, + HMAC_Hmac +}; + +const HMACReference TlsHmacSHA384 = { + 48, + HA_SHA384, + HMAC_Alloc, + HMAC_Free, + HMAC_Init, + HMAC_Update, + HMAC_Final, + HMAC_Hmac +};