/* private constructure */ static VCardKey * vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert) { VCardKey *key; key = (VCardKey *)qemu_malloc(sizeof(VCardKey)); key->slot = PK11_ReferenceSlot(slot); key->cert = CERT_DupCertificate(cert); /* NOTE: if we aren't logged into the token, this could return NULL */ /* NOTE: the cert is a temp cert, not necessarily the cert in the token, * use the DER version of this function */ key->key = PK11_FindKeyByDERCert(slot, cert, NULL); return key; }
// nsPKCS12Blob::ExportToFile // // Having already loaded the certs, form them into a blob (loading the keys // also), encode the blob, and stuff it into the file. // // TODO: handle slots correctly // mirror "slotToUse" behavior from PSM 1.x // verify the cert array to start off with? // open output file as nsIFileStream object? // set appropriate error codes nsresult nsPKCS12Blob::ExportToFile(nsILocalFile *file, nsIX509Cert **certs, int numCerts) { nsNSSShutDownPreventionLock locker; nsresult rv; SECStatus srv = SECSuccess; SEC_PKCS12ExportContext *ecx = NULL; SEC_PKCS12SafeInfo *certSafe = NULL, *keySafe = NULL; SECItem unicodePw; nsAutoString filePath; int i; nsCOMPtr<nsILocalFile> localFileRef; NS_ASSERTION(mToken, "Need to set the token before exporting"); // init slot bool InformedUserNoSmartcardBackup = false; int numCertsExported = 0; rv = mToken->Login(true); if (NS_FAILED(rv)) goto finish; // get file password (unicode) unicodePw.data = NULL; rv = newPKCS12FilePassword(&unicodePw); if (NS_FAILED(rv)) goto finish; if (unicodePw.data == NULL) { handleError(PIP_PKCS12_USER_CANCELED); return NS_OK; } // what about slotToUse in psm 1.x ??? // create export context ecx = SEC_PKCS12CreateExportContext(NULL, NULL, NULL /*slot*/, NULL); if (!ecx) { srv = SECFailure; goto finish; } // add password integrity srv = SEC_PKCS12AddPasswordIntegrity(ecx, &unicodePw, SEC_OID_SHA1); if (srv) goto finish; #if 0 // count the number of certs to export nrv = mCertArray->Count(&numCerts); if (NS_FAILED(nrv)) goto finish; // loop over the certs for (i=0; i<numCerts; i++) { nsCOMPtr<nsIX509Cert> cert; nrv = mCertArray->GetElementAt(i, getter_AddRefs(cert)); if (NS_FAILED(nrv)) goto finish; #endif for (i=0; i<numCerts; i++) { // nsNSSCertificate *cert = reinterpret_cast<nsNSSCertificate *>(certs[i]); nsNSSCertificate *cert = (nsNSSCertificate *)certs[i]; // get it as a CERTCertificate XXX CERTCertificate *nssCert = NULL; CERTCertificateCleaner nssCertCleaner(nssCert); nssCert = cert->GetCert(); if (!nssCert) { rv = NS_ERROR_FAILURE; goto finish; } // We can only successfully export certs that are on // internal token. Most, if not all, smart card vendors // won't let you extract the private key (in any way // shape or form) from the card. So let's punt if // the cert is not in the internal db. if (nssCert->slot && !PK11_IsInternal(nssCert->slot)) { // we aren't the internal token, see if the key is extractable. SECKEYPrivateKey *privKey=PK11_FindKeyByDERCert(nssCert->slot, nssCert, this); if (privKey) { bool privKeyIsExtractable = isExtractable(privKey); SECKEY_DestroyPrivateKey(privKey); if (!privKeyIsExtractable) { if (!InformedUserNoSmartcardBackup) { InformedUserNoSmartcardBackup = true; handleError(PIP_PKCS12_NOSMARTCARD_EXPORT); } continue; } } } // XXX this is why, to verify the slot is the same // PK11_FindObjectForCert(nssCert, NULL, slot); // create the cert and key safes keySafe = SEC_PKCS12CreateUnencryptedSafe(ecx); if (!SEC_PKCS12IsEncryptionAllowed() || PK11_IsFIPS()) { certSafe = keySafe; } else { certSafe = SEC_PKCS12CreatePasswordPrivSafe(ecx, &unicodePw, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); } if (!certSafe || !keySafe) { rv = NS_ERROR_FAILURE; goto finish; } // add the cert and key to the blob srv = SEC_PKCS12AddCertAndKey(ecx, certSafe, NULL, nssCert, CERT_GetDefaultCertDB(), // XXX keySafe, NULL, true, &unicodePw, SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC); if (srv) goto finish; // cert was dup'ed, so release it ++numCertsExported; } if (!numCertsExported) goto finish; // prepare the instance to write to an export file this->mTmpFile = NULL; file->GetPath(filePath); // Use the nsCOMPtr var localFileRef so that // the reference to the nsILocalFile we create gets released as soon as // we're out of scope, ie when this function exits. if (filePath.RFind(".p12", true, -1, 4) < 0) { // We're going to add the .p12 extension to the file name just like // Communicator used to. We create a new nsILocalFile and initialize // it with the new patch. filePath.AppendLiteral(".p12"); localFileRef = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); if (NS_FAILED(rv)) goto finish; localFileRef->InitWithPath(filePath); file = localFileRef; } rv = file->OpenNSPRFileDesc(PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0664, &mTmpFile); if (NS_FAILED(rv) || !this->mTmpFile) goto finish; // encode and write srv = SEC_PKCS12Encode(ecx, write_export_file, this); if (srv) goto finish; handleError(PIP_PKCS12_BACKUP_OK); finish: if (NS_FAILED(rv) || srv != SECSuccess) { handleError(PIP_PKCS12_BACKUP_FAILED); } if (ecx) SEC_PKCS12DestroyExportContext(ecx); if (this->mTmpFile) { PR_Close(this->mTmpFile); this->mTmpFile = NULL; } SECITEM_ZfreeItem(&unicodePw, false); return rv; } /////////////////////////////////////////////////////////////////////// // // private members // /////////////////////////////////////////////////////////////////////// // unicodeToItem // // For the NSS PKCS#12 library, must convert PRUnichars (shorts) to // a buffer of octets. Must handle byte order correctly. // TODO: Is there a mozilla way to do this? In the string lib? void nsPKCS12Blob::unicodeToItem(const PRUnichar *uni, SECItem *item) { int len = 0; while (uni[len++] != 0); SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len); #ifdef IS_LITTLE_ENDIAN int i = 0; for (i=0; i<len; i++) { item->data[2*i ] = (unsigned char )(uni[i] << 8); item->data[2*i+1] = (unsigned char )(uni[i]); } #else memcpy(item->data, uni, item->len); #endif }
SECStatus ConfigSecureServerWithNamedCert(PRFileDesc *fd, const char *certName, /*optional*/ ScopedCERTCertificate *certOut, /*optional*/ SSLKEAType *keaOut) { ScopedCERTCertificate cert(PK11_FindCertFromNickname(certName, nullptr)); if (!cert) { PrintPRError("PK11_FindCertFromNickname failed"); return SECFailure; } // If an intermediate certificate issued the server certificate (rather than // directly by a trust anchor), we want to send it along in the handshake so // we don't encounter unknown issuer errors when that's not what we're // testing. UniqueCERTCertificateList certList; ScopedCERTCertificate issuerCert( CERT_FindCertByName(CERT_GetDefaultCertDB(), &cert->derIssuer)); // If we can't find the issuer cert, continue without it. if (issuerCert) { // Sadly, CERTCertificateList does not have a CERT_NewCertificateList // utility function, so we must create it ourselves. This consists // of creating an arena, allocating space for the CERTCertificateList, // and then transferring ownership of the arena to that list. ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { PrintPRError("PORT_NewArena failed"); return SECFailure; } certList.reset(static_cast<CERTCertificateList*>( PORT_ArenaAlloc(arena.get(), sizeof(CERTCertificateList)))); if (!certList) { PrintPRError("PORT_ArenaAlloc failed"); return SECFailure; } certList->arena = arena.forget(); // We also have to manually copy the certificates we care about to the // list, because there aren't any utility functions for that either. certList->certs = reinterpret_cast<SECItem*>( PORT_ArenaAlloc(certList->arena, 2 * sizeof(SECItem))); if (SECITEM_CopyItem(certList->arena, certList->certs, &cert->derCert) != SECSuccess) { PrintPRError("SECITEM_CopyItem failed"); return SECFailure; } if (SECITEM_CopyItem(certList->arena, certList->certs + 1, &issuerCert->derCert) != SECSuccess) { PrintPRError("SECITEM_CopyItem failed"); return SECFailure; } certList->len = 2; } ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); UniqueSECKEYPrivateKey key( PK11_FindKeyByDERCert(slot.get(), cert.get(), nullptr)); if (!key) { PrintPRError("PK11_FindKeyByDERCert failed"); return SECFailure; } SSLKEAType certKEA = NSS_FindCertKEAType(cert); if (SSL_ConfigSecureServerWithCertChain(fd, cert.get(), certList.get(), key.get(), certKEA) != SECSuccess) { PrintPRError("SSL_ConfigSecureServer failed"); return SECFailure; } if (certOut) { *certOut = cert.forget(); } if (keaOut) { *keaOut = certKEA; } return SECSuccess; }