/* * SecCmsUtilEncryptSymKeyRSA - 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) */ OSStatus SecCmsUtilEncryptSymKeyRSA(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef bulkkey, SecAsn1Item * encKey) { OSStatus rv; SecPublicKeyRef publickey; #if USE_CDSA_CRYPTO rv = SecCertificateCopyPublicKey(cert,&publickey); #else publickey = SecCertificateCopyPublicKey(cert); #endif if (publickey == NULL) return SECFailure; rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, publickey, bulkkey, encKey); CFRelease(publickey); return rv; }
OSStatus SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey, SECOidTag bulkalgtag) { SecCertificateRef cert; SECOidTag certalgtag; OSStatus rv = SECSuccess; #if 0 SecAsn1Item * params = NULL; SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; #endif /* 0 */ const SECAlgorithmID *algid; PLArenaPool *poolp; SecCmsKeyTransRecipientInfoEx *extra = NULL; Boolean usesSubjKeyID; poolp = ri->envelopedData->contentInfo.cmsg->poolp; cert = ri->cert; usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); if (cert) { #if USE_CDSA_CRYPTO rv = SecCertificateGetAlgorithmID(cert,&algid); if (rv) return SECFailure; #else SECAlgorithmID freeAlgID; const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert); freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data; freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length; freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data; freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length; algid = &freeAlgID; #endif } else if (usesSubjKeyID) { extra = &ri->ri.keyTransRecipientInfoEx; /* sanity check */ PORT_Assert(extra->pubKey); if (!extra->pubKey) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } #if USE_CDSA_CRYPTO rv = SecKeyGetAlgorithmID(extra->pubKey,&algid); if (rv) #endif return SECFailure; certalgtag = SECOID_GetAlgorithmTag(algid); } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* XXX set ri->recipientInfoType to the proper value here */ /* or should we look if it's been set already ? */ certalgtag = SECOID_GetAlgorithmTag(algid); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: /* wrap the symkey */ if (cert) { rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } else if (usesSubjKeyID) { PORT_Assert(extra != NULL); rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); break; #if 0 case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_KEA: rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey, bulkalgtag, &ri->ri.keyTransRecipientInfo.encKey, ¶ms, ri->cmsg->pwfn_arg); if (rv != SECSuccess) break; /* here, we DO need to pass the params to the wrap function because, with * RSA, there is no funny stuff going on with generation of IV vectors or so */ rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params); break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); /* see RFC2630 12.3.1.1 */ if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { rv = SECFailure; break; } /* 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. */ rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey, &rek->encKey, &ri->ri.keyAgreeRecipientInfo.ukm, &ri->ri.keyAgreeRecipientInfo.keyEncAlg, &oiok->id.originatorPublicKey.publicKey); break; #endif /* 0 */ default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; break; } #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif return rv; }
OSStatus SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey, SECOidTag bulkalgtag) { SecCertificateRef cert; SECOidTag certalgtag; OSStatus rv = SECSuccess; #if 0 CSSM_DATA_PTR params = NULL; #endif /* 0 */ SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; const SECAlgorithmID *algid; PLArenaPool *poolp; SecCmsKeyTransRecipientInfoEx *extra = NULL; Boolean usesSubjKeyID; uint8 nullData[2] = {SEC_ASN1_NULL, 0}; SECItem nullItem; SecCmsKeyAgreeRecipientInfo *kari; poolp = ri->cmsg->poolp; cert = ri->cert; usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); if (cert) { rv = SecCertificateGetAlgorithmID(cert,&algid); if (rv) return SECFailure; certalgtag = SECOID_GetAlgorithmTag(algid); } else if (usesSubjKeyID) { extra = &ri->ri.keyTransRecipientInfoEx; /* sanity check */ PORT_Assert(extra->pubKey); if (!extra->pubKey) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } rv = SecKeyGetAlgorithmID(extra->pubKey,&algid); if (rv) return SECFailure; certalgtag = SECOID_GetAlgorithmTag(algid); } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* XXX set ri->recipientInfoType to the proper value here */ /* or should we look if it's been set already ? */ certalgtag = SECOID_GetAlgorithmTag(algid); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: /* wrap the symkey */ if (cert) { rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } else if (usesSubjKeyID) { PORT_Assert(extra != NULL); rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); break; #if 0 case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_KEA: rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey, bulkalgtag, &ri->ri.keyTransRecipientInfo.encKey, ¶ms, ri->cmsg->pwfn_arg); if (rv != SECSuccess) break; /* here, we DO need to pass the params to the wrap function because, with * RSA, there is no funny stuff going on with generation of IV vectors or so */ rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params); break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); /* see RFC2630 12.3.1.1 */ if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { rv = SECFailure; break; } /* 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. */ rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey, &rek->encKey, &ri->ri.keyAgreeRecipientInfo.ukm, &ri->ri.keyAgreeRecipientInfo.keyEncAlg, &oiok->id.originatorPublicKey.publicKey); break; #endif /* 0 */ case SEC_OID_EC_PUBLIC_KEY: /* These were set up in nss_cmsrecipientinfo_create() */ kari = &ri->ri.keyAgreeRecipientInfo; rek = kari->recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(kari->originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); /* * RFC 3278 3.1.1 says this AlgId must contain NULL params which is contrary to * any other use of the SEC_OID_EC_PUBLIC_KEY OID. So we provide one * explicitly instead of mucking up the login in SECOID_SetAlgorithmID(). */ nullItem.Data = nullData; nullItem.Length = 2; if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_EC_PUBLIC_KEY, &nullItem) != SECSuccess) { rv = SECFailure; break; } /* 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. */ rv = SecCmsUtilEncryptSymKeyECDH(poolp, cert, bulkkey, &rek->encKey, &kari->ukm, &kari->keyEncAlg, &oiok->id.originatorPublicKey.publicKey); /* this is a BIT STRING */ oiok->id.originatorPublicKey.publicKey.Length <<= 3; break; default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; break; } #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif return rv; }