#include "tls_hmac.h"
#include "sslMemory.h"
#include "cryptType.h"
#include "sslDigests.h"
#include "sslDebug.h"
#include <strings.h>
#include <assert.h>
#ifdef USE_CDSA_CRYPTO
#include "sslCrypto.h"
#include <CommonCrypto/CommonHMAC.h>
struct HMACContext {
SSLContext *ctx;
CCHmacContext ccHmacTemplate;
CCHmacContext ccHmac;
size_t macSize;
const struct HMACReference *hmac;
};
#pragma mark -
#pragma mark CommonCryptor HMAC routines
static OSStatus HMAC_Alloc(
const struct HMACReference *hmac,
SSLContext *ctx,
const void *keyPtr,
unsigned keyLen,
HMACContextRef *hmacCtxOut) {
CCHmacAlgorithm ccAlg;
HMACContextRef hmacCtx = (HMACContextRef)sslMalloc(sizeof(struct HMACContext));
if(hmacCtx == NULL) {
return memFullErr;
}
hmacCtx->ctx = ctx;
hmacCtx->hmac = hmac;
switch(hmac->alg) {
case HA_SHA384:
ccAlg = kCCHmacAlgSHA384;
hmacCtx->macSize = CC_SHA384_DIGEST_LENGTH;
break;
case HA_SHA256:
ccAlg = kCCHmacAlgSHA256;
hmacCtx->macSize = CC_SHA256_DIGEST_LENGTH;
break;
case HA_SHA1:
ccAlg = kCCHmacAlgSHA1;
hmacCtx->macSize = CC_SHA1_DIGEST_LENGTH;
break;
case HA_MD5:
ccAlg = kCCHmacAlgMD5;
hmacCtx->macSize = CC_MD5_DIGEST_LENGTH;
break;
default:
ASSERT(0);
return errSSLInternal;
}
CCHmacInit(&hmacCtx->ccHmacTemplate, ccAlg, keyPtr, keyLen);
*hmacCtxOut = hmacCtx;
return noErr;
}
static OSStatus HMAC_Free(
HMACContextRef hmacCtx)
{
if(hmacCtx != NULL) {
memset(hmacCtx, 0, sizeof(*hmacCtx));
sslFree(hmacCtx);
}
return noErr;
}
static OSStatus HMAC_Init(
HMACContextRef hmacCtx)
{
if(hmacCtx == NULL) {
return errSSLInternal;
}
hmacCtx->ccHmac = hmacCtx->ccHmacTemplate;
return noErr;
}
static OSStatus HMAC_Update(
HMACContextRef hmacCtx,
const void *data,
unsigned dataLen)
{
CCHmacUpdate(&hmacCtx->ccHmac, data, dataLen);
return noErr;
}
static OSStatus HMAC_Final(
HMACContextRef hmacCtx,
void *hmac, unsigned *hmacLen) {
if(*hmacLen < hmacCtx->macSize) {
return errSSLInternal;
}
CCHmacFinal(&hmacCtx->ccHmac, hmac);
*hmacLen = hmacCtx->macSize;
return noErr;
}
static OSStatus HMAC_Hmac (
HMACContextRef hmacCtx,
const void *data,
unsigned dataLen,
void *hmac, unsigned *hmacLen) {
OSStatus serr;
const HMACReference *hmacRef;
if(hmacCtx == NULL) {
return errSSLInternal;
}
hmacRef = hmacCtx->hmac;
assert(hmacRef != NULL);
serr = hmacRef->init(hmacCtx);
if(serr) {
return serr;
}
serr = hmacRef->update(hmacCtx, data, dataLen);
if(serr) {
return serr;
}
return hmacRef->final(hmacCtx, hmac, hmacLen);
}
#else
struct HMACContext {
SSLContext *ctx;
const HashReference *digest;
SSLBuffer outerHashCtx;
SSLBuffer innerHashCtx;
SSLBuffer currentHashCtx;
};
#pragma mark -
#pragma mark Common HMAC routines
static OSStatus HMAC_Alloc(
const struct HMACReference *hmac,
SSLContext *ctx,
const void *keyPtr,
size_t keyLen,
HMACContextRef *hmacCtx) {
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:
assert(0);
return errSSLInternal;
}
context = (uint8_t *)sslMalloc(sizeof(struct HMACContext) +
3 * digest->contextSize);
if(context == NULL)
return memFullErr;
href = (HMACContextRef)context;
href->ctx = ctx;
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, ctx);
digest->init(&href->innerHashCtx, ctx);
uint8_t tmpkey[digest->digestSize];
uint8_t pad[digest_block_size];
SSLBuffer kpad = { digest_block_size, pad };
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;
digest->init(&href->innerHashCtx, ctx);
}
for (ix = 0; ix < keyLen; ++ix)
pad[ix] = key[ix] ^ 0x5c;
memset(pad + keyLen, 0x5c, digest_block_size - keyLen);
digest->update(&href->outerHashCtx, &kpad);
for (ix = 0; ix < keyLen; ++ix)
pad[ix] = key[ix] ^ 0x36;
memset(pad + keyLen, 0x36, digest_block_size - keyLen);
digest->update(&href->innerHashCtx, &kpad);
bzero(pad, keyLen);
digest->clone(&href->innerHashCtx, &href->currentHashCtx);
*hmacCtx = href;
return noErr;
}
static OSStatus HMAC_Free(
HMACContextRef hmacCtx)
{
if(hmacCtx != NULL) {
hmacCtx->digest->close(&hmacCtx->outerHashCtx, hmacCtx->ctx);
hmacCtx->digest->close(&hmacCtx->innerHashCtx, hmacCtx->ctx);
hmacCtx->digest->close(&hmacCtx->currentHashCtx, hmacCtx->ctx);
bzero(hmacCtx->outerHashCtx.data, hmacCtx->outerHashCtx.length);
bzero(hmacCtx->innerHashCtx.data, hmacCtx->innerHashCtx.length);
bzero(hmacCtx->currentHashCtx.data, hmacCtx->currentHashCtx.length);
sslFree(hmacCtx);
}
return noErr;
}
static OSStatus HMAC_Init(
HMACContextRef hmacCtx)
{
if(hmacCtx == NULL)
return errSSLInternal;
assert(hmacCtx->digest != NULL);
hmacCtx->digest->close(&hmacCtx->currentHashCtx, hmacCtx->ctx);
hmacCtx->digest->clone(&hmacCtx->innerHashCtx, &hmacCtx->currentHashCtx);
return noErr;
}
static OSStatus HMAC_Update(
HMACContextRef hmacCtx,
const void *data,
size_t dataLen)
{
SSLBuffer cdata = { dataLen, (uint8_t *)data };
if(hmacCtx == NULL)
return errSSLInternal;
assert(hmacCtx->digest != NULL);
hmacCtx->digest->update(&hmacCtx->currentHashCtx, &cdata);
return noErr;
}
static OSStatus HMAC_Final(
HMACContextRef hmacCtx,
void *hmac, size_t *hmacLen) {
uint8_t bytes[TLS_HMAC_MAX_SIZE];
SSLBuffer digest = { TLS_HMAC_MAX_SIZE, bytes };
SSLBuffer cdata;
if(hmacCtx == NULL) {
return errSSLInternal;
}
if((hmac == NULL) || (hmacLen == NULL)) {
return errSSLInternal;
}
assert(hmacCtx->digest != NULL);
assert(*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 noErr;
}
static OSStatus HMAC_Hmac (
HMACContextRef hmacCtx,
const void *data,
size_t dataLen,
void *hmac, size_t *hmacLen) {
OSStatus serr;
if(hmacCtx == NULL) {
return errSSLInternal;
}
serr = HMAC_Init(hmacCtx);
if(serr) {
return serr;
}
serr = HMAC_Update(hmacCtx, data, dataLen);
if(serr) {
return serr;
}
return HMAC_Final(hmacCtx, hmac, hmacLen);
}
#endif
#pragma mark -
#pragma mark Null HMAC
static OSStatus HMAC_AllocNull(
const struct HMACReference *hmac,
SSLContext *ctx,
const void *keyPtr,
size_t keyLen,
HMACContextRef *hmacCtx) {
*hmacCtx = NULL;
return noErr;
}
static OSStatus HMAC_FreeNull(
HMACContextRef hmacCtx)
{
return noErr;
}
static OSStatus HMAC_InitNull(
HMACContextRef hmacCtx)
{
return noErr;
}
static OSStatus HMAC_UpdateNull(
HMACContextRef hmacCtx,
const void *data,
size_t dataLen)
{
return noErr;
}
static OSStatus HMAC_FinalNull(
HMACContextRef hmacCtx,
void *hmac, size_t *hmacLen) {
return noErr;
}
static OSStatus HMAC_HmacNull (
HMACContextRef hmacCtx,
const void *data,
size_t dataLen,
void *hmac, size_t *hmacLen)
{
return noErr;
}
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
};
const HashHmacReference HashHmacNull = {
&SSLHashNull,
&TlsHmacNull
};
const HashHmacReference HashHmacMD5 = {
&SSLHashMD5,
&TlsHmacMD5
};
const HashHmacReference HashHmacSHA1 = {
&SSLHashSHA1,
&TlsHmacSHA1
};
const HashHmacReference HashHmacSHA256 = {
&SSLHashSHA256,
&TlsHmacSHA256
};
const HashHmacReference HashHmacSHA384 = {
&SSLHashSHA384,
&TlsHmacSHA384
};