NSSCMSMessage * NSS_SMIMEMessage_CreateSigned(CERTCertificate *scert, CERTCertificate *ecert, CERTCertDBHandle *certdb, SECOidTag digestalgtag, SECItem *digest, PK11PasswordFunc pwfn, void *pwfn_arg) { NSSCMSMessage *cmsg; NSSCMSSignedData *sigd; NSSCMSSignerInfo *signerinfo; /* See note in header comment above about digestalg. */ /* Doesn't explain this. PORT_Assert (digestalgtag == SEC_OID_SHA1); */ cmsg = NSS_CMSMessage_Create(NULL); if (cmsg == NULL) return NULL; sigd = NSS_CMSSignedData_Create(cmsg); if (sigd == NULL) goto loser; /* create just one signerinfo */ signerinfo = NSS_CMSSignerInfo_Create(cmsg, scert, digestalgtag); if (signerinfo == NULL) goto loser; /* Add the signing time to the signerinfo. */ if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) != SECSuccess) goto loser; /* and add the SMIME profile */ if (NSS_SMIMESignerInfo_AddSMIMEProfile(signerinfo, scert) != SECSuccess) goto loser; /* now add the signerinfo to the signeddata */ if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) goto loser; /* include the signing cert and its entire chain */ /* note that there are no checks for duplicate certs in place, as all the */ /* essential data structures (like set of certificate) are not there */ if (NSS_CMSSignedData_AddCertChain(sigd, scert) != SECSuccess) goto loser; /* If the encryption cert and the signing cert differ, then include * the encryption cert too. */ if ( ( ecert != NULL ) && ( ecert != scert ) ) { if (NSS_CMSSignedData_AddCertificate(sigd, ecert) != SECSuccess) goto loser; } return cmsg; loser: if (cmsg) NSS_CMSMessage_Destroy(cmsg); return NULL; }
FILE * smime_sign(FILE *ip, struct header *headp) { NSSCMSMessage *msg; NSSCMSContentInfo *content; NSSCMSSignedData *data; NSSCMSSignerInfo *info; CERTCertificate *cert; CERTCertDBHandle *handle; FILE *hp, *bp, *sp; char *addr; if (nss_init() != OKAY) return NULL; if ((addr = myorigin(headp)) == NULL) { fprintf(stderr, "No \"from\" address for signing specified\n"); return NULL; } if ((cert = get_signer_cert(addr)) == NULL) return NULL; handle = CERT_GetDefaultCertDB(); if ((msg = NSS_CMSMessage_Create(NULL)) == NULL) { fprintf(stderr, "Cannot create CMS message.\n"); return NULL; } if ((data = NSS_CMSSignedData_Create(msg)) == NULL) { fprintf(stderr, "Cannot create CMS signed data.\n"); return NULL; } content = NSS_CMSMessage_GetContentInfo(msg); if (NSS_CMSContentInfo_SetContent_SignedData(msg, content, data) != SECSuccess) { fprintf(stderr, "Cannot attach CMS signed data.\n"); return NULL; } content = NSS_CMSSignedData_GetContentInfo(data); if (NSS_CMSContentInfo_SetContent_Data(msg, content, NULL, PR_TRUE) != SECSuccess) { fprintf(stderr, "Cannot attach CMS data.\n"); return NULL; } if ((info = NSS_CMSSignerInfo_Create(msg, cert, SEC_OID_SHA1)) == 0) { fprintf(stderr, "Cannot create signed information.\n"); return NULL; } if (NSS_CMSSignerInfo_IncludeCerts(info, NSSCMSCM_CertOnly, certUsageEmailSigner) != SECSuccess) { fprintf(stderr, "Cannot include certificate.\n"); return NULL; } if (NSS_CMSSignerInfo_AddSigningTime(info, PR_Now()) != SECSuccess) { fprintf(stderr, "Cannot add signing time.\n"); return NULL; } if (NSS_CMSSignerInfo_AddSMIMECaps(info) != SECSuccess) { fprintf(stderr, "Cannot add S/MIME capabilities.\n"); return NULL; } NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(info, cert, handle); NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(info, cert, handle); if (NSS_CMSSignedData_AddCertificate(data, cert) != SECSuccess) { fprintf(stderr, "Cannot add encryption certificate.\n"); return NULL; } if (NSS_CMSSignedData_AddSignerInfo(data, info) != SECSuccess) { fprintf(stderr, "Cannot add signer information.\n"); return NULL; } CERT_DestroyCertificate(cert); if ((sp = encode(ip, &hp, &bp, msg, base64_cb)) == NULL) { NSS_CMSMessage_Destroy(msg); return NULL; } NSS_CMSMessage_Destroy(msg); return smime_sign_assemble(hp, bp, sp); }
static NSSCMSMessage * sm_signing_cmsmessage(CamelSMIMEContext *context, const char *nick, SECOidTag hash, int detached, CamelException *ex) { struct _CamelSMIMEContextPrivate *p = context->priv; NSSCMSMessage *cmsg = NULL; NSSCMSContentInfo *cinfo; NSSCMSSignedData *sigd; NSSCMSSignerInfo *signerinfo; CERTCertificate *cert= NULL, *ekpcert = NULL; if ((cert = CERT_FindUserCertByUsage(p->certdb, (char *)nick, certUsageEmailSigner, PR_FALSE, NULL)) == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate for '%s'"), nick); return NULL; } cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */ if (cmsg == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS message")); goto fail; } if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS signed data")); goto fail; } cinfo = NSS_CMSMessage_GetContentInfo(cmsg); if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS signed data")); goto fail; } /* if !detatched, the contentinfo will alloc a data item for us */ cinfo = NSS_CMSSignedData_GetContentInfo(sigd); if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, detached) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS data")); goto fail; } signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, hash); if (signerinfo == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Signer information")); goto fail; } /* we want the cert chain included for this one */ if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate chain")); goto fail; } /* SMIME RFC says signing time should always be added */ if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS Signing time")); goto fail; } #if 0 /* this can but needn't be added. not sure what general usage is */ if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) { fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.\n"); goto loser; } #endif /* Check if we need to send along our return encrypt cert, rfc2633 2.5.3 */ if (p->send_encrypt_key_prefs) { CERTCertificate *enccert = NULL; if (p->encrypt_key) { /* encrypt key has its own nick */ if ((ekpcert = CERT_FindUserCertByUsage( p->certdb, p->encrypt_key, certUsageEmailRecipient, PR_FALSE, NULL)) == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Encryption certificate for '%s' does not exist"), p->encrypt_key); goto fail; } enccert = ekpcert; } else if (CERT_CheckCertUsage(cert, certUsageEmailRecipient) == SECSuccess) { /* encrypt key is signing key */ enccert = cert; } else { /* encrypt key uses same nick */ if ((ekpcert = CERT_FindUserCertByUsage( p->certdb, (char *)nick, certUsageEmailRecipient, PR_FALSE, NULL)) == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Encryption certificate for '%s' does not exist"), nick); goto fail; } enccert = ekpcert; } if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, enccert, p->certdb) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add SMIMEEncKeyPrefs attribute")); goto fail; } if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, enccert, p->certdb) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add MS SMIMEEncKeyPrefs attribute")); goto fail; } if (ekpcert != NULL && NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add encryption certificate")); goto fail; } } if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS Signer information")); goto fail; } if (ekpcert) CERT_DestroyCertificate(ekpcert); if (cert) CERT_DestroyCertificate(cert); return cmsg; fail: if (ekpcert) CERT_DestroyCertificate(ekpcert); if (cert) CERT_DestroyCertificate(cert); NSS_CMSMessage_Destroy(cmsg); return NULL; }
NS_IMETHODIMP nsCMSMessage::CreateSigned(nsIX509Cert* aSigningCert, nsIX509Cert* aEncryptCert, unsigned char* aDigestData, PRUint32 aDigestDataLen) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned\n")); NSSCMSContentInfo *cinfo; NSSCMSSignedData *sigd; NSSCMSSignerInfo *signerinfo; CERTCertificate *scert = nsnull, *ecert = nsnull; nsCOMPtr<nsIX509Cert2> aSigningCert2 = do_QueryInterface(aSigningCert); nsresult rv = NS_ERROR_FAILURE; /* Get the certs */ if (aSigningCert2) { scert = aSigningCert2->GetCert(); } if (!scert) { return NS_ERROR_FAILURE; } if (aEncryptCert) { nsCOMPtr<nsIX509Cert2> aEncryptCert2 = do_QueryInterface(aEncryptCert); if (aEncryptCert2) { ecert = aEncryptCert2->GetCert(); } } CERTCertificateCleaner ecertCleaner(ecert); CERTCertificateCleaner scertCleaner(scert); /* * create the message object */ m_cmsMsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */ if (m_cmsMsg == NULL) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create new message\n")); rv = NS_ERROR_OUT_OF_MEMORY; goto loser; } /* * build chain of objects: message->signedData->data */ if ((sigd = NSS_CMSSignedData_Create(m_cmsMsg)) == NULL) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signed data\n")); goto loser; } cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg); if (NSS_CMSContentInfo_SetContent_SignedData(m_cmsMsg, cinfo, sigd) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content signed data\n")); goto loser; } cinfo = NSS_CMSSignedData_GetContentInfo(sigd); /* we're always passing data in and detaching optionally */ if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nsnull, PR_TRUE) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content data\n")); goto loser; } /* * create & attach signer information */ if ((signerinfo = NSS_CMSSignerInfo_Create(m_cmsMsg, scert, SEC_OID_SHA1)) == NULL) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signer info\n")); goto loser; } /* we want the cert chain included for this one */ if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't include signer cert chain\n")); goto loser; } if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signing time\n")); goto loser; } if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime caps\n")); goto loser; } if (ecert) { if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ecert, CERT_GetDefaultCertDB()) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime enc key prefs\n")); goto loser; } if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ecert, CERT_GetDefaultCertDB()) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add MS smime enc key prefs\n")); goto loser; } // If signing and encryption cert are identical, don't add it twice. PRBool addEncryptionCert = (ecert && (!scert || !CERT_CompareCerts(ecert, scert))); if (addEncryptionCert && NSS_CMSSignedData_AddCertificate(sigd, ecert) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add own encryption certificate\n")); goto loser; } } if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signer info\n")); goto loser; } // Finally, add the pre-computed digest if passed in if (aDigestData) { SECItem digest; digest.data = aDigestData; digest.len = aDigestDataLen; if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set digest value\n")); goto loser; } } return NS_OK; loser: if (m_cmsMsg) { NSS_CMSMessage_Destroy(m_cmsMsg); m_cmsMsg = nsnull; } return rv; }