SECStatus crmf_encrypted_value_unwrap_priv_key(PLArenaPool *poolp, CRMFEncryptedValue *encValue, SECKEYPrivateKey *privKey, SECKEYPublicKey *newPubKey, SECItem *nickname, PK11SlotInfo *slot, unsigned char keyUsage, SECKEYPrivateKey **unWrappedKey, void *wincx) { PK11SymKey *wrappingKey = NULL; CK_MECHANISM_TYPE wrapMechType; SECOidTag oidTag; SECItem *params = NULL, *publicValue = NULL; int keySize, origLen; CK_KEY_TYPE keyType; CK_ATTRIBUTE_TYPE *usage = NULL; CK_ATTRIBUTE_TYPE rsaUsage[] = { CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER }; CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN }; CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE }; int usageCount = 0; oidTag = SECOID_GetAlgorithmTag(encValue->symmAlg); wrapMechType = crmf_get_pad_mech_from_tag(oidTag); keySize = crmf_get_key_size_from_mech(wrapMechType); wrappingKey = PK11_PubUnwrapSymKey(privKey, &encValue->encSymmKey, wrapMechType, CKA_UNWRAP, keySize); if (wrappingKey == NULL) { goto loser; } /* Make the length a byte length instead of bit length*/ params = (encValue->symmAlg != NULL) ? crmf_decode_params(&encValue->symmAlg->parameters) : NULL; origLen = encValue->encValue.len; encValue->encValue.len = CRMF_BITS_TO_BYTES(origLen); publicValue = crmf_get_public_value(newPubKey, NULL); switch (newPubKey->keyType) { default: case rsaKey: keyType = CKK_RSA; switch (keyUsage & (KU_KEY_ENCIPHERMENT | KU_DIGITAL_SIGNATURE)) { case KU_KEY_ENCIPHERMENT: usage = rsaUsage; usageCount = 2; break; case KU_DIGITAL_SIGNATURE: usage = &rsaUsage[2]; usageCount = 2; break; case KU_KEY_ENCIPHERMENT | KU_DIGITAL_SIGNATURE: case 0: /* default to everything */ usage = rsaUsage; usageCount = 4; break; } break; case dhKey: keyType = CKK_DH; usage = dhUsage; usageCount = sizeof(dhUsage) / sizeof(dhUsage[0]); break; case dsaKey: keyType = CKK_DSA; usage = dsaUsage; usageCount = sizeof(dsaUsage) / sizeof(dsaUsage[0]); break; } PORT_Assert(usage != NULL); PORT_Assert(usageCount != 0); *unWrappedKey = PK11_UnwrapPrivKey(slot, wrappingKey, wrapMechType, params, &encValue->encValue, nickname, publicValue, PR_TRUE, PR_TRUE, keyType, usage, usageCount, wincx); encValue->encValue.len = origLen; if (*unWrappedKey == NULL) { goto loser; } SECITEM_FreeItem(publicValue, PR_TRUE); if (params != NULL) { SECITEM_FreeItem(params, PR_TRUE); } PK11_FreeSymKey(wrappingKey); return SECSuccess; loser: *unWrappedKey = NULL; return SECFailure; }
static int cmmf_create_witness_and_challenge(PRArenaPool *poolp, CMMFChallenge *challenge, long inRandom, SECItem *senderDER, SECKEYPublicKey *inPubKey, void *passwdArg) { SECItem *encodedRandNum; SECItem encodedRandStr = {siBuffer, NULL, 0}; SECItem *dummy; unsigned char *randHash, *senderHash, *encChal=NULL; unsigned modulusLen = 0; SECStatus rv = SECFailure; CMMFRand randStr= { {siBuffer, NULL, 0}, {siBuffer, NULL, 0}}; PK11SlotInfo *slot; PK11SymKey *symKey = NULL; CK_OBJECT_HANDLE id; CERTSubjectPublicKeyInfo *spki = NULL; encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber, inRandom); encodedRandNum = &challenge->randomNumber; randHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH); senderHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH); if (randHash == NULL) { goto loser; } rv = PK11_HashBuf(SEC_OID_SHA1, randHash, encodedRandNum->data, (PRUint32)encodedRandNum->len); if (rv != SECSuccess) { goto loser; } rv = PK11_HashBuf(SEC_OID_SHA1, senderHash, senderDER->data, (PRUint32)senderDER->len); if (rv != SECSuccess) { goto loser; } challenge->witness.data = randHash; challenge->witness.len = SHA1_LENGTH; randStr.integer = *encodedRandNum; randStr.senderHash.data = senderHash; randStr.senderHash.len = SHA1_LENGTH; dummy = SEC_ASN1EncodeItem(NULL, &encodedRandStr, &randStr, CMMFRandTemplate); if (dummy != &encodedRandStr) { rv = SECFailure; goto loser; } /* XXXX Now I have to encrypt encodedRandStr and stash it away. */ modulusLen = SECKEY_PublicKeyStrength(inPubKey); encChal = PORT_ArenaNewArray(poolp, unsigned char, modulusLen); if (encChal == NULL) { rv = SECFailure; goto loser; } slot =PK11_GetBestSlotWithAttributes(CKM_RSA_PKCS, CKF_WRAP, 0, passwdArg); if (slot == NULL) { rv = SECFailure; goto loser; } id = PK11_ImportPublicKey(slot, inPubKey, PR_FALSE); /* In order to properly encrypt the data, we import as a symmetric * key, and then wrap that key. That in essence encrypts the data. * This is the method recommended in the PK11 world in order * to prevent threading issues as well as breaking any other semantics * the PK11 libraries depend on. */ symKey = PK11_ImportSymKey(slot, CKM_RSA_PKCS, PK11_OriginGenerated, CKA_VALUE, &encodedRandStr, passwdArg); if (symKey == NULL) { rv = SECFailure; goto loser; } challenge->challenge.data = encChal; challenge->challenge.len = modulusLen; rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, inPubKey, symKey, &challenge->challenge); PK11_FreeSlot(slot); if (rv != SECSuccess) { goto loser; } rv = SECITEM_CopyItem(poolp, &challenge->senderDER, senderDER); crmf_get_public_value(inPubKey, &challenge->key); /* Fall through */ loser: if (spki != NULL) { SECKEY_DestroySubjectPublicKeyInfo(spki); } if (encodedRandStr.data != NULL) { PORT_Free(encodedRandStr.data); } if (encodedRandNum != NULL) { SECITEM_FreeItem(encodedRandNum, PR_TRUE); } if (symKey != NULL) { PK11_FreeSymKey(symKey); } return rv; }