/* * This callback used by SSL to pull client sertificate upon * server request */ SECStatus NSS_GetClientAuthData(void * arg, PRFileDesc * socket, struct CERTDistNamesStr * caNames, struct CERTCertificateStr ** pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { CERTCertificate * cert = NULL; SECKEYPrivateKey * privkey = NULL; char * chosenNickName = (char *)arg; /* CONST */ void * proto_win = NULL; SECStatus rv = SECFailure; proto_win = SSL_RevealPinArg(socket); if (chosenNickName) { cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), chosenNickName, certUsageSSLClient, PR_FALSE, proto_win); if ( cert ) { privkey = PK11_FindKeyByAnyCert(cert, proto_win); if ( privkey ) { rv = SECSuccess; } else { CERT_DestroyCertificate(cert); } } } else { /* no name given, automatically find the right cert. */ CERTCertNicknames * names; int i; names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), SEC_CERT_NICKNAMES_USER, proto_win); if (names != NULL) { for (i = 0; i < names->numnicknames; i++) { cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), names->nicknames[i], certUsageSSLClient, PR_FALSE, proto_win); if ( !cert ) continue; /* Only check unexpired certs */ if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != secCertTimeValid ) { CERT_DestroyCertificate(cert); continue; } rv = NSS_CmpCertChainWCANames(cert, caNames); if ( rv == SECSuccess ) { privkey = PK11_FindKeyByAnyCert(cert, proto_win); if ( privkey ) break; } rv = SECFailure; CERT_DestroyCertificate(cert); } CERT_FreeNicknames(names); } } if (rv == SECSuccess) { *pRetCert = cert; *pRetKey = privkey; } return rv; }
/* * 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; }
/* * Find all user certificates that match the given criteria. * * "handle" - database to search * "usage" - certificate usage to match * "oneCertPerName" - if set then only return the "best" cert per * name * "validOnly" - only return certs that are curently valid * "proto_win" - window handle passed to pkcs11 */ CERTCertList * CERT_FindUserCertsByUsage(CERTCertDBHandle *handle, SECCertUsage usage, PRBool oneCertPerName, PRBool validOnly, void *proto_win) { CERTCertNicknames *nicknames = NULL; char **nnptr; int nn; CERTCertificate *cert = NULL; CERTCertList *certList = NULL; SECStatus rv; int64 time; CERTCertListNode *node = NULL; CERTCertListNode *freenode = NULL; int n; time = PR_Now(); nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER, proto_win); if ( ( nicknames == NULL ) || ( nicknames->numnicknames == 0 ) ) { goto loser; } nnptr = nicknames->nicknames; nn = nicknames->numnicknames; while ( nn > 0 ) { cert = NULL; /* use the pk11 call so that we pick up any certs on tokens, * which may require login */ if ( proto_win != NULL ) { cert = PK11_FindCertFromNickname(*nnptr,proto_win); } /* Sigh, It turns out if the cert is already in the temp db, because * it's in the perm db, then the nickname lookup doesn't work. * since we already have the cert here, though, than we can just call * CERT_CreateSubjectCertList directly. For those cases where we didn't * find the cert in pkcs #11 (because we didn't have a password arg, * or because the nickname is for a peer, server, or CA cert, then we * go look the cert up. */ if (cert == NULL) { cert = CERT_FindCertByNickname(handle,*nnptr); } if ( cert != NULL ) { /* collect certs for this nickname, sorting them into the list */ certList = CERT_CreateSubjectCertList(certList, handle, &cert->derSubject, time, validOnly); CERT_FilterCertListForUserCerts(certList); /* drop the extra reference */ CERT_DestroyCertificate(cert); } nnptr++; nn--; } /* remove certs with incorrect usage */ rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); if ( rv != SECSuccess ) { goto loser; } /* remove any extra certs for each name */ if ( oneCertPerName ) { PRBool *flags; nn = nicknames->numnicknames; nnptr = nicknames->nicknames; flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn); if ( flags == NULL ) { goto loser; } node = CERT_LIST_HEAD(certList); /* treverse all certs in the list */ while ( !CERT_LIST_END(node, certList) ) { /* find matching nickname index */ for ( n = 0; n < nn; n++ ) { if ( CERT_MatchNickname(nnptr[n], node->cert->nickname) ) { /* We found a match. If this is the first one, then * set the flag and move on to the next cert. If this * is not the first one then delete it from the list. */ if ( flags[n] ) { /* We have already seen a cert with this nickname, * so delete this one. */ freenode = node; node = CERT_LIST_NEXT(node); CERT_RemoveCertListNode(freenode); } else { /* keep the first cert for each nickname, but set the * flag so we know to delete any others with the same * nickname. */ flags[n] = PR_TRUE; node = CERT_LIST_NEXT(node); } break; } } if ( n == nn ) { /* if we get here it means that we didn't find a matching * nickname, which should not happen. */ PORT_Assert(0); node = CERT_LIST_NEXT(node); } } PORT_Free(flags); } goto done; loser: if ( certList != NULL ) { CERT_DestroyCertList(certList); certList = NULL; } done: if ( nicknames != NULL ) { CERT_FreeNicknames(nicknames); } return(certList); }
/* Function: SECStatus ownGetClientAuthData() * * Purpose: This callback is used by SSL to pull client certificate * information upon server request. */ SECStatus myGetClientAuthData(void *arg, PRFileDesc *socket, struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { CERTCertificate * cert; SECKEYPrivateKey * privKey; char * chosenNickName = (char *)arg; void * proto_win = NULL; SECStatus secStatus = SECFailure; proto_win = SSL_RevealPinArg(socket); if (chosenNickName) { cert = PK11_FindCertFromNickname(chosenNickName, proto_win); if (cert) { privKey = PK11_FindKeyByAnyCert(cert, proto_win); if (privKey) { secStatus = SECSuccess; } else { CERT_DestroyCertificate(cert); } } } else { /* no nickname given, automatically find the right cert */ CERTCertNicknames *names; int i; names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), SEC_CERT_NICKNAMES_USER, proto_win); if (names != NULL) { for(i = 0; i < names->numnicknames; i++ ) { cert = PK11_FindCertFromNickname(names->nicknames[i], proto_win); if (!cert) { continue; } /* Only check unexpired certs */ if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE) != secCertTimeValid ) { CERT_DestroyCertificate(cert); continue; } secStatus = NSS_CmpCertChainWCANames(cert, caNames); if (secStatus == SECSuccess) { privKey = PK11_FindKeyByAnyCert(cert, proto_win); if (privKey) { break; } secStatus = SECFailure; } CERT_DestroyCertificate(cert); } /* for loop */ CERT_FreeNicknames(names); } } if (secStatus == SECSuccess) { *pRetCert = cert; *pRetKey = privKey; } return secStatus; }