/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/nss/kdf.c
1 164 строки
36 KB
lsh123
Fix doc build warnings (#1159)
07 май 2026, 01:12
Не верифицирован
07 май 2026, 01:12
52ab355
Код
Авторство
О чём код?
/** * XML Security Library (http://www.aleksey.com/xmlsec). * * This is free software; see the Copyright file in the source distribution for precise wording. * * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. */ /** * @addtogroup xmlsec_nss_crypto * @brief KDF (key derivation) transforms implementation for NSS. */ #include "globals.h" #include <stdint.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <pk11pub.h> #include <secoid.h> #include <xmlsec/xmlsec.h> #include <xmlsec/keys.h> #include <xmlsec/errors.h> #include <xmlsec/private.h> #include <xmlsec/xmltree.h> #include <xmlsec/nss/crypto.h> #include "../cast_helpers.h" #include "../transform_helpers.h" #include "private.h" #if !defined(XMLSEC_NO_PBKDF2) || !defined(XMLSEC_NO_CONCATKDF) || !defined(XMLSEC_NO_HKDF) /****************************************************************************** * * Internal KDF context * *****************************************************************************/ #define XMLSEC_NSS_KDF_DEFAULT_BUF_SIZE 64 #define XMLSEC_NSS_KDF_MAX_HASH_SIZE 64 typedef enum { xmlSecNssKdfType_Unknown = 0, xmlSecNssKdfType_ConcatKdf, xmlSecNssKdfType_Pbkdf2, xmlSecNssKdfType_Hkdf } xmlSecNssKdfType; typedef struct _xmlSecNssKdfCtx xmlSecNssKdfCtx, *xmlSecNssKdfCtxPtr; struct _xmlSecNssKdfCtx { xmlSecNssKdfType kdfType; xmlSecKeyDataId keyId; xmlSecBuffer key; union { struct { xmlSecTransformConcatKdfParams params; SECOidTag digestAlgo; xmlSecBuffer fixedInfo; } concatKdf; struct { xmlSecTransformPbkdf2Params params; SECOidTag hashAlgo; } pbkdf2; struct { xmlSecTransformHkdfParams params; CK_MECHANISM_TYPE hashMech; xmlSecBuffer salt; xmlSecBuffer info; } hkdf; } u; }; XMLSEC_TRANSFORM_DECLARE(NssKdf, xmlSecNssKdfCtx) #define xmlSecNssKdfCtxSize XMLSEC_TRANSFORM_SIZE(NssKdf) static int xmlSecNssKdfCheckId (xmlSecTransformPtr transform); static int xmlSecNssKdfInitialize (xmlSecTransformPtr transform); static void xmlSecNssKdfFinalize (xmlSecTransformPtr transform); static int xmlSecNssKdfSetKeyReq (xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq); static int xmlSecNssKdfSetKey (xmlSecTransformPtr transform, xmlSecKeyPtr key); static int xmlSecNssKdfExecute (xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx); #ifndef XMLSEC_NO_CONCATKDF static int xmlSecNssConcatKdfNodeRead (xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx); static int xmlSecNssConcatKdfGenerateKey (xmlSecNssKdfCtxPtr ctx, xmlSecSize outLen, xmlSecBufferPtr out); #endif /* XMLSEC_NO_CONCATKDF */ #ifndef XMLSEC_NO_PBKDF2 static int xmlSecNssPbkdf2NodeRead (xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx); static int xmlSecNssPbkdf2Derive (xmlSecNssKdfCtxPtr ctx, xmlSecBufferPtr out); #endif /* XMLSEC_NO_PBKDF2 */ #ifndef XMLSEC_NO_HKDF static int xmlSecNssHkdfNodeRead (xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx); static int xmlSecNssHkdfGenerateKey (xmlSecNssKdfCtxPtr ctx, xmlSecSize outLen, xmlSecBufferPtr out); #endif /* XMLSEC_NO_HKDF */ static int xmlSecNssKdfCheckId(xmlSecTransformPtr transform) { #ifndef XMLSEC_NO_CONCATKDF if(xmlSecTransformCheckId(transform, xmlSecNssTransformConcatKdfId)) { return(1); } else #endif /* XMLSEC_NO_CONCATKDF */ #ifndef XMLSEC_NO_PBKDF2 if(xmlSecTransformCheckId(transform, xmlSecNssTransformPbkdf2Id)) { return(1); } else #endif /* XMLSEC_NO_PBKDF2 */ #ifndef XMLSEC_NO_HKDF if(xmlSecTransformCheckId(transform, xmlSecNssTransformHkdfId)) { return(1); } else #endif /* XMLSEC_NO_HKDF */ { return(0); } } static int xmlSecNssKdfInitialize(xmlSecTransformPtr transform) { xmlSecNssKdfCtxPtr ctx; int ret; xmlSecAssert2(xmlSecNssKdfCheckId(transform), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKdfCtxSize), -1); ctx = xmlSecNssKdfGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); memset(ctx, 0, sizeof(xmlSecNssKdfCtx)); #ifndef XMLSEC_NO_CONCATKDF if(xmlSecTransformCheckId(transform, xmlSecNssTransformConcatKdfId)) { ctx->kdfType = xmlSecNssKdfType_ConcatKdf; ctx->keyId = xmlSecNssKeyDataConcatKdfId; ctx->u.concatKdf.digestAlgo = SEC_OID_UNKNOWN; } else #endif /* XMLSEC_NO_CONCATKDF */ #ifndef XMLSEC_NO_PBKDF2 if(xmlSecTransformCheckId(transform, xmlSecNssTransformPbkdf2Id)) { ctx->kdfType = xmlSecNssKdfType_Pbkdf2; ctx->keyId = xmlSecNssKeyDataPbkdf2Id; ctx->u.pbkdf2.hashAlgo = SEC_OID_UNKNOWN; } else #endif /* XMLSEC_NO_PBKDF2 */ #ifndef XMLSEC_NO_HKDF if(xmlSecTransformCheckId(transform, xmlSecNssTransformHkdfId)) { ctx->kdfType = xmlSecNssKdfType_Hkdf; ctx->keyId = xmlSecNssKeyDataHkdfId; ctx->u.hkdf.hashMech = CKM_INVALID_MECHANISM; } else #endif /* XMLSEC_NO_HKDF */ { xmlSecInvalidTransfromError(transform); return(-1); } ret = xmlSecBufferInitialize(&(ctx->key), XMLSEC_NSS_KDF_DEFAULT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(key)", NULL); xmlSecNssKdfFinalize(transform); return(-1); } if(0) { #ifndef XMLSEC_NO_CONCATKDF } else if(ctx->kdfType == xmlSecNssKdfType_ConcatKdf) { ret = xmlSecBufferInitialize(&(ctx->u.concatKdf.fixedInfo), XMLSEC_NSS_KDF_DEFAULT_BUF_SIZE); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(fixedInfo)", NULL); xmlSecNssKdfFinalize(transform); return(-1); } ret = xmlSecTransformConcatKdfParamsInitialize(&(ctx->u.concatKdf.params)); if(ret < 0) { xmlSecInternalError("xmlSecTransformConcatKdfParamsInitialize", NULL); xmlSecNssKdfFinalize(transform); return(-1); } #endif /* XMLSEC_NO_CONCATKDF */ #ifndef XMLSEC_NO_PBKDF2 } else if(ctx->kdfType == xmlSecNssKdfType_Pbkdf2) { ret = xmlSecTransformPbkdf2ParamsInitialize(&(ctx->u.pbkdf2.params)); if(ret < 0) { xmlSecInternalError("xmlSecTransformPbkdf2ParamsInitialize", NULL); xmlSecNssKdfFinalize(transform); return(-1); } #endif /* XMLSEC_NO_PBKDF2 */ #ifndef XMLSEC_NO_HKDF } else if(ctx->kdfType == xmlSecNssKdfType_Hkdf) { ret = xmlSecBufferInitialize(&(ctx->u.hkdf.salt), 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(salt)", NULL); xmlSecNssKdfFinalize(transform); return(-1); } ret = xmlSecBufferInitialize(&(ctx->u.hkdf.info), 0); if(ret < 0) { xmlSecInternalError("xmlSecBufferInitialize(info)", NULL); xmlSecNssKdfFinalize(transform); return(-1); } ret = xmlSecTransformHkdfParamsInitialize(&(ctx->u.hkdf.params)); if(ret < 0) { xmlSecInternalError("xmlSecTransformHkdfParamsInitialize", NULL); xmlSecNssKdfFinalize(transform); return(-1); } #endif /* XMLSEC_NO_HKDF */ } return(0); } static void xmlSecNssKdfFinalize(xmlSecTransformPtr transform) { xmlSecNssKdfCtxPtr ctx; xmlSecAssert(xmlSecNssKdfCheckId(transform)); xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssKdfCtxSize)); ctx = xmlSecNssKdfGetCtx(transform); xmlSecAssert(ctx != NULL); if(0) { #ifndef XMLSEC_NO_CONCATKDF } else if(ctx->kdfType == xmlSecNssKdfType_ConcatKdf) { xmlSecBufferFinalize(&(ctx->u.concatKdf.fixedInfo)); xmlSecTransformConcatKdfParamsFinalize(&(ctx->u.concatKdf.params)); #endif /* XMLSEC_NO_CONCATKDF */ #ifndef XMLSEC_NO_PBKDF2 } else if(ctx->kdfType == xmlSecNssKdfType_Pbkdf2) { xmlSecTransformPbkdf2ParamsFinalize(&(ctx->u.pbkdf2.params)); #endif /* XMLSEC_NO_PBKDF2 */ #ifndef XMLSEC_NO_HKDF } else if(ctx->kdfType == xmlSecNssKdfType_Hkdf) { xmlSecBufferFinalize(&(ctx->u.hkdf.salt)); xmlSecBufferFinalize(&(ctx->u.hkdf.info)); xmlSecTransformHkdfParamsFinalize(&(ctx->u.hkdf.params)); #endif /* XMLSEC_NO_HKDF */ } xmlSecBufferFinalize(&(ctx->key)); memset(ctx, 0, sizeof(xmlSecNssKdfCtx)); } static int xmlSecNssKdfSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { xmlSecNssKdfCtxPtr ctx; xmlSecAssert2(xmlSecNssKdfCheckId(transform), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKdfCtxSize), -1); xmlSecAssert2(keyReq != NULL, -1); ctx = xmlSecNssKdfGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->keyId != NULL, -1); keyReq->keyId = ctx->keyId; keyReq->keyType = xmlSecKeyDataTypeSymmetric; keyReq->keyUsage = xmlSecKeyUsageKeyDerive; return(0); } static int xmlSecNssKdfSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { xmlSecNssKdfCtxPtr ctx; xmlSecKeyDataPtr keyValue; xmlSecBufferPtr keyBuffer; xmlSecByte* keyData; xmlSecSize keySize; int ret; xmlSecAssert2(xmlSecNssKdfCheckId(transform), -1); xmlSecAssert2(((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt)), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKdfCtxSize), -1); xmlSecAssert2(key != NULL, -1); ctx = xmlSecNssKdfGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->keyId != NULL, -1); xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); keyValue = xmlSecKeyGetValue(key); xmlSecAssert2(keyValue != NULL, -1); keyBuffer = xmlSecKeyDataBinaryValueGetBuffer(keyValue); xmlSecAssert2(keyBuffer != NULL, -1); keyData = xmlSecBufferGetData(keyBuffer); keySize = xmlSecBufferGetSize(keyBuffer); if((keyData == NULL) || (keySize == 0)) { xmlSecInvalidZeroKeyDataSizeError(xmlSecTransformGetName(transform)); return(-1); } ret = xmlSecBufferSetData(&(ctx->key), keyData, keySize); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetData(key)", xmlSecTransformGetName(transform)); return(-1); } return(0); } #ifndef XMLSEC_NO_CONCATKDF static int xmlSecNssConcatKdfNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx XMLSEC_ATTRIBUTE_UNUSED) { xmlSecNssKdfCtxPtr ctx; xmlNodePtr cur; int ret; xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecNssTransformConcatKdfId), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKdfCtxSize), -1); xmlSecAssert2(node != NULL, -1); UNREFERENCED_PARAMETER(transformCtx); ctx = xmlSecNssKdfGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->kdfType == xmlSecNssKdfType_ConcatKdf, -1); cur = xmlSecGetNextElementNode(node->children); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeConcatKDFParams, xmlSecEnc11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodeConcatKDFParams, NULL); return(-1); } ret = xmlSecTransformConcatKdfParamsRead(&(ctx->u.concatKdf.params), cur); if(ret < 0) { xmlSecInternalError("xmlSecTransformConcatKdfParamsRead", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } ctx->u.concatKdf.digestAlgo = xmlSecNssGetDigestFromHref(ctx->u.concatKdf.params.digestMethod); if(ctx->u.concatKdf.digestAlgo == SEC_OID_UNKNOWN) { xmlSecInternalError("xmlSecNssGetDigestFromHref", xmlSecTransformGetName(transform)); return(-1); } ret = xmlSecTransformConcatKdfParamsGetFixedInfo(&(ctx->u.concatKdf.params), &(ctx->u.concatKdf.fixedInfo)); if(ret < 0) { xmlSecInternalError("xmlSecTransformConcatKdfParamsGetFixedInfo", xmlSecTransformGetName(transform)); return(-1); } return(0); } static int xmlSecNssConcatKdfGenerateKey(xmlSecNssKdfCtxPtr ctx, xmlSecSize outLen, xmlSecBufferPtr out) { xmlSecByte* keyData; xmlSecSize keySize; xmlSecByte* fixedInfoData; xmlSecSize fixedInfoSize; xmlSecByte* outData; SECOidData* oidData; unsigned int hashLen; xmlSecSize pos; xmlSecByte hashBuf[XMLSEC_NSS_KDF_MAX_HASH_SIZE]; xmlSecByte counter[4]; uint32_t counterVal; PK11Context* hashCtx; SECStatus rv; int ret; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->kdfType == xmlSecNssKdfType_ConcatKdf, -1); xmlSecAssert2(ctx->u.concatKdf.digestAlgo != SEC_OID_UNKNOWN, -1); xmlSecAssert2(outLen > 0, -1); xmlSecAssert2(out != NULL, -1); keyData = xmlSecBufferGetData(&(ctx->key)); keySize = xmlSecBufferGetSize(&(ctx->key)); if((keyData == NULL) || (keySize == 0)) { xmlSecInvalidZeroKeyDataSizeError(NULL); return(-1); } fixedInfoData = xmlSecBufferGetData(&(ctx->u.concatKdf.fixedInfo)); fixedInfoSize = xmlSecBufferGetSize(&(ctx->u.concatKdf.fixedInfo)); oidData = SECOID_FindOIDByTag(ctx->u.concatKdf.digestAlgo); if(oidData == NULL) { xmlSecNssError("SECOID_FindOIDByTag", NULL); return(-1); } ret = xmlSecBufferSetSize(out, outLen); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetSize", NULL, "size=" XMLSEC_SIZE_FMT, outLen); return(-1); } outData = xmlSecBufferGetData(out); xmlSecAssert2(outData != NULL, -1); pos = 0; counterVal = 1; while(pos < outLen) { counter[0] = (xmlSecByte)((counterVal >> 24) & 0xFF); counter[1] = (xmlSecByte)((counterVal >> 16) & 0xFF); counter[2] = (xmlSecByte)((counterVal >> 8) & 0xFF); counter[3] = (xmlSecByte)(counterVal & 0xFF); hashCtx = PK11_CreateDigestContext(oidData->offset); if(hashCtx == NULL) { xmlSecNssError("PK11_CreateDigestContext", NULL); return(-1); } rv = PK11_DigestBegin(hashCtx); if(rv != SECSuccess) { xmlSecNssError("PK11_DigestBegin", NULL); PK11_DestroyContext(hashCtx, PR_TRUE); return(-1); } rv = PK11_DigestOp(hashCtx, counter, 4); if(rv != SECSuccess) { xmlSecNssError("PK11_DigestOp(counter)", NULL); PK11_DestroyContext(hashCtx, PR_TRUE); return(-1); } XMLSEC_SAFE_CAST_SIZE_TO_UINT(keySize, hashLen, PK11_DestroyContext(hashCtx, PR_TRUE); return(-1), NULL); rv = PK11_DigestOp(hashCtx, keyData, hashLen); if(rv != SECSuccess) { xmlSecNssError("PK11_DigestOp(Z)", NULL); PK11_DestroyContext(hashCtx, PR_TRUE); return(-1); } if((fixedInfoData != NULL) && (fixedInfoSize > 0)) { unsigned int fixedInfoLen; XMLSEC_SAFE_CAST_SIZE_TO_UINT(fixedInfoSize, fixedInfoLen, PK11_DestroyContext(hashCtx, PR_TRUE); return(-1), NULL); rv = PK11_DigestOp(hashCtx, fixedInfoData, fixedInfoLen); if(rv != SECSuccess) { xmlSecNssError("PK11_DigestOp(OtherInfo)", NULL); PK11_DestroyContext(hashCtx, PR_TRUE); return(-1); } } hashLen = XMLSEC_NSS_KDF_MAX_HASH_SIZE; rv = PK11_DigestFinal(hashCtx, hashBuf, &hashLen, XMLSEC_NSS_KDF_MAX_HASH_SIZE); PK11_DestroyContext(hashCtx, PR_TRUE); if(rv != SECSuccess) { xmlSecNssError("PK11_DigestFinal", NULL); return(-1); } { xmlSecSize toCopy; toCopy = outLen - pos; if(toCopy > (xmlSecSize)hashLen) { toCopy = (xmlSecSize)hashLen; } memcpy(outData + pos, hashBuf, toCopy); pos += toCopy; } counterVal++; } memset(hashBuf, 0, sizeof(hashBuf)); return(0); } #endif /* XMLSEC_NO_CONCATKDF */ #ifndef XMLSEC_NO_PBKDF2 static SECOidTag xmlSecNssPbkdf2GetMacFromHref(const xmlChar* href) { if(href == NULL) { #ifndef XMLSEC_NO_SHA256 return(SEC_OID_HMAC_SHA256); #else /* XMLSEC_NO_SHA256 */ xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_ALGORITHM, NULL, "SHA256 is disabled; href=%s", xmlSecErrorsSafeString(href)); return(SEC_OID_UNKNOWN); #endif /* XMLSEC_NO_SHA256 */ } else #ifndef XMLSEC_NO_SHA1 if(xmlStrcmp(href, xmlSecHrefHmacSha1) == 0) { return(SEC_OID_HMAC_SHA1); } else #endif /* XMLSEC_NO_SHA1 */ #ifndef XMLSEC_NO_SHA224 if(xmlStrcmp(href, xmlSecHrefHmacSha224) == 0) { return(SEC_OID_HMAC_SHA224); } else #endif /* XMLSEC_NO_SHA224 */ #ifndef XMLSEC_NO_SHA256 if(xmlStrcmp(href, xmlSecHrefHmacSha256) == 0) { return(SEC_OID_HMAC_SHA256); } else #endif /* XMLSEC_NO_SHA256 */ #ifndef XMLSEC_NO_SHA384 if(xmlStrcmp(href, xmlSecHrefHmacSha384) == 0) { return(SEC_OID_HMAC_SHA384); } else #endif /* XMLSEC_NO_SHA384 */ #ifndef XMLSEC_NO_SHA512 if(xmlStrcmp(href, xmlSecHrefHmacSha512) == 0) { return(SEC_OID_HMAC_SHA512); } else #endif /* XMLSEC_NO_SHA512 */ { xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_ALGORITHM, NULL, "href=%s", xmlSecErrorsSafeString(href)); return(SEC_OID_UNKNOWN); } } static int xmlSecNssPbkdf2NodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx XMLSEC_ATTRIBUTE_UNUSED) { xmlSecNssKdfCtxPtr ctx; xmlNodePtr cur; int ret; xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecNssTransformPbkdf2Id), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKdfCtxSize), -1); xmlSecAssert2(node != NULL, -1); UNREFERENCED_PARAMETER(transformCtx); ctx = xmlSecNssKdfGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->kdfType == xmlSecNssKdfType_Pbkdf2, -1); cur = xmlSecGetNextElementNode(node->children); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodePbkdf2Params, xmlSecEnc11Ns))) { xmlSecInvalidNodeError(cur, xmlSecNodePbkdf2Params, NULL); return(-1); } ret = xmlSecTransformPbkdf2ParamsRead(&(ctx->u.pbkdf2.params), cur); if(ret < 0) { xmlSecInternalError("xmlSecTransformPbkdf2ParamsRead", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } ctx->u.pbkdf2.hashAlgo = xmlSecNssPbkdf2GetMacFromHref(ctx->u.pbkdf2.params.prfAlgorithmHref); if(ctx->u.pbkdf2.hashAlgo == SEC_OID_UNKNOWN) { xmlSecInternalError("xmlSecNssPbkdf2GetMacFromHref", xmlSecTransformGetName(transform)); return(-1); } return(0); } static int xmlSecNssPbkdf2Derive(xmlSecNssKdfCtxPtr ctx, xmlSecBufferPtr out) { SECItem passItem = { siBuffer, NULL, 0 }; SECItem saltItem = { siBuffer, NULL, 0 }; xmlSecSize size; xmlSecSize actualSize; xmlSecSize expectedSize; int keyLength; int iterCount; SECAlgorithmID* pbkdf2AlgId = NULL; PK11SlotInfo* slot = NULL; PK11SymKey* symKey = NULL; SECItem* keyItem; SECStatus rv; int ret; int res = -1; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->kdfType == xmlSecNssKdfType_Pbkdf2, -1); xmlSecAssert2(ctx->u.pbkdf2.hashAlgo != SEC_OID_UNKNOWN, -1); xmlSecAssert2(ctx->u.pbkdf2.params.keyLength > 0, -1); xmlSecAssert2(out != NULL, -1); size = xmlSecBufferGetSize(&(ctx->key)); XMLSEC_SAFE_CAST_SIZE_TO_UINT(size, passItem.len, goto done, NULL); passItem.data = xmlSecBufferGetData(&(ctx->key)); xmlSecAssert2(passItem.data != NULL, -1); xmlSecAssert2(passItem.len > 0, -1); size = xmlSecBufferGetSize(&(ctx->u.pbkdf2.params.salt)); XMLSEC_SAFE_CAST_SIZE_TO_UINT(size, saltItem.len, goto done, NULL); saltItem.data = xmlSecBufferGetData(&(ctx->u.pbkdf2.params.salt)); xmlSecAssert2(saltItem.data != NULL, -1); xmlSecAssert2(saltItem.len > 0, -1); XMLSEC_SAFE_CAST_SIZE_TO_INT(ctx->u.pbkdf2.params.iterationCount, iterCount, goto done, NULL); xmlSecAssert2(iterCount > 0, -1); XMLSEC_SAFE_CAST_SIZE_TO_INT(ctx->u.pbkdf2.params.keyLength, keyLength, goto done, NULL); xmlSecAssert2(keyLength > 0, -1); pbkdf2AlgId = PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, ctx->u.pbkdf2.hashAlgo, ctx->u.pbkdf2.hashAlgo, keyLength, iterCount, &saltItem); if(pbkdf2AlgId == NULL) { xmlSecNssError("PK11_CreatePBEV2AlgorithmID", NULL); goto done; } slot = PK11_GetInternalSlot(); if(slot == NULL) { xmlSecNssError("PK11_GetInternalSlot", NULL); goto done; } symKey = PK11_PBEKeyGen(slot, pbkdf2AlgId, &passItem, PR_FALSE, NULL); if(symKey == NULL) { xmlSecNssError("PK11_PBEKeyGen", NULL); goto done; } rv = PK11_ExtractKeyValue(symKey); if(rv != SECSuccess) { xmlSecNssError("PK11_ExtractKeyValue", NULL); goto done; } keyItem = PK11_GetKeyData(symKey); if(keyItem == NULL) { xmlSecNssError("PK11_GetKeyData", NULL); goto done; } XMLSEC_SAFE_CAST_INT_TO_SIZE(keyLength, expectedSize, goto done, NULL); XMLSEC_SAFE_CAST_UINT_TO_SIZE(keyItem->len, actualSize, goto done, NULL); if(actualSize != expectedSize) { xmlSecInvalidSizeError("PBKDF2 output size doesn't match expected", actualSize, expectedSize, NULL); goto done; } ret = xmlSecBufferSetData(out, keyItem->data, keyItem->len); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetData", NULL, "size=%u", keyItem->len); goto done; } res = 0; done: if(symKey != NULL) { PK11_FreeSymKey(symKey); } if(slot != NULL) { PK11_FreeSlot(slot); } if(pbkdf2AlgId != NULL) { SECOID_DestroyAlgorithmID(pbkdf2AlgId, PR_TRUE); } return(res); } #endif /* XMLSEC_NO_PBKDF2 */ #ifndef XMLSEC_NO_HKDF static CK_MECHANISM_TYPE xmlSecNssHkdfGetHashMechFromHref(const xmlChar* href) { if(href == NULL) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_ALGORITHM, NULL, "HKDF PRF algorithm is required"); return(CKM_INVALID_MECHANISM); } else #ifndef XMLSEC_NO_SHA1 if(xmlStrcmp(href, xmlSecHrefHmacSha1) == 0) { return(CKM_SHA_1); } else #endif /* XMLSEC_NO_SHA1 */ #ifndef XMLSEC_NO_SHA224 if(xmlStrcmp(href, xmlSecHrefHmacSha224) == 0) { return(CKM_SHA224); } else #endif /* XMLSEC_NO_SHA224 */ #ifndef XMLSEC_NO_SHA256 if(xmlStrcmp(href, xmlSecHrefHmacSha256) == 0) { return(CKM_SHA256); } else #endif /* XMLSEC_NO_SHA256 */ #ifndef XMLSEC_NO_SHA384 if(xmlStrcmp(href, xmlSecHrefHmacSha384) == 0) { return(CKM_SHA384); } else #endif /* XMLSEC_NO_SHA384 */ #ifndef XMLSEC_NO_SHA512 if(xmlStrcmp(href, xmlSecHrefHmacSha512) == 0) { return(CKM_SHA512); } else #endif /* XMLSEC_NO_SHA512 */ { xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_ALGORITHM, NULL, "href=%s", xmlSecErrorsSafeString(href)); return(CKM_INVALID_MECHANISM); } } static int xmlSecNssHkdfNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx XMLSEC_ATTRIBUTE_UNUSED) { xmlSecNssKdfCtxPtr ctx; xmlNodePtr cur; int ret; xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecNssTransformHkdfId), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKdfCtxSize), -1); xmlSecAssert2(node != NULL, -1); UNREFERENCED_PARAMETER(transformCtx); ctx = xmlSecNssKdfGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->kdfType == xmlSecNssKdfType_Hkdf, -1); cur = xmlSecGetNextElementNode(node->children); if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeHkdfParams, xmlSecXmldsig2021MoreNs))) { xmlSecInvalidNodeError(cur, xmlSecNodeHkdfParams, NULL); return(-1); } ret = xmlSecTransformHkdfParamsRead(&(ctx->u.hkdf.params), cur); if(ret < 0) { xmlSecInternalError("xmlSecTransformHkdfParamsRead", NULL); return(-1); } cur = xmlSecGetNextElementNode(cur->next); if(cur != NULL) { xmlSecUnexpectedNodeError(cur, NULL); return(-1); } ctx->u.hkdf.hashMech = xmlSecNssHkdfGetHashMechFromHref(ctx->u.hkdf.params.prfAlgorithmHref); if(ctx->u.hkdf.hashMech == CKM_INVALID_MECHANISM) { xmlSecInternalError("xmlSecNssHkdfGetHashMechFromHref", xmlSecTransformGetName(transform)); return(-1); } if(xmlSecBufferGetSize(&(ctx->u.hkdf.params.salt)) > 0) { ret = xmlSecBufferSetData(&(ctx->u.hkdf.salt), xmlSecBufferGetData(&(ctx->u.hkdf.params.salt)), xmlSecBufferGetSize(&(ctx->u.hkdf.params.salt))); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetData(salt)", xmlSecTransformGetName(transform)); return(-1); } } if(xmlSecBufferGetSize(&(ctx->u.hkdf.params.info)) > 0) { ret = xmlSecBufferSetData(&(ctx->u.hkdf.info), xmlSecBufferGetData(&(ctx->u.hkdf.params.info)), xmlSecBufferGetSize(&(ctx->u.hkdf.params.info))); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetData(info)", xmlSecTransformGetName(transform)); return(-1); } } return(0); } static int xmlSecNssHkdfGenerateKey(xmlSecNssKdfCtxPtr ctx, xmlSecSize outLen, xmlSecBufferPtr out) { SECItem ikmItem = { siBuffer, NULL, 0 }; SECItem paramsItem = { siBuffer, NULL, 0 }; CK_HKDF_PARAMS params; xmlSecByte* keyData; xmlSecSize keySize; xmlSecByte* saltData; xmlSecSize saltSize; xmlSecByte* infoData; xmlSecSize infoSize; PK11SlotInfo* slot = NULL; PK11SymKey* ikm = NULL; PK11SymKey* derived = NULL; SECItem* rawKey = NULL; SECStatus rv; xmlSecSize actualSize; int outputLen; int ret; int res = -1; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->kdfType == xmlSecNssKdfType_Hkdf, -1); xmlSecAssert2(ctx->u.hkdf.hashMech != CKM_INVALID_MECHANISM, -1); xmlSecAssert2(outLen > 0, -1); xmlSecAssert2(out != NULL, -1); keyData = xmlSecBufferGetData(&(ctx->key)); keySize = xmlSecBufferGetSize(&(ctx->key)); if((keyData == NULL) || (keySize == 0)) { xmlSecInvalidZeroKeyDataSizeError(NULL); return(-1); } XMLSEC_SAFE_CAST_SIZE_TO_UINT(keySize, ikmItem.len, goto done, NULL); ikmItem.data = keyData; saltData = xmlSecBufferGetData(&(ctx->u.hkdf.salt)); saltSize = xmlSecBufferGetSize(&(ctx->u.hkdf.salt)); infoData = xmlSecBufferGetData(&(ctx->u.hkdf.info)); infoSize = xmlSecBufferGetSize(&(ctx->u.hkdf.info)); memset(¶ms, 0, sizeof(params)); params.bExtract = CK_TRUE; params.bExpand = CK_TRUE; params.prfHashMechanism = ctx->u.hkdf.hashMech; params.hSaltKey = CK_INVALID_HANDLE; if((saltData != NULL) && (saltSize > 0)) { params.ulSaltType = CKF_HKDF_SALT_DATA; params.pSalt = saltData; XMLSEC_SAFE_CAST_SIZE_TO_ULONG(saltSize, params.ulSaltLen, goto done, NULL); } else { params.ulSaltType = CKF_HKDF_SALT_NULL; params.pSalt = NULL; params.ulSaltLen = 0; } if((infoData != NULL) && (infoSize > 0)) { params.pInfo = infoData; XMLSEC_SAFE_CAST_SIZE_TO_ULONG(infoSize, params.ulInfoLen, goto done, NULL); } else { params.pInfo = NULL; params.ulInfoLen = 0; } paramsItem.data = (unsigned char*)¶ms; XMLSEC_SAFE_CAST_SIZE_TO_UINT(sizeof(params), paramsItem.len, goto done, NULL); slot = PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL); if(slot == NULL) { xmlSecNssError("PK11_GetBestSlot", NULL); goto done; } ikm = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap, CKA_DERIVE, &ikmItem, NULL); if(ikm == NULL) { xmlSecNssError("PK11_ImportDataKey", NULL); goto done; } XMLSEC_SAFE_CAST_SIZE_TO_INT(outLen, outputLen, goto done, NULL); derived = PK11_DeriveWithFlags(ikm, CKM_HKDF_DATA, ¶msItem, CKM_HKDF_DERIVE, CKA_DERIVE, outputLen, CKF_SIGN | CKF_VERIFY); if(derived == NULL) { xmlSecNssError("PK11_DeriveWithFlags", NULL); goto done; } rv = PK11_ExtractKeyValue(derived); if(rv != SECSuccess) { xmlSecNssError("PK11_ExtractKeyValue", NULL); goto done; } rawKey = PK11_GetKeyData(derived); if(rawKey == NULL) { xmlSecNssError("PK11_GetKeyData", NULL); goto done; } XMLSEC_SAFE_CAST_UINT_TO_SIZE(rawKey->len, actualSize, goto done, NULL); if(actualSize != outLen) { xmlSecInvalidSizeError("HKDF output size doesn't match expected", actualSize, outLen, NULL); goto done; } ret = xmlSecBufferSetData(out, rawKey->data, rawKey->len); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetData", NULL, "size=%u", rawKey->len); goto done; } res = 0; done: if(derived != NULL) { PK11_FreeSymKey(derived); } if(ikm != NULL) { PK11_FreeSymKey(ikm); } if(slot != NULL) { PK11_FreeSlot(slot); } return(res); } #endif /* XMLSEC_NO_HKDF */ static int xmlSecNssKdfExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { xmlSecNssKdfCtxPtr ctx; xmlSecBufferPtr in; xmlSecBufferPtr out; int ret; xmlSecAssert2(xmlSecTransformIsValid(transform), -1); xmlSecAssert2(((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt)), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKdfCtxSize), -1); xmlSecAssert2(transformCtx != NULL, -1); in = &(transform->inBuf); out = &(transform->outBuf); ctx = xmlSecNssKdfGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); if(transform->status == xmlSecTransformStatusNone) { transform->status = xmlSecTransformStatusWorking; } if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) { return(0); } if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { if(transform->expectedOutputSize <= 0) { xmlSecOtherError(XMLSEC_ERRORS_R_INVALID_ALGORITHM, NULL, "KDF output key size is not specified"); return(-1); } if(0) { #ifndef XMLSEC_NO_CONCATKDF } else if(ctx->kdfType == xmlSecNssKdfType_ConcatKdf) { ret = xmlSecNssConcatKdfGenerateKey(ctx, transform->expectedOutputSize, out); if(ret < 0) { xmlSecInternalError("xmlSecNssConcatKdfGenerateKey", xmlSecTransformGetName(transform)); return(-1); } #endif /* XMLSEC_NO_CONCATKDF */ #ifndef XMLSEC_NO_PBKDF2 } else if(ctx->kdfType == xmlSecNssKdfType_Pbkdf2) { if((ctx->u.pbkdf2.params.keyLength > 0) && (ctx->u.pbkdf2.params.keyLength != transform->expectedOutputSize)) { xmlSecInvalidSizeError("Output kdf size doesn't match expected", transform->expectedOutputSize, ctx->u.pbkdf2.params.keyLength, xmlSecTransformGetName(transform)); return(-1); } ctx->u.pbkdf2.params.keyLength = transform->expectedOutputSize; ret = xmlSecNssPbkdf2Derive(ctx, out); if(ret < 0) { xmlSecInternalError("xmlSecNssPbkdf2Derive", xmlSecTransformGetName(transform)); return(-1); } #endif /* XMLSEC_NO_PBKDF2 */ #ifndef XMLSEC_NO_HKDF } else if(ctx->kdfType == xmlSecNssKdfType_Hkdf) { if((ctx->u.hkdf.params.keyLength > 0) && (ctx->u.hkdf.params.keyLength != transform->expectedOutputSize)) { xmlSecInvalidSizeError("Output kdf size doesn't match expected", transform->expectedOutputSize, ctx->u.hkdf.params.keyLength, xmlSecTransformGetName(transform)); return(-1); } ctx->u.hkdf.params.keyLength = transform->expectedOutputSize; ret = xmlSecNssHkdfGenerateKey(ctx, transform->expectedOutputSize, out); if(ret < 0) { xmlSecInternalError("xmlSecNssHkdfGenerateKey", xmlSecTransformGetName(transform)); return(-1); } #endif /* XMLSEC_NO_HKDF */ } else { xmlSecInvalidTransfromError(transform); return(-1); } transform->status = xmlSecTransformStatusFinished; return(0); } if(transform->status == xmlSecTransformStatusFinished) { xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); return(0); } xmlSecInvalidTransfromStatusError(transform); return(-1); } #ifndef XMLSEC_NO_CONCATKDF static xmlSecTransformKlass xmlSecNssConcatKdfKlass = { sizeof(xmlSecTransformKlass), xmlSecNssKdfCtxSize, xmlSecNameConcatKdf, xmlSecHrefConcatKdf, xmlSecTransformUsageKeyDerivationMethod, xmlSecNssKdfInitialize, xmlSecNssKdfFinalize, xmlSecNssConcatKdfNodeRead, NULL, xmlSecNssKdfSetKeyReq, xmlSecNssKdfSetKey, NULL, xmlSecTransformDefaultGetDataType, xmlSecTransformDefaultPushBin, xmlSecTransformDefaultPopBin, NULL, NULL, xmlSecNssKdfExecute, NULL, NULL, }; /** * @brief The ConcatKDF key derivation transform klass. * @return the ConcatKDF key derivation transform klass. */ xmlSecTransformId xmlSecNssTransformConcatKdfGetKlass(void) { return(&xmlSecNssConcatKdfKlass); } #endif /* XMLSEC_NO_CONCATKDF */ #ifndef XMLSEC_NO_PBKDF2 static xmlSecTransformKlass xmlSecNssPbkdf2Klass = { sizeof(xmlSecTransformKlass), xmlSecNssKdfCtxSize, xmlSecNamePbkdf2, xmlSecHrefPbkdf2, xmlSecTransformUsageKeyDerivationMethod, xmlSecNssKdfInitialize, xmlSecNssKdfFinalize, xmlSecNssPbkdf2NodeRead, NULL, xmlSecNssKdfSetKeyReq, xmlSecNssKdfSetKey, NULL, xmlSecTransformDefaultGetDataType, xmlSecTransformDefaultPushBin, xmlSecTransformDefaultPopBin, NULL, NULL, xmlSecNssKdfExecute, NULL, NULL, }; /** * @brief The PBKDF2 key derivation transform klass. * @return the PBKDF2 key derivation transform klass. */ xmlSecTransformId xmlSecNssTransformPbkdf2GetKlass(void) { return(&xmlSecNssPbkdf2Klass); } #endif /* XMLSEC_NO_PBKDF2 */ #ifndef XMLSEC_NO_HKDF static xmlSecTransformKlass xmlSecNssHkdfKlass = { sizeof(xmlSecTransformKlass), xmlSecNssKdfCtxSize, xmlSecNameHkdf, xmlSecHrefHkdf, xmlSecTransformUsageKeyDerivationMethod, xmlSecNssKdfInitialize, xmlSecNssKdfFinalize, xmlSecNssHkdfNodeRead, NULL, xmlSecNssKdfSetKeyReq, xmlSecNssKdfSetKey, NULL, xmlSecTransformDefaultGetDataType, xmlSecTransformDefaultPushBin, xmlSecTransformDefaultPopBin, NULL, NULL, xmlSecNssKdfExecute, NULL, NULL, }; /** * @brief The HKDF key derivation transform klass. * @return pointer to HKDF key derivation transform klass. */ xmlSecTransformId xmlSecNssTransformHkdfGetKlass(void) { return(&xmlSecNssHkdfKlass); } #endif /* XMLSEC_NO_HKDF */ #else typedef int make_iso_compilers_happy; #endif /* !defined(XMLSEC_NO_PBKDF2) || !defined(XMLSEC_NO_CONCATKDF) || !defined(XMLSEC_NO_HKDF) */