220
232
return SECSuccess;
236
* Determine whether the nickname passed in is a filename that needs to
237
* be loaded as a PEM or a regular NSS nickname.
239
* returns 1 for a file
240
* returns 0 for not a file (NSS nickname)
242
static int is_file(const char *filename)
249
if(stat(filename, &st) == 0)
250
if(S_ISREG(st.st_mode))
257
nss_load_cert(const char *filename, PRBool cacert)
259
#ifdef HAVE_PK11_CREATEGENERICOBJECT
261
PK11SlotInfo * slot = NULL;
262
PK11GenericObject *rv;
264
CK_ATTRIBUTE theTemplate[20];
265
CK_BBOOL cktrue = CK_TRUE;
266
CK_BBOOL ckfalse = CK_FALSE;
267
CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
268
char *slotname = NULL;
270
CERTCertificate *cert;
271
char *nickname = NULL;
274
/* If there is no slash in the filename it is assumed to be a regular
277
if(is_file(filename)) {
278
n = strrchr(filename, '/');
285
/* A nickname from the NSS internal database */
287
return 0; /* You can't specify an NSS CA nickname this way */
288
nickname = strdup(filename);
292
#ifdef HAVE_PK11_CREATEGENERICOBJECT
295
/* All CA and trust objects go into slot 0. Other slots are used
296
* for storing certificates. With each new user certificate we increment
297
* the slot count. We only support 1 user certificate right now.
304
slotname = (char *)malloc(SLOTSIZE);
305
nickname = (char *)malloc(PATH_MAX);
306
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
307
snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", slotID, n);
309
slot = PK11_FindSlotByName(slotname);
317
PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
318
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
319
PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename,
320
strlen(filename)+1); attrs++;
322
PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
325
PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
328
/* This load the certificate in our PEM module into the appropriate
331
rv = PK11_CreateGenericObject(slot, theTemplate, 4, PR_FALSE /* isPerm */);
341
/* We don't have PK11_CreateGenericObject but a file-based cert was passed
342
* in. We need to fail.
348
/* Double-check that the certificate or nickname requested exists in
349
* either the token or the NSS certificate database.
352
cert = PK11_FindCertFromNickname((char *)nickname, NULL);
354
/* An invalid nickname was passed in */
357
PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0);
361
CERT_DestroyCertificate(cert);
369
static int nss_load_key(struct connectdata *conn, char *key_file)
371
#ifdef HAVE_PK11_CREATEGENERICOBJECT
372
PK11SlotInfo * slot = NULL;
373
PK11GenericObject *rv;
375
CK_ATTRIBUTE theTemplate[20];
376
CK_BBOOL cktrue = CK_TRUE;
377
CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
379
char *slotname = NULL;
380
pphrase_arg_t *parg = NULL;
384
/* FIXME: grok the various file types */
386
slotID = 1; /* hardcoded for now */
388
slotname = (char *)malloc(SLOTSIZE);
389
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
391
slot = PK11_FindSlotByName(slotname);
397
PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
398
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
399
PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)key_file,
400
strlen(key_file)+1); attrs++;
402
/* When adding an encrypted key the PKCS#11 will be set as removed */
403
rv = PK11_CreateGenericObject(slot, theTemplate, 3, PR_FALSE /* isPerm */);
405
PR_SetError(SEC_ERROR_BAD_KEY, 0);
409
/* This will force the token to be seen as re-inserted */
410
SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
411
PK11_IsPresent(slot);
413
parg = (pphrase_arg_t *) malloc(sizeof(*parg));
414
parg->retryCount = 0;
415
parg->data = conn->data;
416
/* parg is initialized in nss_Init_Tokens() */
417
if(PK11_Authenticate(slot, PR_TRUE, parg) != SECSuccess) {
425
/* If we don't have PK11_CreateGenericObject then we can't load a file-based
428
(void)conn; /* unused */
429
(void)key_file; /* unused */
434
static int display_error(struct connectdata *conn, PRInt32 err,
435
const char *filename)
438
case SEC_ERROR_BAD_PASSWORD:
439
failf(conn->data, "Unable to load client key: Incorrect password\n");
441
case SEC_ERROR_UNKNOWN_CERT:
442
failf(conn->data, "Unable to load certificate %s\n", filename);
447
return 0; /* The caller will print a generic error */
450
static int cert_stuff(struct connectdata *conn, char *cert_file, char *key_file)
452
struct SessionHandle *data = conn->data;
456
rv = nss_load_cert(cert_file, PR_FALSE);
458
if(!display_error(conn, PR_GetError(), cert_file))
459
failf(data, "Unable to load client cert %d.", PR_GetError());
463
if(key_file || (is_file(cert_file))) {
465
rv = nss_load_key(conn, key_file);
467
/* In case the cert file also has the key */
468
rv = nss_load_key(conn, cert_file);
470
if(!display_error(conn, PR_GetError(), key_file))
471
failf(data, "Unable to load client key %d.", PR_GetError());
223
479
static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
225
pphrase_arg_t *parg = (pphrase_arg_t *) arg;
482
parg = (pphrase_arg_t *) arg;
484
(void)slot; /* unused */
487
if(parg->data->set.str[STRING_KEY_PASSWD])
488
return (char *)PORT_Strdup((char *)parg->data->set.str[STRING_KEY_PASSWD]);
493
/* No longer ask for the password, parg has been freed */
494
static char * nss_no_password(PK11SlotInfo *slot, PRBool retry, void *arg)
226
496
(void)slot; /* unused */
227
497
(void)retry; /* unused */
228
if(parg->data->set.key_passwd)
229
return (char *)PORT_Strdup((char *)parg->data->set.key_passwd);
498
(void)arg; /* unused */
234
502
static SECStatus nss_Init_Tokens(struct connectdata * conn)
279
static SECStatus BadCertHandler(void *arg, PRFileDesc * socket)
551
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
281
553
SECStatus success = SECSuccess;
554
struct connectdata *conn = (struct connectdata *)arg;
555
PRErrorCode err = PR_GetError();
556
CERTCertificate *cert = NULL;
557
char *subject, *issuer;
559
if (conn->data->set.ssl.certverifyresult!=0)
562
conn->data->set.ssl.certverifyresult=err;
563
cert = SSL_PeerCertificate(sock);
564
subject = CERT_NameToAscii(&cert->subject);
565
issuer = CERT_NameToAscii(&cert->issuer);
566
CERT_DestroyCertificate(cert);
569
case SEC_ERROR_CA_CERT_INVALID:
570
infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
571
if (conn->data->set.ssl.verifypeer)
572
success = SECFailure;
574
case SEC_ERROR_UNTRUSTED_ISSUER:
575
if (conn->data->set.ssl.verifypeer)
576
success = SECFailure;
577
infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n",
580
case SSL_ERROR_BAD_CERT_DOMAIN:
581
if (conn->data->set.ssl.verifypeer)
582
success = SECFailure;
583
infof(conn->data, "common name: %s (does not match '%s')\n",
584
subject, conn->host.dispname);
586
case SEC_ERROR_EXPIRED_CERTIFICATE:
587
if (conn->data->set.ssl.verifypeer)
588
success = SECFailure;
589
infof(conn->data, "Remote Certificate has expired.\n");
592
if (conn->data->set.ssl.verifypeer)
593
success = SECFailure;
594
infof(conn->data, "Bad certificate received. Subject = '%s', "
595
"Issuer = '%s'\n", subject, issuer);
598
if (success == SECSuccess)
599
infof(conn->data, "SSL certificate verify ok.\n");
289
607
* Inform the application that the handshake is complete.
291
static SECStatus HandshakeCallback(PRFileDesc * socket, void *arg)
609
static SECStatus HandshakeCallback(PRFileDesc *sock, void *arg)
295
613
return SECSuccess;
616
static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
618
SSLChannelInfo channel;
619
SSLCipherSuiteInfo suite;
620
CERTCertificate *cert;
621
char *subject, *issuer, *common_name;
622
PRExplodedTime printableTime;
623
char timeString[256];
624
PRTime notBefore, notAfter;
626
if (SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
627
SECSuccess && channel.length == sizeof channel &&
628
channel.cipherSuite) {
629
if (SSL_GetCipherSuiteInfo(channel.cipherSuite,
630
&suite, sizeof suite) == SECSuccess) {
631
infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
635
infof(conn->data, "Server certificate:\n");
637
cert = SSL_PeerCertificate(sock);
638
subject = CERT_NameToAscii(&cert->subject);
639
issuer = CERT_NameToAscii(&cert->issuer);
640
common_name = CERT_GetCommonName(&cert->subject);
641
infof(conn->data, "\tsubject: %s\n", subject);
643
CERT_GetCertTimes(cert, ¬Before, ¬After);
644
PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
645
PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
646
infof(conn->data, "\tstart date: %s\n", timeString);
647
PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
648
PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
649
infof(conn->data, "\texpire date: %s\n", timeString);
650
infof(conn->data, "\tcommon name: %s\n", common_name);
651
infof(conn->data, "\tissuer: %s\n", issuer);
655
PR_Free(common_name);
657
CERT_DestroyCertificate(cert);
300
664
* Callback to pick the SSL client certificate.
302
static SECStatus SelectClientCert(void *arg, PRFileDesc * socket,
303
struct CERTDistNamesStr * caNames,
304
struct CERTCertificateStr ** pRetCert,
305
struct SECKEYPrivateKeyStr ** pRetKey)
666
static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
667
struct CERTDistNamesStr *caNames,
668
struct CERTCertificateStr **pRetCert,
669
struct SECKEYPrivateKeyStr **pRetKey)
307
671
CERTCertificate *cert;
308
672
SECKEYPrivateKey *privKey;
309
673
char *nickname = (char *)arg;
310
674
void *proto_win = NULL;
311
675
SECStatus secStatus = SECFailure;
314
proto_win = SSL_RevealPinArg(socket);
679
proto_win = SSL_RevealPinArg(sock);
316
684
cert = PK11_FindCertFromNickname(nickname, proto_win);
318
privKey = PK11_FindKeyByAnyCert(cert, proto_win);
320
secStatus = SECSuccess;
687
if(!strncmp(nickname, "PEM Token", 9)) {
688
CK_SLOT_ID slotID = 1; /* hardcoded for now */
689
char * slotname = (char *)malloc(SLOTSIZE);
690
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
691
slot = PK11_FindSlotByName(slotname);
692
privKey = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
696
secStatus = SECSuccess;
323
CERT_DestroyCertificate(cert);
700
privKey = PK11_FindKeyByAnyCert(cert, proto_win);
702
secStatus = SECSuccess;
418
800
curl_socket_t sockfd = conn->sock[sockindex];
419
801
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
421
int curlerr = CURLE_SSL_CONNECT_ERROR;
803
#ifdef HAVE_PK11_CREATEGENERICOBJECT
804
char *configstring = NULL;
806
char *certDir = NULL;
809
curlerr = CURLE_SSL_CONNECT_ERROR;
423
811
/* FIXME. NSS doesn't support multiple databases open at the same time. */
424
812
if(!initialized) {
425
if(!data->set.ssl.CAfile) {
426
if(data->set.ssl.verifypeer) {
427
failf(data, "No NSS cacert database specified.");
428
return CURLE_SSL_CACERT_BADFILE;
431
rv = NSS_NoDB_Init(NULL);
815
certDir = getenv("SSL_DIR"); /* Look in $SSL_DIR */
820
if (stat(SSL_DIR, &st) == 0)
821
if (S_ISDIR(st.st_mode)) {
822
certDir = (char *)SSL_DIR;
827
rv = NSS_NoDB_Init(NULL);
436
rv = NSS_Initialize(data->set.ssl.CAfile, NULL, NULL, "secmod.db",
830
rv = NSS_Initialize(certDir, NULL, NULL, "secmod.db",
437
831
NSS_INIT_READONLY);
439
833
if(rv != SECSuccess) {
834
infof(conn->data, "Unable to initialize NSS database\n");
440
835
curlerr = CURLE_SSL_CACERT_BADFILE;
839
NSS_SetDomesticPolicy();
841
#ifdef HAVE_PK11_CREATEGENERICOBJECT
842
configstring = (char *)malloc(PATH_MAX);
844
PR_snprintf(configstring, PATH_MAX, "library=%s name=PEM", pem_library);
846
mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
848
if (!mod || !mod->loaded) {
850
SECMOD_DestroyModule(mod);
853
infof(data, "WARNING: failed to load NSS PEM library %s. Using OpenSSL "
854
"PEM certificates will not work.\n", pem_library);
445
NSS_SetDomesticPolicy();
447
859
model = PR_NewTCPSocket();
484
896
if(data->set.ssl.cipher_list) {
485
if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess)
897
if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
898
curlerr = CURLE_SSL_CIPHER;
489
if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, NULL)
903
data->set.ssl.certverifyresult=0; /* not checked yet */
904
if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, conn)
492
908
if(SSL_HandshakeCallback(model, (SSLHandshakeCallback) HandshakeCallback,
493
909
NULL) != SECSuccess)
912
if(!data->set.ssl.verifypeer)
913
/* skip the verifying of the peer */
915
else if (data->set.ssl.CAfile) {
916
int rc = nss_load_cert(data->set.ssl.CAfile, PR_TRUE);
918
curlerr = CURLE_SSL_CACERT_BADFILE;
922
else if (data->set.ssl.CApath) {
927
if (stat(data->set.ssl.CApath, &st) == -1) {
928
curlerr = CURLE_SSL_CACERT_BADFILE;
932
if (S_ISDIR(st.st_mode)) {
935
dir = PR_OpenDir(data->set.ssl.CApath);
937
entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN);
940
char fullpath[PATH_MAX];
942
snprintf(fullpath, sizeof(fullpath), "%s/%s", data->set.ssl.CApath,
944
rc = nss_load_cert(fullpath, PR_TRUE);
945
/* FIXME: check this return value! */
947
/* This is purposefully tolerant of errors so non-PEM files
948
* can be in the same directory */
949
} while (entry != NULL);
956
data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
957
data->set.ssl.CApath ? data->set.ssl.CApath : "none");
959
if(data->set.str[STRING_CERT]) {
963
nickname = (char *)malloc(PATH_MAX);
964
if(is_file(data->set.str[STRING_CERT])) {
965
n = strrchr(data->set.str[STRING_CERT], '/');
967
n++; /* skip last slash */
968
snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", 1, n);
972
strncpy(nickname, data->set.str[STRING_CERT], PATH_MAX);
974
if(nss_Init_Tokens(conn) != SECSuccess) {
978
if (!cert_stuff(conn, data->set.str[STRING_CERT],
979
data->set.str[STRING_KEY])) {
980
/* failf() is already done in cert_stuff() */
982
return CURLE_SSL_CERTPROBLEM;
985
connssl->client_nickname = strdup(nickname);
497
986
if(SSL_GetClientAuthDataHook(model,
498
987
(SSLGetClientAuthData) SelectClientCert,
499
(void *)data->set.cert) != SECSuccess) {
988
(void *)connssl->client_nickname) !=
500
990
curlerr = CURLE_SSL_CERTPROBLEM;
503
if(nss_Init_Tokens(conn) != SECSuccess)
996
PK11_SetPasswordFunc(nss_no_password);
999
connssl->client_nickname = NULL;
507
1001
/* Import our model socket onto the existing file descriptor */
508
1002
connssl->handle = PR_ImportTCPSocket(sockfd);
509
1003
connssl->handle = SSL_ImportFD(model, connssl->handle);
510
1004
if(!connssl->handle)
1006
PR_Close(model); /* We don't need this any more */
513
1008
/* Force handshake on next I/O */
514
1009
SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);