585
604
return (char *)PORT_Strdup((char *)arg);
588
static SECStatus nss_Init_Tokens(struct connectdata * conn)
590
PK11SlotList *slotList;
591
PK11SlotListElement *listEntry;
592
SECStatus ret, status = SECSuccess;
594
PK11_SetPasswordFunc(nss_get_password);
597
PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL);
599
for(listEntry = PK11_GetFirstSafe(slotList);
600
listEntry; listEntry = listEntry->next) {
601
PK11SlotInfo *slot = listEntry->slot;
603
if(PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) {
604
if(slot == PK11_GetInternalKeySlot()) {
605
failf(conn->data, "The NSS database has not been initialized");
608
failf(conn->data, "The token %s has not been initialized",
609
PK11_GetTokenName(slot));
615
ret = PK11_Authenticate(slot, PR_TRUE,
616
conn->data->set.str[STRING_KEY_PASSWD]);
617
if(SECSuccess != ret) {
618
if(PR_GetError() == SEC_ERROR_BAD_PASSWORD)
619
infof(conn->data, "The password for token '%s' is incorrect\n",
620
PK11_GetTokenName(slot));
630
607
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
632
609
SECStatus success = SECSuccess;
633
610
struct connectdata *conn = (struct connectdata *)arg;
634
611
PRErrorCode err = PR_GetError();
635
612
CERTCertificate *cert = NULL;
636
char *subject, *issuer;
613
char *subject, *subject_cn, *issuer;
638
615
if(conn->data->set.ssl.certverifyresult!=0)
659
637
case SSL_ERROR_BAD_CERT_DOMAIN:
660
if(conn->data->set.ssl.verifypeer)
638
if(conn->data->set.ssl.verifyhost) {
639
failf(conn->data, "SSL: certificate subject name '%s' does not match "
640
"target host name '%s'", subject_cn, conn->host.dispname);
661
641
success = SECFailure;
662
infof(conn->data, "common name: %s (does not match '%s')\n",
663
subject, conn->host.dispname);
643
infof(conn->data, "warning: SSL: certificate subject name '%s' does not "
644
"match target host name '%s'\n", subject_cn, conn->host.dispname);
665
647
case SEC_ERROR_EXPIRED_CERTIFICATE:
666
648
if(conn->data->set.ssl.verifypeer)
667
649
success = SECFailure;
668
650
infof(conn->data, "Remote Certificate has expired.\n");
652
case SEC_ERROR_UNKNOWN_ISSUER:
653
if(conn->data->set.ssl.verifypeer)
654
success = SECFailure;
655
infof(conn->data, "Peer's certificate issuer is not recognized: '%s'\n",
671
659
if(conn->data->set.ssl.verifypeer)
672
660
success = SECFailure;
692
681
return SECSuccess;
684
static void display_cert_info(struct SessionHandle *data, CERTCertificate *cert) {
685
char *subject, *issuer, *common_name;
686
PRExplodedTime printableTime;
687
char timeString[256];
688
PRTime notBefore, notAfter;
690
subject = CERT_NameToAscii(&cert->subject);
691
issuer = CERT_NameToAscii(&cert->issuer);
692
common_name = CERT_GetCommonName(&cert->subject);
693
infof(data, "\tsubject: %s\n", subject);
695
CERT_GetCertTimes(cert, ¬Before, ¬After);
696
PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
697
PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
698
infof(data, "\tstart date: %s\n", timeString);
699
PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
700
PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
701
infof(data, "\texpire date: %s\n", timeString);
702
infof(data, "\tcommon name: %s\n", common_name);
703
infof(data, "\tissuer: %s\n", issuer);
707
PR_Free(common_name);
695
710
static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
697
712
SSLChannelInfo channel;
698
713
SSLCipherSuiteInfo suite;
699
714
CERTCertificate *cert;
700
char *subject, *issuer, *common_name;
701
PRExplodedTime printableTime;
702
char timeString[256];
703
PRTime notBefore, notAfter;
705
716
if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
706
717
SECSuccess && channel.length == sizeof channel &&
714
725
infof(conn->data, "Server certificate:\n");
716
727
cert = SSL_PeerCertificate(sock);
717
subject = CERT_NameToAscii(&cert->subject);
718
issuer = CERT_NameToAscii(&cert->issuer);
719
common_name = CERT_GetCommonName(&cert->subject);
720
infof(conn->data, "\tsubject: %s\n", subject);
722
CERT_GetCertTimes(cert, ¬Before, ¬After);
723
PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
724
PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
725
infof(conn->data, "\tstart date: %s\n", timeString);
726
PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
727
PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
728
infof(conn->data, "\texpire date: %s\n", timeString);
729
infof(conn->data, "\tcommon name: %s\n", common_name);
730
infof(conn->data, "\tissuer: %s\n", issuer);
734
PR_Free(common_name);
728
display_cert_info(conn->data, cert);
736
729
CERT_DestroyCertificate(cert);
786
779
struct CERTCertificateStr **pRetCert,
787
780
struct SECKEYPrivateKeyStr **pRetKey)
789
SECKEYPrivateKey *privKey;
790
struct ssl_connect_data *connssl = (struct ssl_connect_data *) arg;
791
char *nickname = connssl->client_nickname;
792
void *proto_win = NULL;
793
SECStatus secStatus = SECFailure;
797
proto_win = SSL_RevealPinArg(sock);
802
connssl->client_cert = PK11_FindCertFromNickname(nickname, proto_win);
803
if(connssl->client_cert) {
805
if(!strncmp(nickname, "PEM Token", 9)) {
806
CK_SLOT_ID slotID = 1; /* hardcoded for now */
807
char slotname[SLOTSIZE];
808
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
809
slot = PK11_FindSlotByName(slotname);
810
privKey = PK11_FindPrivateKeyFromCert(slot, connssl->client_cert, NULL);
813
secStatus = SECSuccess;
817
privKey = PK11_FindKeyByAnyCert(connssl->client_cert, proto_win);
819
secStatus = SECSuccess;
823
if(secStatus == SECSuccess) {
824
*pRetCert = connssl->client_cert;
828
if(connssl->client_cert)
829
CERT_DestroyCertificate(connssl->client_cert);
830
connssl->client_cert = NULL;
782
static const char pem_nickname[] = "PEM Token #1";
783
const char *pem_slotname = pem_nickname;
785
struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
786
struct SessionHandle *data = connssl->data;
787
const char *nickname = connssl->client_nickname;
789
if (mod && nickname &&
790
0 == strncmp(nickname, pem_nickname, /* length of "PEM Token" */ 9)) {
792
/* use the cert/key provided by PEM reader */
794
void *proto_win = SSL_RevealPinArg(sock);
797
*pRetCert = PK11_FindCertFromNickname(nickname, proto_win);
798
if (NULL == *pRetCert) {
799
failf(data, "NSS: client certificate not found: %s", nickname);
803
slot = PK11_FindSlotByName(pem_slotname);
805
failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
809
*pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL);
811
if (NULL == *pRetKey) {
812
failf(data, "NSS: private key not found for certificate: %s", nickname);
816
infof(data, "NSS: client certificate: %s\n", nickname);
817
display_cert_info(data, *pRetCert);
821
/* use the default NSS hook */
822
if (SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
824
|| NULL == *pRetCert) {
826
if (NULL == nickname)
827
failf(data, "NSS: client certificate not found (nickname not specified)");
829
failf(data, "NSS: client certificate not found: %s", nickname);
834
/* get certificate nickname if any */
835
nickname = (*pRetCert)->nickname;
836
if (NULL == nickname)
837
nickname = "[unknown]";
839
if (NULL == *pRetKey) {
840
failf(data, "NSS: private key not found for certificate: %s", nickname);
844
infof(data, "NSS: using client certificate: %s\n", nickname);
845
display_cert_info(data, *pRetCert);
909
928
if(connssl->handle) {
910
929
PR_Close(connssl->handle);
931
/* NSS closes the socket we previously handed to it, so we must mark it
932
as closed to avoid double close */
933
fake_sclose(conn->sock[sockindex]);
934
conn->sock[sockindex] = CURL_SOCKET_BAD;
911
935
if(connssl->client_nickname != NULL) {
912
936
free(connssl->client_nickname);
913
937
connssl->client_nickname = NULL;
915
if(connssl->client_cert)
916
CERT_DestroyCertificate(connssl->client_cert);
939
#ifdef HAVE_PK11_CREATEGENERICOBJECT
918
941
(void)PK11_DestroyGenericObject(connssl->key);
919
942
if(connssl->cacert[1])
920
943
(void)PK11_DestroyGenericObject(connssl->cacert[1]);
921
944
if(connssl->cacert[0])
922
945
(void)PK11_DestroyGenericObject(connssl->cacert[0]);
923
947
connssl->handle = NULL;
955
976
if (connssl->state == ssl_connection_complete)
958
connssl->client_cert = NULL;
979
connssl->data = data;
981
#ifdef HAVE_PK11_CREATEGENERICOBJECT
959
982
connssl->cacert[0] = NULL;
960
983
connssl->cacert[1] = NULL;
961
984
connssl->key = NULL;
963
987
/* FIXME. NSS doesn't support multiple databases open at the same time. */
964
988
PR_Lock(nss_initlock);
965
989
if(!initialized) {
967
certDir = getenv("SSL_DIR"); /* Look in $SSL_DIR */
992
/* First we check if $SSL_DIR points to a valid dir */
993
certDir = getenv("SSL_DIR");
995
if((stat(certDir, &st) != 0) ||
996
(!S_ISDIR(st.st_mode))) {
1001
/* Now we check if the default location is a valid dir */
972
if(stat(SSL_DIR, &st) == 0)
973
if(S_ISDIR(st.st_mode)) {
974
certDir = (char *)SSL_DIR;
1003
if((stat(SSL_DIR, &st) == 0) &&
1004
(S_ISDIR(st.st_mode))) {
1005
certDir = (char *)SSL_DIR;
978
1009
if (!NSS_IsInitialized()) {
979
1010
initialized = 1;
1011
infof(conn->data, "Initializing NSS with certpath: %s\n",
1012
certDir ? certDir : "none");
981
1014
rv = NSS_NoDB_Init(NULL);
984
rv = NSS_Initialize(certDir, NULL, NULL, "secmod.db",
1017
char *certpath = PR_smprintf("%s%s",
1018
NSS_VersionCheck("3.12.0") ? "sql:" : "",
1020
rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY);
1021
PR_smprintf_free(certpath);
987
1023
if(rv != SECSuccess) {
988
1024
infof(conn->data, "Unable to initialize NSS database\n");
997
1033
NSS_SetDomesticPolicy();
999
1035
#ifdef HAVE_PK11_CREATEGENERICOBJECT
1000
configstring = aprintf("library=%s name=PEM", pem_library);
1002
PR_Unlock(nss_initlock);
1005
mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
1037
char *configstring = aprintf("library=%s name=PEM", pem_library);
1039
PR_Unlock(nss_initlock);
1042
mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
1008
if(!mod || !mod->loaded) {
1010
SECMOD_DestroyModule(mod);
1045
if(!mod || !mod->loaded) {
1047
SECMOD_DestroyModule(mod);
1050
infof(data, "WARNING: failed to load NSS PEM library %s. Using OpenSSL "
1051
"PEM certificates will not work.\n", pem_library);
1013
infof(data, "WARNING: failed to load NSS PEM library %s. Using OpenSSL "
1014
"PEM certificates will not work.\n", pem_library);
1056
PK11_SetPasswordFunc(nss_get_password);
1018
1059
PR_Unlock(nss_initlock);
1145
1189
if(data->set.str[STRING_CERT]) {
1148
1190
bool nickname_alloc = FALSE;
1150
if(is_file(data->set.str[STRING_CERT])) {
1151
n = strrchr(data->set.str[STRING_CERT], '/');
1153
n++; /* skip last slash */
1154
nickname = aprintf("PEM Token #%d:%s", 1, n);
1156
return CURLE_OUT_OF_MEMORY;
1158
nickname_alloc = TRUE;
1162
nickname = data->set.str[STRING_CERT];
1164
if(nss_Init_Tokens(conn) != SECSuccess) {
1191
char *nickname = fmt_nickname(data->set.str[STRING_CERT], &nickname_alloc);
1193
return CURLE_OUT_OF_MEMORY;
1169
1195
if(!cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
1170
1196
data->set.str[STRING_KEY])) {
1171
1197
/* failf() is already done in cert_stuff() */
1180
1206
if(!connssl->client_nickname)
1181
1207
return CURLE_OUT_OF_MEMORY;
1183
if(SSL_GetClientAuthDataHook(model,
1184
(SSLGetClientAuthData) SelectClientCert,
1185
(void *)connssl) != SECSuccess) {
1186
curlerr = CURLE_SSL_CERTPROBLEM;
1191
1211
connssl->client_nickname = NULL;
1213
if(SSL_GetClientAuthDataHook(model, SelectClientCert,
1214
(void *)connssl) != SECSuccess) {
1215
curlerr = CURLE_SSL_CERTPROBLEM;
1194
1219
/* Import our model socket onto the existing file descriptor */
1195
1220
connssl->handle = PR_ImportTCPSocket(sockfd);
1217
1249
display_conn_info(conn, connssl->handle);
1219
1251
if (data->set.str[STRING_SSL_ISSUERCERT]) {
1222
bool nickname_alloc = FALSE;
1253
bool nickname_alloc = FALSE;
1254
char *nickname = fmt_nickname(data->set.str[STRING_SSL_ISSUERCERT],
1225
if(is_file(data->set.str[STRING_SSL_ISSUERCERT])) {
1226
n = strrchr(data->set.str[STRING_SSL_ISSUERCERT], '/');
1228
n++; /* skip last slash */
1229
nickname = aprintf("PEM Token #%d:%s", 1, n);
1231
return CURLE_OUT_OF_MEMORY;
1232
nickname_alloc = TRUE;
1236
nickname = data->set.str[STRING_SSL_ISSUERCERT];
1258
return CURLE_OUT_OF_MEMORY;
1238
1260
ret = check_issuer_cert(connssl->handle, nickname);