/* * SecCmsEncryptedDataEncodeBeforeStart - do all the necessary things to a EncryptedData * before encoding begins. * * In particular: * - set the correct version value. * - get the encryption key */ OSStatus SecCmsEncryptedDataEncodeBeforeStart(SecCmsEncryptedDataRef encd) { int version; SecSymmetricKeyRef bulkkey = NULL; CSSM_DATA_PTR dummy; SecCmsContentInfoRef cinfo = &(encd->contentInfo); if (SecCmsArrayIsEmpty((void **)encd->unprotectedAttr)) version = SEC_CMS_ENCRYPTED_DATA_VERSION; else version = SEC_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, SecCmsContentInfoGetContentEncAlg(cinfo)); if (bulkkey == NULL) return SECFailure; /* store the bulk key in the contentInfo so that the encoder can find it */ SecCmsContentInfoSetBulkKey(cinfo, bulkkey); CFRelease(bulkkey); /* This assumes the decrypt_key_cb hands us a copy of the key --mb */ return SECSuccess; }
int main() { PRBool failed = PR_FALSE; unsigned int i; unsigned int j; for (i = 0; i < sizeof(testCase)/sizeof(testCase[0]); i++) { SECItem encoded; if (SEC_ASN1EncodeInteger(NULL, &encoded, testCase[i].value) == NULL) { fprintf(stderr, "SEC_ASN1EncodeInteger failed\n"); failed = PR_TRUE; continue; } if (encoded.len != testCase[i].len || memcmp(encoded.data, testCase[i].data, encoded.len) != 0) { fprintf(stderr, "Encoding of %ld is incorrect:", testCase[i].value); for (j = 0; j < encoded.len; j++) { fprintf(stderr, " 0x%02X", (unsigned int)encoded.data[j]); } fputs("\n", stderr); failed = PR_TRUE; } PORT_Free(encoded.data); } if (failed) { fprintf(stderr, "FAIL\n"); return 1; } printf("PASS\n"); return 0; }
/* * 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; }
SECStatus crmf_encode_integer(PLArenaPool *poolp, SECItem *dest, long value) { SECItem *dummy; dummy = SEC_ASN1EncodeInteger(poolp, dest, value); PORT_Assert (dummy == dest); if (dummy == NULL) { return SECFailure; } return SECSuccess; }
/* * NSS_CMSDigestedData_Encode_BeforeStart - do all the necessary things to a DigestedData * before encoding begins. * * In particular: * - set the right version number. The contentInfo's content type must be set up already. */ SECStatus NSS_CMSDigestedData_Encode_BeforeStart(NSSCMSDigestedData *digd) { unsigned long version; SECItem *dummy; version = NSS_CMS_DIGESTED_DATA_VERSION_DATA; if (NSS_CMSContentInfo_GetContentTypeTag(&(digd->contentInfo)) != SEC_OID_PKCS7_DATA) version = NSS_CMS_DIGESTED_DATA_VERSION_ENCAP; dummy = SEC_ASN1EncodeInteger(digd->cmsg->poolp, &(digd->version), version); return (dummy == NULL) ? SECFailure : SECSuccess; }
/* * SecCmsDigestedDataEncodeBeforeStart - do all the necessary things to a DigestedData * before encoding begins. * * In particular: * - set the right version number. The contentInfo's content type must be set up already. */ OSStatus SecCmsDigestedDataEncodeBeforeStart(SecCmsDigestedDataRef digd) { unsigned long version; SecAsn1Item * dummy; version = SEC_CMS_DIGESTED_DATA_VERSION_DATA; if (SecCmsContentInfoGetContentTypeTag(&(digd->contentInfo)) != SEC_OID_PKCS7_DATA) version = SEC_CMS_DIGESTED_DATA_VERSION_ENCAP; dummy = SEC_ASN1EncodeInteger(digd->contentInfo.cmsg->poolp, &(digd->version), version); return (dummy == NULL) ? SECFailure : SECSuccess; }
SECStatus cmmf_PKIStatusInfoSetStatus(CMMFPKIStatusInfo *statusInfo, PLArenaPool *poolp, CMMFPKIStatus inStatus) { SECItem *dummy; if (inStatus < cmmfGranted || inStatus >= cmmfNumPKIStatus) { return SECFailure; } dummy = SEC_ASN1EncodeInteger(poolp, &statusInfo->status, inStatus); PORT_Assert(dummy == &statusInfo->status); if (dummy != &statusInfo->status) { SECITEM_FreeItem(dummy, PR_TRUE); return SECFailure; } return SECSuccess; }
CMMFCertResponse * CMMF_CreateCertResponse(long inCertReqId) { SECItem *dummy; CMMFCertResponse *newResp; newResp = PORT_ZNew(CMMFCertResponse); if (newResp == NULL) { goto loser; } dummy = SEC_ASN1EncodeInteger(NULL, &newResp->certReqId, inCertReqId); if (dummy != &newResp->certReqId) { goto loser; } return newResp; loser: if (newResp != NULL) { CMMF_DestroyCertResponse(newResp); } return NULL; }
NSSCMSRecipientInfo * nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, NSSCMSRecipientIDSelector type, CERTCertificate *cert, SECKEYPublicKey *pubKey, SECItem *subjKeyID, void* pwfn_arg, SECItem* DERinput) { NSSCMSRecipientInfo *ri; void *mark; SECOidTag certalgtag; SECStatus rv = SECSuccess; NSSCMSRecipientEncryptedKey *rek; NSSCMSOriginatorIdentifierOrKey *oiok; unsigned long version; SECItem *dummy; PLArenaPool *poolp; CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; NSSCMSRecipientIdentifier *rid; extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; if (!cmsg) { /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc * and a private arena pool */ cmsg = NSS_CMSMessage_Create(NULL); cmsg->pwfn_arg = pwfn_arg; /* mark it as a special cms message */ cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent; } poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo)); if (ri == NULL) goto loser; ri->cmsg = cmsg; if (DERinput) { /* decode everything from DER */ SECItem newinput; SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput); if (SECSuccess != rv) goto loser; rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput); if (SECSuccess != rv) goto loser; } switch (type) { case NSSCMSRecipientID_IssuerSN: { ri->cert = CERT_DupCertificate(cert); if (NULL == ri->cert) goto loser; spki = &(cert->subjectPublicKeyInfo); break; } case NSSCMSRecipientID_SubjectKeyID: { PORT_Assert(pubKey); spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); break; } case NSSCMSRecipientID_BrandNew: goto done; break; default: /* unkown type */ goto loser; break; } certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans; rid->identifierType = type; if (type == NSSCMSRecipientID_IssuerSN) { rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); if (rid->id.issuerAndSN == NULL) { break; } } else if (type == NSSCMSRecipientID_SubjectKeyID){ NSSCMSKeyTransRecipientInfoEx *riExtra; rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem); if (rid->id.subjectKeyID == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); if (rid->id.subjectKeyID->data == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } riExtra = &ri->ri.keyTransRecipientInfoEx; riExtra->version = 0; riExtra->pubKey = SECKEY_CopyPublicKey(pubKey); if (riExtra->pubKey == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ PORT_Assert(type == NSSCMSRecipientID_IssuerSN); if (type != NSSCMSRecipientID_IssuerSN) { rv = SECFailure; break; } /* a key agreement op */ ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree; if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { rv = SECFailure; break; } /* we do not support the case where multiple recipients * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys * in this case, we would need to walk all the recipientInfos, take the * ones that do KeyAgreement algorithms and join them, algorithm by algorithm * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ /* only epheremal-static Diffie-Hellman is supported for now * this is the only form of key agreement that provides potential anonymity * of the sender, plus we do not have to include certs in the message */ /* force single recipientEncryptedKey for now */ if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) { rv = SECFailure; break; } /* hardcoded IssuerSN choice for now */ rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN; if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); /* see RFC2630 12.3.1.1 */ oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey; rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, (void *)rek); 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 (rv == SECFailure) goto loser; /* set version */ switch (ri->recipientInfoType) { case NSSCMSRecipientInfoID_KeyTrans: if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN) version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; else version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); if (dummy == NULL) goto loser; break; case NSSCMSRecipientInfoID_KeyAgree: dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; case NSSCMSRecipientInfoID_KEK: /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), NSS_CMS_KEK_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; } done: PORT_ArenaUnmark (poolp, mark); if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); return ri; loser: if (ri && ri->cert) { CERT_DestroyCertificate(ri->cert); } if (freeSpki) { SECKEY_DestroySubjectPublicKeyInfo(freeSpki); } PORT_ArenaRelease (poolp, mark); if (cmsg->contentInfo.contentTypeTag == &fakeContent) { NSS_CMSMessage_Destroy(cmsg); } return NULL; }
/* * NSS_CMSSignedData_Encode_BeforeStart - do all the necessary things to a SignedData * before start of encoding. * * In detail: * - find out about the right value to put into sigd->version * - come up with a list of digestAlgorithms (which should be the union of the algorithms * in the signerinfos). * If we happen to have a pre-set list of algorithms (and digest values!), we * check if we have all the signerinfos' algorithms. If not, this is an error. */ SECStatus NSS_CMSSignedData_Encode_BeforeStart(NSSCMSSignedData *sigd) { NSSCMSSignerInfo *signerinfo; SECOidTag digestalgtag; SECItem *dummy; int version; SECStatus rv; PRBool haveDigests = PR_FALSE; int n, i; PLArenaPool *poolp; if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } poolp = sigd->cmsg->poolp; /* we assume that we have precomputed digests if there is a list of algorithms, and */ /* a chunk of data for each of those algorithms */ if (sigd->digestAlgorithms != NULL && sigd->digests != NULL) { for (i = 0; sigd->digestAlgorithms[i] != NULL; i++) { if (sigd->digests[i] == NULL) break; } if (sigd->digestAlgorithms[i] == NULL) /* reached the end of the array? */ haveDigests = PR_TRUE; /* yes: we must have all the digests */ } version = NSS_CMS_SIGNED_DATA_VERSION_BASIC; /* RFC2630 5.1 "version is the syntax version number..." */ if (NSS_CMSContentInfo_GetContentTypeTag(&(sigd->contentInfo)) != SEC_OID_PKCS7_DATA) version = NSS_CMS_SIGNED_DATA_VERSION_EXT; /* prepare all the SignerInfos (there may be none) */ for (i = 0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) { signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i); /* RFC2630 5.1 "version is the syntax version number..." */ if (NSS_CMSSignerInfo_GetVersion(signerinfo) != NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN) version = NSS_CMS_SIGNED_DATA_VERSION_EXT; /* collect digestAlgorithms from SignerInfos */ /* (we need to know which algorithms we have when the content comes in) */ /* do not overwrite any existing digestAlgorithms (and digest) */ digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo); n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag); if (n < 0 && haveDigests) { /* oops, there is a digestalg we do not have a digest for */ /* but we were supposed to have all the digests already... */ goto loser; } else if (n < 0) { /* add the digestAlgorithm & a NULL digest */ rv = NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, NULL); if (rv != SECSuccess) goto loser; } else { /* found it, nothing to do */ } } dummy = SEC_ASN1EncodeInteger(poolp, &(sigd->version), (long)version); if (dummy == NULL) return SECFailure; /* this is a SET OF, so we need to sort them guys */ rv = NSS_CMSArray_SortByDER((void **)sigd->digestAlgorithms, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), (void **)sigd->digests); if (rv != SECSuccess) return SECFailure; return SECSuccess; loser: return SECFailure; }
/* * 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; }
SecCmsSignerInfoRef nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, SecCertificateRef cert, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag) { void *mark; SecCmsSignerInfoRef signerinfo; int version; PLArenaPool *poolp; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); signerinfo = (SecCmsSignerInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsSignerInfo)); if (signerinfo == NULL) { PORT_ArenaRelease(poolp, mark); return NULL; } signerinfo->cmsg = cmsg; switch(type) { case SecCmsSignerIDIssuerSN: signerinfo->signerIdentifier.identifierType = SecCmsSignerIDIssuerSN; if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL) goto loser; if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) goto loser; dprintfRC("nss_cmssignerinfo_create: SecCmsSignerIDIssuerSN: cert.rc %d\n", (int)CFGetRetainCount(signerinfo->cert)); break; case SecCmsSignerIDSubjectKeyID: signerinfo->signerIdentifier.identifierType = SecCmsSignerIDSubjectKeyID; PORT_Assert(subjKeyID); if (!subjKeyID) goto loser; signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, CSSM_DATA); if (SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID, subjKeyID)) { goto loser; } signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey); if (!signerinfo->pubKey) goto loser; break; default: goto loser; } if (!signingKey) goto loser; signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey); if (!signerinfo->signingKey) goto loser; /* set version right now */ version = SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN; /* RFC2630 5.3 "version is the syntax version number. If the .... " */ if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) version = SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY; (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version); if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return signerinfo; loser: PORT_ArenaRelease(poolp, mark); return NULL; }
NSSCMSSignerInfo * nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type, CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey, SECKEYPrivateKey *signingKey, SECOidTag digestalgtag) { void *mark; NSSCMSSignerInfo *signerinfo; int version; PLArenaPool *poolp; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo)); if (signerinfo == NULL) { PORT_ArenaRelease(poolp, mark); return NULL; } signerinfo->cmsg = cmsg; switch(type) { case NSSCMSSignerID_IssuerSN: signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN; if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL) goto loser; if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) goto loser; break; case NSSCMSSignerID_SubjectKeyID: signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID; PORT_Assert(subjKeyID); if (!subjKeyID) goto loser; signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem); SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID, subjKeyID); signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey); if (!signerinfo->signingKey) goto loser; signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey); if (!signerinfo->pubKey) goto loser; break; default: goto loser; } /* set version right now */ version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN; /* RFC2630 5.3 "version is the syntax version number. If the .... " */ if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY; (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version); if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return signerinfo; loser: PORT_ArenaRelease(poolp, mark); return NULL; }
static SecCmsRecipientInfoRef nss_cmsrecipientinfo_create(SecCmsEnvelopedDataRef envd, SecCmsRecipientIDSelector type, SecCertificateRef cert, SecPublicKeyRef pubKey, const SecAsn1Item *subjKeyID) { SecCmsRecipientInfoRef ri; void *mark; SECOidTag certalgtag; OSStatus rv = SECSuccess; SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; unsigned long version; SecAsn1Item * dummy; PLArenaPool *poolp; const SECAlgorithmID *algid; SECAlgorithmID freeAlgID; SecCmsRecipientIdentifier *rid; poolp = envd->contentInfo.cmsg->poolp; mark = PORT_ArenaMark(poolp); ri = (SecCmsRecipientInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsRecipientInfo)); if (ri == NULL) goto loser; ri->envelopedData = envd; #if USE_CDSA_CRYPTO if (type == SecCmsRecipientIDIssuerSN) { rv = SecCertificateGetAlgorithmID(cert,&algid); } else { PORT_Assert(pubKey); rv = SecKeyGetAlgorithmID(pubKey,&algid); } #else ri->cert = CERT_DupCertificate(cert); if (ri->cert == NULL) goto loser; 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 certalgtag = SECOID_GetAlgorithmTag(algid); rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans; rid->identifierType = type; if (type == SecCmsRecipientIDIssuerSN) { rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); if (rid->id.issuerAndSN == NULL) { break; } } else if (type == SecCmsRecipientIDSubjectKeyID){ rid->id.subjectKeyID = PORT_ArenaNew(poolp, SecAsn1Item); if (rid->id.subjectKeyID == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); if (rid->id.subjectKeyID->Data == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } #if 0 SecCmsKeyTransRecipientInfoEx *riExtra; riExtra = &ri->ri.keyTransRecipientInfoEx; riExtra->version = 0; riExtra->pubKey = SECKEY_CopyPublicKey(pubKey); if (riExtra->pubKey == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } #endif } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_KEA: PORT_Assert(type != SecCmsRecipientIDSubjectKeyID); if (type == SecCmsRecipientIDSubjectKeyID) { rv = SECFailure; break; } /* backward compatibility - this is not really a keytrans operation */ ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans; /* hardcoded issuerSN choice for now */ ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType = SecCmsRecipientIDIssuerSN; ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { rv = SECFailure; break; } break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ PORT_Assert(type != SecCmsRecipientIDSubjectKeyID); if (type == SecCmsRecipientIDSubjectKeyID) { rv = SECFailure; break; } /* a key agreement op */ ri->recipientInfoType = SecCmsRecipientInfoIDKeyAgree; if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { rv = SECFailure; break; } /* we do not support the case where multiple recipients * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys * in this case, we would need to walk all the recipientInfos, take the * ones that do KeyAgreement algorithms and join them, algorithm by algorithm * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ /* only epheremal-static Diffie-Hellman is supported for now * this is the only form of key agreement that provides potential anonymity * of the sender, plus we do not have to include certs in the message */ /* force single recipientEncryptedKey for now */ if ((rek = SecCmsRecipientEncryptedKeyCreate(poolp)) == NULL) { rv = SECFailure; break; } /* hardcoded IssuerSN choice for now */ rek->recipientIdentifier.identifierType = SecCmsKeyAgreeRecipientIDIssuerSN; if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); /* see RFC2630 12.3.1.1 */ oiok->identifierType = SecCmsOriginatorIDOrKeyOriginatorPublicKey; rv = SecCmsArrayAdd(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, (void *)rek); 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 (rv == SECFailure) goto loser; /* set version */ switch (ri->recipientInfoType) { case SecCmsRecipientInfoIDKeyTrans: if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == SecCmsRecipientIDIssuerSN) version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; else version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); if (dummy == NULL) goto loser; break; case SecCmsRecipientInfoIDKeyAgree: dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), SEC_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; case SecCmsRecipientInfoIDKEK: /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), SEC_CMS_KEK_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; } if (SecCmsEnvelopedDataAddRecipient(envd, ri)) goto loser; PORT_ArenaUnmark (poolp, mark); #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif return ri; loser: #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif PORT_ArenaRelease (poolp, mark); return NULL; }
static SECItem * sec_CreateRSAPSSParameters(PLArenaPool *arena, SECItem *result, SECOidTag hashAlgTag, const SECItem *params, const SECKEYPrivateKey *key) { SECKEYRSAPSSParams pssParams; int modBytes, hashLength; unsigned long saltLength; PRBool defaultSHA1 = PR_FALSE; SECStatus rv; if (key->keyType != rsaKey && key->keyType != rsaPssKey) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } PORT_Memset(&pssParams, 0, sizeof(pssParams)); if (params && params->data) { /* The parameters field should either be empty or contain * valid RSA-PSS parameters */ PORT_Assert(!(params->len == 2 && params->data[0] == SEC_ASN1_NULL && params->data[1] == 0)); rv = SEC_QuickDERDecodeItem(arena, &pssParams, SECKEY_RSAPSSParamsTemplate, params); if (rv != SECSuccess) { return NULL; } defaultSHA1 = PR_TRUE; } if (pssParams.trailerField.data) { unsigned long trailerField; rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.trailerField, &trailerField); if (rv != SECSuccess) { return NULL; } if (trailerField != 1) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } } modBytes = PK11_GetPrivateModulusLen((SECKEYPrivateKey *)key); /* Determine the hash algorithm to use, based on hashAlgTag and * pssParams.hashAlg; there are four cases */ if (hashAlgTag != SEC_OID_UNKNOWN) { SECOidTag tag = SEC_OID_UNKNOWN; if (pssParams.hashAlg) { tag = SECOID_GetAlgorithmTag(pssParams.hashAlg); } else if (defaultSHA1) { tag = SEC_OID_SHA1; } if (tag != SEC_OID_UNKNOWN && tag != hashAlgTag) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } } else if (hashAlgTag == SEC_OID_UNKNOWN) { if (pssParams.hashAlg) { hashAlgTag = SECOID_GetAlgorithmTag(pssParams.hashAlg); } else if (defaultSHA1) { hashAlgTag = SEC_OID_SHA1; } else { /* Find a suitable hash algorithm based on the NIST recommendation */ if (modBytes <= 384) { /* 128, in NIST 800-57, Part 1 */ hashAlgTag = SEC_OID_SHA256; } else if (modBytes <= 960) { /* 192, NIST 800-57, Part 1 */ hashAlgTag = SEC_OID_SHA384; } else { hashAlgTag = SEC_OID_SHA512; } } } if (hashAlgTag != SEC_OID_SHA1 && hashAlgTag != SEC_OID_SHA224 && hashAlgTag != SEC_OID_SHA256 && hashAlgTag != SEC_OID_SHA384 && hashAlgTag != SEC_OID_SHA512) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } /* Now that the hash algorithm is decided, check if it matches the * existing parameters if any */ if (pssParams.maskAlg) { SECAlgorithmID maskHashAlg; if (SECOID_GetAlgorithmTag(pssParams.maskAlg) != SEC_OID_PKCS1_MGF1) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } if (pssParams.maskAlg->parameters.data == NULL) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } PORT_Memset(&maskHashAlg, 0, sizeof(maskHashAlg)); rv = SEC_QuickDERDecodeItem(arena, &maskHashAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), &pssParams.maskAlg->parameters); if (rv != SECSuccess) { return NULL; } /* Following the recommendation in RFC 4055, assume the hash * algorithm identical to pssParam.hashAlg */ if (SECOID_GetAlgorithmTag(&maskHashAlg) != hashAlgTag) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } } else if (defaultSHA1) { if (hashAlgTag != SEC_OID_SHA1) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } } hashLength = HASH_ResultLenByOidTag(hashAlgTag); if (pssParams.saltLength.data) { rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.saltLength, &saltLength); if (rv != SECSuccess) { return NULL; } /* The specified salt length is too long */ if (saltLength > modBytes - hashLength - 2) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } } else if (defaultSHA1) { saltLength = 20; } /* Fill in the parameters */ if (pssParams.hashAlg) { if (hashAlgTag == SEC_OID_SHA1) { /* Omit hashAlg if the the algorithm is SHA-1 (default) */ pssParams.hashAlg = NULL; } } else { if (hashAlgTag != SEC_OID_SHA1) { pssParams.hashAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); if (!pssParams.hashAlg) { return NULL; } rv = SECOID_SetAlgorithmID(arena, pssParams.hashAlg, hashAlgTag, NULL); if (rv != SECSuccess) { return NULL; } } } if (pssParams.maskAlg) { if (hashAlgTag == SEC_OID_SHA1) { /* Omit maskAlg if the the algorithm is SHA-1 (default) */ pssParams.maskAlg = NULL; } } else { if (hashAlgTag != SEC_OID_SHA1) { SECItem *hashAlgItem; PORT_Assert(pssParams.hashAlg != NULL); hashAlgItem = SEC_ASN1EncodeItem(arena, NULL, pssParams.hashAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)); if (!hashAlgItem) { return NULL; } pssParams.maskAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); if (!pssParams.maskAlg) { return NULL; } rv = SECOID_SetAlgorithmID(arena, pssParams.maskAlg, SEC_OID_PKCS1_MGF1, hashAlgItem); if (rv != SECSuccess) { return NULL; } } } if (pssParams.saltLength.data) { if (saltLength == 20) { /* Omit the salt length if it is the default */ pssParams.saltLength.data = NULL; } } else { /* Find a suitable length from the hash algorithm and modulus bits */ saltLength = PR_MIN(hashLength, modBytes - hashLength - 2); if (saltLength != 20 && !SEC_ASN1EncodeInteger(arena, &pssParams.saltLength, saltLength)) { return NULL; } } if (pssParams.trailerField.data) { /* Omit trailerField if the value is 1 (default) */ pssParams.trailerField.data = NULL; } return SEC_ASN1EncodeItem(arena, result, &pssParams, SECKEY_RSAPSSParamsTemplate); }
/* * SecCmsEnvelopedDataEncodeBeforeStart - 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. */ OSStatus SecCmsEnvelopedDataEncodeBeforeStart(SecCmsEnvelopedData *envd) { int version; SecCmsRecipientInfo **recipientinfos; SecCmsContentInfo *cinfo; SecSymmetricKeyRef bulkkey = NULL; CSSM_ALGORITHMS algorithm; SECOidTag bulkalgtag; //CK_MECHANISM_TYPE type; //PK11SlotInfo *slot; OSStatus rv; CSSM_DATA *dummy; PLArenaPool *poolp; extern const SEC_ASN1Template SecCmsRecipientInfoTemplate[]; 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 = SEC_CMS_ENVELOPED_DATA_VERSION_REG; if (envd->originatorInfo != NULL || envd->unprotectedAttr != NULL) { version = SEC_CMS_ENVELOPED_DATA_VERSION_ADV; } else { for (i = 0; recipientinfos[i] != NULL; i++) { if (SecCmsRecipientInfoGetVersion(recipientinfos[i]) != 0) { version = SEC_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 = SecCmsContentInfoGetContentEncAlgTag(cinfo)) == SEC_OID_UNKNOWN) { rv = SecCmsContentInfoSetContentEncAlg(poolp, cinfo, SEC_OID_DES_EDE3_CBC, NULL, 168); if (rv != SECSuccess) goto loser; bulkalgtag = SEC_OID_DES_EDE3_CBC; } algorithm = SECOID_FindyCssmAlgorithmByTag(bulkalgtag); if (!algorithm) goto loser; rv = SecKeyGenerate(NULL, /* keychainRef */ algorithm, SecCmsContentInfoGetBulkKeySize(cinfo), 0, /* contextHandle */ CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT, CSSM_KEYATTR_EXTRACTABLE, NULL, /* initialAccess */ &bulkkey); if (rv) goto loser; mark = PORT_ArenaMark(poolp); /* Encrypt the bulk key with the public key of each recipient. */ for (i = 0; recipientinfos[i] != NULL; i++) { rv = SecCmsRecipientInfoWrapBulkKey(recipientinfos[i], bulkkey, bulkalgtag); if (rv != SECSuccess) goto loser; /* error has been set by SecCmsRecipientInfoEncryptBulkKey */ /* could be: alg not supported etc. */ } /* the recipientinfos are all finished. now sort them by DER for SET OF encoding */ rv = SecCmsArraySortByDER((void **)envd->recipientInfos, SecCmsRecipientInfoTemplate, NULL); if (rv != SECSuccess) goto loser; /* error has been set by SecCmsArraySortByDER */ /* store the bulk key in the contentInfo so that the encoder can find it */ SecCmsContentInfoSetBulkKey(cinfo, bulkkey); PORT_ArenaUnmark(poolp, mark); CFRelease(bulkkey); return SECSuccess; loser: if (mark != NULL) PORT_ArenaRelease (poolp, mark); if (bulkkey) CFRelease(bulkkey); return SECFailure; }
int generate_spc_signed_data(SECItem *sdp, cms_context *ctx) { SignedData sd; if (!sdp) return -1; memset(&sd, '\0', sizeof (sd)); if (SEC_ASN1EncodeInteger(ctx->arena, &sd.version, 1) == NULL) return -1; if (generate_algorithm_id_list(&sd.algorithms, ctx) < 0) goto err; if (generate_spc_content_info(&sd.cinfo, ctx) < 0) goto err_algorithms; if (generate_certificate_list(&sd.certificates, ctx) < 0) goto err_cinfo; sd.crls = NULL; if (generate_signerInfo_list(&sd.signerInfos, ctx) < 0) goto err_certificate_list; SECItem encoded = { 0, }; if (SEC_ASN1EncodeItem(ctx->arena, &encoded, &sd, SignedDataTemplate) == NULL) { fprintf(stderr, "Could not encode SignedData: %s\n", PORT_ErrorToString(PORT_GetError())); goto err_signer_infos; } ContentInfo sdw; memset(&sdw, '\0', sizeof (sdw)); SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS7_SIGNED_DATA); memcpy(&sdw.contentType, &oid->oid, sizeof (sdw.contentType)); memcpy(&sdw.content, &encoded, sizeof (sdw.content)); SECItem wrapper = { 0, }; if (SEC_ASN1EncodeItem(ctx->arena, &wrapper, &sdw, ContentInfoTemplate) == NULL) { fprintf(stderr, "Could not encode SignedData: %s\n", PORT_ErrorToString(PORT_GetError())); goto err_signed_data; } memcpy(sdp, &wrapper, sizeof(*sdp)); return 0; err_signed_data: SECITEM_FreeItem(&encoded, PR_FALSE); err_signer_infos: free_signerInfo_list(sd.signerInfos, ctx); err_certificate_list: free_certificate_list(sd.certificates, ctx); err_cinfo: free_spc_content_info(&sd.cinfo, ctx); err_algorithms: free_algorithm_list(sd.algorithms, ctx); err: #if 0 SECITEM_FreeItem(&sd.version, PR_TRUE); #endif return -1; }
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; }
static CERTSignedCrl* CreateNewCrl(PLArenaPool *arena, CERTCertDBHandle *certHandle, CERTCertificate *cert) { CERTSignedCrl *signCrl = NULL; void *dummy = NULL; SECStatus rv; void* mark = NULL; /* if the CERTSignedCrl structure changes, this function will need to be updated as well */ if (!cert || !arena) { PORT_SetError(SEC_ERROR_INVALID_ARGS); SECU_PrintError(progName, "invalid args for function " "CreateNewCrl\n"); return NULL; } mark = PORT_ArenaMark(arena); signCrl = PORT_ArenaZNew(arena, CERTSignedCrl); if (signCrl == NULL) { SECU_PrintError(progName, "fail to allocate memory\n"); return NULL; } dummy = SEC_ASN1EncodeInteger(arena, &signCrl->crl.version, SEC_CRL_VERSION_2); /* set crl->version */ if (!dummy) { SECU_PrintError(progName, "fail to create crl version data " "container\n"); goto loser; } /* copy SECItem name from cert */ rv = SECITEM_CopyItem(arena, &signCrl->crl.derName, &cert->derSubject); if (rv != SECSuccess) { SECU_PrintError(progName, "fail to duplicate der name from " "certificate.\n"); goto loser; } /* copy CERTName name structure from cert issuer */ rv = CERT_CopyName (arena, &signCrl->crl.name, &cert->subject); if (rv != SECSuccess) { SECU_PrintError(progName, "fail to duplicate RD name from " "certificate.\n"); goto loser; } rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now()); if (rv != SECSuccess) { SECU_PrintError(progName, "fail to encode current time\n"); goto loser; } /* set fields */ signCrl->arena = arena; signCrl->dbhandle = certHandle; signCrl->crl.arena = arena; return signCrl; loser: PORT_ArenaRelease(arena, mark); return NULL; }
SECStatus NSS_CMSUtil_EncryptSymKey_MISSI(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *bulkkey, SECOidTag symalgtag, SECItem *encKey, SECItem **pparams, void *pwfn_arg) { SECOidTag certalgtag; /* the certificate's encryption algorithm */ SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */ SECStatus rv = SECFailure; SECItem *params = NULL; SECStatus err; PK11SymKey *tek; CERTCertificate *ourCert; SECKEYPublicKey *ourPubKey, *publickey = NULL; SECKEYPrivateKey *ourPrivKey = NULL; NSSCMSKEATemplateSelector whichKEA = NSSCMSKEAInvalid; NSSCMSSMIMEKEAParameters keaParams; PLArenaPool *arena = NULL; extern const SEC_ASN1Template *nss_cms_get_kea_template(NSSCMSKEATemplateSelector whichTemplate); /* Clear keaParams, since cleanup code checks the lengths */ (void) memset(&keaParams, 0, sizeof(keaParams)); certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); PORT_Assert(certalgtag == SEC_OID_MISSI_KEA_DSS_OLD || certalgtag == SEC_OID_MISSI_KEA_DSS || certalgtag == SEC_OID_MISSI_KEA); #define SMIME_FORTEZZA_RA_LENGTH 128 #define SMIME_FORTEZZA_IV_LENGTH 24 #define SMIME_FORTEZZA_MAX_KEY_SIZE 256 /* We really want to show our KEA tag as the key exchange algorithm tag. */ encalgtag = SEC_OID_NETSCAPE_SMIME_KEA; /* Get the public key of the recipient. */ publickey = CERT_ExtractPublicKey(cert); if (publickey == NULL) goto loser; /* Find our own cert, and extract its keys. */ ourCert = PK11_FindBestKEAMatch(cert, pwfn_arg); if (ourCert == NULL) goto loser; arena = PORT_NewArena(1024); if (arena == NULL) goto loser; ourPubKey = CERT_ExtractPublicKey(ourCert); if (ourPubKey == NULL) { CERT_DestroyCertificate(ourCert); goto loser; } /* While we're here, copy the public key into the outgoing * KEA parameters. */ SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey), &(ourPubKey->u.fortezza.KEAKey)); SECKEY_DestroyPublicKey(ourPubKey); ourPubKey = NULL; /* Extract our private key in order to derive the KEA key. */ ourPrivKey = PK11_FindKeyByAnyCert(ourCert, pwfn_arg); CERT_DestroyCertificate(ourCert); /* we're done with this */ if (!ourPrivKey) goto loser; /* Prepare raItem with 128 bytes (filled with zeros). */ keaParams.originatorRA.data = (unsigned char *)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH); keaParams.originatorRA.len = SMIME_FORTEZZA_RA_LENGTH; /* Generate the TEK (token exchange key) which we use * to wrap the bulk encryption key. (keaparams.originatorRA) will be * filled with a random seed which we need to send to * the recipient. (user keying material in RFC2630/DSA speak) */ tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE, &keaParams.originatorRA, NULL, CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP, CKA_WRAP, 0, pwfn_arg); SECKEY_DestroyPublicKey(publickey); SECKEY_DestroyPrivateKey(ourPrivKey); publickey = NULL; ourPrivKey = NULL; if (!tek) goto loser; /* allocate space for the wrapped key data */ encKey->data = (unsigned char *)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE); encKey->len = SMIME_FORTEZZA_MAX_KEY_SIZE; if (encKey->data == NULL) { PK11_FreeSymKey(tek); goto loser; } /* Wrap the bulk key. What we do with the resulting data depends on whether we're using Skipjack to wrap the key. */ switch (PK11_AlgtagToMechanism(symalgtag)) { case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: /* SKIPJACK, we use the wrap mechanism because we can do it on the hardware */ err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, tek, bulkkey, encKey); whichKEA = NSSCMSKEAUsesSkipjack; break; default: /* Not SKIPJACK, we encrypt the raw key data */ keaParams.nonSkipjackIV.data = (unsigned char *)PORT_ArenaAlloc(arena, SMIME_FORTEZZA_IV_LENGTH); keaParams.nonSkipjackIV.len = SMIME_FORTEZZA_IV_LENGTH; err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV, tek, bulkkey, encKey); if (err != SECSuccess) goto loser; if (encKey->len != PK11_GetKeyLength(bulkkey)) { /* The size of the encrypted key is not the same as that of the original bulk key, presumably due to padding. Encode and store the real size of the bulk key. */ if (SEC_ASN1EncodeInteger(arena, &keaParams.bulkKeySize, PK11_GetKeyLength(bulkkey)) == NULL) err = (SECStatus)PORT_GetError(); else /* use full template for encoding */ whichKEA = NSSCMSKEAUsesNonSkipjackWithPaddedEncKey; } else /* enc key length == bulk key length */ whichKEA = NSSCMSKEAUsesNonSkipjack; break; } PK11_FreeSymKey(tek); if (err != SECSuccess) goto loser; PORT_Assert(whichKEA != NSSCMSKEAInvalid); /* Encode the KEA parameters into the recipient info. */ params = SEC_ASN1EncodeItem(poolp, NULL, &keaParams, nss_cms_get_kea_template(whichKEA)); if (params == NULL) goto loser; /* pass back the algorithm params */ *pparams = params; rv = SECSuccess; loser: if (arena) PORT_FreeArena(arena, PR_FALSE); if (publickey) SECKEY_DestroyPublicKey(publickey); if (ourPrivKey) SECKEY_DestroyPrivateKey(ourPrivKey); return rv; }