Skip to content

Commit

Permalink
Centralize hmac code for writing and verifying results (#483)
Browse files Browse the repository at this point in the history
  • Loading branch information
lsh123 authored Feb 6, 2023
1 parent 03c1dfd commit acfd85c
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 299 deletions.
81 changes: 25 additions & 56 deletions src/gcrypt/hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct _xmlSecGCryptHmacCtx {
int digest;
gcry_md_hd_t digestCtx;
xmlSecByte dgst[XMLSEC_TRASNFORM_HMAC_MAX_OUTPUT_SIZE];
xmlSecSize dgstSize; /* dgst size in bits */
xmlSecSize dgstSizeInBits; /* dgst size in bits */
};

/******************************************************************************
Expand Down Expand Up @@ -126,6 +126,7 @@ xmlSecGCryptHmacCheckId(xmlSecTransformPtr transform) {
static int
xmlSecGCryptHmacInitialize(xmlSecTransformPtr transform) {
xmlSecGCryptHmacCtxPtr ctx;
xmlSecSize hmacSize;
gcry_error_t err;

xmlSecAssert2(xmlSecGCryptHmacCheckId(transform), -1);
Expand Down Expand Up @@ -178,6 +179,11 @@ xmlSecGCryptHmacInitialize(xmlSecTransformPtr transform) {
return(-1);
}

hmacSize = gcry_md_get_algo_dlen(ctx->digest);
xmlSecAssert2(hmacSize > 0, -1);
xmlSecAssert2(hmacSize <= XMLSEC_TRASNFORM_HMAC_MAX_OUTPUT_SIZE, -1);
ctx->dgstSizeInBits = 8 * hmacSize;

/* open context */
err = gcry_md_open(&ctx->digestCtx, ctx->digest, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE); /* we are paranoid */
if(err != GPG_ERR_NO_ERROR) {
Expand Down Expand Up @@ -222,12 +228,14 @@ xmlSecGCryptHmacNodeRead(xmlSecTransformPtr transform, xmlNodePtr node,
ctx = xmlSecGCryptHmacGetCtx(transform);
xmlSecAssert2(ctx != NULL, -1);

ret = xmlSecTransformHmacReadOutputBitsSize(node, ctx->dgstSize, &ctx->dgstSize);
ret = xmlSecTransformHmacReadOutputBitsSize(node, ctx->dgstSizeInBits, &ctx->dgstSizeInBits);
if (ret < 0) {
xmlSecInternalError("xmlSecTransformHmacReadOutputBitsSize()",
xmlSecTransformGetName(transform));
return(-1);
}
xmlSecAssert2(ctx->dgstSizeInBits > 0, -1);
xmlSecAssert2(XMLSEC_TRASNFORM_HMAC_BITS_TO_BYTES(ctx->dgstSizeInBits) < XMLSEC_TRASNFORM_HMAC_MAX_OUTPUT_SIZE, -1);

return(0);
}
Expand Down Expand Up @@ -297,11 +305,8 @@ static int
xmlSecGCryptHmacVerify(xmlSecTransformPtr transform,
const xmlSecByte* data, xmlSecSize dataSize,
xmlSecTransformCtxPtr transformCtx ATTRIBUTE_UNUSED) {
static xmlSecByte last_byte_masks[] =
{ 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };

xmlSecGCryptHmacCtxPtr ctx;
xmlSecByte mask;
int ret;

xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGCryptHmacSize), -1);
Expand All @@ -313,38 +318,21 @@ xmlSecGCryptHmacVerify(xmlSecTransformPtr transform,
ctx = xmlSecGCryptHmacGetCtx(transform);
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->digestCtx != NULL, -1);
xmlSecAssert2(ctx->dgstSize > 0, -1);

/* compare the digest size in bytes */
if(dataSize != ((ctx->dgstSize + 7) / 8)) {
xmlSecInvalidSizeError("HMAC digest size",
dataSize, ((ctx->dgstSize + 7) / 8),
xmlSecTransformGetName(transform));
transform->status = xmlSecTransformStatusFail;
return(0);
}
xmlSecAssert2(ctx->dgstSizeInBits > 0, -1);

/* we check the last byte separately */
xmlSecAssert2(dataSize > 0, -1);
mask = last_byte_masks[ctx->dgstSize % 8];
if((ctx->dgst[dataSize - 1] & mask) != (data[dataSize - 1] & mask)) {
xmlSecOtherError(XMLSEC_ERRORS_R_DATA_NOT_MATCH,
xmlSecTransformGetName(transform),
"data and digest do not match (last byte)");
transform->status = xmlSecTransformStatusFail;
return(0);
/* Returns 1 for match, 0 for no match, <0 for errors. */
ret = xmlSecTransformHmacVerify(data, dataSize, ctx->dgst, ctx->dgstSizeInBits, sizeof(ctx->dgst));
if(ret < 0) {
xmlSecInternalError("xmlSecTransformHmacVerify", xmlSecTransformGetName(transform));
return(-1);
}

/* now check the rest of the digest */
if((dataSize > 1) && (memcmp(ctx->dgst, data, dataSize - 1) != 0)) {
xmlSecOtherError(XMLSEC_ERRORS_R_DATA_NOT_MATCH,
xmlSecTransformGetName(transform),
"data and digest do not match");
if(ret == 1) {
transform->status = xmlSecTransformStatusOk;
} else {
transform->status = xmlSecTransformStatusFail;
return(0);
}

transform->status = xmlSecTransformStatusOk;
/* done */
return(0);
}

Expand All @@ -353,7 +341,6 @@ xmlSecGCryptHmacExecute(xmlSecTransformPtr transform, int last, xmlSecTransformC
xmlSecGCryptHmacCtxPtr ctx;
xmlSecBufferPtr in, out;
xmlSecByte* dgst;
xmlSecSize dgstSize;
int ret;

xmlSecAssert2(xmlSecGCryptHmacCheckId(transform), -1);
Expand Down Expand Up @@ -396,31 +383,13 @@ xmlSecGCryptHmacExecute(xmlSecTransformPtr transform, int last, xmlSecTransformC
xmlSecTransformGetName(transform));
return(-1);
}
memcpy(ctx->dgst, dgst, XMLSEC_TRASNFORM_HMAC_BITS_TO_BYTES(ctx->dgstSizeInBits));

/* copy it to our internal buffer */
dgstSize = gcry_md_get_algo_dlen(ctx->digest);
xmlSecAssert2(dgstSize > 0, -1);
xmlSecAssert2(dgstSize <= sizeof(ctx->dgst), -1);
memcpy(ctx->dgst, dgst, dgstSize);

/* check/set the result digest size */
if(ctx->dgstSize == 0) {
ctx->dgstSize = dgstSize * 8; /* no dgst size specified, use all we have */
} else if(ctx->dgstSize <= 8 * dgstSize) {
xmlSecSize adjustedDigestSize = ((ctx->dgstSize + 7) / 8); /* we need to truncate result digest */
XMLSEC_SAFE_CAST_SIZE_TO_UINT(adjustedDigestSize, dgstSize, return(-1), xmlSecTransformGetName(transform));
} else {
xmlSecInvalidSizeLessThanError("HMAC digest (bits)",
8 * dgstSize, ctx->dgstSize,
xmlSecTransformGetName(transform));
return(-1);
}

/* write results if needed */
if(transform->operation == xmlSecTransformOperationSign) {
ret = xmlSecBufferAppend(out, ctx->dgst, dgstSize);
ret = xmlSecTransformHmacWriteOutput(ctx->dgst, ctx->dgstSizeInBits, XMLSEC_TRASNFORM_HMAC_MAX_OUTPUT_SIZE, out);
if(ret < 0) {
xmlSecInternalError2("xmlSecBufferAppend", xmlSecTransformGetName(transform),
"size=" XMLSEC_SIZE_FMT, dgstSize);
xmlSecInternalError("xmlSecTransformHmacWriteOutput", xmlSecTransformGetName(transform));
return(-1);
}
}
Expand Down
56 changes: 15 additions & 41 deletions src/gnutls/hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ struct _xmlSecGnuTLSHmacCtx {
gnutls_hmac_hd_t hmac;
gnutls_mac_algorithm_t hmacAlgo;
xmlSecSize hmacSizeInBits;
xmlSecByte hmacOutput[XMLSEC_GNUTLS_MAX_DIGEST_SIZE];
xmlSecByte hmacOutput[XMLSEC_TRASNFORM_HMAC_MAX_OUTPUT_SIZE];
};

/******************************************************************************
Expand Down Expand Up @@ -158,7 +158,7 @@ xmlSecGnuTLSHmacInitialize(xmlSecTransformPtr transform) {
xmlSecGnuTLSError("gnutls_hmac_get_len", 0, NULL);
return(-1);
}
xmlSecAssert2(hmacSize < XMLSEC_GNUTLS_MAX_DIGEST_SIZE, -1);
xmlSecAssert2(hmacSize < XMLSEC_TRASNFORM_HMAC_MAX_OUTPUT_SIZE, -1);
ctx->hmacSizeInBits = 8 * hmacSize;

/* done */
Expand Down Expand Up @@ -204,7 +204,7 @@ xmlSecGnuTLSHmacNodeRead(xmlSecTransformPtr transform, xmlNodePtr node,
xmlSecTransformGetName(transform));
return(-1);
}
xmlSecAssert2((ctx->hmacSizeInBits + 7) / 8 <= XMLSEC_GNUTLS_MAX_DIGEST_SIZE, -1);
xmlSecAssert2(XMLSEC_TRASNFORM_HMAC_BITS_TO_BYTES(ctx->hmacSizeInBits) <= XMLSEC_TRASNFORM_HMAC_MAX_OUTPUT_SIZE, -1);

return(0);
}
Expand Down Expand Up @@ -277,11 +277,8 @@ static int
xmlSecGnuTLSHmacVerify(xmlSecTransformPtr transform,
const xmlSecByte* data, xmlSecSize dataSize,
xmlSecTransformCtxPtr transformCtx ATTRIBUTE_UNUSED) {
static xmlSecByte last_byte_masks[] =
{ 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };

xmlSecGnuTLSHmacCtxPtr ctx;
xmlSecByte mask;
int ret;

xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1);
Expand All @@ -294,36 +291,19 @@ xmlSecGnuTLSHmacVerify(xmlSecTransformPtr transform,
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->hmacSizeInBits > 0, -1);

