280
static char *fmt_nickname(char *str, bool *nickname_alloc)
282
char *nickname = NULL;
283
*nickname_alloc = FALSE;
286
char *n = strrchr(str, '/');
288
*nickname_alloc = TRUE;
289
n++; /* skip last slash */
290
nickname = aprintf("PEM Token #%d:%s", 1, n);
285
/* Return on heap allocated filename/nickname of a certificate. The returned
286
* string should be later deallocated using free(). *is_nickname is set to TRUE
287
* if the given string is treated as nickname; FALSE if the given string is
288
* treated as file name.
290
static char *fmt_nickname(struct SessionHandle *data, enum dupstring cert_kind,
293
const char *str = data->set.str[cert_kind];
298
/* no such file exists, use the string as nickname */
301
/* search the last slash; we require at least one slash in a file name */
302
n = strrchr(str, '/');
304
infof(data, "warning: certificate file name \"%s\" handled as nickname; "
305
"please use \"./%s\" to force file name\n", str, str);
309
/* we'll use the PEM reader to read the certificate from file */
310
*is_nickname = FALSE;
312
n++; /* skip last slash */
313
return aprintf("PEM Token #%d:%s", 1, n);
316
#ifdef HAVE_PK11_CREATEGENERICOBJECT
317
/* Call PK11_CreateGenericObject() with the given obj_class and filename. If
318
* the call succeeds, append the object handle to the list of objects so that
319
* the object can be destroyed in Curl_nss_close(). */
320
static CURLcode nss_create_object(struct ssl_connect_data *ssl,
321
CK_OBJECT_CLASS obj_class,
322
const char *filename, bool cacert)
325
PK11GenericObject *obj;
326
CK_BBOOL cktrue = CK_TRUE;
327
CK_BBOOL ckfalse = CK_FALSE;
328
CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
331
const int slot_id = (cacert) ? 0 : 1;
332
char *slot_name = aprintf("PEM Token #%d", slot_id);
334
return CURLE_OUT_OF_MEMORY;
336
slot = PK11_FindSlotByName(slot_name);
339
return CURLE_SSL_CERTPROBLEM;
341
PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
342
PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
343
PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
344
strlen(filename) + 1);
346
if(CKO_CERTIFICATE == obj_class) {
347
CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
348
PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
351
obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
354
return CURLE_SSL_CERTPROBLEM;
356
if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) {
357
PK11_DestroyGenericObject(obj);
358
return CURLE_OUT_OF_MEMORY;
364
/* Destroy the NSS object whose handle is given by ptr. This function is
365
* a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
366
* NSS objects in Curl_nss_close() */
367
static void nss_destroy_object(void *user, void *ptr)
369
PK11GenericObject *obj = (PK11GenericObject *)ptr;
371
PK11_DestroyGenericObject(obj);
298
375
static int nss_load_cert(struct ssl_connect_data *ssl,
299
376
const char *filename, PRBool cacert)
301
378
#ifdef HAVE_PK11_CREATEGENERICOBJECT
303
PK11SlotInfo * slot = NULL;
305
CK_ATTRIBUTE theTemplate[20];
306
CK_BBOOL cktrue = CK_TRUE;
307
CK_BBOOL ckfalse = CK_FALSE;
308
CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
309
char slotname[SLOTSIZE];
379
/* All CA and trust objects go into slot 0. Other slots are used
380
* for storing certificates.
382
const int slot_id = (cacert) ? 0 : 1;
311
384
CERTCertificate *cert;
312
385
char *nickname = NULL;
335
408
#ifdef HAVE_PK11_CREATEGENERICOBJECT
338
/* All CA and trust objects go into slot 0. Other slots are used
339
* for storing certificates. With each new user certificate we increment
340
* the slot count. We only support 1 user certificate right now.
347
snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
349
nickname = aprintf("PEM Token #%ld:%s", slotID, n);
409
nickname = aprintf("PEM Token #%d:%s", slot_id, n);
353
slot = PK11_FindSlotByName(slotname);
360
PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) );
362
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) );
364
PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename,
368
PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) );
371
PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) );
375
/* This load the certificate in our PEM module into the appropriate
378
ssl->cacert[slotID] = PK11_CreateGenericObject(slot, theTemplate, 4,
379
PR_FALSE /* isPerm */);
383
if(ssl->cacert[slotID] == NULL) {
413
if(CURLE_OK != nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert)) {
388
419
/* We don't have PK11_CreateGenericObject but a file-based cert was passed
389
420
* in. We need to fail.
505
536
#ifdef HAVE_PK11_CREATEGENERICOBJECT
506
PK11SlotInfo * slot = NULL;
508
CK_ATTRIBUTE theTemplate[20];
509
CK_BBOOL cktrue = CK_TRUE;
510
CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
512
char slotname[SLOTSIZE];
513
struct ssl_connect_data *sslconn = &conn->ssl[sockindex];
517
/* FIXME: grok the various file types */
519
slotID = 1; /* hardcoded for now */
521
snprintf(slotname, sizeof(slotname), "PEM Token #%ld", slotID);
522
slot = PK11_FindSlotByName(slotname);
527
PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
528
PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
529
PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)key_file,
530
strlen(key_file)+1); attrs++;
532
/* When adding an encrypted key the PKCS#11 will be set as removed */
533
sslconn->key = PK11_CreateGenericObject(slot, theTemplate, 3,
534
PR_FALSE /* isPerm */);
535
if(sslconn->key == NULL) {
539
struct ssl_connect_data *ssl = conn->ssl;
540
(void)sockindex; /* unused */
542
if(CURLE_OK != nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE)) {
536
543
PR_SetError(SEC_ERROR_BAD_KEY, 0);
547
slot = PK11_FindSlotByName("PEM Token #1");
540
551
/* This will force the token to be seen as re-inserted */
541
552
SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
542
553
PK11_IsPresent(slot);
544
/* parg is initialized in nss_Init_Tokens() */
545
if(PK11_Authenticate(slot, PR_TRUE,
546
conn->data->set.str[STRING_KEY_PASSWD]) != SECSuccess) {
555
status = PK11_Authenticate(slot, PR_TRUE,
556
conn->data->set.str[STRING_KEY_PASSWD]);
551
557
PK11_FreeSlot(slot);
558
return (SECSuccess == status) ? 1 : 0;
555
560
/* If we don't have PK11_CreateGenericObject then we can't load a file-based
558
563
(void)conn; /* unused */
559
564
(void)key_file; /* unused */
565
(void)sockindex; /* unused */
1095
1097
static Curl_recv nss_recv;
1096
1098
static Curl_send nss_send;
1100
static CURLcode nss_load_ca_certificates(struct connectdata *conn,
1103
struct SessionHandle *data = conn->data;
1104
const char *cafile = data->set.ssl.CAfile;
1105
const char *capath = data->set.ssl.CApath;
1107
if(cafile && !nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE))
1108
return CURLE_SSL_CACERT_BADFILE;
1112
if(stat(capath, &st) == -1)
1113
return CURLE_SSL_CACERT_BADFILE;
1115
if(S_ISDIR(st.st_mode)) {
1117
PRDir *dir = PR_OpenDir(capath);
1119
return CURLE_SSL_CACERT_BADFILE;
1121
while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
1122
char *fullpath = aprintf("%s/%s", capath, entry->name);
1125
return CURLE_OUT_OF_MEMORY;
1128
if(!nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
1129
/* This is purposefully tolerant of errors so non-PEM files can
1130
* be in the same directory */
1131
infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
1139
infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
1142
infof(data, " CAfile: %s\n CApath: %s\n",
1143
cafile ? cafile : "none",
1144
capath ? capath : "none");
1098
1149
CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
1236
1288
NULL) != SECSuccess)
1239
if(!data->set.ssl.verifypeer)
1240
/* skip the verifying of the peer */
1242
else if(data->set.ssl.CAfile) {
1243
int rc = nss_load_cert(&conn->ssl[sockindex], data->set.ssl.CAfile,
1246
curlerr = CURLE_SSL_CACERT_BADFILE;
1250
else if(data->set.ssl.CApath) {
1255
if(stat(data->set.ssl.CApath, &st) == -1) {
1256
curlerr = CURLE_SSL_CACERT_BADFILE;
1260
if(S_ISDIR(st.st_mode)) {
1263
dir = PR_OpenDir(data->set.ssl.CApath);
1265
entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN);
1268
char fullpath[PATH_MAX];
1270
snprintf(fullpath, sizeof(fullpath), "%s/%s", data->set.ssl.CApath,
1272
rc = nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE);
1273
/* FIXME: check this return value! */
1275
/* This is purposefully tolerant of errors so non-PEM files
1276
* can be in the same directory */
1277
} while(entry != NULL);
1284
data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
1285
data->set.ssl.CApath ? data->set.ssl.CApath : "none");
1291
if(data->set.ssl.verifypeer && (CURLE_OK !=
1292
(curlerr = nss_load_ca_certificates(conn, sockindex))))
1287
1295
if (data->set.ssl.CRLfile) {
1288
1296
if(SECSuccess != nss_load_crl(data->set.ssl.CRLfile)) {
1297
1305
if(data->set.str[STRING_CERT]) {
1298
bool nickname_alloc = FALSE;
1299
char *nickname = fmt_nickname(data->set.str[STRING_CERT], &nickname_alloc);
1307
char *nickname = fmt_nickname(data, STRING_CERT, &is_nickname);
1301
1309
return CURLE_OUT_OF_MEMORY;
1303
if(!cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
1304
data->set.str[STRING_KEY])) {
1311
if(!is_nickname && !cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
1312
data->set.str[STRING_KEY])) {
1305
1313
/* failf() is already done in cert_stuff() */
1308
1315
return CURLE_SSL_CERTPROBLEM;
1311
/* this "takes over" the pointer to the allocated name or makes a
1313
connssl->client_nickname = nickname_alloc?nickname:strdup(nickname);
1314
if(!connssl->client_nickname)
1315
return CURLE_OUT_OF_MEMORY;
1318
/* store the nickname for SelectClientCert() called during handshake */
1319
connssl->client_nickname = nickname;
1319
1322
connssl->client_nickname = NULL;
1367
1370
display_conn_info(conn, connssl->handle);
1369
1372
if (data->set.str[STRING_SSL_ISSUERCERT]) {
1371
bool nickname_alloc = FALSE;
1372
char *nickname = fmt_nickname(data->set.str[STRING_SSL_ISSUERCERT],
1373
SECStatus ret = SECFailure;
1375
char *nickname = fmt_nickname(data, STRING_SSL_ISSUERCERT, &is_nickname);
1376
1377
return CURLE_OUT_OF_MEMORY;
1378
ret = check_issuer_cert(connssl->handle, nickname);
1380
/* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */
1381
ret = check_issuer_cert(connssl->handle, nickname);
1383
1385
if(SECFailure == ret) {
1384
1386
infof(data,"SSL certificate issuer check failed\n");