/* * NSS_CMSSignedData_AddCertChain - add cert and its entire chain to the set of certs */ SECStatus NSS_CMSSignedData_AddCertChain(NSSCMSSignedData *sigd, CERTCertificate *cert) { CERTCertificateList *certlist; SECCertUsage usage; SECStatus rv; usage = certUsageEmailSigner; if (!sigd || !cert) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* do not include root */ certlist = CERT_CertChainFromCert(cert, usage, PR_FALSE); if (certlist == NULL) return SECFailure; rv = NSS_CMSSignedData_AddCertList(sigd, certlist); return rv; }
NS_IMETHODIMP nsNSSCertificate::ExportAsCMS(uint32_t chainMode, uint32_t *aLength, uint8_t **aArray) { NS_ENSURE_ARG(aLength); NS_ENSURE_ARG(aArray); nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; if (!mCert) return NS_ERROR_FAILURE; switch (chainMode) { case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly: case nsIX509Cert3::CMS_CHAIN_MODE_CertChain: case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot: break; default: return NS_ERROR_INVALID_ARG; }; PLArenaPool *arena = PORT_NewArena(1024); PLArenaPoolCleanerFalseParam arenaCleaner(arena); if (!arena) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSCertificate::ExportAsCMS - out of memory\n")); return NS_ERROR_OUT_OF_MEMORY; } NSSCMSMessage *cmsg = NSS_CMSMessage_Create(nullptr); NSSCMSMessageCleaner cmsgCleaner(cmsg); if (!cmsg) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n")); return NS_ERROR_OUT_OF_MEMORY; } /* * first, create SignedData with the certificate only (no chain) */ NSSCMSSignedData *sigd = NSS_CMSSignedData_CreateCertsOnly(cmsg, mCert, false); NSSCMSSignedDataCleaner sigdCleaner(sigd); if (!sigd) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n")); return NS_ERROR_FAILURE; } /* * Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us * to specify the inclusion of the root, but CERT_CertChainFromCert() does. * Since CERT_CertChainFromCert() also includes the certificate itself, * we have to start at the issuing cert (to avoid duplicate certs * in the SignedData). */ if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain || chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) { CERTCertificate *issuerCert = CERT_FindCertIssuer(mCert, PR_Now(), certUsageAnyCA); CERTCertificateCleaner issuerCertCleaner(issuerCert); /* * the issuerCert of a self signed root is the cert itself, * so make sure we're not adding duplicates, again */ if (issuerCert && issuerCert != mCert) { bool includeRoot = (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot); CERTCertificateList *certChain = CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot); CERTCertificateListCleaner certChainCleaner(certChain); if (certChain) { if (NSS_CMSSignedData_AddCertList(sigd, certChain) == SECSuccess) { certChainCleaner.detach(); } else { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSCertificate::ExportAsCMS - can't add chain\n")); return NS_ERROR_FAILURE; } } else { /* try to add the issuerCert, at least */ if (NSS_CMSSignedData_AddCertificate(sigd, issuerCert) == SECSuccess) { issuerCertCleaner.detach(); } else { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n")); return NS_ERROR_FAILURE; } } } } NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(cmsg); if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) == SECSuccess) { sigdCleaner.detach(); } else { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n")); return NS_ERROR_FAILURE; } SECItem certP7 = { siBuffer, nullptr, 0 }; NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(cmsg, nullptr, nullptr, &certP7, arena, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (!ecx) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n")); return NS_ERROR_FAILURE; } if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n")); return NS_ERROR_FAILURE; } *aArray = (uint8_t*)nsMemory::Alloc(certP7.len); if (!*aArray) return NS_ERROR_OUT_OF_MEMORY; memcpy(*aArray, certP7.data, certP7.len); *aLength = certP7.len; return NS_OK; }