5
5
* | (__| |_| | _ <| |___
6
6
* \___|\___/|_| \_\_____|
8
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
8
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
10
10
* This software is licensed as described in the file COPYING, which
11
11
* you should have received as part of this distribution. The terms
18
18
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
* KIND, either express or implied.
21
* $Id: nss.c,v 1.18 2008-05-26 01:59:00 yangtse Exp $
21
* $Id: nss.c,v 1.47 2009-05-11 09:13:49 bagder Exp $
22
22
***************************************************************************/
74
79
PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
81
PRLock * nss_initlock = NULL;
83
volatile int initialized = 0;
78
85
#define HANDSHAKE_TIMEOUT 30
82
struct SessionHandle *data;
88
90
PRInt32 version; /* protocol version valid for this cipher */
97
93
#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
98
94
(x)->pValue=(v); (x)->ulValueLen = (l)
102
98
enum sslversion { SSL2 = 1, SSL3 = 2, TLS = 4 };
104
static const cipher_s cipherlist[ciphernum] = {
100
#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
101
static const cipher_s cipherlist[] = {
105
102
/* SSL2 cipher suites */
106
103
{"rc4", SSL_EN_RC4_128_WITH_MD5, SSL2},
104
{"rc4-md5", SSL_EN_RC4_128_WITH_MD5, SSL2},
107
105
{"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL2},
108
106
{"rc2", SSL_EN_RC2_128_CBC_WITH_MD5, SSL2},
109
107
{"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL2},
160
/* following ciphers are new in NSS 3.4 and not enabled by default, therefor
161
they are enabled explicitly */
162
static const int enable_ciphers_by_default[] = {
163
TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
164
TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
165
TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
166
TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
167
TLS_RSA_WITH_AES_128_CBC_SHA,
168
TLS_RSA_WITH_AES_256_CBC_SHA,
169
SSL_NULL_WITH_NULL_NULL
162
172
#ifdef HAVE_PK11_CREATEGENERICOBJECT
163
173
static const char* pem_library = "libnsspem.so";
219
229
/* Finally actually enable the selected ciphers */
220
for(i=0; i<ciphernum; i++) {
230
for(i=0; i<NUM_OF_CIPHERS; i++) {
221
231
rv = SSL_CipherPrefSet(model, cipherlist[i].num, cipher_state[i]);
222
232
if(rv != SECSuccess) {
223
233
failf(data, "Unknown cipher in cipher list");
242
* Get the number of ciphers that are enabled. We use this to determine
243
* if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
245
static int num_enabled_ciphers(void)
251
for(i=0; i<NUM_OF_CIPHERS; i++) {
252
SSL_CipherPolicyGet(cipherlist[i].num, &policy);
232
260
* Determine whether the nickname passed in is a filename that needs to
233
261
* be loaded as a PEM or a regular NSS nickname.
253
nss_load_cert(const char *filename, PRBool cacert)
280
static int nss_load_cert(struct ssl_connect_data *ssl,
281
const char *filename, PRBool cacert)
255
283
#ifdef HAVE_PK11_CREATEGENERICOBJECT
256
284
CK_SLOT_ID slotID;
257
285
PK11SlotInfo * slot = NULL;
258
PK11GenericObject *rv;
259
286
CK_ATTRIBUTE *attrs;
260
287
CK_ATTRIBUTE theTemplate[20];
261
288
CK_BBOOL cktrue = CK_TRUE;
262
289
CK_BBOOL ckfalse = CK_FALSE;
263
290
CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
264
char *slotname = NULL;
291
char slotname[SLOTSIZE];
266
293
CERTCertificate *cert;
267
294
char *nickname = NULL;
300
slotname = (char *)malloc(SLOTSIZE);
301
nickname = (char *)malloc(PATH_MAX);
302
329
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
303
snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", slotID, n);
331
nickname = aprintf("PEM Token #%ld:%s", slotID, n);
305
335
slot = PK11_FindSlotByName(slotname);
313
PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
314
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
342
PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) );
344
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) );
315
346
PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename,
316
strlen(filename)+1); attrs++;
318
PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
350
PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) );
321
PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
353
PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) );
324
357
/* This load the certificate in our PEM module into the appropriate
327
rv = PK11_CreateGenericObject(slot, theTemplate, 4, PR_FALSE /* isPerm */);
360
ssl->cacert[slotID] = PK11_CreateGenericObject(slot, theTemplate, 4,
361
PR_FALSE /* isPerm */);
329
363
PK11_FreeSlot(slot);
365
if(ssl->cacert[slotID] == NULL) {
365
static int nss_load_key(struct connectdata *conn, char *key_file)
398
static int nss_load_crl(const char* crlfilename, PRBool ascii)
406
CERTSignedCrl *crl=NULL;
407
PK11SlotInfo *slot=NULL;
409
infile = PR_Open(crlfilename,PR_RDONLY,0);
414
prstat = PR_GetOpenFileInfo(infile,&info);
415
if (prstat!=PR_SUCCESS)
420
filedata.data = NULL;
421
if (!SECITEM_AllocItem(NULL,&filedata,info.size))
423
nb = PR_Read(infile,filedata.data,info.size);
426
asc = (char*)filedata.data;
430
body=strstr(asc,"-----BEGIN");
434
body = PORT_Strchr(asc,'\n');
436
body = PORT_Strchr(asc,'\r');
438
trailer = strstr(++body,"-----END");
447
rv = ATOB_ConvertAsciiToItem(&crlDER,body);
448
PORT_Free(filedata.data);
453
if (!SECITEM_AllocItem(NULL,&crlDER,info.size))
455
nb = PR_Read(infile,crlDER.data,info.size);
460
slot = PK11_GetInternalKeySlot();
461
crl = PK11_ImportCRL(slot,&crlDER,
463
NULL,CRL_IMPORT_DEFAULT_OPTIONS,
464
NULL,(CRL_DECODE_DEFAULT_OPTIONS|
465
CRL_DECODE_DONT_COPY_DER));
466
if (slot) PK11_FreeSlot(slot);
472
static int nss_load_key(struct connectdata *conn, int sockindex, char *key_file)
367
474
#ifdef HAVE_PK11_CREATEGENERICOBJECT
368
475
PK11SlotInfo * slot = NULL;
369
PK11GenericObject *rv;
370
476
CK_ATTRIBUTE *attrs;
371
477
CK_ATTRIBUTE theTemplate[20];
372
478
CK_BBOOL cktrue = CK_TRUE;
373
479
CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
374
480
CK_SLOT_ID slotID;
375
char *slotname = NULL;
376
pphrase_arg_t *parg = NULL;
481
char slotname[SLOTSIZE];
482
struct ssl_connect_data *sslconn = &conn->ssl[sockindex];
378
484
attrs = theTemplate;
382
488
slotID = 1; /* hardcoded for now */
384
slotname = (char *)malloc(SLOTSIZE);
385
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
490
snprintf(slotname, sizeof(slotname), "PEM Token #%ld", slotID);
387
491
slot = PK11_FindSlotByName(slotname);
396
499
strlen(key_file)+1); attrs++;
398
501
/* When adding an encrypted key the PKCS#11 will be set as removed */
399
rv = PK11_CreateGenericObject(slot, theTemplate, 3, PR_FALSE /* isPerm */);
502
sslconn->key = PK11_CreateGenericObject(slot, theTemplate, 3,
503
PR_FALSE /* isPerm */);
504
if(sslconn->key == NULL) {
401
505
PR_SetError(SEC_ERROR_BAD_KEY, 0);
406
510
SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
407
511
PK11_IsPresent(slot);
409
parg = (pphrase_arg_t *) malloc(sizeof(*parg));
410
parg->retryCount = 0;
411
parg->data = conn->data;
412
513
/* parg is initialized in nss_Init_Tokens() */
413
if(PK11_Authenticate(slot, PR_TRUE, parg) != SECSuccess) {
514
if(PK11_Authenticate(slot, PR_TRUE,
515
conn->data->set.str[STRING_KEY_PASSWD]) != SECSuccess) {
443
546
return 0; /* The caller will print a generic error */
446
static int cert_stuff(struct connectdata *conn, char *cert_file, char *key_file)
549
static int cert_stuff(struct connectdata *conn,
550
int sockindex, char *cert_file, char *key_file)
448
552
struct SessionHandle *data = conn->data;
452
rv = nss_load_cert(cert_file, PR_FALSE);
556
rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
454
558
if(!display_error(conn, PR_GetError(), cert_file))
455
559
failf(data, "Unable to load client cert %d.", PR_GetError());
459
563
if(key_file || (is_file(cert_file))) {
461
rv = nss_load_key(conn, key_file);
565
rv = nss_load_key(conn, sockindex, key_file);
463
567
/* In case the cert file also has the key */
464
rv = nss_load_key(conn, cert_file);
568
rv = nss_load_key(conn, sockindex, cert_file);
466
570
if(!display_error(conn, PR_GetError(), key_file))
467
571
failf(data, "Unable to load client key %d.", PR_GetError());
475
579
static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
478
parg = (pphrase_arg_t *) arg;
480
581
(void)slot; /* unused */
582
if(retry || NULL == arg)
483
if(parg->data->set.str[STRING_KEY_PASSWD])
484
return (char *)PORT_Strdup((char *)parg->data->set.str[STRING_KEY_PASSWD]);
489
/* No longer ask for the password, parg has been freed */
490
static char * nss_no_password(PK11SlotInfo *slot, PRBool retry, void *arg)
492
(void)slot; /* unused */
493
(void)retry; /* unused */
494
(void)arg; /* unused */
585
return (char *)PORT_Strdup((char *)arg);
498
588
static SECStatus nss_Init_Tokens(struct connectdata * conn)
530
ret = PK11_Authenticate(slot, PR_TRUE, parg);
615
ret = PK11_Authenticate(slot, PR_TRUE,
616
conn->data->set.str[STRING_KEY_PASSWD]);
531
617
if(SECSuccess != ret) {
532
618
if(PR_GetError() == SEC_ERROR_BAD_PASSWORD)
533
619
infof(conn->data, "The password for token '%s' is incorrect\n",
620
703
PRTime notBefore, notAfter;
622
705
if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
623
SECSuccess && channel.length == sizeof channel &&
624
channel.cipherSuite) {
706
SECSuccess && channel.length == sizeof channel &&
707
channel.cipherSuite) {
625
708
if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
626
&suite, sizeof suite) == SECSuccess) {
709
&suite, sizeof suite) == SECSuccess) {
627
710
infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
743
* Check that the Peer certificate's issuer certificate matches the one found
744
* by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
745
* issuer check, so we provide comments that mimic the OpenSSL
746
* X509_check_issued function (in x509v3/v3_purp.c)
748
static SECStatus check_issuer_cert(PRFileDesc *sock,
749
char *issuer_nickname)
751
CERTCertificate *cert,*cert_issuer,*issuer;
752
SECStatus res=SECSuccess;
753
void *proto_win = NULL;
756
PRArenaPool *tmpArena = NULL;
757
CERTAuthKeyID *authorityKeyID = NULL;
758
SECITEM *caname = NULL;
761
cert = SSL_PeerCertificate(sock);
762
cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
764
proto_win = SSL_RevealPinArg(sock);
766
issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
768
if ((!cert_issuer) || (!issuer))
770
else if (SECITEM_CompareItem(&cert_issuer->derCert,
771
&issuer->derCert)!=SECEqual)
774
CERT_DestroyCertificate(cert);
775
CERT_DestroyCertificate(issuer);
776
CERT_DestroyCertificate(cert_issuer);
660
782
* Callback to pick the SSL client certificate.
662
784
static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
664
786
struct CERTCertificateStr **pRetCert,
665
787
struct SECKEYPrivateKeyStr **pRetKey)
667
CERTCertificate *cert;
668
789
SECKEYPrivateKey *privKey;
669
char *nickname = (char *)arg;
790
struct ssl_connect_data *connssl = (struct ssl_connect_data *) arg;
791
char *nickname = connssl->client_nickname;
670
792
void *proto_win = NULL;
671
793
SECStatus secStatus = SECFailure;
672
794
PK11SlotInfo *slot;
678
800
return secStatus;
680
cert = PK11_FindCertFromNickname(nickname, proto_win);
802
connssl->client_cert = PK11_FindCertFromNickname(nickname, proto_win);
803
if(connssl->client_cert) {
683
805
if(!strncmp(nickname, "PEM Token", 9)) {
684
806
CK_SLOT_ID slotID = 1; /* hardcoded for now */
685
char * slotname = (char *)malloc(SLOTSIZE);
807
char slotname[SLOTSIZE];
686
808
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
687
809
slot = PK11_FindSlotByName(slotname);
688
privKey = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
810
privKey = PK11_FindPrivateKeyFromCert(slot, connssl->client_cert, NULL);
689
811
PK11_FreeSlot(slot);
692
813
secStatus = SECSuccess;
696
privKey = PK11_FindKeyByAnyCert(cert, proto_win);
817
privKey = PK11_FindKeyByAnyCert(connssl->client_cert, proto_win);
698
819
secStatus = SECSuccess;
702
823
if(secStatus == SECSuccess) {
824
*pRetCert = connssl->client_cert;
704
825
*pRetKey = privKey;
708
CERT_DestroyCertificate(cert);
828
if(connssl->client_cert)
829
CERT_DestroyCertificate(connssl->client_cert);
830
connssl->client_cert = NULL;
711
833
return secStatus;
773
912
free(connssl->client_nickname);
774
913
connssl->client_nickname = NULL;
915
if(connssl->client_cert)
916
CERT_DestroyCertificate(connssl->client_cert);
918
(void)PK11_DestroyGenericObject(connssl->key);
919
if(connssl->cacert[1])
920
(void)PK11_DestroyGenericObject(connssl->cacert[1]);
921
if(connssl->cacert[0])
922
(void)PK11_DestroyGenericObject(connssl->cacert[0]);
776
923
connssl->handle = NULL;
802
949
char *certDir = NULL;
951
const int *cipher_to_enable;
805
953
curlerr = CURLE_SSL_CONNECT_ERROR;
955
if (connssl->state == ssl_connection_complete)
958
connssl->client_cert = NULL;
959
connssl->cacert[0] = NULL;
960
connssl->cacert[1] = NULL;
807
963
/* FIXME. NSS doesn't support multiple databases open at the same time. */
964
PR_Lock(nss_initlock);
808
965
if(!initialized) {
811
967
certDir = getenv("SSL_DIR"); /* Look in $SSL_DIR */
823
rv = NSS_NoDB_Init(NULL);
826
rv = NSS_Initialize(certDir, NULL, NULL, "secmod.db",
829
if(rv != SECSuccess) {
830
infof(conn->data, "Unable to initialize NSS database\n");
831
curlerr = CURLE_SSL_CACERT_BADFILE;
978
if (!NSS_IsInitialized()) {
981
rv = NSS_NoDB_Init(NULL);
984
rv = NSS_Initialize(certDir, NULL, NULL, "secmod.db",
987
if(rv != SECSuccess) {
988
infof(conn->data, "Unable to initialize NSS database\n");
989
curlerr = CURLE_SSL_CACERT_BADFILE;
991
PR_Unlock(nss_initlock);
996
if(num_enabled_ciphers() == 0)
997
NSS_SetDomesticPolicy();
999
#ifdef HAVE_PK11_CREATEGENERICOBJECT
1000
configstring = aprintf("library=%s name=PEM", pem_library);
1002
PR_Unlock(nss_initlock);
835
NSS_SetDomesticPolicy();
837
#ifdef HAVE_PK11_CREATEGENERICOBJECT
838
configstring = (char *)malloc(PATH_MAX);
840
PR_snprintf(configstring, PATH_MAX, "library=%s name=PEM", pem_library);
842
1005
mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
843
1006
free(configstring);
844
1008
if(!mod || !mod->loaded) {
846
1010
SECMOD_DestroyModule(mod);
892
1057
if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess)
1060
/* enable all ciphers from enable_ciphers_by_default */
1061
cipher_to_enable = enable_ciphers_by_default;
1062
while (SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) {
1063
if (SSL_CipherPrefSet(model, *cipher_to_enable, PR_TRUE) != SECSuccess) {
1064
curlerr = CURLE_SSL_CIPHER;
895
1070
if(data->set.ssl.cipher_list) {
896
1071
if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
897
1072
curlerr = CURLE_SSL_CIPHER;
912
1087
/* skip the verifying of the peer */
914
1089
else if(data->set.ssl.CAfile) {
915
int rc = nss_load_cert(data->set.ssl.CAfile, PR_TRUE);
1090
int rc = nss_load_cert(&conn->ssl[sockindex], data->set.ssl.CAfile,
917
1093
curlerr = CURLE_SSL_CACERT_BADFILE;
941
1117
snprintf(fullpath, sizeof(fullpath), "%s/%s", data->set.ssl.CApath,
943
rc = nss_load_cert(fullpath, PR_TRUE);
1119
rc = nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE);
944
1120
/* FIXME: check this return value! */
946
/* This is purposefully tolerant of errors so non-PEM files
947
* can be in the same directory */
1122
/* This is purposefully tolerant of errors so non-PEM files
1123
* can be in the same directory */
948
1124
} while(entry != NULL);
949
1125
PR_CloseDir(dir);
955
1131
data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
956
1132
data->set.ssl.CApath ? data->set.ssl.CApath : "none");
1134
if (data->set.ssl.CRLfile) {
1135
int rc = nss_load_crl(data->set.ssl.CRLfile, PR_FALSE);
1137
curlerr = CURLE_SSL_CRL_BADFILE;
1142
data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none");
958
1145
if(data->set.str[STRING_CERT]) {
1148
bool nickname_alloc = FALSE;
962
nickname = (char *)malloc(PATH_MAX);
963
1150
if(is_file(data->set.str[STRING_CERT])) {
964
1151
n = strrchr(data->set.str[STRING_CERT], '/');
966
1153
n++; /* skip last slash */
967
snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", 1, n);
1154
nickname = aprintf("PEM Token #%d:%s", 1, n);
1156
return CURLE_OUT_OF_MEMORY;
1158
nickname_alloc = TRUE;
971
strncpy(nickname, data->set.str[STRING_CERT], PATH_MAX);
1162
nickname = data->set.str[STRING_CERT];
973
1164
if(nss_Init_Tokens(conn) != SECSuccess) {
977
if(!cert_stuff(conn, data->set.str[STRING_CERT],
1169
if(!cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
978
1170
data->set.str[STRING_KEY])) {
979
1171
/* failf() is already done in cert_stuff() */
981
1174
return CURLE_SSL_CERTPROBLEM;
984
connssl->client_nickname = strdup(nickname);
1177
/* this "takes over" the pointer to the allocated name or makes a
1179
connssl->client_nickname = nickname_alloc?nickname:strdup(nickname);
1180
if(!connssl->client_nickname)
1181
return CURLE_OUT_OF_MEMORY;
985
1183
if(SSL_GetClientAuthDataHook(model,
986
1184
(SSLGetClientAuthData) SelectClientCert,
987
(void *)connssl->client_nickname) !=
1185
(void *)connssl) != SECSuccess) {
989
1186
curlerr = CURLE_SSL_CERTPROBLEM;
995
PK11_SetPasswordFunc(nss_no_password);
998
1191
connssl->client_nickname = NULL;
1000
1194
/* Import our model socket onto the existing file descriptor */
1001
1195
connssl->handle = PR_ImportTCPSocket(sockfd);
1002
1196
connssl->handle = SSL_ImportFD(model, connssl->handle);
1023
1217
display_conn_info(conn, connssl->handle);
1219
if (data->set.str[STRING_SSL_ISSUERCERT]) {
1222
bool nickname_alloc = FALSE;
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];
1238
ret = check_issuer_cert(connssl->handle, nickname);
1243
if(SECFailure == ret) {
1244
infof(data,"SSL certificate issuer check failed\n");
1245
curlerr = CURLE_SSL_ISSUER_ERROR;
1249
infof(data, "SSL certificate issuer check ok\n");
1025
1253
return CURLE_OK;
1035
1263
/* return number of sent (non-SSL) bytes */
1036
1264
int Curl_nss_send(struct connectdata *conn, /* connection data */
1037
1265
int sockindex, /* socketindex */
1038
void *mem, /* send this data */
1266
const void *mem, /* send this data */
1039
1267
size_t len) /* amount to write */