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; }
void nsCMSMessage::destructorSafeDestroyNSSReference() { if (isAlreadyShutDown()) return; if (m_cmsMsg) { NSS_CMSMessage_Destroy(m_cmsMsg); } }
/* * nsCMSSecureMessage::ReceiveMessage */ nsresult nsCMSSecureMessage:: ReceiveMessage(const char *msg, char **_retval) { nsNSSShutDownPreventionLock locker; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage\n")); nsresult rv = NS_OK; NSSCMSDecoderContext *dcx; unsigned char *der = 0; PRInt32 derLen; NSSCMSMessage *cmsMsg = 0; SECItem *content; nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); /* Step 1. Decode the base64 wrapper */ rv = decode(msg, &der, &derLen); if (NS_FAILED(rv)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't base64 decode\n")); goto done; } dcx = NSS_CMSDecoder_Start(0, 0, 0, /* pw */ 0, ctx, /* key */ 0, 0); if (!dcx) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't start decoder\n")); rv = NS_ERROR_FAILURE; goto done; } (void)NSS_CMSDecoder_Update(dcx, (char *)der, derLen); cmsMsg = NSS_CMSDecoder_Finish(dcx); if (!cmsMsg) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't finish decoder\n")); rv = NS_ERROR_FAILURE; /* Memory leak on dcx?? */ goto done; } content = NSS_CMSMessage_GetContent(cmsMsg); if (!content) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't get content\n")); rv = NS_ERROR_FAILURE; goto done; } /* Copy the data */ *_retval = (char*)malloc(content->len+1); memcpy(*_retval, content->data, content->len); (*_retval)[content->len] = 0; done: if (der) free(der); if (cmsMsg) NSS_CMSMessage_Destroy(cmsMsg); return rv; }
void NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri) { if (!ri) { return; } /* version was allocated on the pool, so no need to destroy it */ /* issuerAndSN was allocated on the pool, so no need to destroy it */ if (ri->cert != NULL) CERT_DestroyCertificate(ri->cert); if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) { NSSCMSKeyTransRecipientInfoEx *extra; extra = &ri->ri.keyTransRecipientInfoEx; if (extra->pubKey) SECKEY_DestroyPublicKey(extra->pubKey); } if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) { NSS_CMSMessage_Destroy(ri->cmsg); } /* we're done. */ }
enum okay smime_certsave(struct message *m, int n, FILE *op) { NSSCMSMessage *msg; CERTCertDBHandle *handle; int nlevels, i, cnt = 0; enum okay ok = OKAY; if (nss_init() == STOP) return STOP; if ((m = getsig(m, n, &msg)) == NULL) return 1; handle = CERT_GetDefaultCertDB(); nlevels = NSS_CMSMessage_ContentLevelCount(msg); for (i = 0; i < nlevels; i++) { NSSCMSContentInfo *content; SECOidTag tag; content = NSS_CMSMessage_ContentLevel(msg, i); tag = NSS_CMSContentInfo_GetContentTypeTag(content); if (tag == SEC_OID_PKCS7_SIGNED_DATA) { NSSCMSSignedData *data; int nsigners, j; if ((data = NSS_CMSContentInfo_GetContent(content)) == NULL) { fprintf(stderr, "Signed data missing for " "message %d.\n", n); ok = STOP; break; } if (NSS_CMSSignedData_ImportCerts(data, handle, certUsageEmailSigner, PR_FALSE) != SECSuccess) { fprintf(stderr, "Cannot temporarily import " "certificates for " "message %d.\n", n); ok = STOP; break; } nsigners = NSS_CMSSignedData_SignerInfoCount(data); if (nsigners == 0) { fprintf(stderr, "Message %d has no signers.\n", n); ok = STOP; break; } for (j = 0; j < nsigners; j++) { NSSCMSSignerInfo *info; CERTCertificateList *list; CERTCertificate *cert; int k; info = NSS_CMSSignedData_GetSignerInfo(data, j); list = NSS_CMSSignerInfo_GetCertList(info); if (list) { for (k = 0; k < list->len; k++) { cert = (CERTCertificate *) &list->certs[k]; dumpcert(cert, op); cnt++; } } cert = NSS_CMSSignerInfo_GetSigningCertificate (info, handle); if (cert) { dumpcert(cert, op); cnt++; } } } } NSS_CMSMessage_Destroy(msg); if (cnt == 0) { fprintf(stderr, "No certificates found in message %d.\n", n); ok = STOP; } return ok; }
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; }
static CamelCipherValidity * sm_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex) { NSSCMSDecoderContext *dec; NSSCMSMessage *cmsg; CamelStreamMem *istream; CamelStream *ostream; CamelCipherValidity *valid = NULL; /* FIXME: This assumes the content is only encrypted. Perhaps its ok for this api to do this ... */ ostream = camel_stream_mem_new(); camel_stream_mem_set_secure((CamelStreamMem *)ostream); /* FIXME: stream this to the decoder incrementally */ istream = (CamelStreamMem *)camel_stream_mem_new(); camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)ipart), (CamelStream *)istream); camel_stream_reset((CamelStream *)istream); dec = NSS_CMSDecoder_Start(NULL, sm_write_stream, ostream, /* content callback */ NULL, NULL, NULL, NULL); /* decrypt key callback */ if (NSS_CMSDecoder_Update(dec, (char *) istream->buffer->data, istream->buffer->len) != SECSuccess) { printf("decoder update failed\n"); } camel_object_unref(istream); cmsg = NSS_CMSDecoder_Finish(dec); if (cmsg == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Decoder failed, error %d"), PORT_GetError()); goto fail; } #if 0 /* not sure if we really care about this? */ if (!NSS_CMSMessage_IsEncrypted(cmsg)) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("S/MIME Decrypt: No encrypted content found")); NSS_CMSMessage_Destroy(cmsg); goto fail; } #endif camel_stream_reset(ostream); camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream); if (NSS_CMSMessage_IsSigned(cmsg)) { valid = sm_verify_cmsg(context, cmsg, NULL, ex); } else { valid = camel_cipher_validity_new(); valid->encrypt.description = g_strdup(_("Encrypted content")); valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED; } NSS_CMSMessage_Destroy(cmsg); fail: camel_object_unref(ostream); return valid; }
static int sm_encrypt(CamelCipherContext *context, const char *userid, GPtrArray *recipients, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex) { struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv; /*NSSCMSRecipientInfo **recipient_infos;*/ CERTCertificate **recipient_certs = NULL; NSSCMSContentInfo *cinfo; PK11SymKey *bulkkey = NULL; SECOidTag bulkalgtag; int bulkkeysize, i; CK_MECHANISM_TYPE type; PK11SlotInfo *slot; PLArenaPool *poolp; NSSCMSMessage *cmsg = NULL; NSSCMSEnvelopedData *envd; NSSCMSEncoderContext *enc = NULL; CamelStreamMem *mem; CamelStream *ostream = NULL; CamelDataWrapper *dw; CamelContentType *ct; poolp = PORT_NewArena(1024); if (poolp == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM)); return -1; } /* Lookup all recipients certs, for later working */ recipient_certs = (CERTCertificate **)PORT_ArenaZAlloc(poolp, sizeof(*recipient_certs[0])*(recipients->len + 1)); if (recipient_certs == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM)); goto fail; } for (i=0;i<recipients->len;i++) { recipient_certs[i] = CERT_FindCertByNicknameOrEmailAddr(p->certdb, recipients->pdata[i]); if (recipient_certs[i] == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate for `%s'"), recipients->pdata[i]); goto fail; } } /* Find a common algorithm, probably 3DES anyway ... */ if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipient_certs, &bulkalgtag, &bulkkeysize) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find common bulk encryption algorithm")); goto fail; } /* Generate a new bulk key based on the common algorithm - expensive */ type = PK11_AlgtagToMechanism(bulkalgtag); slot = PK11_GetBestSlot(type, context); if (slot == NULL) { /* PORT_GetError(); ?? */ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot allocate slot for encryption bulk key")); goto fail; } bulkkey = PK11_KeyGen(slot, type, NULL, bulkkeysize/8, context); PK11_FreeSlot(slot); /* Now we can start building the message */ /* msg->envelopedData->data */ cmsg = NSS_CMSMessage_Create(NULL); if (cmsg == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Message")); goto fail; } envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, bulkkeysize); if (envd == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Enveloped data")); goto fail; } cinfo = NSS_CMSMessage_GetContentInfo(cmsg); if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS Enveloped data")); goto fail; } cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd); if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS data object")); goto fail; } /* add recipient certs */ for (i=0;recipient_certs[i];i++) { NSSCMSRecipientInfo *ri = NSS_CMSRecipientInfo_Create(cmsg, recipient_certs[i]); if (ri == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Recipient information")); goto fail; } if (NSS_CMSEnvelopedData_AddRecipient(envd, ri) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS Recipient information")); goto fail; } } /* dump it out */ ostream = camel_stream_mem_new(); enc = NSS_CMSEncoder_Start(cmsg, sm_write_stream, ostream, NULL, NULL, NULL, NULL, sm_decrypt_key, bulkkey, NULL, NULL); if (enc == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create encoder context")); goto fail; } /* FIXME: Stream the input */ /* FIXME: Canonicalise the input? */ mem = (CamelStreamMem *)camel_stream_mem_new(); camel_data_wrapper_write_to_stream((CamelDataWrapper *)ipart, (CamelStream *)mem); if (NSS_CMSEncoder_Update(enc, (char *) mem->buffer->data, mem->buffer->len) != SECSuccess) { NSS_CMSEncoder_Cancel(enc); camel_object_unref(mem); camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to add data to encoder")); goto fail; } camel_object_unref(mem); if (NSS_CMSEncoder_Finish(enc) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to encode data")); goto fail; } PK11_FreeSymKey(bulkkey); NSS_CMSMessage_Destroy(cmsg); for (i=0;recipient_certs[i];i++) CERT_DestroyCertificate(recipient_certs[i]); PORT_FreeArena(poolp, PR_FALSE); dw = camel_data_wrapper_new(); camel_data_wrapper_construct_from_stream(dw, ostream); camel_object_unref(ostream); dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY; ct = camel_content_type_new("application", "x-pkcs7-mime"); camel_content_type_set_param(ct, "name", "smime.p7m"); camel_content_type_set_param(ct, "smime-type", "enveloped-data"); camel_data_wrapper_set_mime_type_field(dw, ct); camel_content_type_unref(ct); camel_medium_set_content_object((CamelMedium *)opart, dw); camel_object_unref(dw); camel_mime_part_set_disposition(opart, "attachment"); camel_mime_part_set_filename(opart, "smime.p7m"); camel_mime_part_set_description(opart, "S/MIME Encrypted Message"); camel_mime_part_set_encoding(opart, CAMEL_TRANSFER_ENCODING_BASE64); return 0; fail: if (ostream) camel_object_unref(ostream); if (cmsg) NSS_CMSMessage_Destroy(cmsg); if (bulkkey) PK11_FreeSymKey(bulkkey); if (recipient_certs) { for (i=0;recipient_certs[i];i++) CERT_DestroyCertificate(recipient_certs[i]); } PORT_FreeArena(poolp, PR_FALSE); return -1; }
UtlBoolean SmimeBody::nssSmimeEncrypt(int numResipientCerts, const char* derPublicKeyCerts[], int derPublicKeyCertLengths[], const char* dataToEncrypt, int dataToEncryptLength, UtlBoolean encryptedDataInBase64Format, UtlString& encryptedData) { UtlBoolean encryptionSucceeded = FALSE; encryptedData.remove(0); #ifdef ENABLE_NSS_SMIME // nickname can be NULL as we are not putting this in a database char *nickname = NULL; // copyDER = true so we copy the DER format cert passed in so memory // is internally alloc'd and freed PRBool copyDER = true; // Create an envelope or container for the encrypted data SECOidTag algorithm = SEC_OID_DES_EDE3_CBC; // or SEC_OID_AES_128_CBC // Should be able to get the key size from the cert somehow int keysize = 1024; NSSCMSMessage* cmsMessage = NSS_CMSMessage_Create(NULL); NSSCMSEnvelopedData* myEnvelope = NSS_CMSEnvelopedData_Create(cmsMessage, algorithm, keysize); // Do the following for each recipient if there is more than one. // For each recipient: for(int certIndex = 0; certIndex < numResipientCerts; certIndex++) { // Convert the DER to a NSS CERT SECItem derFormatCertItem; SECItem* derFormatCertItemPtr = &derFormatCertItem; derFormatCertItem.data = (unsigned char*) derPublicKeyCerts[certIndex]; derFormatCertItem.len = derPublicKeyCertLengths[certIndex]; CERTCertificate* myCertFromDer = NULL; myCertFromDer = __CERT_DecodeDERCertificate(&derFormatCertItem, copyDER, nickname); // Add just the recipient Subject key Id, if it exists to the envelope // This is the minimal information needed to identify which recipient // the the symetric/session key is encrypted for NSSCMSRecipientInfo* recipientInfo = NULL; // Add the full set of recipient information including // the Cert. issuer location and org. info. recipientInfo = NSS_CMSRecipientInfo_Create(cmsMessage, myCertFromDer); if(recipientInfo) { if(NSS_CMSEnvelopedData_AddRecipient(myEnvelope , recipientInfo) != SECSuccess) { NSS_CMSEnvelopedData_Destroy(myEnvelope); myEnvelope = NULL; NSS_CMSRecipientInfo_Destroy(recipientInfo); } } // No recipientInfo else { NSS_CMSEnvelopedData_Destroy(myEnvelope); myEnvelope = NULL; } } //end for each recipient // Get the content out of the envelop NSSCMSContentInfo* envelopContentInfo = NSS_CMSEnvelopedData_GetContentInfo(myEnvelope); //TODO: why are we copying or setting the content pointer from the envelope into the msg???????? if (NSS_CMSContentInfo_SetContent_Data(cmsMessage, envelopContentInfo, NULL, PR_FALSE) != SECSuccess) { // release cmsg and other stuff NSS_CMSEnvelopedData_Destroy(myEnvelope); myEnvelope = NULL; } //TODO: why are we copying or setting the content pointer from the message and // putting it back into the msg???????? NSSCMSContentInfo* messageContentInfo = NSS_CMSMessage_GetContentInfo(cmsMessage); if(NSS_CMSContentInfo_SetContent_EnvelopedData(cmsMessage, messageContentInfo, myEnvelope) != SECSuccess) { // release cmsg and other stuff NSS_CMSEnvelopedData_Destroy(myEnvelope); myEnvelope = NULL; } if(cmsMessage) { // Create an encoder and context to do the encryption. // The encodedItem will stort the encoded result //SECItem encodedItem; //encodedItem.data = NULL; //encodedItem.len = 0; //SECITEM_AllocItem(NULL, &encodedItem, 0); printf("start encoder\n"); NSSCMSEncoderContext* encoderContext = NSS_CMSEncoder_Start(cmsMessage, nssOutToUtlString, &encryptedData, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); // Add encrypted content printf("update encoder\n"); NSS_CMSEncoder_Update(encoderContext, dataToEncrypt, dataToEncryptLength); // Finished encrypting printf("finish encoder\n"); NSS_CMSEncoder_Finish(encoderContext); myEnvelope = NULL; if(encryptedData.length() > 0) { encryptionSucceeded = TRUE; } // Clean up the message memory, the envelop gets cleaned up // with the message NSS_CMSMessage_Destroy(cmsMessage); cmsMessage = NULL; } #else Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SmimeBody::nssSmimeEncrypt invoked with ENABLE_NSS_SMIME not defined"); #endif return(encryptionSucceeded); }
struct message * smime_decrypt(struct message *m, const char *to, const char *cc, int signcall) { NSSCMSDecoderContext *ctx; NSSCMSMessage *msg; FILE *op, *hp, *bp; char *buf = NULL; size_t bufsize = 0, buflen, count; char *cp; struct str in, out; FILE *yp; long size; int i, nlevels; int binary = 0; if ((yp = setinput(&mb, m, NEED_BODY)) == NULL) return NULL; if (nss_init() != OKAY) return NULL; if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) { perror("tempfile"); return NULL; } rm(cp); Ftfree(&cp); if ((ctx = NSS_CMSDecoder_Start(NULL, decoder_cb, op, password_cb, "Pass phrase:", NULL, NULL)) == NULL) { fprintf(stderr, "Cannot start decoder.\n"); return NULL; } size = m->m_size; if ((smime_split(yp, &hp, &bp, size, 1)) == STOP) return NULL; count = fsize(bp); while (fgetline(&buf, &bufsize, &count, &buflen, bp, 0) != NULL) { if (buf[0] == '\n') break; if ((cp = thisfield(buf, "content-transfer-encoding")) != NULL) if (ascncasecmp(cp, "binary", 7) == 0) binary = 1; } while (fgetline(&buf, &bufsize, &count, &buflen, bp, 0) != NULL) { if (binary) NSS_CMSDecoder_Update(ctx, buf, buflen); else { in.s = buf; in.l = buflen; mime_fromb64_b(&in, &out, 0, bp); NSS_CMSDecoder_Update(ctx, out.s, out.l); free(out.s); } } free(buf); if ((msg = NSS_CMSDecoder_Finish(ctx)) == NULL) { fprintf(stderr, "Failed to decode message.\n"); Fclose(hp); Fclose(bp); return NULL; } nlevels = NSS_CMSMessage_ContentLevelCount(msg); for (i = 0; i < nlevels; i++) { NSSCMSContentInfo *content; SECOidTag tag; content = NSS_CMSMessage_ContentLevel(msg, i); tag = NSS_CMSContentInfo_GetContentTypeTag(content); if (tag == SEC_OID_PKCS7_DATA) { const char *fld = "X-Encryption-Cipher"; SECOidTag alg; int keysize; alg = NSS_CMSContentInfo_GetContentEncAlgTag(content); keysize = NSS_CMSContentInfo_GetBulkKeySize(content); fseek(hp, 0L, SEEK_END); switch (alg) { case 0: if (signcall) { NSS_CMSMessage_Destroy(msg); Fclose(hp); Fclose(bp); setinput(&mb, m, NEED_BODY); return (struct message *)-1; } fprintf(hp, "%s: none\n", fld); break; case SEC_OID_RC2_CBC: fprintf(hp, "%s: RC2, %d bits\n", fld, keysize); break; case SEC_OID_DES_CBC: fprintf(hp, "%s: DES, 56 bits\n", fld); break; case SEC_OID_DES_EDE3_CBC: fprintf(hp, "%s: 3DES, 112/168 bits\n", fld); break; case SEC_OID_FORTEZZA_SKIPJACK: fprintf(hp, "%s: Fortezza\n", fld); break; default: fprintf(hp, "%s: unknown type %lu\n", fld, (unsigned long)alg); } fflush(hp); rewind(hp); } } NSS_CMSMessage_Destroy(msg); fflush(op); rewind(op); Fclose(bp); return smime_decrypt_assemble(m, hp, op); }
/* TODO: This is suboptimal, but the only other solution is to pass around NSSCMSMessages */ guint32 camel_smime_context_describe_part(CamelSMIMEContext *context, CamelMimePart *part) { guint32 flags = 0; CamelContentType *ct; const char *tmp; if (!part) return flags; ct = camel_mime_part_get_content_type(part); if (camel_content_type_is(ct, "multipart", "signed")) { tmp = camel_content_type_param(ct, "protocol"); if (tmp && (g_ascii_strcasecmp(tmp, ((CamelCipherContext *)context)->sign_protocol) == 0 || g_ascii_strcasecmp(tmp, "application/pkcs7-signature") == 0)) flags = CAMEL_SMIME_SIGNED; } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) { CamelStreamMem *istream; NSSCMSMessage *cmsg; NSSCMSDecoderContext *dec; /* FIXME: stream this to the decoder incrementally */ istream = (CamelStreamMem *)camel_stream_mem_new(); camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)part), (CamelStream *)istream); camel_stream_reset((CamelStream *)istream); dec = NSS_CMSDecoder_Start(NULL, NULL, NULL, NULL, NULL, /* password callback */ NULL, NULL); /* decrypt key callback */ NSS_CMSDecoder_Update(dec, (char *) istream->buffer->data, istream->buffer->len); camel_object_unref(istream); cmsg = NSS_CMSDecoder_Finish(dec); if (cmsg) { if (NSS_CMSMessage_IsSigned(cmsg)) { printf("message is signed\n"); flags |= CAMEL_SMIME_SIGNED; } if (NSS_CMSMessage_IsEncrypted(cmsg)) { printf("message is encrypted\n"); flags |= CAMEL_SMIME_ENCRYPTED; } #if 0 if (NSS_CMSMessage_ContainsCertsOrCrls(cmsg)) { printf("message contains certs or crls\n"); flags |= CAMEL_SMIME_CERTS; } #endif NSS_CMSMessage_Destroy(cmsg); } else { printf("Message could not be parsed\n"); } } return flags; }
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; }
NS_IMETHODIMP nsCMSMessage::CreateEncrypted(nsIArray * aRecipientCerts) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted\n")); NSSCMSContentInfo *cinfo; NSSCMSEnvelopedData *envd; NSSCMSRecipientInfo *recipientInfo; nsZeroTerminatedCertArray recipientCerts; SECOidTag bulkAlgTag; int keySize; PRUint32 i; nsCOMPtr<nsIX509Cert2> nssRecipientCert; nsresult rv = NS_ERROR_FAILURE; // Check the recipient certificates // PRUint32 recipientCertCount; aRecipientCerts->GetLength(&recipientCertCount); PR_ASSERT(recipientCertCount > 0); if (!recipientCerts.allocate(recipientCertCount)) { goto loser; } for (i=0; i<recipientCertCount; i++) { nsCOMPtr<nsIX509Cert> x509cert = do_QueryElementAt(aRecipientCerts, i); nssRecipientCert = do_QueryInterface(x509cert); if (!nssRecipientCert) return NS_ERROR_FAILURE; CERTCertificate *c = nssRecipientCert->GetCert(); CERTCertificateCleaner rcCleaner(c); recipientCerts.set(i, c); } // Find a bulk key algorithm // if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientCerts.getRawArray(), &bulkAlgTag, &keySize) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't find bulk alg for recipients\n")); rv = NS_ERROR_CMS_ENCRYPT_NO_BULK_ALG; goto loser; } m_cmsMsg = NSS_CMSMessage_Create(NULL); if (m_cmsMsg == nsnull) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create new cms message\n")); rv = NS_ERROR_OUT_OF_MEMORY; goto loser; } if ((envd = NSS_CMSEnvelopedData_Create(m_cmsMsg, bulkAlgTag, keySize)) == nsnull) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create enveloped data\n")); goto loser; } cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg); if (NSS_CMSContentInfo_SetContent_EnvelopedData(m_cmsMsg, cinfo, envd) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create content enveloped data\n")); goto loser; } cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd); if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nsnull, PR_FALSE) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't set content data\n")); goto loser; } // Create and attach recipient information // for (i=0; i < recipientCertCount; i++) { CERTCertificate *rc = recipientCerts.get(i); CERTCertificateCleaner rcCleaner(rc); if ((recipientInfo = NSS_CMSRecipientInfo_Create(m_cmsMsg, rc)) == nsnull) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create recipient info\n")); goto loser; } if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientInfo) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't add recipient info\n")); goto loser; } } return NS_OK; loser: if (m_cmsMsg) { NSS_CMSMessage_Destroy(m_cmsMsg); m_cmsMsg = nsnull; } return rv; }
// nsCMSSecureMessage::SendMessage nsresult nsCMSSecureMessage:: SendMessage(const char *msg, const char *base64Cert, char ** _retval) { nsNSSShutDownPreventionLock locker; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage\n")); nsresult rv = NS_OK; CERTCertificate *cert = 0; NSSCMSMessage *cmsMsg = 0; unsigned char *certDER = 0; PRInt32 derLen; NSSCMSEnvelopedData *env; NSSCMSContentInfo *cinfo; NSSCMSRecipientInfo *rcpt; SECItem item; SECItem output; PLArenaPool *arena = PORT_NewArena(1024); SECStatus s; nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); /* Step 0. Create a CMS Message */ cmsMsg = NSS_CMSMessage_Create(NULL); if (!cmsMsg) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't create NSSCMSMessage\n")); rv = NS_ERROR_FAILURE; goto done; } /* Step 1. Import the certificate into NSS */ rv = decode(base64Cert, &certDER, &derLen); if (NS_FAILED(rv)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't decode / import cert into NSS\n")); goto done; } cert = CERT_DecodeCertFromPackage((char *)certDER, derLen); if (!cert) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't decode cert from package\n")); rv = NS_ERROR_FAILURE; goto done; } #if 0 cert->dbhandle = CERT_GetDefaultCertDB(); /* work-around */ #endif /* Step 2. Get a signature cert */ /* Step 3. Build inner (signature) content */ /* Step 4. Build outer (enveloped) content */ env = NSS_CMSEnvelopedData_Create(cmsMsg, SEC_OID_DES_EDE3_CBC, 0); if (!env) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't create envelope data\n")); rv = NS_ERROR_FAILURE; goto done; } cinfo = NSS_CMSEnvelopedData_GetContentInfo(env); item.data = (unsigned char *)msg; item.len = strlen(msg); /* XPCOM equiv?? */ s = NSS_CMSContentInfo_SetContent_Data(cmsMsg, cinfo, 0, PR_FALSE); if (s != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't set content data\n")); rv = NS_ERROR_FAILURE; goto done; } rcpt = NSS_CMSRecipientInfo_Create(cmsMsg, cert); if (!rcpt) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't create recipient info\n")); rv = NS_ERROR_FAILURE; goto done; } s = NSS_CMSEnvelopedData_AddRecipient(env, rcpt); if (s != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't add recipient\n")); rv = NS_ERROR_FAILURE; goto done; } /* Step 5. Add content to message */ cinfo = NSS_CMSMessage_GetContentInfo(cmsMsg); s = NSS_CMSContentInfo_SetContent_EnvelopedData(cmsMsg, cinfo, env); if (s != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't set content enveloped data\n")); rv = NS_ERROR_FAILURE; goto done; } /* Step 6. Encode */ NSSCMSEncoderContext *ecx; output.data = 0; output.len = 0; ecx = NSS_CMSEncoder_Start(cmsMsg, 0, 0, &output, arena, 0, ctx, 0, 0, 0, 0); if (!ecx) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't start cms encoder\n")); rv = NS_ERROR_FAILURE; goto done; } s = NSS_CMSEncoder_Update(ecx, msg, strlen(msg)); if (s != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't update encoder\n")); rv = NS_ERROR_FAILURE; goto done; } s = NSS_CMSEncoder_Finish(ecx); if (s != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't finish encoder\n")); rv = NS_ERROR_FAILURE; goto done; } /* Step 7. Base64 encode and return the result */ rv = encode(output.data, output.len, _retval); done: if (certDER) nsCRT::free((char *)certDER); if (cert) CERT_DestroyCertificate(cert); if (cmsMsg) NSS_CMSMessage_Destroy(cmsMsg); if (arena) PORT_FreeArena(arena, PR_FALSE); /* PR_FALSE? */ return rv; }
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); }
FILE * smime_encrypt(FILE *ip, const char *ignored, const char *to) { NSSCMSMessage *msg; NSSCMSContentInfo *content; NSSCMSEnvelopedData *data; NSSCMSRecipientInfo *info; CERTCertificate *cert[2]; CERTCertDBHandle *handle; SECOidTag tag; FILE *hp, *pp, *yp; int keysize; char *nickname, *vn; int vs; if (nss_init() != OKAY) return NULL; handle = CERT_GetDefaultCertDB(); vn = ac_alloc(vs = strlen(to) + 30); snprintf(vn, vs, "smime-nickname-%s", to); nickname = value(vn); ac_free(vn); if ((cert[0] = CERT_FindCertByNicknameOrEmailAddr(handle, nickname ? nickname : (char *)to)) == NULL) { if (nickname) fprintf(stderr, "Cannot find certificate \"%s\".\n", nickname); else fprintf(stderr, "Cannot find certificate for <%s>.\n", to); return NULL; } cert[1] = NULL; if (getcipher(to, &tag, &keysize) != OKAY) return NULL; if ((msg = NSS_CMSMessage_Create(NULL)) == NULL) { fprintf(stderr, "Cannot create CMS message.\n"); return NULL; } if ((data = NSS_CMSEnvelopedData_Create(msg, tag, keysize)) == NULL) { fprintf(stderr, "Cannot create enveloped data.\n"); return NULL; } content = NSS_CMSMessage_GetContentInfo(msg); if (NSS_CMSContentInfo_SetContent_EnvelopedData(msg, content, data) != SECSuccess) { fprintf(stderr, "Cannot attach enveloped data.\n"); return NULL; } content = NSS_CMSEnvelopedData_GetContentInfo(data); if (NSS_CMSContentInfo_SetContent_Data(msg, content, NULL, PR_FALSE) != SECSuccess) { fprintf(stderr, "Cannot attach CMS data.\n"); return NULL; } if ((info = NSS_CMSRecipientInfo_Create(msg, cert[0])) == NULL) { fprintf(stderr, "Cannot create CMS recipient information.\n"); return NULL; } if (NSS_CMSEnvelopedData_AddRecipient(data, info) != SECSuccess) { fprintf(stderr, "Cannot add CMS recipient information.\n"); return NULL; } CERT_DestroyCertificate(cert[0]); if ((yp = encode(ip, &hp, &pp, msg, base64_cb)) == NULL) return NULL; NSS_CMSMessage_Destroy(msg); return smime_encrypt_assemble(hp, yp); }
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; }
static int verify1(struct message *m, int n) { SECItem **digests; NSSCMSMessage *msg; PLArenaPool *poolp; SECAlgorithmID **algids; CERTCertDBHandle *handle; int nlevels, i; int status = 0; int foundsender = 0; char *sender; if ((m = getsig(m, n, &msg)) == NULL) return 1; sender = getsender(m); handle = CERT_GetDefaultCertDB(); nlevels = NSS_CMSMessage_ContentLevelCount(msg); for (i = 0; i < nlevels; i++) { NSSCMSContentInfo *content; SECOidTag tag; content = NSS_CMSMessage_ContentLevel(msg, i); tag = NSS_CMSContentInfo_GetContentTypeTag(content); if (tag == SEC_OID_PKCS7_SIGNED_DATA) { NSSCMSSignedData *data; int nsigners, j; if ((data = NSS_CMSContentInfo_GetContent(content)) == NULL) { fprintf(stderr, "Signed data missing for " "message %d.\n", n); status = -1; break; } if (!NSS_CMSSignedData_HasDigests(data)) { algids = NSS_CMSSignedData_GetDigestAlgs(data); if (getdig(m, n, &digests, &poolp, algids) != OKAY) { status = -1; break; } if (NSS_CMSSignedData_SetDigests(data, algids, digests) != SECSuccess) { fprintf(stderr, "Cannot set digests " "for message %d.\n", n); status = -1; break; } PORT_FreeArena(poolp, PR_FALSE); } if (NSS_CMSSignedData_ImportCerts(data, handle, certUsageEmailSigner, PR_FALSE) != SECSuccess) { fprintf(stderr, "Cannot temporarily import " "certificates for " "message %d.\n", n); status = -1; break; } nsigners = NSS_CMSSignedData_SignerInfoCount(data); if (nsigners == 0) { fprintf(stderr, "Message %d has no signers.\n", n); status = -1; break; } if (!NSS_CMSSignedData_HasDigests(data)) { fprintf(stderr, "Message %d has no digests.\n", n); status = -1; break; } for (j = 0; j < nsigners; j++) { const char *svs; NSSCMSSignerInfo *info; NSSCMSVerificationStatus vs; SECStatus bad; CERTCertificate *cert; const char *addr; int passed = 0; info = NSS_CMSSignedData_GetSignerInfo(data, j); cert = NSS_CMSSignerInfo_GetSigningCertificate (info, handle); bad = NSS_CMSSignedData_VerifySignerInfo(data, j, handle, certUsageEmailSigner); vs = NSS_CMSSignerInfo_GetVerificationStatus (info); svs = NSS_CMSUtil_VerificationStatusToString (vs); addr = CERT_GetCertEmailAddress(&cert->subject); if (sender != NULL && addr != NULL && asccasecmp(sender, addr) == 0) foundsender++; else { addr = CERT_GetFirstEmailAddress(cert); while (sender && addr) { if (!asccasecmp(sender, addr)) { foundsender++; break; } addr = CERT_GetNextEmailAddress (cert, addr); } } if (CERT_VerifyCertNow(handle, cert, PR_TRUE, certUsageEmailSigner, NULL) != SECSuccess) fprintf(stderr, "Bad certificate for " "signer <%s> of " "message %d: %s.\n", addr ? addr : "?", n, bad_cert_str()); else passed++; if (bad) fprintf(stderr, "Bad status for " "signer <%s> of " "message %d: %s.\n", addr ? addr : "?", n, svs); else passed++; if (passed < 2) status = -1; else if (status == 0) status = 1; } } } if (foundsender == 0) { if (sender) { fprintf(stderr, "Signers of message " "%d do not include the sender <%s>\n", n, sender); status = -1; } else fprintf(stderr, "Warning: Message %d has no From: " "header field.\n", n); } else if (status == 1) printf("Message %d was verified successfully.\n", n); if (status == 0) fprintf(stderr, "No verification information found in " "message %d.\n", n); NSS_CMSMessage_Destroy(msg); return status != 1; }
static CamelCipherValidity * sm_verify(CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex) { NSSCMSDecoderContext *dec; NSSCMSMessage *cmsg; CamelStreamMem *mem; CamelStream *constream = NULL; CamelCipherValidity *valid = NULL; CamelContentType *ct; const char *tmp; CamelMimePart *sigpart; CamelDataWrapper *dw; dw = camel_medium_get_content_object((CamelMedium *)ipart); ct = dw->mime_type; /* FIXME: we should stream this to the decoder */ mem = (CamelStreamMem *)camel_stream_mem_new(); if (camel_content_type_is(ct, "multipart", "signed")) { CamelMultipart *mps = (CamelMultipart *)dw; tmp = camel_content_type_param(ct, "protocol"); if (!CAMEL_IS_MULTIPART_SIGNED(mps) || tmp == NULL || (g_ascii_strcasecmp(tmp, context->sign_protocol) != 0 && g_ascii_strcasecmp(tmp, "application/pkcs7-signature") != 0)) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot verify message signature: Incorrect message format")); goto fail; } constream = camel_multipart_signed_get_content_stream((CamelMultipartSigned *)mps, ex); if (constream == NULL) goto fail; sigpart = camel_multipart_get_part(mps, CAMEL_MULTIPART_SIGNED_SIGNATURE); if (sigpart == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot verify message signature: Incorrect message format")); goto fail; } } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) { sigpart = ipart; } else { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot verify message signature: Incorrect message format")); goto fail; } dec = NSS_CMSDecoder_Start(NULL, NULL, NULL, /* content callback */ NULL, NULL, /* password callback */ NULL, NULL); /* decrypt key callback */ camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)sigpart), (CamelStream *)mem); (void)NSS_CMSDecoder_Update(dec, (char *) mem->buffer->data, mem->buffer->len); cmsg = NSS_CMSDecoder_Finish(dec); if (cmsg == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Decoder failed")); goto fail; } valid = sm_verify_cmsg(context, cmsg, constream, ex); NSS_CMSMessage_Destroy(cmsg); fail: camel_object_unref(mem); if (constream) camel_object_unref(constream); return valid; }