NS_IMETHODIMP nsNSSCertificate::SaveSMimeProfile() { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; if (SECSuccess != CERT_SaveSMimeProfile(mCert, nullptr, nullptr)) return NS_ERROR_FAILURE; else return NS_OK; }
/* * XXXX the following needs to be done in the S/MIME layer code * after signature of a signerinfo is verified */ SECStatus NSS_SMIMESignerInfo_SaveSMIMEProfile(NSSCMSSignerInfo *signerinfo) { CERTCertificate *cert = NULL; SECItem *profile = NULL; NSSCMSAttribute *attr; SECItem *stime = NULL; SECItem *ekp; CERTCertDBHandle *certdb; int save_error; SECStatus rv; PRBool must_free_cert = PR_FALSE; certdb = CERT_GetDefaultCertDB(); /* sanity check - see if verification status is ok (unverified does not count...) */ if (signerinfo->verificationStatus != NSSCMSVS_GoodSignature) return SECFailure; /* find preferred encryption cert */ if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr) && (attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL) { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! */ ekp = NSS_CMSAttribute_GetValue(attr); if (ekp == NULL) return SECFailure; /* we assume that all certs coming with the message have been imported to the */ /* temporary database */ cert = NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(certdb, ekp); if (cert == NULL) return SECFailure; must_free_cert = PR_TRUE; } if (cert == NULL) { /* no preferred cert found? * find the cert the signerinfo is signed with instead */ cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb); if (cert == NULL || cert->emailAddr == NULL || !cert->emailAddr[0]) return SECFailure; } /* verify this cert for encryption (has been verified for signing so far) */ /* don't verify this cert for encryption. It may just be a signing cert. * that's OK, we can still save the S/MIME profile. The encryption cert * should have already been saved */ #ifdef notdef if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) { if (must_free_cert) CERT_DestroyCertificate(cert); return SECFailure; } #endif /* XXX store encryption cert permanently? */ /* * Remember the current error set because we do not care about * anything set by the functions we are about to call. */ save_error = PORT_GetError(); if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) { attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_SMIME_CAPABILITIES, PR_TRUE); profile = NSS_CMSAttribute_GetValue(attr); attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE); stime = NSS_CMSAttribute_GetValue(attr); } rv = CERT_SaveSMimeProfile (cert, profile, stime); if (must_free_cert) CERT_DestroyCertificate(cert); /* * Restore the saved error in case the calls above set a new * one that we do not actually care about. */ PORT_SetError (save_error); return rv; }
/* * [noscript] void importEmailCertificates(in charPtr data, in unsigned long length, * in nsIInterfaceRequestor ctx); */ NS_IMETHODIMP nsNSSCertificateDB::ImportEmailCertificate(PRUint8 * data, PRUint32 length, nsIInterfaceRequestor *ctx) { nsNSSShutDownPreventionLock locker; SECStatus srv = SECFailure; nsresult nsrv = NS_OK; CERTCertDBHandle *certdb; CERTCertificate **certArray = NULL; CERTCertList *certList = NULL; CERTCertListNode *node; PRTime now; SECCertUsage certusage; SECItem **rawArray; int numcerts; int i; PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) return NS_ERROR_OUT_OF_MEMORY; CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length); if (!certCollection) { PORT_FreeArena(arena, PR_FALSE); return NS_ERROR_FAILURE; } certdb = CERT_GetDefaultCertDB(); certusage = certUsageEmailRecipient; numcerts = certCollection->numcerts; rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts); if ( !rawArray ) { nsrv = NS_ERROR_FAILURE; goto loser; } for (i=0; i < numcerts; i++) { rawArray[i] = &certCollection->rawCerts[i]; } srv = CERT_ImportCerts(certdb, certusage, numcerts, rawArray, &certArray, PR_FALSE, PR_FALSE, NULL); PORT_Free(rawArray); rawArray = NULL; if (srv != SECSuccess) { nsrv = NS_ERROR_FAILURE; goto loser; } // build a CertList for filtering certList = CERT_NewCertList(); if (certList == NULL) { nsrv = NS_ERROR_FAILURE; goto loser; } for (i=0; i < numcerts; i++) { CERTCertificate *cert = certArray[i]; if (cert) cert = CERT_DupCertificate(cert); if (cert) CERT_AddCertToListTail(certList, cert); } /* go down the remaining list of certs and verify that they have * valid chains, then import them. */ now = PR_Now(); for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node,certList); node = CERT_LIST_NEXT(node)) { bool alert_and_skip = false; if (!node->cert) { continue; } if (CERT_VerifyCert(certdb, node->cert, PR_TRUE, certusage, now, ctx, NULL) != SECSuccess) { alert_and_skip = true; } CERTCertificateList *certChain = nsnull; CERTCertificateListCleaner chainCleaner(certChain); if (!alert_and_skip) { certChain = CERT_CertChainFromCert(node->cert, certusage, PR_FALSE); if (!certChain) { alert_and_skip = true; } } if (alert_and_skip) { nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(node->cert); DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow); continue; } /* * CertChain returns an array of SECItems, import expects an array of * SECItem pointers. Create the SECItem Pointers from the array of * SECItems. */ rawArray = (SECItem **) PORT_Alloc(certChain->len * sizeof(SECItem *)); if (!rawArray) { continue; } for (i=0; i < certChain->len; i++) { rawArray[i] = &certChain->certs[i]; } CERT_ImportCerts(certdb, certusage, certChain->len, rawArray, NULL, PR_TRUE, PR_FALSE, NULL); CERT_SaveSMimeProfile(node->cert, NULL, NULL); PORT_Free(rawArray); } loser: if (certArray) { CERT_DestroyCertArray(certArray, numcerts); } if (certList) { CERT_DestroyCertList(certList); } if (arena) PORT_FreeArena(arena, PR_TRUE); return nsrv; }
/* * XXXX the following needs to be done in the S/MIME layer code * after signature of a signerinfo is verified */ OSStatus SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo) { SecCertificateRef cert = NULL; CSSM_DATA_PTR profile = NULL; SecCmsAttribute *attr; CSSM_DATA_PTR utc_stime = NULL; CSSM_DATA_PTR ekp; int save_error; OSStatus rv; Boolean must_free_cert = PR_FALSE; OSStatus status; SecKeychainRef keychainOrArray; status = SecKeychainCopyDefault(&keychainOrArray); /* sanity check - see if verification status is ok (unverified does not count...) */ if (signerinfo->verificationStatus != SecCmsVSGoodSignature) return SECFailure; /* find preferred encryption cert */ if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr) && (attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL) { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! */ ekp = SecCmsAttributeGetValue(attr); if (ekp == NULL) return SECFailure; /* we assume that all certs coming with the message have been imported to the */ /* temporary database */ cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, ekp); if (cert == NULL) return SECFailure; must_free_cert = PR_TRUE; } if (cert == NULL) { /* no preferred cert found? * find the cert the signerinfo is signed with instead */ CFStringRef emailAddress=NULL; cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray); if (cert == NULL) return SECFailure; if (SecCertificateGetEmailAddress(cert,&emailAddress)) return SECFailure; } /* verify this cert for encryption (has been verified for signing so far) */ /* don't verify this cert for encryption. It may just be a signing cert. * that's OK, we can still save the S/MIME profile. The encryption cert * should have already been saved */ #ifdef notdef if (CERT_VerifyCert(keychainOrArray, cert, certUsageEmailRecipient, CFAbsoluteTimeGetCurrent(), NULL) != SECSuccess) { if (must_free_cert) CERT_DestroyCertificate(cert); return SECFailure; } #endif /* XXX store encryption cert permanently? */ /* * Remember the current error set because we do not care about * anything set by the functions we are about to call. */ save_error = PORT_GetError(); if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) { attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_SMIME_CAPABILITIES, PR_TRUE); profile = SecCmsAttributeGetValue(attr); attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE); utc_stime = SecCmsAttributeGetValue(attr); } rv = CERT_SaveSMimeProfile (cert, profile, utc_stime); if (must_free_cert) CERT_DestroyCertificate(cert); /* * Restore the saved error in case the calls above set a new * one that we do not actually care about. */ PORT_SetError (save_error); return rv; }