/* * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption */ SECStatus NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd) { PK11SymKey *bulkkey = NULL; NSSCMSContentInfo *cinfo; SECAlgorithmID *bulkalg; SECStatus rv = SECFailure; cinfo = &(encd->contentInfo); bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo); if (encd->cmsg->decrypt_key_cb == NULL) /* no callback? no key../ */ goto loser; bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg); if (bulkkey == NULL) /* no success finding a bulk key */ goto loser; NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey); cinfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg); if (cinfo->ciphcx == NULL) goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */ /* we are done with (this) bulkkey now. */ PK11_FreeSymKey(bulkkey); rv = SECSuccess; loser: return rv; }
/* * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData * before encoding begins. * * In particular: * - set the correct version value. * - get the encryption key */ SECStatus NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd) { int version; PK11SymKey *bulkkey = NULL; SECItem *dummy; NSSCMSContentInfo *cinfo = &(encd->contentInfo); if (NSS_CMSArray_IsEmpty((void **)encd->unprotectedAttr)) version = NSS_CMS_ENCRYPTED_DATA_VERSION; else version = NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR; dummy = SEC_ASN1EncodeInteger (encd->cmsg->poolp, &(encd->version), version); if (dummy == NULL) return SECFailure; /* now get content encryption key (bulk key) by using our cmsg callback */ if (encd->cmsg->decrypt_key_cb) bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, NSS_CMSContentInfo_GetContentEncAlg(cinfo)); if (bulkkey == NULL) return SECFailure; /* store the bulk key in the contentInfo so that the encoder can find it */ NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey); PK11_FreeSymKey (bulkkey); return SECSuccess; }
/* * NSS_CMSEnvelopedData_Decode_BeforeData - find our recipientinfo, * derive bulk key & set up our contentinfo */ SECStatus NSS_CMSEnvelopedData_Decode_BeforeData(NSSCMSEnvelopedData *envd) { NSSCMSRecipientInfo *ri; PK11SymKey *bulkkey = NULL; SECOidTag bulkalgtag; SECAlgorithmID *bulkalg; SECStatus rv = SECFailure; NSSCMSContentInfo *cinfo; NSSCMSRecipient **recipient_list = NULL; NSSCMSRecipient *recipient; int rlIndex; if (NSS_CMSArray_Count((void **)envd->recipientInfos) == 0) { PORT_SetError(SEC_ERROR_BAD_DATA); #if 0 PORT_SetErrorString("No recipient data in envelope."); #endif goto loser; } /* look if one of OUR cert's issuerSN is on the list of recipients, and if so, */ /* get the cert and private key for it right away */ recipient_list = nss_cms_recipient_list_create(envd->recipientInfos); if (recipient_list == NULL) goto loser; /* what about multiple recipientInfos that match? * especially if, for some reason, we could not produce a bulk key with the first match?! * we could loop & feed partial recipient_list to PK11_FindCertAndKeyByRecipientList... * maybe later... */ rlIndex = PK11_FindCertAndKeyByRecipientListNew(recipient_list, envd->cmsg->pwfn_arg); /* if that fails, then we're not an intended recipient and cannot decrypt */ if (rlIndex < 0) { PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT); #if 0 PORT_SetErrorString("Cannot decrypt data because proper key cannot be found."); #endif goto loser; } recipient = recipient_list[rlIndex]; if (!recipient->cert || !recipient->privkey) { /* XXX should set an error code ?!? */ goto loser; } /* get a pointer to "our" recipientinfo */ ri = envd->recipientInfos[recipient->riIndex]; cinfo = &(envd->contentInfo); bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo); if (bulkalgtag == SEC_OID_UNKNOWN) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); } else bulkkey = NSS_CMSRecipientInfo_UnwrapBulkKey(ri,recipient->subIndex, recipient->cert, recipient->privkey, bulkalgtag); if (bulkkey == NULL) { /* no success finding a bulk key */ goto loser; } NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey); bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo); rv = NSS_CMSContentInfo_Private_Init(cinfo); if (rv != SECSuccess) { goto loser; } rv = SECFailure; cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg); if (cinfo->privateInfo->ciphcx == NULL) goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */ rv = SECSuccess; loser: if (bulkkey) PK11_FreeSymKey(bulkkey); if (recipient_list != NULL) nss_cms_recipient_list_destroy(recipient_list); return rv; }
/* * NSS_CMSEnvelopedData_Encode_BeforeStart - prepare this envelopedData for encoding * * at this point, we need * - recipientinfos set up with recipient's certificates * - a content encryption algorithm (if none, 3DES will be used) * * this function will generate a random content encryption key (aka bulk key), * initialize the recipientinfos with certificate identification and wrap the bulk key * using the proper algorithm for every certificiate. * it will finally set the bulk algorithm and key so that the encode step can find it. */ SECStatus NSS_CMSEnvelopedData_Encode_BeforeStart(NSSCMSEnvelopedData *envd) { int version; NSSCMSRecipientInfo **recipientinfos; NSSCMSContentInfo *cinfo; PK11SymKey *bulkkey = NULL; SECOidTag bulkalgtag; CK_MECHANISM_TYPE type; PK11SlotInfo *slot; SECStatus rv; SECItem *dummy; PLArenaPool *poolp; extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; void *mark = NULL; int i; poolp = envd->cmsg->poolp; cinfo = &(envd->contentInfo); recipientinfos = envd->recipientInfos; if (recipientinfos == NULL) { PORT_SetError(SEC_ERROR_BAD_DATA); #if 0 PORT_SetErrorString("Cannot find recipientinfos to encode."); #endif goto loser; } version = NSS_CMS_ENVELOPED_DATA_VERSION_REG; if (envd->originatorInfo != NULL || envd->unprotectedAttr != NULL) { version = NSS_CMS_ENVELOPED_DATA_VERSION_ADV; } else { for (i = 0; recipientinfos[i] != NULL; i++) { if (NSS_CMSRecipientInfo_GetVersion(recipientinfos[i]) != 0) { version = NSS_CMS_ENVELOPED_DATA_VERSION_ADV; break; } } } dummy = SEC_ASN1EncodeInteger(poolp, &(envd->version), version); if (dummy == NULL) goto loser; /* now we need to have a proper content encryption algorithm * on the SMIME level, we would figure one out by looking at SMIME capabilities * we cannot do that on our level, so if none is set already, we'll just go * with one of the mandatory algorithms (3DES) */ if ((bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo)) == SEC_OID_UNKNOWN) { rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, cinfo, SEC_OID_DES_EDE3_CBC, NULL, 168); if (rv != SECSuccess) goto loser; bulkalgtag = SEC_OID_DES_EDE3_CBC; } /* generate a random bulk key suitable for content encryption alg */ type = PK11_AlgtagToMechanism(bulkalgtag); slot = PK11_GetBestSlot(type, envd->cmsg->pwfn_arg); if (slot == NULL) goto loser; /* error has been set by PK11_GetBestSlot */ /* this is expensive... */ bulkkey = PK11_KeyGen(slot, type, NULL, NSS_CMSContentInfo_GetBulkKeySize(cinfo) / 8, envd->cmsg->pwfn_arg); PK11_FreeSlot(slot); if (bulkkey == NULL) goto loser; /* error has been set by PK11_KeyGen */ mark = PORT_ArenaMark(poolp); /* Encrypt the bulk key with the public key of each recipient. */ for (i = 0; recipientinfos[i] != NULL; i++) { rv = NSS_CMSRecipientInfo_WrapBulkKey(recipientinfos[i], bulkkey, bulkalgtag); if (rv != SECSuccess) goto loser; /* error has been set by NSS_CMSRecipientInfo_EncryptBulkKey */ /* could be: alg not supported etc. */ } /* the recipientinfos are all finished. now sort them by DER for SET OF encoding */ rv = NSS_CMSArray_SortByDER((void **)envd->recipientInfos, NSSCMSRecipientInfoTemplate, NULL); if (rv != SECSuccess) goto loser; /* error has been set by NSS_CMSArray_SortByDER */ /* store the bulk key in the contentInfo so that the encoder can find it */ NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey); PORT_ArenaUnmark(poolp, mark); PK11_FreeSymKey(bulkkey); return SECSuccess; loser: if (mark != NULL) PORT_ArenaRelease (poolp, mark); if (bulkkey) PK11_FreeSymKey(bulkkey); return SECFailure; }