/********************************************************************* * * i n s t a l l _ c e r t * * Installs the cert in the permanent database. */ static CERTCertificate* install_cert(CERTCertDBHandle *db, SECItem *derCert, char *nickname) { CERTCertificate * newcert; PK11SlotInfo * newSlot; newSlot = PK11_ImportDERCertForKey(derCert, nickname, &pwdata); if ( newSlot == NULL ) { PR_fprintf(errorFD, "Unable to install certificate\n"); errorCount++; exit(ERRX); } newcert = PK11_FindCertFromDERCertItem(newSlot, derCert, &pwdata); PK11_FreeSlot(newSlot); if (newcert == NULL) { PR_fprintf(errorFD, "%s: can't find new certificate\n", PROGRAM_NAME); errorCount++; exit (ERRX); } if (verbosity >= 0) { PR_fprintf(outputFD, "certificate \"%s\" added to database\n", nickname); } return newcert; }
/** * * Callback to pick the SSL client certificate. */ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; struct SessionHandle *data = connssl->data; const char *nickname = connssl->client_nickname; if(connssl->obj_clicert) { /* use the cert/key provided by PEM reader */ static const char pem_slotname[] = "PEM Token #1"; SECItem cert_der = { 0, NULL, 0 }; void *proto_win = SSL_RevealPinArg(sock); struct CERTCertificateStr *cert; struct SECKEYPrivateKeyStr *key; PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname); if(NULL == slot) { failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; } if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE, &cert_der) != SECSuccess) { failf(data, "NSS: CKA_VALUE not found in PK11 generic object"); PK11_FreeSlot(slot); return SECFailure; } cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win); SECITEM_FreeItem(&cert_der, PR_FALSE); if(NULL == cert) { failf(data, "NSS: client certificate from file not found"); PK11_FreeSlot(slot); return SECFailure; } key = PK11_FindPrivateKeyFromCert(slot, cert, NULL); PK11_FreeSlot(slot); if(NULL == key) { failf(data, "NSS: private key from file not found"); CERT_DestroyCertificate(cert); return SECFailure; } infof(data, "NSS: client certificate from file\n"); display_cert_info(data, cert); *pRetCert = cert; *pRetKey = key; return SECSuccess; } /* use the default NSS hook */ if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, pRetCert, pRetKey) || NULL == *pRetCert) { if(NULL == nickname) failf(data, "NSS: client certificate not found (nickname not " "specified)"); else failf(data, "NSS: client certificate not found: %s", nickname); return SECFailure; } /* get certificate nickname if any */ nickname = (*pRetCert)->nickname; if(NULL == nickname) nickname = "[unknown]"; if(NULL == *pRetKey) { failf(data, "NSS: private key not found for certificate: %s", nickname); return SECFailure; } infof(data, "NSS: using client certificate: %s\n", nickname); display_cert_info(data, *pRetCert); return SECSuccess; }
// 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; }