static FILE * encode(FILE *ip, FILE **hp, FILE **bp, NSSCMSMessage *msg, void (*cb)(void *, const char *, unsigned long)) { NSSCMSEncoderContext *ctx; char *buf = NULL, *cp; size_t bufsize = 0, buflen, count; FILE *op; if (smime_split(ip, hp, bp, -1, 0) == STOP) return NULL; if ((op = Ftemp(&cp, "Ry", "w+", 0600, 1)) == NULL) { perror("tempfile"); return NULL; } rm(cp); Ftfree(&cp); if ((ctx = NSS_CMSEncoder_Start(msg, cb, op, NULL, NULL, password_cb, "Pass phrase:", NULL, NULL, NULL, NULL)) == NULL) { fprintf(stderr, "Cannot create encoder context.\n"); Fclose(op); return NULL; } count = fsize(*bp); while (fgetline(&buf, &bufsize, &count, &buflen, *bp, 0) != NULL) { buf[buflen-1] = '\r'; buf[buflen] = '\n'; if (NSS_CMSEncoder_Update(ctx, buf, buflen+1) != 0) { fprintf(stderr, "Failed to add data to encoder.\n"); Fclose(op); return NULL; } } free(buf); if (NSS_CMSEncoder_Finish(ctx) != 0) { fprintf(stderr, "Failed to encode data.\n"); Fclose(op); return NULL; } rewind(*bp); cb(op, (void *)-1, 0); fflush(op); if (ferror(op)) { perror("tempfile"); Fclose(op); return NULL; } rewind(op); return op; }
/* void start (); */ NS_IMETHODIMP nsCMSEncoder::Start(nsICMSMessage *aMsg, NSSCMSContentCallback cb, void * arg) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Start\n")); nsCMSMessage *cmsMsg = static_cast<nsCMSMessage*>(aMsg); m_ctx = new PipUIContext(); m_ecx = NSS_CMSEncoder_Start(cmsMsg->getCMS(), cb, arg, 0, 0, 0, m_ctx, 0, 0, 0, 0); if (m_ecx == nsnull) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Start - can't start encoder\n")); return NS_ERROR_FAILURE; } return NS_OK; }
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; }
static int sm_sign(CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex) { int res = -1; NSSCMSMessage *cmsg; CamelStream *ostream, *istream; SECOidTag sechash; NSSCMSEncoderContext *enc; CamelDataWrapper *dw; CamelContentType *ct; switch (hash) { case CAMEL_CIPHER_HASH_SHA1: case CAMEL_CIPHER_HASH_DEFAULT: default: sechash = SEC_OID_SHA1; break; case CAMEL_CIPHER_HASH_MD5: sechash = SEC_OID_MD5; break; } cmsg = sm_signing_cmsmessage((CamelSMIMEContext *)context, userid, sechash, ((CamelSMIMEContext *)context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN, ex); if (cmsg == NULL) return -1; ostream = camel_stream_mem_new(); /* FIXME: stream this, we stream output at least */ istream = camel_stream_mem_new(); if (camel_cipher_canonical_to_stream(ipart, CAMEL_MIME_FILTER_CANON_STRIP |CAMEL_MIME_FILTER_CANON_CRLF |CAMEL_MIME_FILTER_CANON_FROM, istream) == -1) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Could not generate signing data: %s"), g_strerror(errno)); goto fail; } enc = NSS_CMSEncoder_Start(cmsg, sm_write_stream, ostream, /* DER output callback */ NULL, NULL, /* destination storage */ NULL, NULL, /* password callback */ NULL, NULL, /* decrypt key callback */ NULL, NULL ); /* detached digests */ if (!enc) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create encoder context")); goto fail; } if (NSS_CMSEncoder_Update(enc, (char *) ((CamelStreamMem *)istream)->buffer->data, ((CamelStreamMem *)istream)->buffer->len) != SECSuccess) { NSS_CMSEncoder_Cancel(enc); camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to add data to CMS encoder")); goto fail; } if (NSS_CMSEncoder_Finish(enc) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to encode data")); goto fail; } res = 0; dw = camel_data_wrapper_new(); camel_stream_reset(ostream); camel_data_wrapper_construct_from_stream(dw, ostream); dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY; if (((CamelSMIMEContext *)context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN) { CamelMultipartSigned *mps; CamelMimePart *sigpart; sigpart = camel_mime_part_new(); ct = camel_content_type_new("application", "x-pkcs7-signature"); camel_content_type_set_param(ct, "name", "smime.p7s"); camel_data_wrapper_set_mime_type_field(dw, ct); camel_content_type_unref(ct); camel_medium_set_content_object((CamelMedium *)sigpart, dw); camel_mime_part_set_filename(sigpart, "smime.p7s"); camel_mime_part_set_disposition(sigpart, "attachment"); camel_mime_part_set_encoding(sigpart, CAMEL_TRANSFER_ENCODING_BASE64); mps = camel_multipart_signed_new(); ct = camel_content_type_new("multipart", "signed"); camel_content_type_set_param(ct, "micalg", camel_cipher_hash_to_id(context, hash)); camel_content_type_set_param(ct, "protocol", context->sign_protocol); camel_data_wrapper_set_mime_type_field((CamelDataWrapper *)mps, ct); camel_content_type_unref(ct); camel_multipart_set_boundary((CamelMultipart *)mps, NULL); mps->signature = sigpart; mps->contentraw = istream; camel_stream_reset(istream); camel_object_ref(istream); camel_medium_set_content_object((CamelMedium *)opart, (CamelDataWrapper *)mps); } else { 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", "signed-data"); camel_data_wrapper_set_mime_type_field(dw, ct); camel_content_type_unref(ct); camel_medium_set_content_object((CamelMedium *)opart, dw); camel_mime_part_set_filename(opart, "smime.p7m"); camel_mime_part_set_description(opart, "S/MIME Signed Message"); camel_mime_part_set_disposition(opart, "attachment"); camel_mime_part_set_encoding(opart, CAMEL_TRANSFER_ENCODING_BASE64); } camel_object_unref(dw); fail: camel_object_unref(ostream); camel_object_unref(istream); return res; }
// 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; }
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; }
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); }