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.41 2009-02-27 08:53:10 bagder Exp $
22
22
***************************************************************************/
88
95
PRInt32 version; /* protocol version valid for this cipher */
97
98
#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
98
99
(x)->pValue=(v); (x)->ulValueLen = (l)
102
103
enum sslversion { SSL2 = 1, SSL3 = 2, TLS = 4 };
104
static const cipher_s cipherlist[ciphernum] = {
105
#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
106
static const cipher_s cipherlist[] = {
105
107
/* SSL2 cipher suites */
106
108
{"rc4", SSL_EN_RC4_128_WITH_MD5, SSL2},
109
{"rc4-md5", SSL_EN_RC4_128_WITH_MD5, SSL2},
107
110
{"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL2},
108
111
{"rc2", SSL_EN_RC2_128_CBC_WITH_MD5, SSL2},
109
112
{"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL2},
199
202
found = PR_FALSE;
201
for(i=0; i<ciphernum; i++) {
202
if(!strcasecmp(cipher, cipherlist[i].name)) {
204
for(i=0; i<NUM_OF_CIPHERS; i++) {
205
if(Curl_raw_equal(cipher, cipherlist[i].name)) {
203
206
cipher_state[i] = PR_TRUE;
219
222
/* Finally actually enable the selected ciphers */
220
for(i=0; i<ciphernum; i++) {
223
for(i=0; i<NUM_OF_CIPHERS; i++) {
221
224
rv = SSL_CipherPrefSet(model, cipherlist[i].num, cipher_state[i]);
222
225
if(rv != SECSuccess) {
223
226
failf(data, "Unknown cipher in cipher list");
235
* Get the number of ciphers that are enabled. We use this to determine
236
* if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
238
static int num_enabled_ciphers(void)
244
for(i=0; i<NUM_OF_CIPHERS; i++) {
245
SSL_CipherPolicyGet(cipherlist[i].num, &policy);
232
253
* Determine whether the nickname passed in is a filename that needs to
233
254
* be loaded as a PEM or a regular NSS nickname.
300
slotname = (char *)malloc(SLOTSIZE);
301
nickname = (char *)malloc(PATH_MAX);
302
323
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
303
snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", slotID, n);
325
nickname = aprintf("PEM Token #%ld:%s", slotID, n);
305
329
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++;
336
PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) );
338
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) );
315
340
PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename,
316
strlen(filename)+1); attrs++;
318
PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
344
PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) );
321
PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
347
PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) );
324
351
/* This load the certificate in our PEM module into the appropriate
391
static int nss_load_crl(const char* crlfilename, PRBool ascii)
399
CERTSignedCrl *crl=NULL;
400
PK11SlotInfo *slot=NULL;
402
infile = PR_Open(crlfilename,PR_RDONLY,0);
407
prstat = PR_GetOpenFileInfo(infile,&info);
408
if (prstat!=PR_SUCCESS)
413
filedata.data = NULL;
414
if (!SECITEM_AllocItem(NULL,&filedata,info.size))
416
nb = PR_Read(infile,filedata.data,info.size);
419
asc = (char*)filedata.data;
423
body=strstr(asc,"-----BEGIN");
427
body = PORT_Strchr(asc,'\n');
429
body = PORT_Strchr(asc,'\r');
431
trailer = strstr(++body,"-----END");
440
rv = ATOB_ConvertAsciiToItem(&crlDER,body);
441
PORT_Free(filedata.data);
446
if (!SECITEM_AllocItem(NULL,&crlDER,info.size))
448
nb = PR_Read(infile,crlDER.data,info.size);
453
slot = PK11_GetInternalKeySlot();
454
crl = PK11_ImportCRL(slot,&crlDER,
456
NULL,CRL_IMPORT_DEFAULT_OPTIONS,
457
NULL,(CRL_DECODE_DEFAULT_OPTIONS|
458
CRL_DECODE_DONT_COPY_DER));
459
if (slot) PK11_FreeSlot(slot);
365
465
static int nss_load_key(struct connectdata *conn, char *key_file)
367
467
#ifdef HAVE_PK11_CREATEGENERICOBJECT
382
482
slotID = 1; /* hardcoded for now */
384
slotname = (char *)malloc(SLOTSIZE);
385
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
484
snprintf(slotname, sizeof(slotname), "PEM Token #%ld", slotID);
387
485
slot = PK11_FindSlotByName(slotname);
406
503
SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
407
504
PK11_IsPresent(slot);
409
parg = (pphrase_arg_t *) malloc(sizeof(*parg));
506
parg = malloc(sizeof(pphrase_arg_t));
410
509
parg->retryCount = 0;
411
510
parg->data = conn->data;
412
511
/* parg is initialized in nss_Init_Tokens() */
502
601
SECStatus ret, status = SECSuccess;
503
602
pphrase_arg_t *parg = NULL;
505
parg = (pphrase_arg_t *) malloc(sizeof(*parg));
604
parg = malloc(sizeof(pphrase_arg_t));
506
608
parg->retryCount = 0;
507
609
parg->data = conn->data;
620
722
PRTime notBefore, notAfter;
622
724
if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
623
SECSuccess && channel.length == sizeof channel &&
624
channel.cipherSuite) {
725
SECSuccess && channel.length == sizeof channel &&
726
channel.cipherSuite) {
625
727
if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
626
&suite, sizeof suite) == SECSuccess) {
728
&suite, sizeof suite) == SECSuccess) {
627
729
infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
762
* Check that the Peer certificate's issuer certificate matches the one found
763
* by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
764
* issuer check, so we provide comments that mimic the OpenSSL
765
* X509_check_issued function (in x509v3/v3_purp.c)
767
static SECStatus check_issuer_cert(PRFileDesc *sock,
768
char *issuer_nickname)
770
CERTCertificate *cert,*cert_issuer,*issuer;
771
SECStatus res=SECSuccess;
772
void *proto_win = NULL;
775
PRArenaPool *tmpArena = NULL;
776
CERTAuthKeyID *authorityKeyID = NULL;
777
SECITEM *caname = NULL;
780
cert = SSL_PeerCertificate(sock);
781
cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
783
proto_win = SSL_RevealPinArg(sock);
785
issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
787
if ((!cert_issuer) || (!issuer))
789
else if (SECITEM_CompareItem(&cert_issuer->derCert,
790
&issuer->derCert)!=SECEqual)
793
CERT_DestroyCertificate(cert);
794
CERT_DestroyCertificate(issuer);
795
CERT_DestroyCertificate(cert_issuer);
660
801
* Callback to pick the SSL client certificate.
662
803
static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
683
824
if(!strncmp(nickname, "PEM Token", 9)) {
684
825
CK_SLOT_ID slotID = 1; /* hardcoded for now */
685
char * slotname = (char *)malloc(SLOTSIZE);
826
char slotname[SLOTSIZE];
686
827
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
687
828
slot = PK11_FindSlotByName(slotname);
688
829
privKey = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
689
830
PK11_FreeSlot(slot);
692
832
secStatus = SECSuccess;
720
860
int Curl_nss_init(void)
862
/* curl_global_init() is not thread-safe so this test is ok */
863
if (nss_initlock == NULL) {
723
864
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
865
nss_initlock = PR_NewLock();
725
868
/* We will actually initialize NSS later */
805
958
curlerr = CURLE_SSL_CONNECT_ERROR;
960
if (connssl->state == ssl_connection_complete)
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);
943
1108
rc = nss_load_cert(fullpath, PR_TRUE);
944
1109
/* FIXME: check this return value! */
946
/* This is purposefully tolerant of errors so non-PEM files
947
* can be in the same directory */
1111
/* This is purposefully tolerant of errors so non-PEM files
1112
* can be in the same directory */
948
1113
} while(entry != NULL);
949
1114
PR_CloseDir(dir);
955
1120
data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
956
1121
data->set.ssl.CApath ? data->set.ssl.CApath : "none");
1123
if (data->set.ssl.CRLfile) {
1124
int rc = nss_load_crl(data->set.ssl.CRLfile, PR_FALSE);
1126
curlerr = CURLE_SSL_CRL_BADFILE;
1131
data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none");
958
1134
if(data->set.str[STRING_CERT]) {
1137
bool nickname_alloc = FALSE;
962
nickname = (char *)malloc(PATH_MAX);
963
1139
if(is_file(data->set.str[STRING_CERT])) {
964
1140
n = strrchr(data->set.str[STRING_CERT], '/');
966
1142
n++; /* skip last slash */
967
snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", 1, n);
1143
nickname = aprintf("PEM Token #%d:%s", 1, n);
1145
return CURLE_OUT_OF_MEMORY;
1147
nickname_alloc = TRUE;
971
strncpy(nickname, data->set.str[STRING_CERT], PATH_MAX);
1151
nickname = data->set.str[STRING_CERT];
973
1153
if(nss_Init_Tokens(conn) != SECSuccess) {
977
1158
if(!cert_stuff(conn, data->set.str[STRING_CERT],
978
1159
data->set.str[STRING_KEY])) {
979
1160
/* failf() is already done in cert_stuff() */
981
1163
return CURLE_SSL_CERTPROBLEM;
984
connssl->client_nickname = strdup(nickname);
1166
/* this "takes over" the pointer to the allocated name or makes a
1168
connssl->client_nickname = nickname_alloc?nickname:strdup(nickname);
1169
if(!connssl->client_nickname)
1170
return CURLE_OUT_OF_MEMORY;
985
1172
if(SSL_GetClientAuthDataHook(model,
986
1173
(SSLGetClientAuthData) SelectClientCert,
987
1174
(void *)connssl->client_nickname) !=
995
1180
PK11_SetPasswordFunc(nss_no_password);
998
1183
connssl->client_nickname = NULL;
1000
1186
/* Import our model socket onto the existing file descriptor */
1001
1187
connssl->handle = PR_ImportTCPSocket(sockfd);
1002
1188
connssl->handle = SSL_ImportFD(model, connssl->handle);
1023
1209
display_conn_info(conn, connssl->handle);
1211
if (data->set.str[STRING_SSL_ISSUERCERT]) {
1214
bool nickname_alloc = FALSE;
1217
if(is_file(data->set.str[STRING_SSL_ISSUERCERT])) {
1218
n = strrchr(data->set.str[STRING_SSL_ISSUERCERT], '/');
1220
n++; /* skip last slash */
1221
nickname = aprintf("PEM Token #%d:%s", 1, n);
1223
return CURLE_OUT_OF_MEMORY;
1224
nickname_alloc = TRUE;
1228
nickname = data->set.str[STRING_SSL_ISSUERCERT];
1230
ret = check_issuer_cert(connssl->handle, nickname);
1235
if(SECFailure == ret) {
1236
infof(data,"SSL certificate issuer check failed\n");
1237
curlerr = CURLE_SSL_ISSUER_ERROR;
1241
infof(data, "SSL certificate issuer check ok\n");
1025
1245
return CURLE_OK;
1035
1255
/* return number of sent (non-SSL) bytes */
1036
1256
int Curl_nss_send(struct connectdata *conn, /* connection data */
1037
1257
int sockindex, /* socketindex */
1038
void *mem, /* send this data */
1258
const void *mem, /* send this data */
1039
1259
size_t len) /* amount to write */