/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* * NSS_CMSUtil_EncryptSymKey_RSA - wrap a symmetric key with RSA * * this function takes a symmetric key and encrypts it using an RSA public key * according to PKCS#1 and RFC2633 (S/MIME)
*/
SECStatus
NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert,
PK11SymKey *bulkkey,
SECItem *encKey)
{
SECStatus rv;
SECKEYPublicKey *publickey;
publickey = CERT_ExtractPublicKey(cert); if (publickey == NULL) return SECFailure;
/* * NSS_CMSUtil_DecryptSymKey_RSA_OAEP - unwrap a RSA-wrapped symmetric key * * this function takes an RSA-OAEP-wrapped symmetric key and unwraps it, returning a symmetric * key handle. Please note that the actual unwrapped key data may not be allowed to leave * a hardware token...
*/
PK11SymKey *
NSS_CMSUtil_DecryptSymKey_RSA_OAEP(SECKEYPrivateKey *privkey, SECItem *parameters, SECItem *encKey, SECOidTag bulkalgtag)
{
CK_RSA_PKCS_OAEP_PARAMS oaep_params;
RSA_OAEP_CMS_params encoded_params;
SECAlgorithmID mgf1hashAlg;
SECOidTag mgfAlgtag, pSourcetag;
SECItem encoding_params, params;
PK11SymKey *bulkkey = NULL;
SECStatus rv;
/* Set default values for the OAEP parameters */
oaep_params.hashAlg = CKM_SHA_1;
oaep_params.mgf = CKG_MGF1_SHA1;
oaep_params.source = CKZ_DATA_SPECIFIED;
oaep_params.pSourceData = NULL;
oaep_params.ulSourceDataLen = 0;
if (parameters->len == 2) { /* For some reason SEC_ASN1DecodeItem cannot process parameters if it is an emtpy SEQUENCE */ /* Just check that this is a properly encoded empty SEQUENCE */ /* TODO: Investigate if there a better way to handle this as part of decoding. */ if ((parameters->data[0] != 0x30) || (parameters->data[1] != 0)) { return NULL;
}
} else {
rv = SEC_ASN1DecodeItem(NULL, &encoded_params, RSA_OAEP_CMS_paramsTemplate, parameters); if (rv != SECSuccess) { goto loser;
} if (encoded_params.hashFunc != NULL) {
oaep_params.hashAlg = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(encoded_params.hashFunc));
} if (encoded_params.maskGenFunc != NULL) {
mgfAlgtag = SECOID_GetAlgorithmTag(encoded_params.maskGenFunc); if (mgfAlgtag != SEC_OID_PKCS1_MGF1) { /* MGF1 is the only supported mask generation function */ goto loser;
} /* The parameters field contains an AlgorithmIdentifier specifying the * hash function to use with MGF1.
*/
rv = SEC_ASN1DecodeItem(NULL, &mgf1hashAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
&encoded_params.maskGenFunc->parameters); if (rv != SECSuccess) { goto loser;
}
oaep_params.mgf = SEC_GetMgfTypeByOidTag(SECOID_GetAlgorithmTag(&mgf1hashAlg)); if (!oaep_params.mgf) { goto loser;
}
} if (encoded_params.pSourceFunc != NULL) {
pSourcetag = SECOID_GetAlgorithmTag(encoded_params.pSourceFunc); if (pSourcetag != SEC_OID_PKCS1_PSPECIFIED) { goto loser;
} /* The encoding parameters (P) are provided as an OCTET STRING in the parameters field. */ if (encoded_params.pSourceFunc->parameters.len != 0) {
rv = SEC_ASN1DecodeItem(NULL, &encoding_params, SEC_ASN1_GET(SEC_OctetStringTemplate),
&encoded_params.pSourceFunc->parameters); if (rv != SECSuccess) { goto loser;
}
oaep_params.ulSourceDataLen = encoding_params.len;
oaep_params.pSourceData = encoding_params.data;
}
}
}
params.type = siBuffer;
params.data = (unsignedchar *)&oaep_params;
params.len = sizeof(CK_RSA_PKCS_OAEP_PARAMS);
bulkkey = PK11_PubUnwrapSymKeyWithMechanism(privkey, CKM_RSA_PKCS_OAEP, ¶ms,
encKey, target, CKA_DECRYPT, 0);
loser:
PORT_Free(oaep_params.pSourceData); if (encoded_params.hashFunc) {
SECOID_DestroyAlgorithmID(encoded_params.hashFunc, PR_TRUE);
} if (encoded_params.maskGenFunc) {
SECOID_DestroyAlgorithmID(encoded_params.maskGenFunc, PR_TRUE);
} if (encoded_params.pSourceFunc) {
SECOID_DestroyAlgorithmID(encoded_params.pSourceFunc, PR_TRUE);
}
SECOID_DestroyAlgorithmID(&mgf1hashAlg, PR_FALSE); return bulkkey;
}
/* this will generate a key pair, compute the shared secret, */ /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. * The ukm is optional per RFC 5753. Pass a NULL value to request an empty ukm. * Pass a SECItem with the size set to zero, to request allocating a random * ukm of a default size. Or provide an explicit ukm that was defined by the caller.
*/
SECStatus
NSS_CMSUtil_EncryptSymKey_ESECDH(PLArenaPool *poolp, CERTCertificate *cert,
PK11SymKey *bulkkey, SECItem *encKey,
PRBool genUkm, SECItem *ukm,
SECAlgorithmID *keyEncAlg, SECItem *pubKey, void *wincx)
{
SECOidTag certalgtag; /* the certificate's encryption algorithm */
SECStatus rv;
SECStatus err;
PK11SymKey *kek;
SECKEYPublicKey *publickey = NULL;
SECKEYPublicKey *ourPubKey = NULL;
SECKEYPrivateKey *ourPrivKey = NULL; unsignedint bulkkey_size, kek_size;
SECAlgorithmID keyWrapAlg;
SECOidTag keyEncAlgtag;
SECItem keyWrapAlg_params, *keyEncAlg_params, *SharedInfo;
CK_MECHANISM_TYPE keyDerivationType, keyWrapMech;
CK_ULONG kdf;
/* Parameters are supposed to be absent for AES key wrap algorithms. * However, Microsoft Outlook cannot decrypt message unless
* parameters field is NULL. */
keyWrapAlg_params.len = 2;
keyWrapAlg_params.data = (unsignedchar *)PORT_ArenaAlloc(poolp, keyWrapAlg_params.len); if (keyWrapAlg_params.data == NULL) goto loser;
/* RFC5753 specifies id-aes128-wrap as the mandatory to support algorithm. * So, use id-aes128-wrap unless bulkkey provides more than 128 bits of * security. If bulkkey provides more than 128 bits of security, use
* the algorithms from KE Set 2 in RFC 6318. */
/* TODO: NIST Special Publication SP 800-56A requires the use of * Cofactor ECDH. However, RFC 6318 specifies the use of * dhSinglePass-stdDH-sha256kdf-scheme or dhSinglePass-stdDH-sha384kdf-scheme * for Suite B. The reason for this is that all of the NIST recommended * prime curves in FIPS 186-3 (including the Suite B curves) have a cofactor * of 1, and so for these curves standard and cofactor ECDH are the same. * This code should really look at the key's parameters and choose cofactor
* ECDH if the curve has a cofactor other than 1. */ if ((PK11_GetMechanism(bulkkey) == CKM_AES_CBC) && (bulkkey_size > 16)) {
rv = SECOID_SetAlgorithmID(poolp, &keyWrapAlg, SEC_OID_AES_256_KEY_WRAP, &keyWrapAlg_params);
kek_size = 32;
keyWrapMech = CKM_NSS_AES_KEY_WRAP;
kdf = CKD_SHA384_KDF;
keyEncAlgtag = SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME;
keyDerivationType = CKM_ECDH1_DERIVE;
} else {
rv = SECOID_SetAlgorithmID(poolp, &keyWrapAlg, SEC_OID_AES_128_KEY_WRAP, &keyWrapAlg_params);
kek_size = 16;
keyWrapMech = CKM_NSS_AES_KEY_WRAP;
kdf = CKD_SHA256_KDF;
keyEncAlgtag = SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME;
keyDerivationType = CKM_ECDH1_DERIVE;
} if (rv != SECSuccess) { goto loser;
}
/* ukm is optional, but RFC 5753 says that originators SHOULD include the ukm. * I made ukm 64 bytes, since RFC 2631 states that UserKeyingMaterial must
* contain 512 bits for Diffie-Hellman key agreement. */
/* Generate the KEK (key exchange key) according to RFC5753 which we use
* to wrap the bulk encryption key. */
kek = PK11_PubDeriveWithKDF(ourPrivKey, publickey, PR_TRUE,
NULL, NULL,
keyDerivationType, keyWrapMech,
CKA_WRAP, kek_size, kdf, SharedInfo, NULL); if (!kek) { goto loser;
}
/* now set keyEncAlg */
rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, keyEncAlgtag, keyEncAlg_params); if (rv != SECSuccess) { goto loser;
}
return SECSuccess;
loser: if (publickey) {
SECKEY_DestroyPublicKey(publickey);
} if (ourPubKey) {
SECKEY_DestroyPublicKey(ourPubKey);
} if (ourPrivKey) {
SECKEY_DestroyPrivateKey(ourPrivKey);
} return SECFailure;
}
/* TODO: Move to pk11wrap and export? */ staticint
cms_GetKekSizeFromKeyWrapAlgTag(SECOidTag keyWrapAlgtag)
{ switch (keyWrapAlgtag) { case SEC_OID_AES_128_KEY_WRAP: return 16; case SEC_OID_AES_192_KEY_WRAP: return 24; case SEC_OID_AES_256_KEY_WRAP: return 32; default: break;
} return 0;
}
/* TODO: Move to smimeutil and export? */ static CK_ULONG
cms_GetKdfFromKeyEncAlgTag(SECOidTag keyEncAlgtag)
{ switch (keyEncAlgtag) { case SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME: case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME: return CKD_SHA1_KDF; case SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME: case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME: return CKD_SHA224_KDF; case SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME: case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA256KDF_SCHEME: return CKD_SHA256_KDF; case SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME: case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA384KDF_SCHEME: return CKD_SHA384_KDF; case SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME: case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA512KDF_SCHEME: return CKD_SHA512_KDF; default: break;
} return 0;
}
kek_size = cms_GetKekSizeFromKeyWrapAlgTag(keyWrapAlgtag); if (!kek_size) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser;
}
kdf = cms_GetKdfFromKeyEncAlgTag(keyEncAlgtag); if (!kdf) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser;
}
/* Get originator's public key */ /* TODO: Add support for static-static ECDH */ if (oiok->identifierType != NSSCMSOriginatorIDOrKey_OriginatorPublicKey) {
PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE); goto loser;
}
/* PK11_PubDeriveWithKDF only uses the keyType u.ec.publicValue.data
* and u.ec.publicValue.len from the originator's public key. */
oiok_publicKey = &(oiok->id.originatorPublicKey.publicKey);
originatorpublickey.keyType = ecKey;
originatorpublickey.u.ec.publicValue.data = oiok_publicKey->data;
originatorpublickey.u.ec.publicValue.len = oiok_publicKey->len / 8;
/* Generate the KEK (key exchange key) according to RFC5753 which we use
* to wrap the bulk encryption key. */
kek = PK11_PubDeriveWithKDF(privkey, &originatorpublickey, PR_TRUE,
NULL, NULL,
keyDerivationType, keyWrapMech,
CKA_WRAP, kek_size, kdf, SharedInfo, wincx);
SECITEM_FreeItem(SharedInfo, PR_TRUE);
if (kek == NULL) { goto loser;
}
bulkkey = PK11_UnwrapSymKey(kek, keyWrapMech, NULL, encKey, target, CKA_UNWRAP, 0);
PK11_FreeSymKey(kek); /* we do not need the KEK anymore */
loser:
SECOID_DestroyAlgorithmID(&keyWrapAlg, PR_FALSE); return bulkkey;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet)
¤
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.