/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* *ThisfileimplementsPKCS11ontopofourexistingsecuritymodules * *FormoreinformationaboutPKCS11SeePKCS11TokenIntefaceStandard. *Thisimplementationhastwoslots: *slot1isourgenericcryptosupport.Itdoesnotrequirelogin. *ItsupportsPublicKeyops,andalltheybulkciphersandhashes. *ItcanalsosupportPrivateKeyopsforimportedPrivatekeys.Itdoes *nothaveanytokenstorage. *slot2isourprivatekeysupport.Itrequiresaloginbeforeuse.It *canstorePrivateKeysandCertsastokenobjects.Currentlyonlyprivate *keysandtheirassociatedCertificatesaresavedonthetoken. * *Inthisimplementation,sessionobjectsareonlyvisibletothesession *thatcreatedorgeneratedthem.
*/ #include"seccomon.h" #include"secitem.h" #include"secport.h" #include"blapi.h" #include"pkcs11.h" #include"pkcs11i.h" #include"pkcs1sig.h" #include"lowkeyi.h" #include"secder.h" #include"secdig.h" #include"lowpbe.h"/* We do PBE below */ #include"pkcs11t.h" #include"secoid.h" #include"alghmac.h" #include"softoken.h" #include"secasn1.h" #include"secerr.h"
/* iv full of zeros used in several places in aes xcbc */ staticconstunsignedchar iv_zero[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* first make sure out input key is the correct length *rfc4434.Ifkeyisshorter,padwithzerostothe *theright.IfkeyislongernewKey=aes_xcbc(0,key,keyLen).
*/ if (keyLen < AES_BLOCK_SIZE) {
PORT_Memcpy(newKey, keyValue, keyLen);
PORT_Memset(&newKey[keyLen], 0, AES_BLOCK_SIZE - keyLen);
keyValue = newKey;
} elseif (keyLen > AES_BLOCK_SIZE) { /* calculate our new key = aes_xcbc(0, key, keyLen). Because the *keyaboveisfixed(0),wecanprecalculatek1,k2,andk3. *ifthiscodeeverneedstobemoregeneric(supportanyxcbc *functionratherthanjustaes,wewouldprobablywanttojust *recursehereusingourprffunctions.Thiswouldbesafebecause *therecursecasewouldhavekeyLen==blocksizeandthusskip *thisconditional.
*/
aes_context = AES_CreateContext(k1_0, iv_zero, NSS_AES_CBC,
PR_TRUE, AES_BLOCK_SIZE, AES_BLOCK_SIZE); /* we know the following loop will execute at least once */ while (keyLen > AES_BLOCK_SIZE) {
rv = AES_Encrypt(aes_context, newKey, &tmpLen, AES_BLOCK_SIZE,
keyValue, AES_BLOCK_SIZE); if (rv != SECSuccess) { goto fail;
}
keyValue += AES_BLOCK_SIZE;
keyLen -= AES_BLOCK_SIZE;
}
PORT_Memcpy(newKey, keyValue, keyLen);
sftk_xcbc_mac_pad(newKey, keyLen, AES_BLOCK_SIZE, k2_0, k3_0);
rv = AES_Encrypt(aes_context, newKey, &tmpLen, AES_BLOCK_SIZE,
newKey, AES_BLOCK_SIZE); if (rv != SECSuccess) { goto fail;
}
keyValue = newKey;
AES_DestroyContext(aes_context, PR_TRUE);
} /* the length of the key in keyValue is known to be AES_BLOCK_SIZE, *eitherbecauseitwasoninput,oritwasshorterandextended,or *becauseitwasmac'ddownusingaes_xcbc_prf.
*/
aes_context = AES_CreateContext(keyValue, iv_zero,
NSS_AES, PR_TRUE, AES_BLOCK_SIZE, AES_BLOCK_SIZE); if (aes_context == NULL) { goto fail;
}
rv = AES_Encrypt(aes_context, k1, &tmpLen, AES_BLOCK_SIZE,
k1data, sizeof(k1data)); if (rv != SECSuccess) { goto fail;
}
rv = AES_Encrypt(aes_context, k2, &tmpLen, AES_BLOCK_SIZE,
k2data, sizeof(k2data)); if (rv != SECSuccess) { goto fail;
}
rv = AES_Encrypt(aes_context, k3, &tmpLen, AES_BLOCK_SIZE,
k3data, sizeof(k3data)); if (rv != SECSuccess) { goto fail;
}
AES_DestroyContext(aes_context, PR_TRUE);
PORT_Memset(newKey, 0, AES_BLOCK_SIZE); return CKR_OK;
fail:
crv = sftk_MapCryptError(PORT_GetError()); if (aes_context) {
AES_DestroyContext(aes_context, PR_TRUE);
}
PORT_Memset(k1, 0, AES_BLOCK_SIZE);
PORT_Memset(k2, 0, AES_BLOCK_SIZE);
PORT_Memset(k3, 0, AES_BLOCK_SIZE);
PORT_Memset(newKey, 0, AES_BLOCK_SIZE); return crv;
}
/* encode the final pad block of aes xcbc, padBuf is modified */
CK_RV
sftk_xcbc_mac_pad(unsignedchar *padBuf, unsignedint bufLen, unsignedint blockSize, constunsignedchar *k2, constunsignedchar *k3)
{ unsignedint i; if (bufLen == blockSize) { for (i = 0; i < blockSize; i++) {
padBuf[i] ^= k2[i];
}
} else {
padBuf[bufLen++] = 0x80; for (i = bufLen; i < blockSize; i++) {
padBuf[i] = 0x00;
} for (i = 0; i < blockSize; i++) {
padBuf[i] ^= k3[i];
}
} return CKR_OK;
}
/* Map the mechanism to the underlying hash. If the type is not a hash *orHMAC,returnHASH_AlgNULL.Thiscanhappenlegitimatelyif
* we are doing AES XCBC */ static HASH_HashType
sftk_map_hmac_to_hash(CK_MECHANISM_TYPE type)
{ switch (type) { case CKM_SHA_1_HMAC: case CKM_SHA_1: return HASH_AlgSHA1; case CKM_MD5_HMAC: case CKM_MD5: return HASH_AlgMD5; case CKM_MD2_HMAC: case CKM_MD2: return HASH_AlgMD2; case CKM_SHA224_HMAC: case CKM_SHA224: return HASH_AlgSHA224; case CKM_SHA256_HMAC: case CKM_SHA256: return HASH_AlgSHA256; case CKM_SHA384_HMAC: case CKM_SHA384: return HASH_AlgSHA384; case CKM_SHA512_HMAC: case CKM_SHA512: return HASH_AlgSHA512;
} return HASH_AlgNULL;
}
/* return the underlying prf length for this context. This will
* function once the context is setup */ static CK_RV
prf_length(prfContext *context)
{ if (context->hashObj) { return context->hashObj->length;
} return AES_BLOCK_SIZE; /* AES */
}
/* set up the key for the prf. prf_update or prf_final should not be called if *prf_inithasnotbeencalledfirst.Onceprf_initreturnshmacand *aescontextsshouldsetandvalid.
*/ static CK_RV
prf_init(prfContext *context, constunsignedchar *keyValue, unsignedint keyLen)
{
CK_RV crv;
if (context->hmac) {
HMAC_Update(context->hmac, buf, len);
} else { /* AES MAC XCBC*/ /* We must keep the last block back so that it can be processed in *final.ThisiswhyweonlycheckthatnextChar+len>blocksize,
* rather than checking that nextChar + len >= blocksize */ while (context->nextChar + len > AES_BLOCK_SIZE) { if (context->nextChar != 0) { /* first handle fill in any partial blocks in the buffer */ unsignedint left = AES_BLOCK_SIZE - context->nextChar; /* note: left can be zero */
PORT_Memcpy(context->padBuf + context->nextChar, buf, left); /* NOTE: AES MAC XCBC xors the data with the previous block *Wedon'tdothatstepherebecauseourAES_Encryptmode
* is CBC, which does the xor automatically */
rv = AES_Encrypt(context->aes, context->macBuf, &tmpLen, sizeof(context->macBuf), context->padBuf, sizeof(context->padBuf)); if (rv != SECSuccess) { return sftk_MapCryptError(PORT_GetError());
}
context->nextChar = 0;
len -= left;
buf += left;
} else { /* optimization. if we have complete blocks to write out *(andwillstillhaveleftoverblocksforpadbufintheend). *wecanmacdirectlyoutofourbufferwithoutfirstcopying
* them to padBuf */
rv = AES_Encrypt(context->aes, context->macBuf, &tmpLen, sizeof(context->macBuf), buf, AES_BLOCK_SIZE); if (rv != SECSuccess) { return sftk_MapCryptError(PORT_GetError());
}
len -= AES_BLOCK_SIZE;
buf += AES_BLOCK_SIZE;
}
}
PORT_Memcpy(context->padBuf + context->nextChar, buf, len);
context->nextChar += len;
} return CKR_OK;
}
/* Bound the caller-supplied nonce lengths so that ulNiLen + ulNrLen can *neveroverfloworbetruncatedwhenstoredintheunsigned-int *newInKeySizeusedtosizetheNi||Nrconcatenationbufferbelow. *IKEnoncesareatmost256octets(RFC7296section2.10)andIKE *payloadlengthfieldsare16-bit,so0xffffisfaraboveany
* legitimate value. */ if (params->ulNiLen > 0xffff || params->ulNrLen > 0xffff) { return CKR_MECHANISM_PARAM_INVALID;
}
crv = prf_setup(&context, params->prfMechanism); if (crv != CKR_OK) { return crv;
}
macSize = prf_length(&context); if ((params->bDataAsKey) && (params->bRekey)) { return CKR_ARGUMENTS_BAD;
} if (params->bRekey) { /* lookup the value of new key from the session and key handle */
SFTKSession *session = sftk_SessionFromHandle(hSession); if (session == NULL) { return CKR_SESSION_HANDLE_INVALID;
}
newKeyObj = sftk_ObjectFromHandle(params->hNewKey, session);
sftk_FreeSession(session); if (newKeyObj == NULL) { return CKR_KEY_HANDLE_INVALID;
}
newKeyValue = sftk_FindAttribute(newKeyObj, CKA_VALUE); if (newKeyValue == NULL) {
crv = CKR_KEY_HANDLE_INVALID; goto fail;
}
} if (params->bDataAsKey) { /* The key is Ni || Np, so we need to concatenate them together first */
newInKeySize = params->ulNiLen + params->ulNrLen;
newInKey = PORT_Alloc(newInKeySize); if (newInKey == NULL) {
crv = CKR_HOST_MEMORY; goto fail;
}
PORT_Memcpy(newInKey, params->pNi, params->ulNiLen);
PORT_Memcpy(newInKey + params->ulNiLen, params->pNr, params->ulNrLen);
crv = prf_init(&context, newInKey, newInKeySize); if (crv != CKR_OK) { goto fail;
} /* key as the data */
crv = prf_update(&context, inKey->attrib.pValue,
inKey->attrib.ulValueLen); if (crv != CKR_OK) { goto fail;
}
} else { /* ikev1 isn't validated, if we use this function in ikev1 mode,
* mark the resulting key as not FIPS */ if (!params->bRekey) {
sftk_setFIPS(outKey, PR_FALSE);
}
if (params->ulExtraDataLen != 0) {
quickMode = PR_TRUE;
}
macSize = prf_length(&context);
if (keySize == 0) {
keySize = macSize;
}
/* In appendix B, we are just expanding or contracting a single key. *Iftheinputkeyislessthanorequaltothethekeysizewewant, *justsubsettheoriginalkey.Inquickmodeweareactuallygetting *newkeys(saltedwithourseeddataandourgxykey),sowewantto
* run through our algorithm */ if ((!quickMode) && (keySize <= inKey->attrib.ulValueLen)) { return sftk_forceAttribute(outKey, CKA_VALUE,
inKey->attrib.pValue, keySize);
}
outKeySize = PR_ROUNDUP(keySize, macSize); /* Reject if PR_ROUNDUP overflowed 32-bit unsigned arithmetic, which
* would yield an undersized allocation for the loop below. */ if (outKeySize < keySize) {
crv = CKR_KEY_SIZE_RANGE; goto fail;
}
outKeyData = PORT_Alloc(outKeySize); if (outKeyData == NULL) {
crv = CKR_HOST_MEMORY; goto fail;
}
/* *thisloopgeneratesonblockoftheprf,basically *kn=prf(key,Kn-1|[Keygxy]|[ExtraData]) *KnisthisKey,Kn-1islastKey *keyisinKey
*/
thisKey = outKeyData; for (genKeySize = 0; genKeySize < keySize; genKeySize += macSize) {
PRBool hashedData = PR_FALSE;
crv = prf_init(&context, inKey->attrib.pValue, inKey->attrib.ulValueLen); if (crv != CKR_OK) { goto fail;
} if (lastKey != NULL) {
crv = prf_update(&context, lastKey, macSize); if (crv != CKR_OK) { goto fail;
}
hashedData = PR_TRUE;
} if (gxyKeyValue != NULL) {
crv = prf_update(&context, gxyKeyValue->attrib.pValue,
gxyKeyValue->attrib.ulValueLen); if (crv != CKR_OK) { goto fail;
}
hashedData = PR_TRUE;
} if (params->ulExtraDataLen != 0) {
crv = prf_update(&context, params->pExtraData, params->ulExtraDataLen); if (crv != CKR_OK) { goto fail;
}
hashedData = PR_TRUE;
} /* if we haven't hashed anything yet, hash a zero */ if (hashedData == PR_FALSE) { constunsignedchar zero = 0;
crv = prf_update(&context, &zero, 1); if (crv != CKR_OK) { goto fail;
}
}
crv = prf_final(&context, thisKey, macSize); if (crv != CKR_OK) { goto fail;
}
lastKey = thisKey;
thisKey += macSize;
}
crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize);
fail: if (gxyKeyValue) {
sftk_FreeAttribute(gxyKeyValue);
} if (gxyKeyObj) {
sftk_FreeObject(gxyKeyObj);
} if (outKeyData) {
PORT_ZFree(outKeyData, outKeySize);
}
prf_free(&context); return crv;
}
/* *nowletscreateanobjecttohangtheattributesoffof
*/
key = sftk_NewObject(slot); /* fill in the handle later */ if (key == NULL) {
crv = CKR_HOST_MEMORY; goto fail;
}
/* make sure we don't have any class, key_type, or value fields */
sftk_DeleteAttributeType(key, CKA_CLASS);
sftk_DeleteAttributeType(key, CKA_KEY_TYPE);
sftk_DeleteAttributeType(key, CKA_VALUE);
sftk_DeleteAttributeType(key, CKA_SIGN);
/* Add the class, key_type, and value */
crv = sftk_AddAttributeType(key, CKA_CLASS, &objclass, sizeof(CK_OBJECT_CLASS)); if (crv != CKR_OK) { goto fail;
}
crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)); if (crv != CKR_OK) { goto fail;
}
crv = sftk_AddAttributeType(key, CKA_SIGN, &ck_true, sizeof(CK_BBOOL)); if (crv != CKR_OK) { goto fail;
}
crv = sftk_AddAttributeType(key, CKA_VALUE, buf, AES_BLOCK_SIZE); if (crv != CKR_OK) { goto fail;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.