SECStatus JSSL_GetClientAuthData( void * arg, PRFileDesc * fd, CERTDistNames * caNames, CERTCertificate ** pRetCert, SECKEYPrivateKey ** pRetKey) { SECKEYPrivateKey * privkey; JSSL_SocketData * sock; SECStatus rv = SECFailure; PR_ASSERT(arg != NULL); sock = (JSSL_SocketData*) arg; if (sock->clientCert) { privkey = PK11_FindPrivateKeyFromCert(sock->clientCertSlot, sock->clientCert, NULL /*pinarg*/); if ( privkey ) { rv = SECSuccess; *pRetCert = CERT_DupCertificate(sock->clientCert); *pRetKey = privkey; } } return rv; }
int sign_value(pkcs11_handle_t *h, cert_object_t *cert, CK_BYTE *data, CK_ULONG length, CK_BYTE **signature, CK_ULONG *signature_length) { SECOidTag algtag; SECKEYPrivateKey *key; SECItem result; SECStatus rv; if (h->slot == NULL) { return -1; } /* get the key */ key = PK11_FindPrivateKeyFromCert(h->slot, (CERTCertificate *)cert, NULL); if (key == NULL) { DBG1("Couldn't Find key for Cert: %s", SECU_Strerror(PR_GetError())); return -1; } /* get the oid */ algtag = SEC_GetSignatureAlgorithmOidTag(key->keyType, SEC_OID_SHA1); /* sign the data */ rv = SEC_SignData(&result, data, length, key, algtag); SECKEY_DestroyPrivateKey(key); if (rv != SECSuccess) { DBG1("Signature failed: %s", SECU_Strerror(PR_GetError())); return -1; } *signature = (CK_BYTE *)result.data; *signature_length = result.len; return 0; }
/* * grab the nss key from a VCardKey. If it doesn't exist, try to look it up */ static SECKEYPrivateKey * vcard_emul_get_nss_key(VCardKey *key) { if (key->key) { return key->key; } /* NOTE: if we aren't logged into the token, this could return NULL */ key->key = PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL); return key->key; }
/** * * Callback to pick the SSL client certificate. */ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { SECKEYPrivateKey *privKey; struct ssl_connect_data *connssl = (struct ssl_connect_data *) arg; char *nickname = connssl->client_nickname; void *proto_win = NULL; SECStatus secStatus = SECFailure; PK11SlotInfo *slot; (void)caNames; proto_win = SSL_RevealPinArg(sock); if(!nickname) return secStatus; connssl->client_cert = PK11_FindCertFromNickname(nickname, proto_win); if(connssl->client_cert) { if(!strncmp(nickname, "PEM Token", 9)) { CK_SLOT_ID slotID = 1; /* hardcoded for now */ char slotname[SLOTSIZE]; snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID); slot = PK11_FindSlotByName(slotname); privKey = PK11_FindPrivateKeyFromCert(slot, connssl->client_cert, NULL); PK11_FreeSlot(slot); if(privKey) { secStatus = SECSuccess; } } else { privKey = PK11_FindKeyByAnyCert(connssl->client_cert, proto_win); if(privKey) secStatus = SECSuccess; } } if(secStatus == SECSuccess) { *pRetCert = connssl->client_cert; *pRetKey = privKey; } else { if(connssl->client_cert) CERT_DestroyCertificate(connssl->client_cert); connssl->client_cert = NULL; } return secStatus; }
/** * * 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; }
SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri, CERTCertificate** retcert, SECKEYPrivateKey** retkey) { CERTCertificate* cert = NULL; NSSCMSRecipient** recipients = NULL; NSSCMSRecipientInfo* recipientInfos[2]; SECStatus rv = SECSuccess; SECKEYPrivateKey* key = NULL; if (!ri) return SECFailure; if (!retcert && !retkey) { /* nothing requested, nothing found, success */ return SECSuccess; } if (retcert) { *retcert = NULL; } if (retkey) { *retkey = NULL; } if (ri->cert) { cert = CERT_DupCertificate(ri->cert); if (!cert) { rv = SECFailure; } } if (SECSuccess == rv && !cert) { /* we don't have the cert, we have to look for it */ /* first build an NSS_CMSRecipient */ recipientInfos[0] = ri; recipientInfos[1] = NULL; recipients = nss_cms_recipient_list_create(recipientInfos); if (recipients) { /* now look for the cert and key */ if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients, ri->cmsg->pwfn_arg)) { cert = CERT_DupCertificate(recipients[0]->cert); key = SECKEY_CopyPrivateKey(recipients[0]->privkey); } else { rv = SECFailure; } nss_cms_recipient_list_destroy(recipients); } else { rv = SECFailure; } } else if (SECSuccess == rv && cert && retkey) { /* we have the cert, we just need the key now */ key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg); } if (retcert) { *retcert = cert; } else { if (cert) { CERT_DestroyCertificate(cert); } } if (retkey) { *retkey = key; } else { if (key) { SECKEY_DestroyPrivateKey(key); } } return rv; }
// 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; }
/** * * Callback to pick the SSL client certificate. */ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { static const char pem_nickname[] = "PEM Token #1"; const char *pem_slotname = pem_nickname; struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; struct SessionHandle *data = connssl->data; const char *nickname = connssl->client_nickname; if (mod && nickname && 0 == strncmp(nickname, pem_nickname, /* length of "PEM Token" */ 9)) { /* use the cert/key provided by PEM reader */ PK11SlotInfo *slot; void *proto_win = SSL_RevealPinArg(sock); *pRetKey = NULL; *pRetCert = PK11_FindCertFromNickname(nickname, proto_win); if (NULL == *pRetCert) { failf(data, "NSS: client certificate not found: %s", nickname); return SECFailure; } slot = PK11_FindSlotByName(pem_slotname); if (NULL == slot) { failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; } *pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL); PK11_FreeSlot(slot); if (NULL == *pRetKey) { failf(data, "NSS: private key not found for certificate: %s", nickname); return SECFailure; } infof(data, "NSS: client certificate: %s\n", nickname); display_cert_info(data, *pRetCert); 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; }
/* * This callback is called when the peer has request you to send you * client-auth certificate. You get to pick which one you want * to send. * * Expected return values: * 0 SECSuccess * -1 SECFailure - No suitable certificate found. * -2 SECWouldBlock (we're waiting while we ask the user). */ SECStatus JSSL_CallCertSelectionCallback( void * arg, PRFileDesc * fd, CERTDistNames * caNames, CERTCertificate ** pRetCert, SECKEYPrivateKey ** pRetKey) { CERTCertificate * cert; PK11SlotInfo * slot; SECKEYPrivateKey * privkey; jobject nicknamecallback = (jobject)arg; SECStatus rv = SECFailure; CERTCertNicknames * names; int i; int count =0; jclass vectorclass; jmethodID vectorcons; jobject vector; jmethodID vector_add; jstring nickname_string; jstring chosen_nickname; char *chosen_nickname_for_c; jboolean chosen_nickname_cleanup; jclass clientcertselectionclass; jmethodID clientcertselectionclass_select; JNIEnv *env; int debug_cc=0; if((*JSS_javaVM)->AttachCurrentThread(JSS_javaVM, (void**)&env, NULL) != 0){ PR_ASSERT(PR_FALSE); goto loser; } PR_ASSERT(env != NULL); clientcertselectionclass = (*env)->GetObjectClass(env,nicknamecallback); clientcertselectionclass_select = (*env)->GetMethodID( env, clientcertselectionclass, "select", "(Ljava/util/Vector;)Ljava/lang/String;" ); /* get java bits and piece ready to create a new vector */ vectorclass = (*env)->FindClass( env, "java/util/Vector"); if (debug_cc) { PR_fprintf(PR_STDOUT," got vectorclass: %lx\n",vectorclass); } vectorcons = (*env)->GetMethodID( env, vectorclass,"<init>","()V"); if (debug_cc) { PR_fprintf(PR_STDOUT," got vectorcons: %lx\n",vectorcons); } vector_add = (*env)->GetMethodID( env, vectorclass, "addElement", "(Ljava/lang/Object;)V"); if (debug_cc) { PR_fprintf(PR_STDOUT," got vectoradd: %lx\n",vector_add); } /* create new vector */ vector = (*env)->NewObject( env, vectorclass, vectorcons); if (debug_cc) { PR_fprintf(PR_STDOUT," got new vector: %lx\n",vector); } /* next, get a list of all the valid nicknames */ names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), SEC_CERT_NICKNAMES_USER, NULL /*pinarg*/); if (names != NULL) { for (i = 0; i < names->numnicknames; i++) { if (debug_cc) { PR_fprintf(PR_STDOUT,"checking nn: %s\n",names->nicknames[i]); } cert = JSS_PK11_findCertAndSlotFromNickname( names->nicknames[i], NULL /*pinarg*/, &slot); if ( !cert ) continue; /* Only check unexpired certs */ if ( CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE /*allowOverride*/) != secCertTimeValid ) { if (debug_cc) { PR_fprintf(PR_STDOUT," not valid\n"); } CERT_DestroyCertificate(cert); PK11_FreeSlot(slot); continue; } rv = secCmpCertChainWCANames(cert, caNames); if ( rv == SECSuccess ) { if (debug_cc) { PR_fprintf(PR_STDOUT," matches ca name\n"); } privkey = PK11_FindPrivateKeyFromCert(slot, cert, NULL /*pinarg*/); /* just test if we have the private key */ if ( privkey ) { count++; if (debug_cc) { PR_fprintf(PR_STDOUT," found privkey\n"); } SECKEY_DestroyPrivateKey(privkey); /* if we have, then this nickname has passed all the tests necessary to put it in the list */ nickname_string = (*env)->NewStringUTF(env, names->nicknames[i]); if (debug_cc) { PR_fprintf(PR_STDOUT," calling vector_add\n"); } (*env)->CallVoidMethod(env,vector,vector_add, nickname_string ); if (debug_cc) { PR_fprintf(PR_STDOUT," back from vector_add\n"); } } } CERT_DestroyCertificate(cert); PK11_FreeSlot(slot); } CERT_FreeNicknames(names); } /* okay - so we made a vector of the certs - now call the java class to figure out which one to send */ chosen_nickname = (*env)->CallObjectMethod(env,nicknamecallback, clientcertselectionclass_select, vector ); if (chosen_nickname == NULL) { rv = SECFailure; goto loser; } chosen_nickname_for_c = (char*)(*env)->GetStringUTFChars(env, chosen_nickname, &chosen_nickname_cleanup); if (debug_cc) { PR_fprintf(PR_STDOUT," chosen nickname: %s\n",chosen_nickname_for_c); } cert = JSS_PK11_findCertAndSlotFromNickname(chosen_nickname_for_c, NULL /*pinarg*/, &slot); if (debug_cc) { PR_fprintf(PR_STDOUT," found certificate\n"); } if (chosen_nickname_cleanup == JNI_TRUE) { (*env)->ReleaseStringUTFChars(env, chosen_nickname, chosen_nickname_for_c); } if (cert == NULL) { rv = SECFailure; goto loser; } privkey = PK11_FindPrivateKeyFromCert(slot, cert, NULL /*pinarg*/); PK11_FreeSlot(slot); if ( privkey == NULL ) { CERT_DestroyCertificate(cert); rv = SECFailure; goto loser; } if (debug_cc) { PR_fprintf(PR_STDOUT," found privkey. returning\n"); } *pRetCert = cert; *pRetKey = privkey; rv = SECSuccess; loser: return rv; }