/* compare the digest size in bytes */
if(dataSize != ((ctx->hmacSizeInBits + 7) / 8)){
xmlSecInvalidSizeError("HMAC digest",
dataSize, ((ctx->hmacSizeInBits + 7) / 8),
xmlSecTransformGetName(transform));
transform->status = xmlSecTransformStatusFail;
return(0);
}

/* we check the last byte separately */
xmlSecAssert2(dataSize > 0, -1);
mask = last_byte_masks[ctx->hmacSizeInBits % 8];
if((ctx->hmacOutput[dataSize - 1] & mask) != (data[dataSize - 1] & mask)) {
xmlSecOtherError(XMLSEC_ERRORS_R_DATA_NOT_MATCH,
xmlSecTransformGetName(transform),
"data and digest do not match (last byte)");
transform->status = xmlSecTransformStatusFail;
return(0);
/* Returns 1 for match, 0 for no match, <0 for errors. */
ret = xmlSecTransformHmacVerify(data, dataSize, ctx->hmacOutput, ctx->hmacSizeInBits, XMLSEC_TRASNFORM_HMAC_MAX_OUTPUT_SIZE);
if(ret < 0) {
xmlSecInternalError("xmlSecTransformHmacVerify", xmlSecTransformGetName(transform));
return(-1);
}

/* now check the rest of the digest */
if((dataSize > 1) && (memcmp(ctx->hmacOutput, data, dataSize - 1) != 0)) {
xmlSecOtherError(XMLSEC_ERRORS_R_DATA_NOT_MATCH,
xmlSecTransformGetName(transform),
"data and digest do not match");
if(ret == 1) {
transform->status = xmlSecTransformStatusOk;
} else {
transform->status = xmlSecTransformStatusFail;
return(0);
}

transform->status = xmlSecTransformStatusOk;
/* done */
return(0);
}

Expand Down Expand Up @@ -380,15 +360,9 @@ xmlSecGnuTLSHmacExecute(xmlSecTransformPtr transform, int last, xmlSecTransformC

/* write results if needed */
if(transform->operation == xmlSecTransformOperationSign) {
xmlSecSize hmacSize;

hmacSize = (ctx->hmacSizeInBits + 7) / 8;
xmlSecAssert2(hmacSize < XMLSEC_GNUTLS_MAX_DIGEST_SIZE, -1);

ret = xmlSecBufferAppend(out, ctx->hmacOutput, hmacSize);
ret = xmlSecTransformHmacWriteOutput(ctx->hmacOutput, ctx->hmacSizeInBits, XMLSEC_TRASNFORM_HMAC_MAX_OUTPUT_SIZE, out);
if(ret < 0) {
xmlSecInternalError2("xmlSecBufferAppend", xmlSecTransformGetName(transform),
"size=" XMLSEC_SIZE_FMT, hmacSize);
xmlSecInternalError("xmlSecTransformHmacWriteOutput", xmlSecTransformGetName(transform));
return(-1);
}
}
Expand Down
67 changes: 19 additions & 48 deletions src/mscng/hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ struct _xmlSecMSCngHmacCtx {
BCRYPT_ALG_HANDLE hAlg;
PBYTE hash;
DWORD hashLength;
/* truncation length in bits */
xmlSecSize dgstSize;
xmlSecSize dgstSizeInBits; /* truncation length in bits */
BCRYPT_HASH_HANDLE hHash;
};

Expand Down Expand Up @@ -187,7 +186,7 @@ xmlSecMSCngHmacNodeRead(xmlSecTransformPtr transform, xmlNodePtr node,
ctx = xmlSecMSCngHmacGetCtx(transform);
xmlSecAssert2(ctx != NULL, -1);

ret = xmlSecTransformHmacReadOutputBitsSize(node, ctx->dgstSize, &ctx->dgstSize);
ret = xmlSecTransformHmacReadOutputBitsSize(node, ctx->dgstSizeInBits, &ctx->dgstSizeInBits);
if (ret < 0) {
xmlSecInternalError("xmlSecTransformHmacReadOutputBitsSize()",
xmlSecTransformGetName(transform));
Expand Down Expand Up @@ -289,9 +288,9 @@ xmlSecMSCngHmacSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
return(-1);
}

if (ctx->dgstSize == 0) {
if (ctx->dgstSizeInBits == 0) {
/* no custom value is requested, then default to the full length */
ctx->dgstSize = ctx->hashLength * 8;
ctx->dgstSizeInBits = ctx->hashLength * 8;
}

ctx->initialized = 1;
Expand All @@ -302,10 +301,7 @@ static int
xmlSecMSCngHmacVerify(xmlSecTransformPtr transform, const xmlSecByte* data,
xmlSecSize dataSize, xmlSecTransformCtxPtr transformCtx ATTRIBUTE_UNUSED) {
xmlSecMSCngHmacCtxPtr ctx;
xmlSecSize truncationBytes;
static xmlSecByte lastByteMasks[] = { 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8,
0xFC, 0xFE };
xmlSecByte mask;
int ret;

xmlSecAssert2(xmlSecTransformIsValid(transform), -1);
xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCngHmacSize), -1);
Expand All @@ -317,41 +313,20 @@ xmlSecMSCngHmacVerify(xmlSecTransformPtr transform, const xmlSecByte* data,

ctx = xmlSecMSCngHmacGetCtx(transform);
xmlSecAssert2(ctx != NULL, -1);
xmlSecAssert2(ctx->dgstSize > 0, -1);

/* round up */
truncationBytes = (ctx->dgstSize + 7) / 8;
xmlSecAssert2(ctx->dgstSizeInBits > 0, -1);

/* compare the digest size in bytes */
if(dataSize != truncationBytes) {
xmlSecInvalidSizeError("HMAC digest",
dataSize, truncationBytes,
xmlSecTransformGetName(transform));
transform->status = xmlSecTransformStatusFail;
return(0);
/* Returns 1 for match, 0 for no match, <0 for errors. */
ret = xmlSecTransformHmacVerify(data, dataSize, ctx->hash, ctx->dgstSizeInBits, ctx->hashLength);
if (ret < 0) {
xmlSecInternalError("xmlSecTransformHmacVerify", xmlSecTransformGetName(transform));
return(-1);
}

/* we check the last byte separately as possibly not all bits should be
* compared */
mask = lastByteMasks[ctx->dgstSize % 8];
if((ctx->hash[dataSize - 1] & mask) != (data[dataSize - 1] & mask)) {
xmlSecOtherError(XMLSEC_ERRORS_R_DATA_NOT_MATCH,
xmlSecTransformGetName(transform),
"data and digest do not match (last byte)");
transform->status = xmlSecTransformStatusFail;
return(0);
if (ret == 1) {
transform->status = xmlSecTransformStatusOk;
}

/* now check the rest of the digest */
if((dataSize > 1) && (memcmp(ctx->hash, data, dataSize - 1) != 0)) {
xmlSecOtherError(XMLSEC_ERRORS_R_DATA_NOT_MATCH,
xmlSecTransformGetName(transform),
"data and digest do not match");
else {
transform->status = xmlSecTransformStatusFail;
return(0);
}

transform->status = xmlSecTransformStatusOk;
return(0);
}

Expand Down Expand Up @@ -414,15 +389,11 @@ xmlSecMSCngHmacExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCt
return(-1);
}

/* copy result to output */
if(transform->operation == xmlSecTransformOperationSign) {
/* round up */
xmlSecSize truncationBytes = (ctx->dgstSize + 7) / 8;

ret = xmlSecBufferAppend(out, ctx->hash, truncationBytes);
if(ret < 0) {
xmlSecInternalError2("xmlSecBufferAppend", xmlSecTransformGetName(transform),
"size=" XMLSEC_SIZE_FMT, truncationBytes);
/* write results if needed */
if (transform->operation == xmlSecTransformOperationSign) {
ret = xmlSecTransformHmacWriteOutput(ctx->hash, ctx->dgstSizeInBits, ctx->hashLength, out);
if (ret < 0) {
xmlSecInternalError("xmlSecTransformHmacWriteOutput", xmlSecTransformGetName(transform));
return(-1);
}
}
Expand Down
Loading

0 comments on commit acfd85c

Please sign in to comment.