/* import PFX item * der_pfx is the der encoded pfx structure * pbef and pbearg are the integrity/encryption password call back * ncCall is the nickname collision calllback * slot is the destination token * wincx window handler * * on error, error code set and SECFailure returned */ SECStatus SEC_PKCS12PutPFX(SECItem *der_pfx, SECItem *pwitem, SEC_PKCS12NicknameCollisionCallback ncCall, PK11SlotInfo *slot, void *wincx) { SEC_PKCS12PFXItem *pfx; SEC_PKCS12AuthenticatedSafe *asafe; SEC_PKCS12SafeContents *safe_contents = NULL; SECStatus rv; if(!der_pfx || !pwitem || !slot) { return SECFailure; } /* decode and validate each section */ rv = SECFailure; pfx = sec_pkcs12_get_pfx(der_pfx, pwitem); if(pfx != NULL) { asafe = sec_pkcs12_get_auth_safe(pfx); if(asafe != NULL) { /* decrypt safe -- only if not empty */ if(asafe->emptySafe != PR_TRUE) { rv = sec_pkcs12_decrypt_auth_safe(asafe, pwitem, wincx); if(rv == SECSuccess) { safe_contents = sec_pkcs12_get_safe_contents(asafe); if(safe_contents == NULL) { rv = SECFailure; } } } else { safe_contents = sec_pkcs12_create_safe_contents(asafe->poolp); if(safe_contents == NULL) { rv = SECFailure; } else { safe_contents->swapUnicode = pfx->swapUnicode; rv = SECSuccess; } } /* get safe contents and begin import */ if(rv == SECSuccess) { SEC_PKCS12DecoderContext *p12dcx; p12dcx = sec_PKCS12ConvertOldSafeToNew(pfx->poolp, slot, pfx->swapUnicode, pwitem, wincx, safe_contents, &asafe->baggage); if(!p12dcx) { rv = SECFailure; goto loser; } if(SEC_PKCS12DecoderValidateBags(p12dcx, ncCall) != SECSuccess) { rv = SECFailure; goto loser; } rv = SEC_PKCS12DecoderImportBags(p12dcx); } } } loser: if(pfx) { SEC_PKCS12DestroyPFX(pfx); } return rv; }
nsresult nsPKCS12Blob::ImportFromFileHelper(nsILocalFile *file, nsPKCS12Blob::ImportMode aImportMode, nsPKCS12Blob::RetryReason &aWantRetry) { nsNSSShutDownPreventionLock locker; nsresult rv; SECStatus srv = SECSuccess; SEC_PKCS12DecoderContext *dcx = NULL; SECItem unicodePw; PK11SlotInfo *slot=nsnull; nsXPIDLString tokenName; unicodePw.data = NULL; aWantRetry = rr_do_not_retry; if (aImportMode == im_try_zero_length_secitem) { unicodePw.len = 0; } else { // get file password (unicode) rv = getPKCS12FilePassword(&unicodePw); if (NS_FAILED(rv)) goto finish; if (unicodePw.data == NULL) { handleError(PIP_PKCS12_USER_CANCELED); return NS_OK; } } mToken->GetTokenName(getter_Copies(tokenName)); { NS_ConvertUTF16toUTF8 tokenNameCString(tokenName); slot = PK11_FindSlotByName(tokenNameCString.get()); } if (!slot) { srv = SECFailure; goto finish; } // initialize the decoder dcx = SEC_PKCS12DecoderStart(&unicodePw, slot, NULL, digest_open, digest_close, digest_read, digest_write, this); if (!dcx) { srv = SECFailure; goto finish; } // read input file and feed it to the decoder rv = inputToDecoder(dcx, file); if (NS_FAILED(rv)) { if (NS_ERROR_ABORT == rv) { // inputToDecoder indicated a NSS error srv = SECFailure; } goto finish; } // verify the blob srv = SEC_PKCS12DecoderVerify(dcx); if (srv) goto finish; // validate bags srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision); if (srv) goto finish; // import cert and key srv = SEC_PKCS12DecoderImportBags(dcx); if (srv) goto finish; // Later - check to see if this should become default email cert handleError(PIP_PKCS12_RESTORE_OK); finish: // If srv != SECSuccess, NSS probably set a specific error code. // We should use that error code instead of inventing a new one // for every error possible. if (srv != SECSuccess) { if (SEC_ERROR_BAD_PASSWORD == PORT_GetError()) { if (unicodePw.len == sizeof(PRUnichar)) { // no password chars available, // unicodeToItem allocated space for the trailing zero character only. aWantRetry = rr_auto_retry_empty_password_flavors; } else { aWantRetry = rr_bad_password; handleError(PIP_PKCS12_NSS_ERROR); } } else { handleError(PIP_PKCS12_NSS_ERROR); } } else if (NS_FAILED(rv)) { handleError(PIP_PKCS12_RESTORE_FAILED); } if (slot) PK11_FreeSlot(slot); // finish the decoder if (dcx) SEC_PKCS12DecoderFinish(dcx); SECITEM_ZfreeItem(&unicodePw, false); return NS_OK; }
static gboolean import_from_file_helper (EPKCS12 *pkcs12, PK11SlotInfo *slot, const gchar *path, gboolean *aWantRetry, GError **error) { /*nsNSSShutDownPreventionLock locker; */ gboolean rv; SECStatus srv = SECSuccess; SEC_PKCS12DecoderContext *dcx = NULL; SECItem passwd; GError *err = NULL; *aWantRetry = FALSE; passwd.data = NULL; rv = prompt_for_password ( _("PKCS12 File Password"), _("Enter password for PKCS12 file:"), &passwd); if (!rv) goto finish; if (passwd.data == NULL) { handle_error (PKCS12_USER_CANCELED); return TRUE; } /* initialize the decoder */ dcx = SEC_PKCS12DecoderStart ( &passwd, slot, /* we specify NULL for all the * funcs + data so it'll use the * default pk11wrap functions */ NULL, NULL, NULL, NULL, NULL, NULL); if (!dcx) { srv = SECFailure; goto finish; } /* read input file and feed it to the decoder */ rv = input_to_decoder (dcx, path, &err); if (!rv) { #ifdef notyet /* XXX we need this to check the gerror */ if (NS_ERROR_ABORT == rv) { /* inputToDecoder indicated a NSS error */ srv = SECFailure; } #else srv = SECFailure; #endif goto finish; } /* verify the blob */ srv = SEC_PKCS12DecoderVerify (dcx); if (srv) goto finish; /* validate bags */ srv = SEC_PKCS12DecoderValidateBags (dcx, nickname_collision); if (srv) goto finish; /* import cert and key */ srv = SEC_PKCS12DecoderImportBags (dcx); if (srv) goto finish; /* Later - check to see if this should become default email cert */ handle_error (PKCS12_RESTORE_OK); finish: /* If srv != SECSuccess, NSS probably set a specific error code. * We should use that error code instead of inventing a new one * for every error possible. */ if (srv != SECSuccess) { if (SEC_ERROR_BAD_PASSWORD == PORT_GetError ()) { *aWantRetry = TRUE; } handle_error (PKCS12_NSS_ERROR); } else if (!rv) { handle_error (PKCS12_RESTORE_FAILED); } /* finish the decoder */ if (dcx) SEC_PKCS12DecoderFinish (dcx); return TRUE; }
// Based on nsPKCS12Blob::ImportFromFileHelper. int nsPKCS12Blob_ImportHelper(const char* pkcs12_data, size_t pkcs12_len, const base::string16& password, bool is_extractable, bool try_zero_length_secitem, PK11SlotInfo *slot, net::CertificateList* imported_certs) { DCHECK(pkcs12_data); DCHECK(slot); int import_result = net::ERR_PKCS12_IMPORT_FAILED; SECStatus srv = SECSuccess; SEC_PKCS12DecoderContext *dcx = NULL; SECItem unicodePw; SECItem attribute_value; CK_BBOOL attribute_data = CK_FALSE; const SEC_PKCS12DecoderItem* decoder_item = NULL; unicodePw.type = siBuffer; unicodePw.len = 0; unicodePw.data = NULL; if (!try_zero_length_secitem) { unicodeToItem(password.c_str(), &unicodePw); } // Initialize the decoder dcx = SEC_PKCS12DecoderStart(&unicodePw, slot, // wincx NULL, // dOpen, dClose, dRead, dWrite, dArg: NULL // specifies default impl using memory buffer. NULL, NULL, NULL, NULL, NULL); if (!dcx) { srv = SECFailure; goto finish; } // feed input to the decoder srv = SEC_PKCS12DecoderUpdate(dcx, (unsigned char*)pkcs12_data, pkcs12_len); if (srv) goto finish; // verify the blob srv = SEC_PKCS12DecoderVerify(dcx); if (srv) goto finish; // validate bags srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision); if (srv) goto finish; // import certificate and key srv = SEC_PKCS12DecoderImportBags(dcx); if (srv) goto finish; attribute_value.data = &attribute_data; attribute_value.len = sizeof(attribute_data); srv = SEC_PKCS12DecoderIterateInit(dcx); if (srv) goto finish; if (imported_certs) imported_certs->clear(); // Collect the list of decoded certificates, and mark private keys // non-extractable if needed. while (SEC_PKCS12DecoderIterateNext(dcx, &decoder_item) == SECSuccess) { if (decoder_item->type != SEC_OID_PKCS12_V1_CERT_BAG_ID) continue; CERTCertificate* cert = PK11_FindCertFromDERCertItem( slot, decoder_item->der, NULL); // wincx if (!cert) { LOG(ERROR) << "Could not grab a handle to the certificate in the slot " << "from the corresponding PKCS#12 DER certificate."; continue; } // Add the cert to the list if (imported_certs) { // Empty list of intermediates. net::X509Certificate::OSCertHandles intermediates; imported_certs->push_back( net::X509Certificate::CreateFromHandle(cert, intermediates)); } // Once we have determined that the imported certificate has an // associated private key too, only then can we mark the key as // non-extractable. if (!decoder_item->hasKey) { CERT_DestroyCertificate(cert); continue; } // Iterate through all the imported PKCS12 items and mark any accompanying // private keys as non-extractable. if (!is_extractable) { SECKEYPrivateKey* privKey = PK11_FindPrivateKeyFromCert(slot, cert, NULL); // wincx if (privKey) { // Mark the private key as non-extractable. srv = PK11_WriteRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE, &attribute_value); SECKEY_DestroyPrivateKey(privKey); if (srv) { LOG(ERROR) << "Could not set CKA_EXTRACTABLE attribute on private " << "key."; CERT_DestroyCertificate(cert); break; } } } CERT_DestroyCertificate(cert); if (srv) goto finish; } import_result = net::OK; finish: // If srv != SECSuccess, NSS probably set a specific error code. // We should use that error code instead of inventing a new one // for every error possible. if (srv != SECSuccess) { int error = PORT_GetError(); LOG(ERROR) << "PKCS#12 import failed with error " << error; switch (error) { case SEC_ERROR_BAD_PASSWORD: case SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT: import_result = net::ERR_PKCS12_IMPORT_BAD_PASSWORD; break; case SEC_ERROR_PKCS12_INVALID_MAC: import_result = net::ERR_PKCS12_IMPORT_INVALID_MAC; break; case SEC_ERROR_BAD_DER: case SEC_ERROR_PKCS12_DECODING_PFX: case SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE: import_result = net::ERR_PKCS12_IMPORT_INVALID_FILE; break; case SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM: case SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE: case SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM: case SEC_ERROR_PKCS12_UNSUPPORTED_VERSION: import_result = net::ERR_PKCS12_IMPORT_UNSUPPORTED; break; default: import_result = net::ERR_PKCS12_IMPORT_FAILED; break; } } // Finish the decoder if (dcx) SEC_PKCS12DecoderFinish(dcx); SECITEM_ZfreeItem(&unicodePw, PR_FALSE); return import_result; }
UtlBoolean SmimeBody::nssSmimeDecrypt(const char* derPkcs12, int derPkcs12Length, const char* pkcs12Password, UtlBoolean dataIsInBase64Format, const char* dataToDecrypt, int dataToDecryptLength, UtlString& decryptedData) { UtlBoolean decryptSucceeded = FALSE; decryptedData.remove(0); #ifdef ENABLE_NSS_SMIME Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SmimeBody::nssSmimeDecrypt not implemented"); ////// BEGIN WARNING: THIS CODE HAS NOT BEEN TESTED AT ALL /////// // allocate a temporaty slot in the database PK11SlotInfo *slot = PK11_GetInternalKeySlot(); PRBool swapUnicode = PR_FALSE; SEC_PKCS12DecoderContext *p12Decoder = NULL; // Need to put the pkcs12 password into a SECItem SECItem passwordItem; passwordItem.data = (unsigned char*) pkcs12Password; passwordItem.len = strlen(pkcs12Password); SECItem uniPasswordItem; uniPasswordItem.data = NULL; uniPasswordItem.len = 0; #ifdef IS_LITTLE_ENDIAN swapUnicode = PR_TRUE; #endif // Allocate a temporary internal slot slot = PK11_GetInternalSlot(); if(slot == NULL) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "unable to use slot in NSS dataqbase for S/MIME decryption"); } else { // Do UNICODE conversion of password based upon the platform // (not sure this is even neccessary in our application). I do not // know how we would get unicode passwords if(0) //P12U_UnicodeConversion(NULL, &uniPasswordItem, passwordItem, PR_TRUE, // swapUnicode) != SECSuccess) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "NSS Unicode conversion failed for PKCS12 object for S/MIME decryption"); } else { // Initialze the decoder for the PKCS12 container for the private key p12Decoder = SEC_PKCS12DecoderStart(&passwordItem, slot, NULL, NULL, NULL, NULL, NULL, NULL); if(!p12Decoder) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "failed to initialize PKCS12 decoder to extract private key for S/MIME decryption"); } else { // Add the PKCS12 data to the decoder if(SEC_PKCS12DecoderUpdate(p12Decoder, (unsigned char *) derPkcs12, derPkcs12Length) != SECSuccess || // Validate the decoded PKCS12 SEC_PKCS12DecoderVerify(p12Decoder) != SECSuccess) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "unable to decrypt PKCS12 for S/MIME decryption. Perhaps invalid PKCS12 or PKCS12 password"); } else { // Import the private key and certificate from the // decoded PKCS12 into the database if(SEC_PKCS12DecoderImportBags(p12Decoder) != SECSuccess) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "failed to import private key and certificate into NSS database"); } else { // Put the S/MIME data in a SECItem SECItem dataToDecodeItem; dataToDecodeItem.data = (unsigned char *) dataToDecrypt; dataToDecodeItem.len = dataToDecryptLength; if(dataIsInBase64Format) { // TODO: // Use some NSS util. to convert base64 to binary Os::Logger::instance().log(FAC_SIP, PRI_ERR, "NSS decrypt of base64 S/MIME message not implemented"); } else { // Decode the S/MIME blob NSSCMSMessage *cmsMessage = NSS_CMSMessage_CreateFromDER(&dataToDecodeItem, nssOutToUtlString, &decryptedData, NULL, NULL, NULL, NULL); if(cmsMessage && decryptedData.length() > 0) { decryptSucceeded = TRUE; } // TODO: // Remove the temporary private key from the // database using the slot handle } } } } } } // Clean up if(p12Decoder) { SEC_PKCS12DecoderFinish(p12Decoder); } if(uniPasswordItem.data) { SECITEM_ZfreeItem(&uniPasswordItem, PR_FALSE); } ////// END WARNING ///// #else Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SmimeBody::nssSmimeDecrypt invoked with ENABLE_NSS_SMIME not defined"); #endif return(decryptSucceeded); }