1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23/*
24 * Source file for all NSS-specific code for the TLS/SSL layer. No code
25 * but sslgen.c should ever call or use these functions.
26 */
27
28#include "setup.h"
29
30#ifdef HAVE_SYS_SOCKET_H
31#include <sys/socket.h>
32#endif
33
34#include "urldata.h"
35#include "sendf.h"
36#include "formdata.h" /* for the boundary function */
37#include "url.h" /* for the ssl config check function */
38#include "connect.h"
39#include "strequal.h"
40#include "select.h"
41#include "sslgen.h"
42#include "llist.h"
43
44#define _MPRINTF_REPLACE /* use the internal *printf() functions */
45#include <curl/mprintf.h>
46
47#ifdef USE_NSS
48
49#include "nssg.h"
50#include <nspr.h>
51#include <nss.h>
52#include <ssl.h>
53#include <sslerr.h>
54#include <secerr.h>
55#include <secmod.h>
56#include <sslproto.h>
57#include <prtypes.h>
58#include <pk11pub.h>
59#include <prio.h>
60#include <secitem.h>
61#include <secport.h>
62#include <certdb.h>
63#include <base64.h>
64#include <cert.h>
65
66#include "curl_memory.h"
67#include "rawstr.h"
68
69/* The last #include file should be: */
70#include "memdebug.h"
71
72#define SSL_DIR "/etc/pki/nssdb"
73
74/* enough to fit the string "PEM Token #[0|1]" */
75#define SLOTSIZE 13
76
77PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
78
79PRLock * nss_initlock = NULL;
80PRLock * nss_crllock = NULL;
81
82volatile int initialized = 0;
83
84typedef struct {
85  const char *name;
86  int num;
87  PRInt32 version; /* protocol version valid for this cipher */
88} cipher_s;
89
90#define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do {  \
91  CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++);                 \
92  ptr->type = (_type);                                      \
93  ptr->pValue = (_val);                                     \
94  ptr->ulValueLen = (_len);                                 \
95} WHILE_FALSE
96
97#define CERT_NewTempCertificate __CERT_NewTempCertificate
98
99enum sslversion { SSL2 = 1, SSL3 = 2, TLS = 4 };
100
101#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
102static const cipher_s cipherlist[] = {
103  /* SSL2 cipher suites */
104  {"rc4", SSL_EN_RC4_128_WITH_MD5, SSL2},
105  {"rc4-md5", SSL_EN_RC4_128_WITH_MD5, SSL2},
106  {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL2},
107  {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5, SSL2},
108  {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL2},
109  {"des", SSL_EN_DES_64_CBC_WITH_MD5, SSL2},
110  {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL2},
111  /* SSL3/TLS cipher suites */
112  {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5, SSL3 | TLS},
113  {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA, SSL3 | TLS},
114  {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL3 | TLS},
115  {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA, SSL3 | TLS},
116  {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL3 | TLS},
117  {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL3 | TLS},
118  {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5, SSL3 | TLS},
119  {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA, SSL3 | TLS},
120  {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL3 | TLS},
121  {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL3 | TLS},
122  {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, SSL3 | TLS},
123  {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, SSL3 | TLS},
124  {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA, SSL3 | TLS},
125  /* TLS 1.0: Exportable 56-bit Cipher Suites. */
126  {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL3 | TLS},
127  {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL3 | TLS},
128  /* AES ciphers. */
129  {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA, SSL3 | TLS},
130  {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA, SSL3 | TLS},
131#ifdef NSS_ENABLE_ECC
132  /* ECC ciphers. */
133  {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS},
134  {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS},
135  {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS},
136  {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS},
137  {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS},
138  {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS},
139  {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS},
140  {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS},
141  {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS},
142  {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS},
143  {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA, TLS},
144  {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS},
145  {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS},
146  {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS},
147  {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS},
148  {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA, TLS},
149  {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS},
150  {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS},
151  {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS},
152  {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS},
153  {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA, TLS},
154  {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA, TLS},
155  {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, TLS},
156  {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA, TLS},
157  {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA, TLS},
158#endif
159};
160
161/* following ciphers are new in NSS 3.4 and not enabled by default, therefore
162   they are enabled explicitly */
163static const int enable_ciphers_by_default[] = {
164  TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
165  TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
166  TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
167  TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
168  TLS_RSA_WITH_AES_128_CBC_SHA,
169  TLS_RSA_WITH_AES_256_CBC_SHA,
170  SSL_NULL_WITH_NULL_NULL
171};
172
173#ifdef HAVE_PK11_CREATEGENERICOBJECT
174static const char* pem_library = "libnsspem.so";
175#endif
176SECMODModule* mod = NULL;
177
178static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
179                             char *cipher_list)
180{
181  unsigned int i;
182  PRBool cipher_state[NUM_OF_CIPHERS];
183  PRBool found;
184  char *cipher;
185  SECStatus rv;
186
187  /* First disable all ciphers. This uses a different max value in case
188   * NSS adds more ciphers later we don't want them available by
189   * accident
190   */
191  for(i=0; i<SSL_NumImplementedCiphers; i++) {
192    SSL_CipherPrefSet(model, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED);
193  }
194
195  /* Set every entry in our list to false */
196  for(i=0; i<NUM_OF_CIPHERS; i++) {
197    cipher_state[i] = PR_FALSE;
198  }
199
200  cipher = cipher_list;
201
202  while(cipher_list && (cipher_list[0])) {
203    while((*cipher) && (ISSPACE(*cipher)))
204      ++cipher;
205
206    if((cipher_list = strchr(cipher, ','))) {
207      *cipher_list++ = '\0';
208    }
209
210    found = PR_FALSE;
211
212    for(i=0; i<NUM_OF_CIPHERS; i++) {
213      if(Curl_raw_equal(cipher, cipherlist[i].name)) {
214        cipher_state[i] = PR_TRUE;
215        found = PR_TRUE;
216        break;
217      }
218    }
219
220    if(found == PR_FALSE) {
221      failf(data, "Unknown cipher in list: %s", cipher);
222      return SECFailure;
223    }
224
225    if(cipher_list) {
226      cipher = cipher_list;
227    }
228  }
229
230  /* Finally actually enable the selected ciphers */
231  for(i=0; i<NUM_OF_CIPHERS; i++) {
232    rv = SSL_CipherPrefSet(model, cipherlist[i].num, cipher_state[i]);
233    if(rv != SECSuccess) {
234      failf(data, "Unknown cipher in cipher list");
235      return SECFailure;
236    }
237  }
238
239  return SECSuccess;
240}
241
242/*
243 * Get the number of ciphers that are enabled. We use this to determine
244 * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
245 */
246static int num_enabled_ciphers(void)
247{
248  PRInt32 policy = 0;
249  int count = 0;
250  unsigned int i;
251
252  for(i=0; i<NUM_OF_CIPHERS; i++) {
253    SSL_CipherPolicyGet(cipherlist[i].num, &policy);
254    if(policy)
255      count++;
256  }
257  return count;
258}
259
260/*
261 * Determine whether the nickname passed in is a filename that needs to
262 * be loaded as a PEM or a regular NSS nickname.
263 *
264 * returns 1 for a file
265 * returns 0 for not a file (NSS nickname)
266 */
267static int is_file(const char *filename)
268{
269  struct_stat st;
270
271  if(filename == NULL)
272    return 0;
273
274  if(stat(filename, &st) == 0)
275    if(S_ISREG(st.st_mode))
276      return 1;
277
278  return 0;
279}
280
281/* Check if the given string is filename or nickname of a certificate.  If the
282 * given string is recognized as filename, return NULL.  If the given string is
283 * recognized as nickname, return a duplicated string.  The returned string
284 * should be later deallocated using free().  If the OOM failure occurs, we
285 * return NULL, too.
286 */
287static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind)
288{
289  const char *str = data->set.str[cert_kind];
290  const char *n;
291
292  if(!is_file(str))
293    /* no such file exists, use the string as nickname */
294    return strdup(str);
295
296  /* search the last slash; we require at least one slash in a file name */
297  n = strrchr(str, '/');
298  if(!n) {
299    infof(data, "warning: certificate file name \"%s\" handled as nickname; "
300          "please use \"./%s\" to force file name\n", str, str);
301    return strdup(str);
302  }
303
304  /* we'll use the PEM reader to read the certificate from file */
305  return NULL;
306}
307
308#ifdef HAVE_PK11_CREATEGENERICOBJECT
309/* Call PK11_CreateGenericObject() with the given obj_class and filename.  If
310 * the call succeeds, append the object handle to the list of objects so that
311 * the object can be destroyed in Curl_nss_close(). */
312static CURLcode nss_create_object(struct ssl_connect_data *ssl,
313                                  CK_OBJECT_CLASS obj_class,
314                                  const char *filename, bool cacert)
315{
316  PK11SlotInfo *slot;
317  PK11GenericObject *obj;
318  CK_BBOOL cktrue = CK_TRUE;
319  CK_BBOOL ckfalse = CK_FALSE;
320  CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
321  int attr_cnt = 0;
322  CURLcode err = (cacert)
323    ? CURLE_SSL_CACERT_BADFILE
324    : CURLE_SSL_CERTPROBLEM;
325
326  const int slot_id = (cacert) ? 0 : 1;
327  char *slot_name = aprintf("PEM Token #%d", slot_id);
328  if(!slot_name)
329    return CURLE_OUT_OF_MEMORY;
330
331  slot = PK11_FindSlotByName(slot_name);
332  free(slot_name);
333  if(!slot)
334    return err;
335
336  PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
337  PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
338  PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
339                strlen(filename) + 1);
340
341  if(CKO_CERTIFICATE == obj_class) {
342    CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
343    PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
344  }
345
346  obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
347  PK11_FreeSlot(slot);
348  if(!obj)
349    return err;
350
351  if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) {
352    PK11_DestroyGenericObject(obj);
353    return CURLE_OUT_OF_MEMORY;
354  }
355
356  if(!cacert && CKO_CERTIFICATE == obj_class)
357    /* store reference to a client certificate */
358    ssl->obj_clicert = obj;
359
360  return CURLE_OK;
361}
362
363/* Destroy the NSS object whose handle is given by ptr.  This function is
364 * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
365 * NSS objects in Curl_nss_close() */
366static void nss_destroy_object(void *user, void *ptr)
367{
368  PK11GenericObject *obj = (PK11GenericObject *)ptr;
369  (void) user;
370  PK11_DestroyGenericObject(obj);
371}
372#endif
373
374static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
375                              const char *filename, PRBool cacert)
376{
377  CURLcode err = (cacert)
378    ? CURLE_SSL_CACERT_BADFILE
379    : CURLE_SSL_CERTPROBLEM;
380
381#ifdef HAVE_PK11_CREATEGENERICOBJECT
382  /* libnsspem.so leaks memory if the requested file does not exist.  For more
383   * details, go to <https://bugzilla.redhat.com/734760>. */
384  if(is_file(filename))
385    err = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
386
387  if(CURLE_OK == err && !cacert) {
388    /* we have successfully loaded a client certificate */
389    CERTCertificate *cert;
390    char *nickname = NULL;
391    char *n = strrchr(filename, '/');
392    if(n)
393      n++;
394
395    /* The following undocumented magic helps to avoid a SIGSEGV on call
396     * of PK11_ReadRawAttribute() from SelectClientCert() when using an
397     * immature version of libnsspem.so.  For more details, go to
398     * <https://bugzilla.redhat.com/733685>. */
399    nickname = aprintf("PEM Token #1:%s", n);
400    if(nickname) {
401      cert = PK11_FindCertFromNickname(nickname, NULL);
402      if(cert)
403        CERT_DestroyCertificate(cert);
404
405      free(nickname);
406    }
407  }
408#endif
409
410  return err;
411}
412
413/* add given CRL to cache if it is not already there */
414static SECStatus nss_cache_crl(SECItem *crlDER)
415{
416  CERTCertDBHandle *db = CERT_GetDefaultCertDB();
417  CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crlDER, 0);
418  if(crl) {
419    /* CRL already cached */
420    SEC_DestroyCrl(crl);
421    SECITEM_FreeItem(crlDER, PR_FALSE);
422    return SECSuccess;
423  }
424
425  /* acquire lock before call of CERT_CacheCRL() */
426  PR_Lock(nss_crllock);
427  if(SECSuccess != CERT_CacheCRL(db, crlDER)) {
428    /* unable to cache CRL */
429    PR_Unlock(nss_crllock);
430    SECITEM_FreeItem(crlDER, PR_FALSE);
431    return SECFailure;
432  }
433
434  /* we need to clear session cache, so that the CRL could take effect */
435  SSL_ClearSessionCache();
436  PR_Unlock(nss_crllock);
437  return SECSuccess;
438}
439
440static SECStatus nss_load_crl(const char* crlfilename)
441{
442  PRFileDesc *infile;
443  PRFileInfo  info;
444  SECItem filedata = { 0, NULL, 0 };
445  SECItem crlDER = { 0, NULL, 0 };
446  char *body;
447
448  infile = PR_Open(crlfilename, PR_RDONLY, 0);
449  if(!infile)
450    return SECFailure;
451
452  if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
453    goto fail;
454
455  if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
456    goto fail;
457
458  if(info.size != PR_Read(infile, filedata.data, info.size))
459    goto fail;
460
461  /* place a trailing zero right after the visible data */
462  body = (char*)filedata.data;
463  body[--filedata.len] = '\0';
464
465  body = strstr(body, "-----BEGIN");
466  if(body) {
467    /* assume ASCII */
468    char *trailer;
469    char *begin = PORT_Strchr(body, '\n');
470    if(!begin)
471      begin = PORT_Strchr(body, '\r');
472    if(!begin)
473      goto fail;
474
475    trailer = strstr(++begin, "-----END");
476    if(!trailer)
477      goto fail;
478
479    /* retrieve DER from ASCII */
480    *trailer = '\0';
481    if(ATOB_ConvertAsciiToItem(&crlDER, begin))
482      goto fail;
483
484    SECITEM_FreeItem(&filedata, PR_FALSE);
485  }
486  else
487    /* assume DER */
488    crlDER = filedata;
489
490  PR_Close(infile);
491  return nss_cache_crl(&crlDER);
492
493fail:
494  PR_Close(infile);
495  SECITEM_FreeItem(&filedata, PR_FALSE);
496  return SECFailure;
497}
498
499static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
500                             char *key_file)
501{
502#ifdef HAVE_PK11_CREATEGENERICOBJECT
503  PK11SlotInfo *slot;
504  SECStatus status;
505  struct ssl_connect_data *ssl = conn->ssl;
506
507  CURLcode rv = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
508  if(CURLE_OK != rv) {
509    PR_SetError(SEC_ERROR_BAD_KEY, 0);
510    return rv;
511  }
512
513  slot = PK11_FindSlotByName("PEM Token #1");
514  if(!slot)
515    return CURLE_SSL_CERTPROBLEM;
516
517  /* This will force the token to be seen as re-inserted */
518  SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
519  PK11_IsPresent(slot);
520
521  status = PK11_Authenticate(slot, PR_TRUE,
522                             conn->data->set.str[STRING_KEY_PASSWD]);
523  PK11_FreeSlot(slot);
524  return (SECSuccess == status)
525    ? CURLE_OK
526    : CURLE_SSL_CERTPROBLEM;
527#else
528  /* If we don't have PK11_CreateGenericObject then we can't load a file-based
529   * key.
530   */
531  (void)conn; /* unused */
532  (void)key_file; /* unused */
533  return CURLE_SSL_CERTPROBLEM;
534#endif
535  (void)sockindex; /* unused */
536}
537
538static int display_error(struct connectdata *conn, PRInt32 err,
539                         const char *filename)
540{
541  switch(err) {
542  case SEC_ERROR_BAD_PASSWORD:
543    failf(conn->data, "Unable to load client key: Incorrect password");
544    return 1;
545  case SEC_ERROR_UNKNOWN_CERT:
546    failf(conn->data, "Unable to load certificate %s", filename);
547    return 1;
548  default:
549    break;
550  }
551  return 0; /* The caller will print a generic error */
552}
553
554static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
555                           char *cert_file, char *key_file)
556{
557  struct SessionHandle *data = conn->data;
558  CURLcode rv;
559
560  if(cert_file) {
561    rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
562    if(CURLE_OK != rv) {
563      if(!display_error(conn, PR_GetError(), cert_file))
564        failf(data, "Unable to load client cert %d.", PR_GetError());
565
566      return rv;
567    }
568  }
569
570  if(key_file || (is_file(cert_file))) {
571    if(key_file)
572      rv = nss_load_key(conn, sockindex, key_file);
573    else
574      /* In case the cert file also has the key */
575      rv = nss_load_key(conn, sockindex, cert_file);
576    if(CURLE_OK != rv) {
577      if(!display_error(conn, PR_GetError(), key_file))
578        failf(data, "Unable to load client key %d.", PR_GetError());
579
580      return rv;
581    }
582  }
583
584  return CURLE_OK;
585}
586
587static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
588{
589  (void)slot; /* unused */
590  if(retry || NULL == arg)
591    return NULL;
592  else
593    return (char *)PORT_Strdup((char *)arg);
594}
595
596/* bypass the default SSL_AuthCertificate() hook in case we do not want to
597 * verify peer */
598static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
599                                    PRBool isServer)
600{
601  struct connectdata *conn = (struct connectdata *)arg;
602  if(!conn->data->set.ssl.verifypeer) {
603    infof(conn->data, "skipping SSL peer certificate verification\n");
604    return SECSuccess;
605  }
606
607  return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
608}
609
610static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
611{
612  SECStatus result = SECFailure;
613  struct connectdata *conn = (struct connectdata *)arg;
614  PRErrorCode err = PR_GetError();
615  CERTCertificate *cert = NULL;
616  char *subject, *subject_cn, *issuer;
617
618  conn->data->set.ssl.certverifyresult=err;
619  cert = SSL_PeerCertificate(sock);
620  subject = CERT_NameToAscii(&cert->subject);
621  subject_cn = CERT_GetCommonName(&cert->subject);
622  issuer = CERT_NameToAscii(&cert->issuer);
623  CERT_DestroyCertificate(cert);
624
625  switch(err) {
626  case SEC_ERROR_CA_CERT_INVALID:
627    infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
628    break;
629  case SEC_ERROR_UNTRUSTED_ISSUER:
630    infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n",
631          issuer);
632    break;
633  case SSL_ERROR_BAD_CERT_DOMAIN:
634    if(conn->data->set.ssl.verifyhost) {
635      failf(conn->data, "SSL: certificate subject name '%s' does not match "
636            "target host name '%s'", subject_cn, conn->host.dispname);
637    }
638    else {
639      result = SECSuccess;
640      infof(conn->data, "warning: SSL: certificate subject name '%s' does not "
641            "match target host name '%s'\n", subject_cn, conn->host.dispname);
642    }
643    break;
644  case SEC_ERROR_EXPIRED_CERTIFICATE:
645    infof(conn->data, "Remote Certificate has expired.\n");
646    break;
647  case SEC_ERROR_UNKNOWN_ISSUER:
648    infof(conn->data, "Peer's certificate issuer is not recognized: '%s'\n",
649          issuer);
650    break;
651  default:
652    infof(conn->data, "Bad certificate received. Subject = '%s', "
653          "Issuer = '%s'\n", subject, issuer);
654    break;
655  }
656  if(result == SECSuccess)
657    infof(conn->data, "SSL certificate verify ok.\n");
658  PR_Free(subject);
659  PR_Free(subject_cn);
660  PR_Free(issuer);
661
662  return result;
663}
664
665/**
666 * Inform the application that the handshake is complete.
667 */
668static SECStatus HandshakeCallback(PRFileDesc *sock, void *arg)
669{
670  (void)sock;
671  (void)arg;
672  return SECSuccess;
673}
674
675static void display_cert_info(struct SessionHandle *data,
676                              CERTCertificate *cert)
677{
678  char *subject, *issuer, *common_name;
679  PRExplodedTime printableTime;
680  char timeString[256];
681  PRTime notBefore, notAfter;
682
683  subject = CERT_NameToAscii(&cert->subject);
684  issuer = CERT_NameToAscii(&cert->issuer);
685  common_name = CERT_GetCommonName(&cert->subject);
686  infof(data, "\tsubject: %s\n", subject);
687
688  CERT_GetCertTimes(cert, &notBefore, &notAfter);
689  PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
690  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
691  infof(data, "\tstart date: %s\n", timeString);
692  PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
693  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
694  infof(data, "\texpire date: %s\n", timeString);
695  infof(data, "\tcommon name: %s\n", common_name);
696  infof(data, "\tissuer: %s\n", issuer);
697
698  PR_Free(subject);
699  PR_Free(issuer);
700  PR_Free(common_name);
701}
702
703static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
704{
705  SSLChannelInfo channel;
706  SSLCipherSuiteInfo suite;
707  CERTCertificate *cert;
708
709  if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
710     SECSuccess && channel.length == sizeof channel &&
711     channel.cipherSuite) {
712    if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
713                              &suite, sizeof suite) == SECSuccess) {
714      infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
715    }
716  }
717
718  infof(conn->data, "Server certificate:\n");
719
720  cert = SSL_PeerCertificate(sock);
721  display_cert_info(conn->data, cert);
722  CERT_DestroyCertificate(cert);
723
724  return;
725}
726
727/**
728 *
729 * Check that the Peer certificate's issuer certificate matches the one found
730 * by issuer_nickname.  This is not exactly the way OpenSSL and GNU TLS do the
731 * issuer check, so we provide comments that mimic the OpenSSL
732 * X509_check_issued function (in x509v3/v3_purp.c)
733 */
734static SECStatus check_issuer_cert(PRFileDesc *sock,
735                                   char *issuer_nickname)
736{
737  CERTCertificate *cert,*cert_issuer,*issuer;
738  SECStatus res=SECSuccess;
739  void *proto_win = NULL;
740
741  /*
742    PRArenaPool   *tmpArena = NULL;
743    CERTAuthKeyID *authorityKeyID = NULL;
744    SECITEM       *caname = NULL;
745  */
746
747  cert = SSL_PeerCertificate(sock);
748  cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
749
750  proto_win = SSL_RevealPinArg(sock);
751  issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
752
753  if((!cert_issuer) || (!issuer))
754    res = SECFailure;
755  else if(SECITEM_CompareItem(&cert_issuer->derCert,
756                              &issuer->derCert)!=SECEqual)
757    res = SECFailure;
758
759  CERT_DestroyCertificate(cert);
760  CERT_DestroyCertificate(issuer);
761  CERT_DestroyCertificate(cert_issuer);
762  return res;
763}
764
765/**
766 *
767 * Callback to pick the SSL client certificate.
768 */
769static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
770                                  struct CERTDistNamesStr *caNames,
771                                  struct CERTCertificateStr **pRetCert,
772                                  struct SECKEYPrivateKeyStr **pRetKey)
773{
774  struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
775  struct SessionHandle *data = connssl->data;
776  const char *nickname = connssl->client_nickname;
777
778#ifdef HAVE_PK11_CREATEGENERICOBJECT
779  if(connssl->obj_clicert) {
780    /* use the cert/key provided by PEM reader */
781    static const char pem_slotname[] = "PEM Token #1";
782    SECItem cert_der = { 0, NULL, 0 };
783    void *proto_win = SSL_RevealPinArg(sock);
784
785    PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname);
786    if(NULL == slot) {
787      failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
788      return SECFailure;
789    }
790
791    if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE,
792                             &cert_der) != SECSuccess) {
793      failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
794      PK11_FreeSlot(slot);
795      return SECFailure;
796    }
797
798    *pRetCert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
799    SECITEM_FreeItem(&cert_der, PR_FALSE);
800    if(NULL == *pRetCert) {
801      failf(data, "NSS: client certificate from file not found");
802      PK11_FreeSlot(slot);
803      return SECFailure;
804    }
805
806    *pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL);
807    PK11_FreeSlot(slot);
808    if(NULL == *pRetKey) {
809      failf(data, "NSS: private key from file not found");
810      CERT_DestroyCertificate(*pRetCert);
811      return SECFailure;
812    }
813
814    infof(data, "NSS: client certificate from file\n");
815    display_cert_info(data, *pRetCert);
816    return SECSuccess;
817  }
818#endif
819
820  /* use the default NSS hook */
821  if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
822                                          pRetCert, pRetKey)
823      || NULL == *pRetCert) {
824
825    if(NULL == nickname)
826      failf(data, "NSS: client certificate not found (nickname not "
827            "specified)");
828    else
829      failf(data, "NSS: client certificate not found: %s", nickname);
830
831    return SECFailure;
832  }
833
834  /* get certificate nickname if any */
835  nickname = (*pRetCert)->nickname;
836  if(NULL == nickname)
837    nickname = "[unknown]";
838
839  if(NULL == *pRetKey) {
840    failf(data, "NSS: private key not found for certificate: %s", nickname);
841    return SECFailure;
842  }
843
844  infof(data, "NSS: using client certificate: %s\n", nickname);
845  display_cert_info(data, *pRetCert);
846  return SECSuccess;
847}
848
849/* This function is supposed to decide, which error codes should be used
850 * to conclude server is TLS intolerant.
851 *
852 * taken from xulrunner - nsNSSIOLayer.cpp
853 */
854static PRBool
855isTLSIntoleranceError(PRInt32 err)
856{
857  switch (err) {
858  case SSL_ERROR_BAD_MAC_ALERT:
859  case SSL_ERROR_BAD_MAC_READ:
860  case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
861  case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
862  case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
863  case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
864  case SSL_ERROR_NO_CYPHER_OVERLAP:
865  case SSL_ERROR_BAD_SERVER:
866  case SSL_ERROR_BAD_BLOCK_PADDING:
867  case SSL_ERROR_UNSUPPORTED_VERSION:
868  case SSL_ERROR_PROTOCOL_VERSION_ALERT:
869  case SSL_ERROR_RX_MALFORMED_FINISHED:
870  case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
871  case SSL_ERROR_DECODE_ERROR_ALERT:
872  case SSL_ERROR_RX_UNKNOWN_ALERT:
873    return PR_TRUE;
874  default:
875    return PR_FALSE;
876  }
877}
878
879static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir)
880{
881  if(NSS_IsInitialized())
882    return CURLE_OK;
883
884  if(cert_dir) {
885    SECStatus rv;
886    const bool use_sql = NSS_VersionCheck("3.12.0");
887    char *certpath = aprintf("%s%s", use_sql ? "sql:" : "", cert_dir);
888    if(!certpath)
889      return CURLE_OUT_OF_MEMORY;
890
891    infof(data, "Initializing NSS with certpath: %s\n", certpath);
892    rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY);
893    free(certpath);
894
895    if(rv == SECSuccess)
896      return CURLE_OK;
897
898    infof(data, "Unable to initialize NSS database\n");
899  }
900
901  infof(data, "Initializing NSS with certpath: none\n");
902  if(NSS_NoDB_Init(NULL) == SECSuccess)
903    return CURLE_OK;
904
905  infof(data, "Unable to initialize NSS\n");
906  return CURLE_SSL_CACERT_BADFILE;
907}
908
909static CURLcode nss_init(struct SessionHandle *data)
910{
911  char *cert_dir;
912  struct_stat st;
913  CURLcode rv;
914
915  if(initialized)
916    return CURLE_OK;
917
918  /* First we check if $SSL_DIR points to a valid dir */
919  cert_dir = getenv("SSL_DIR");
920  if(cert_dir) {
921    if((stat(cert_dir, &st) != 0) ||
922        (!S_ISDIR(st.st_mode))) {
923      cert_dir = NULL;
924    }
925  }
926
927  /* Now we check if the default location is a valid dir */
928  if(!cert_dir) {
929    if((stat(SSL_DIR, &st) == 0) &&
930        (S_ISDIR(st.st_mode))) {
931      cert_dir = (char *)SSL_DIR;
932    }
933  }
934
935  rv = nss_init_core(data, cert_dir);
936  if(rv)
937    return rv;
938
939  if(num_enabled_ciphers() == 0)
940    NSS_SetDomesticPolicy();
941
942  initialized = 1;
943  return CURLE_OK;
944}
945
946/**
947 * Global SSL init
948 *
949 * @retval 0 error initializing SSL
950 * @retval 1 SSL initialized successfully
951 */
952int Curl_nss_init(void)
953{
954  /* curl_global_init() is not thread-safe so this test is ok */
955  if(nss_initlock == NULL) {
956    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
957    nss_initlock = PR_NewLock();
958    nss_crllock = PR_NewLock();
959  }
960
961  /* We will actually initialize NSS later */
962
963  return 1;
964}
965
966CURLcode Curl_nss_force_init(struct SessionHandle *data)
967{
968  CURLcode rv;
969  if(!nss_initlock) {
970    failf(data,
971          "unable to initialize NSS, curl_global_init() should have been "
972          "called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
973    return CURLE_FAILED_INIT;
974  }
975
976  PR_Lock(nss_initlock);
977  rv = nss_init(data);
978  PR_Unlock(nss_initlock);
979  return rv;
980}
981
982/* Global cleanup */
983void Curl_nss_cleanup(void)
984{
985  /* This function isn't required to be threadsafe and this is only done
986   * as a safety feature.
987   */
988  PR_Lock(nss_initlock);
989  if(initialized) {
990    /* Free references to client certificates held in the SSL session cache.
991     * Omitting this hampers destruction of the security module owning
992     * the certificates. */
993    SSL_ClearSessionCache();
994
995    if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) {
996      SECMOD_DestroyModule(mod);
997      mod = NULL;
998    }
999    NSS_Shutdown();
1000  }
1001  PR_Unlock(nss_initlock);
1002
1003  PR_DestroyLock(nss_initlock);
1004  PR_DestroyLock(nss_crllock);
1005  nss_initlock = NULL;
1006
1007  initialized = 0;
1008}
1009
1010/*
1011 * This function uses SSL_peek to determine connection status.
1012 *
1013 * Return codes:
1014 *     1 means the connection is still in place
1015 *     0 means the connection has been closed
1016 *    -1 means the connection status is unknown
1017 */
1018int
1019Curl_nss_check_cxn(struct connectdata *conn)
1020{
1021  int rc;
1022  char buf;
1023
1024  rc =
1025    PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK,
1026            PR_SecondsToInterval(1));
1027  if(rc > 0)
1028    return 1; /* connection still in place */
1029
1030  if(rc == 0)
1031    return 0; /* connection has been closed */
1032
1033  return -1;  /* connection status unknown */
1034}
1035
1036/*
1037 * This function is called when an SSL connection is closed.
1038 */
1039void Curl_nss_close(struct connectdata *conn, int sockindex)
1040{
1041  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1042
1043  if(connssl->handle) {
1044    /* NSS closes the socket we previously handed to it, so we must mark it
1045       as closed to avoid double close */
1046    fake_sclose(conn->sock[sockindex]);
1047    conn->sock[sockindex] = CURL_SOCKET_BAD;
1048    if(connssl->client_nickname != NULL) {
1049      free(connssl->client_nickname);
1050      connssl->client_nickname = NULL;
1051
1052      /* force NSS to ask again for a client cert when connecting
1053       * next time to the same server */
1054      SSL_InvalidateSession(connssl->handle);
1055    }
1056#ifdef HAVE_PK11_CREATEGENERICOBJECT
1057    /* destroy all NSS objects in order to avoid failure of NSS shutdown */
1058    Curl_llist_destroy(connssl->obj_list, NULL);
1059    connssl->obj_list = NULL;
1060    connssl->obj_clicert = NULL;
1061#endif
1062    PR_Close(connssl->handle);
1063    connssl->handle = NULL;
1064  }
1065}
1066
1067/*
1068 * This function is called when the 'data' struct is going away. Close
1069 * down everything and free all resources!
1070 */
1071int Curl_nss_close_all(struct SessionHandle *data)
1072{
1073  (void)data;
1074  return 0;
1075}
1076
1077/* handle client certificate related errors if any; return false otherwise */
1078static bool handle_cc_error(PRInt32 err, struct SessionHandle *data)
1079{
1080  switch(err) {
1081  case SSL_ERROR_BAD_CERT_ALERT:
1082    failf(data, "SSL error: SSL_ERROR_BAD_CERT_ALERT");
1083    return true;
1084
1085  case SSL_ERROR_REVOKED_CERT_ALERT:
1086    failf(data, "SSL error: SSL_ERROR_REVOKED_CERT_ALERT");
1087    return true;
1088
1089  case SSL_ERROR_EXPIRED_CERT_ALERT:
1090    failf(data, "SSL error: SSL_ERROR_EXPIRED_CERT_ALERT");
1091    return true;
1092
1093  default:
1094    return false;
1095  }
1096}
1097
1098static Curl_recv nss_recv;
1099static Curl_send nss_send;
1100
1101static CURLcode nss_load_ca_certificates(struct connectdata *conn,
1102                                         int sockindex)
1103{
1104  struct SessionHandle *data = conn->data;
1105  const char *cafile = data->set.ssl.CAfile;
1106  const char *capath = data->set.ssl.CApath;
1107
1108  if(cafile) {
1109    CURLcode rv = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
1110    if(CURLE_OK != rv)
1111      return rv;
1112  }
1113
1114  if(capath) {
1115    struct_stat st;
1116    if(stat(capath, &st) == -1)
1117      return CURLE_SSL_CACERT_BADFILE;
1118
1119    if(S_ISDIR(st.st_mode)) {
1120      PRDirEntry *entry;
1121      PRDir *dir = PR_OpenDir(capath);
1122      if(!dir)
1123        return CURLE_SSL_CACERT_BADFILE;
1124
1125      while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
1126        char *fullpath = aprintf("%s/%s", capath, entry->name);
1127        if(!fullpath) {
1128          PR_CloseDir(dir);
1129          return CURLE_OUT_OF_MEMORY;
1130        }
1131
1132        if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
1133          /* This is purposefully tolerant of errors so non-PEM files can
1134           * be in the same directory */
1135          infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
1136
1137        free(fullpath);
1138      }
1139
1140      PR_CloseDir(dir);
1141    }
1142    else
1143      infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
1144  }
1145
1146  infof(data, "  CAfile: %s\n  CApath: %s\n",
1147      cafile ? cafile : "none",
1148      capath ? capath : "none");
1149
1150  return CURLE_OK;
1151}
1152
1153CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
1154{
1155  PRInt32 err;
1156  PRFileDesc *model = NULL;
1157  PRBool ssl2 = PR_FALSE;
1158  PRBool ssl3 = PR_FALSE;
1159  PRBool tlsv1 = PR_FALSE;
1160  PRBool ssl_no_cache;
1161  struct SessionHandle *data = conn->data;
1162  curl_socket_t sockfd = conn->sock[sockindex];
1163  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1164  CURLcode curlerr;
1165  const int *cipher_to_enable;
1166  PRSocketOptionData sock_opt;
1167  long time_left;
1168  PRUint32 timeout;
1169
1170  if(connssl->state == ssl_connection_complete)
1171    return CURLE_OK;
1172
1173  connssl->data = data;
1174
1175#ifdef HAVE_PK11_CREATEGENERICOBJECT
1176  /* list of all NSS objects we need to destroy in Curl_nss_close() */
1177  connssl->obj_list = Curl_llist_alloc(nss_destroy_object);
1178  if(!connssl->obj_list)
1179    return CURLE_OUT_OF_MEMORY;
1180#endif
1181
1182  /* FIXME. NSS doesn't support multiple databases open at the same time. */
1183  PR_Lock(nss_initlock);
1184  curlerr = nss_init(conn->data);
1185  if(CURLE_OK != curlerr) {
1186    PR_Unlock(nss_initlock);
1187    goto error;
1188  }
1189
1190  curlerr = CURLE_SSL_CONNECT_ERROR;
1191
1192#ifdef HAVE_PK11_CREATEGENERICOBJECT
1193  if(!mod) {
1194    char *configstring = aprintf("library=%s name=PEM", pem_library);
1195    if(!configstring) {
1196      PR_Unlock(nss_initlock);
1197      goto error;
1198    }
1199    mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
1200    free(configstring);
1201
1202    if(!mod || !mod->loaded) {
1203      if(mod) {
1204        SECMOD_DestroyModule(mod);
1205        mod = NULL;
1206      }
1207      infof(data, "WARNING: failed to load NSS PEM library %s. Using "
1208            "OpenSSL PEM certificates will not work.\n", pem_library);
1209    }
1210  }
1211#endif
1212
1213  PK11_SetPasswordFunc(nss_get_password);
1214  PR_Unlock(nss_initlock);
1215
1216  model = PR_NewTCPSocket();
1217  if(!model)
1218    goto error;
1219  model = SSL_ImportFD(NULL, model);
1220
1221  /* make the socket nonblocking */
1222  sock_opt.option = PR_SockOpt_Nonblocking;
1223  sock_opt.value.non_blocking = PR_TRUE;
1224  if(PR_SetSocketOption(model, &sock_opt) != PR_SUCCESS)
1225    goto error;
1226
1227  if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
1228    goto error;
1229  if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
1230    goto error;
1231  if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
1232    goto error;
1233
1234  /* do not use SSL cache if we are not going to verify peer */
1235  ssl_no_cache = (data->set.ssl.verifypeer) ? PR_FALSE : PR_TRUE;
1236  if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
1237    goto error;
1238
1239  switch (data->set.ssl.version) {
1240  default:
1241  case CURL_SSLVERSION_DEFAULT:
1242    ssl3 = PR_TRUE;
1243    if(data->state.ssl_connect_retry)
1244      infof(data, "TLS disabled due to previous handshake failure\n");
1245    else
1246      tlsv1 = PR_TRUE;
1247    break;
1248  case CURL_SSLVERSION_TLSv1:
1249    tlsv1 = PR_TRUE;
1250    break;
1251  case CURL_SSLVERSION_SSLv2:
1252    ssl2 = PR_TRUE;
1253    break;
1254  case CURL_SSLVERSION_SSLv3:
1255    ssl3 = PR_TRUE;
1256    break;
1257  }
1258
1259  if(SSL_OptionSet(model, SSL_ENABLE_SSL2, ssl2) != SECSuccess)
1260    goto error;
1261  if(SSL_OptionSet(model, SSL_ENABLE_SSL3, ssl3) != SECSuccess)
1262    goto error;
1263  if(SSL_OptionSet(model, SSL_ENABLE_TLS, tlsv1) != SECSuccess)
1264    goto error;
1265
1266  if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess)
1267    goto error;
1268
1269  /* reset the flag to avoid an infinite loop */
1270  data->state.ssl_connect_retry = FALSE;
1271
1272  /* enable all ciphers from enable_ciphers_by_default */
1273  cipher_to_enable = enable_ciphers_by_default;
1274  while(SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) {
1275    if(SSL_CipherPrefSet(model, *cipher_to_enable, PR_TRUE) != SECSuccess) {
1276      curlerr = CURLE_SSL_CIPHER;
1277      goto error;
1278    }
1279    cipher_to_enable++;
1280  }
1281
1282  if(data->set.ssl.cipher_list) {
1283    if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
1284      curlerr = CURLE_SSL_CIPHER;
1285      goto error;
1286    }
1287  }
1288
1289  if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost)
1290    infof(data, "warning: ignoring value of ssl.verifyhost\n");
1291  else if(data->set.ssl.verifyhost == 1)
1292    infof(data, "warning: ignoring unsupported value (1) of ssl.verifyhost\n");
1293
1294  /* bypass the default SSL_AuthCertificate() hook in case we do not want to
1295   * verify peer */
1296  if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
1297    goto error;
1298
1299  data->set.ssl.certverifyresult=0; /* not checked yet */
1300  if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, conn)
1301     != SECSuccess) {
1302    goto error;
1303  }
1304  if(SSL_HandshakeCallback(model, (SSLHandshakeCallback) HandshakeCallback,
1305                           NULL) != SECSuccess)
1306    goto error;
1307
1308  if(data->set.ssl.verifypeer) {
1309    const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
1310    if(CURLE_OK != rv) {
1311      curlerr = rv;
1312      goto error;
1313    }
1314  }
1315
1316  if(data->set.ssl.CRLfile) {
1317    if(SECSuccess != nss_load_crl(data->set.ssl.CRLfile)) {
1318      curlerr = CURLE_SSL_CRL_BADFILE;
1319      goto error;
1320    }
1321    infof(data,
1322          "  CRLfile: %s\n",
1323          data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none");
1324  }
1325
1326  if(data->set.str[STRING_CERT]) {
1327    char *nickname = dup_nickname(data, STRING_CERT);
1328    if(nickname) {
1329      /* we are not going to use libnsspem.so to read the client cert */
1330#ifdef HAVE_PK11_CREATEGENERICOBJECT
1331      connssl->obj_clicert = NULL;
1332#endif
1333    }
1334    else {
1335      CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
1336                               data->set.str[STRING_KEY]);
1337      if(CURLE_OK != rv) {
1338        /* failf() is already done in cert_stuff() */
1339        curlerr = rv;
1340        goto error;
1341      }
1342    }
1343
1344    /* store the nickname for SelectClientCert() called during handshake */
1345    connssl->client_nickname = nickname;
1346  }
1347  else
1348    connssl->client_nickname = NULL;
1349
1350  if(SSL_GetClientAuthDataHook(model, SelectClientCert,
1351                               (void *)connssl) != SECSuccess) {
1352    curlerr = CURLE_SSL_CERTPROBLEM;
1353    goto error;
1354  }
1355
1356  /* Import our model socket  onto the existing file descriptor */
1357  connssl->handle = PR_ImportTCPSocket(sockfd);
1358  connssl->handle = SSL_ImportFD(model, connssl->handle);
1359  if(!connssl->handle)
1360    goto error;
1361
1362  PR_Close(model); /* We don't need this any more */
1363  model = NULL;
1364
1365  /* This is the password associated with the cert that we're using */
1366  if(data->set.str[STRING_KEY_PASSWD]) {
1367    SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]);
1368  }
1369
1370  /* Force handshake on next I/O */
1371  SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
1372
1373  SSL_SetURL(connssl->handle, conn->host.name);
1374
1375  /* check timeout situation */
1376  time_left = Curl_timeleft(data, NULL, TRUE);
1377  if(time_left < 0L) {
1378    failf(data, "timed out before SSL handshake");
1379    goto error;
1380  }
1381  timeout = PR_MillisecondsToInterval((PRUint32) time_left);
1382
1383  /* Force the handshake now */
1384  if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
1385    if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
1386      curlerr = CURLE_PEER_FAILED_VERIFICATION;
1387    else if(conn->data->set.ssl.certverifyresult!=0)
1388      curlerr = CURLE_SSL_CACERT;
1389    goto error;
1390  }
1391
1392  connssl->state = ssl_connection_complete;
1393  conn->recv[sockindex] = nss_recv;
1394  conn->send[sockindex] = nss_send;
1395
1396  display_conn_info(conn, connssl->handle);
1397
1398  if(data->set.str[STRING_SSL_ISSUERCERT]) {
1399    SECStatus ret = SECFailure;
1400    char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT);
1401    if(nickname) {
1402      /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */
1403      ret = check_issuer_cert(connssl->handle, nickname);
1404      free(nickname);
1405    }
1406
1407    if(SECFailure == ret) {
1408      infof(data,"SSL certificate issuer check failed\n");
1409      curlerr = CURLE_SSL_ISSUER_ERROR;
1410      goto error;
1411    }
1412    else {
1413      infof(data, "SSL certificate issuer check ok\n");
1414    }
1415  }
1416
1417  return CURLE_OK;
1418
1419  error:
1420  /* reset the flag to avoid an infinite loop */
1421  data->state.ssl_connect_retry = FALSE;
1422
1423  err = PR_GetError();
1424  if(handle_cc_error(err, data))
1425    curlerr = CURLE_SSL_CERTPROBLEM;
1426  else
1427    infof(data, "NSS error %d\n", err);
1428
1429  if(model)
1430    PR_Close(model);
1431
1432#ifdef HAVE_PK11_CREATEGENERICOBJECT
1433    /* cleanup on connection failure */
1434    Curl_llist_destroy(connssl->obj_list, NULL);
1435    connssl->obj_list = NULL;
1436#endif
1437
1438  if(ssl3 && tlsv1 && isTLSIntoleranceError(err)) {
1439    /* schedule reconnect through Curl_retry_request() */
1440    data->state.ssl_connect_retry = TRUE;
1441    infof(data, "Error in TLS handshake, trying SSLv3...\n");
1442    return CURLE_OK;
1443  }
1444
1445  return curlerr;
1446}
1447
1448static ssize_t nss_send(struct connectdata *conn,  /* connection data */
1449                        int sockindex,             /* socketindex */
1450                        const void *mem,           /* send this data */
1451                        size_t len,                /* amount to write */
1452                        CURLcode *curlcode)
1453{
1454  int rc;
1455
1456  rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, -1);
1457
1458  if(rc < 0) {
1459    PRInt32 err = PR_GetError();
1460    if(err == PR_WOULD_BLOCK_ERROR)
1461      *curlcode = CURLE_AGAIN;
1462    else if(handle_cc_error(err, conn->data))
1463      *curlcode = CURLE_SSL_CERTPROBLEM;
1464    else {
1465      failf(conn->data, "SSL write: error %d", err);
1466      *curlcode = CURLE_SEND_ERROR;
1467    }
1468    return -1;
1469  }
1470  return rc; /* number of bytes */
1471}
1472
1473static ssize_t nss_recv(struct connectdata * conn, /* connection data */
1474                        int num,                   /* socketindex */
1475                        char *buf,                 /* store read data here */
1476                        size_t buffersize,         /* max amount to read */
1477                        CURLcode *curlcode)
1478{
1479  ssize_t nread;
1480
1481  nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, -1);
1482  if(nread < 0) {
1483    /* failed SSL read */
1484    PRInt32 err = PR_GetError();
1485
1486    if(err == PR_WOULD_BLOCK_ERROR)
1487      *curlcode = CURLE_AGAIN;
1488    else if(handle_cc_error(err, conn->data))
1489      *curlcode = CURLE_SSL_CERTPROBLEM;
1490    else {
1491      failf(conn->data, "SSL read: errno %d", err);
1492      *curlcode = CURLE_RECV_ERROR;
1493    }
1494    return -1;
1495  }
1496  return nread;
1497}
1498
1499size_t Curl_nss_version(char *buffer, size_t size)
1500{
1501  return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
1502}
1503
1504int Curl_nss_seed(struct SessionHandle *data)
1505{
1506  /* TODO: implement? */
1507  (void) data;
1508  return 0;
1509}
1510
1511#endif /* USE_NSS */
1512