1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2014, 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 vtls.c should ever call or use these functions.
26 */
27
28#include "curl_setup.h"
29
30#ifdef USE_NSS
31
32#include "urldata.h"
33#include "sendf.h"
34#include "formdata.h" /* for the boundary function */
35#include "url.h" /* for the ssl config check function */
36#include "connect.h"
37#include "strequal.h"
38#include "select.h"
39#include "vtls.h"
40#include "llist.h"
41
42#define _MPRINTF_REPLACE /* use the internal *printf() functions */
43#include <curl/mprintf.h>
44
45#include "nssg.h"
46#include <nspr.h>
47#include <nss.h>
48#include <ssl.h>
49#include <sslerr.h>
50#include <secerr.h>
51#include <secmod.h>
52#include <sslproto.h>
53#include <prtypes.h>
54#include <pk11pub.h>
55#include <prio.h>
56#include <secitem.h>
57#include <secport.h>
58#include <certdb.h>
59#include <base64.h>
60#include <cert.h>
61#include <prerror.h>
62
63#include "curl_memory.h"
64#include "rawstr.h"
65#include "warnless.h"
66#include "x509asn1.h"
67
68/* The last #include file should be: */
69#include "memdebug.h"
70
71#define SSL_DIR "/etc/pki/nssdb"
72
73/* enough to fit the string "PEM Token #[0|1]" */
74#define SLOTSIZE 13
75
76PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
77
78PRLock * nss_initlock = NULL;
79PRLock * nss_crllock = NULL;
80struct curl_llist *nss_crl_list = NULL;
81NSSInitContext * nss_context = NULL;
82
83volatile int initialized = 0;
84
85typedef struct {
86  const char *name;
87  int num;
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
99#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
100static const cipher_s cipherlist[] = {
101  /* SSL2 cipher suites */
102  {"rc4",                        SSL_EN_RC4_128_WITH_MD5},
103  {"rc4-md5",                    SSL_EN_RC4_128_WITH_MD5},
104  {"rc4export",                  SSL_EN_RC4_128_EXPORT40_WITH_MD5},
105  {"rc2",                        SSL_EN_RC2_128_CBC_WITH_MD5},
106  {"rc2export",                  SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
107  {"des",                        SSL_EN_DES_64_CBC_WITH_MD5},
108  {"desede3",                    SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
109  /* SSL3/TLS cipher suites */
110  {"rsa_rc4_128_md5",            SSL_RSA_WITH_RC4_128_MD5},
111  {"rsa_rc4_128_sha",            SSL_RSA_WITH_RC4_128_SHA},
112  {"rsa_3des_sha",               SSL_RSA_WITH_3DES_EDE_CBC_SHA},
113  {"rsa_des_sha",                SSL_RSA_WITH_DES_CBC_SHA},
114  {"rsa_rc4_40_md5",             SSL_RSA_EXPORT_WITH_RC4_40_MD5},
115  {"rsa_rc2_40_md5",             SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
116  {"rsa_null_md5",               SSL_RSA_WITH_NULL_MD5},
117  {"rsa_null_sha",               SSL_RSA_WITH_NULL_SHA},
118  {"fips_3des_sha",              SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
119  {"fips_des_sha",               SSL_RSA_FIPS_WITH_DES_CBC_SHA},
120  {"fortezza",                   SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
121  {"fortezza_rc4_128_sha",       SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
122  {"fortezza_null",              SSL_FORTEZZA_DMS_WITH_NULL_SHA},
123  /* TLS 1.0: Exportable 56-bit Cipher Suites. */
124  {"rsa_des_56_sha",             TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
125  {"rsa_rc4_56_sha",             TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
126  /* AES ciphers. */
127  {"dhe_dss_aes_128_cbc_sha",    TLS_DHE_DSS_WITH_AES_128_CBC_SHA},
128  {"dhe_dss_aes_256_cbc_sha",    TLS_DHE_DSS_WITH_AES_256_CBC_SHA},
129  {"dhe_rsa_aes_128_cbc_sha",    TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
130  {"dhe_rsa_aes_256_cbc_sha",    TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
131  {"rsa_aes_128_sha",            TLS_RSA_WITH_AES_128_CBC_SHA},
132  {"rsa_aes_256_sha",            TLS_RSA_WITH_AES_256_CBC_SHA},
133  /* ECC ciphers. */
134  {"ecdh_ecdsa_null_sha",        TLS_ECDH_ECDSA_WITH_NULL_SHA},
135  {"ecdh_ecdsa_rc4_128_sha",     TLS_ECDH_ECDSA_WITH_RC4_128_SHA},
136  {"ecdh_ecdsa_3des_sha",        TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA},
137  {"ecdh_ecdsa_aes_128_sha",     TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA},
138  {"ecdh_ecdsa_aes_256_sha",     TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA},
139  {"ecdhe_ecdsa_null_sha",       TLS_ECDHE_ECDSA_WITH_NULL_SHA},
140  {"ecdhe_ecdsa_rc4_128_sha",    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
141  {"ecdhe_ecdsa_3des_sha",       TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA},
142  {"ecdhe_ecdsa_aes_128_sha",    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
143  {"ecdhe_ecdsa_aes_256_sha",    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
144  {"ecdh_rsa_null_sha",          TLS_ECDH_RSA_WITH_NULL_SHA},
145  {"ecdh_rsa_128_sha",           TLS_ECDH_RSA_WITH_RC4_128_SHA},
146  {"ecdh_rsa_3des_sha",          TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA},
147  {"ecdh_rsa_aes_128_sha",       TLS_ECDH_RSA_WITH_AES_128_CBC_SHA},
148  {"ecdh_rsa_aes_256_sha",       TLS_ECDH_RSA_WITH_AES_256_CBC_SHA},
149  {"echde_rsa_null",             TLS_ECDHE_RSA_WITH_NULL_SHA},
150  {"ecdhe_rsa_rc4_128_sha",      TLS_ECDHE_RSA_WITH_RC4_128_SHA},
151  {"ecdhe_rsa_3des_sha",         TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
152  {"ecdhe_rsa_aes_128_sha",      TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
153  {"ecdhe_rsa_aes_256_sha",      TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
154  {"ecdh_anon_null_sha",         TLS_ECDH_anon_WITH_NULL_SHA},
155  {"ecdh_anon_rc4_128sha",       TLS_ECDH_anon_WITH_RC4_128_SHA},
156  {"ecdh_anon_3des_sha",         TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA},
157  {"ecdh_anon_aes_128_sha",      TLS_ECDH_anon_WITH_AES_128_CBC_SHA},
158  {"ecdh_anon_aes_256_sha",      TLS_ECDH_anon_WITH_AES_256_CBC_SHA},
159#ifdef TLS_RSA_WITH_NULL_SHA256
160  /* new HMAC-SHA256 cipher suites specified in RFC */
161  {"rsa_null_sha_256",                TLS_RSA_WITH_NULL_SHA256},
162  {"rsa_aes_128_cbc_sha_256",         TLS_RSA_WITH_AES_128_CBC_SHA256},
163  {"rsa_aes_256_cbc_sha_256",         TLS_RSA_WITH_AES_256_CBC_SHA256},
164  {"dhe_rsa_aes_128_cbc_sha_256",     TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
165  {"dhe_rsa_aes_256_cbc_sha_256",     TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
166  {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
167  {"ecdhe_rsa_aes_128_cbc_sha_256",   TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
168#endif
169#ifdef TLS_RSA_WITH_AES_128_GCM_SHA256
170  /* AES GCM cipher suites in RFC 5288 and RFC 5289 */
171  {"rsa_aes_128_gcm_sha_256",         TLS_RSA_WITH_AES_128_GCM_SHA256},
172  {"dhe_rsa_aes_128_gcm_sha_256",     TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
173  {"dhe_dss_aes_128_gcm_sha_256",     TLS_DHE_DSS_WITH_AES_128_GCM_SHA256},
174  {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
175  {"ecdh_ecdsa_aes_128_gcm_sha_256",  TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256},
176  {"ecdhe_rsa_aes_128_gcm_sha_256",   TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
177  {"ecdh_rsa_aes_128_gcm_sha_256",    TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256},
178#endif
179};
180
181static const char* pem_library = "libnsspem.so";
182SECMODModule* mod = NULL;
183
184/* NSPR I/O layer we use to detect blocking direction during SSL handshake */
185static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
186static PRIOMethods nspr_io_methods;
187
188static const char* nss_error_to_name(PRErrorCode code)
189{
190  const char *name = PR_ErrorToName(code);
191  if(name)
192    return name;
193
194  return "unknown error";
195}
196
197static void nss_print_error_message(struct SessionHandle *data, PRUint32 err)
198{
199  failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
200}
201
202static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
203                             char *cipher_list)
204{
205  unsigned int i;
206  PRBool cipher_state[NUM_OF_CIPHERS];
207  PRBool found;
208  char *cipher;
209
210  /* First disable all ciphers. This uses a different max value in case
211   * NSS adds more ciphers later we don't want them available by
212   * accident
213   */
214  for(i=0; i<SSL_NumImplementedCiphers; i++) {
215    SSL_CipherPrefSet(model, SSL_ImplementedCiphers[i], PR_FALSE);
216  }
217
218  /* Set every entry in our list to false */
219  for(i=0; i<NUM_OF_CIPHERS; i++) {
220    cipher_state[i] = PR_FALSE;
221  }
222
223  cipher = cipher_list;
224
225  while(cipher_list && (cipher_list[0])) {
226    while((*cipher) && (ISSPACE(*cipher)))
227      ++cipher;
228
229    if((cipher_list = strchr(cipher, ','))) {
230      *cipher_list++ = '\0';
231    }
232
233    found = PR_FALSE;
234
235    for(i=0; i<NUM_OF_CIPHERS; i++) {
236      if(Curl_raw_equal(cipher, cipherlist[i].name)) {
237        cipher_state[i] = PR_TRUE;
238        found = PR_TRUE;
239        break;
240      }
241    }
242
243    if(found == PR_FALSE) {
244      failf(data, "Unknown cipher in list: %s", cipher);
245      return SECFailure;
246    }
247
248    if(cipher_list) {
249      cipher = cipher_list;
250    }
251  }
252
253  /* Finally actually enable the selected ciphers */
254  for(i=0; i<NUM_OF_CIPHERS; i++) {
255    if(!cipher_state[i])
256      continue;
257
258    if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) {
259      failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name);
260      return SECFailure;
261    }
262  }
263
264  return SECSuccess;
265}
266
267/*
268 * Get the number of ciphers that are enabled. We use this to determine
269 * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
270 */
271static int num_enabled_ciphers(void)
272{
273  PRInt32 policy = 0;
274  int count = 0;
275  unsigned int i;
276
277  for(i=0; i<NUM_OF_CIPHERS; i++) {
278    SSL_CipherPolicyGet(cipherlist[i].num, &policy);
279    if(policy)
280      count++;
281  }
282  return count;
283}
284
285/*
286 * Determine whether the nickname passed in is a filename that needs to
287 * be loaded as a PEM or a regular NSS nickname.
288 *
289 * returns 1 for a file
290 * returns 0 for not a file (NSS nickname)
291 */
292static int is_file(const char *filename)
293{
294  struct_stat st;
295
296  if(filename == NULL)
297    return 0;
298
299  if(stat(filename, &st) == 0)
300    if(S_ISREG(st.st_mode))
301      return 1;
302
303  return 0;
304}
305
306/* Check if the given string is filename or nickname of a certificate.  If the
307 * given string is recognized as filename, return NULL.  If the given string is
308 * recognized as nickname, return a duplicated string.  The returned string
309 * should be later deallocated using free().  If the OOM failure occurs, we
310 * return NULL, too.
311 */
312static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind)
313{
314  const char *str = data->set.str[cert_kind];
315  const char *n;
316
317  if(!is_file(str))
318    /* no such file exists, use the string as nickname */
319    return strdup(str);
320
321  /* search the last slash; we require at least one slash in a file name */
322  n = strrchr(str, '/');
323  if(!n) {
324    infof(data, "warning: certificate file name \"%s\" handled as nickname; "
325          "please use \"./%s\" to force file name\n", str, str);
326    return strdup(str);
327  }
328
329  /* we'll use the PEM reader to read the certificate from file */
330  return NULL;
331}
332
333/* Call PK11_CreateGenericObject() with the given obj_class and filename.  If
334 * the call succeeds, append the object handle to the list of objects so that
335 * the object can be destroyed in Curl_nss_close(). */
336static CURLcode nss_create_object(struct ssl_connect_data *ssl,
337                                  CK_OBJECT_CLASS obj_class,
338                                  const char *filename, bool cacert)
339{
340  PK11SlotInfo *slot;
341  PK11GenericObject *obj;
342  CK_BBOOL cktrue = CK_TRUE;
343  CK_BBOOL ckfalse = CK_FALSE;
344  CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
345  int attr_cnt = 0;
346  CURLcode err = (cacert)
347    ? CURLE_SSL_CACERT_BADFILE
348    : CURLE_SSL_CERTPROBLEM;
349
350  const int slot_id = (cacert) ? 0 : 1;
351  char *slot_name = aprintf("PEM Token #%d", slot_id);
352  if(!slot_name)
353    return CURLE_OUT_OF_MEMORY;
354
355  slot = PK11_FindSlotByName(slot_name);
356  free(slot_name);
357  if(!slot)
358    return err;
359
360  PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
361  PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
362  PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
363                strlen(filename) + 1);
364
365  if(CKO_CERTIFICATE == obj_class) {
366    CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
367    PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
368  }
369
370  obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
371  PK11_FreeSlot(slot);
372  if(!obj)
373    return err;
374
375  if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) {
376    PK11_DestroyGenericObject(obj);
377    return CURLE_OUT_OF_MEMORY;
378  }
379
380  if(!cacert && CKO_CERTIFICATE == obj_class)
381    /* store reference to a client certificate */
382    ssl->obj_clicert = obj;
383
384  return CURLE_OK;
385}
386
387/* Destroy the NSS object whose handle is given by ptr.  This function is
388 * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
389 * NSS objects in Curl_nss_close() */
390static void nss_destroy_object(void *user, void *ptr)
391{
392  PK11GenericObject *obj = (PK11GenericObject *)ptr;
393  (void) user;
394  PK11_DestroyGenericObject(obj);
395}
396
397/* same as nss_destroy_object() but for CRL items */
398static void nss_destroy_crl_item(void *user, void *ptr)
399{
400  SECItem *crl_der = (SECItem *)ptr;
401  (void) user;
402  SECITEM_FreeItem(crl_der, PR_TRUE);
403}
404
405static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
406                              const char *filename, PRBool cacert)
407{
408  CURLcode err = (cacert)
409    ? CURLE_SSL_CACERT_BADFILE
410    : CURLE_SSL_CERTPROBLEM;
411
412  /* libnsspem.so leaks memory if the requested file does not exist.  For more
413   * details, go to <https://bugzilla.redhat.com/734760>. */
414  if(is_file(filename))
415    err = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
416
417  if(CURLE_OK == err && !cacert) {
418    /* we have successfully loaded a client certificate */
419    CERTCertificate *cert;
420    char *nickname = NULL;
421    char *n = strrchr(filename, '/');
422    if(n)
423      n++;
424
425    /* The following undocumented magic helps to avoid a SIGSEGV on call
426     * of PK11_ReadRawAttribute() from SelectClientCert() when using an
427     * immature version of libnsspem.so.  For more details, go to
428     * <https://bugzilla.redhat.com/733685>. */
429    nickname = aprintf("PEM Token #1:%s", n);
430    if(nickname) {
431      cert = PK11_FindCertFromNickname(nickname, NULL);
432      if(cert)
433        CERT_DestroyCertificate(cert);
434
435      free(nickname);
436    }
437  }
438
439  return err;
440}
441
442/* add given CRL to cache if it is not already there */
443static CURLcode nss_cache_crl(SECItem *crl_der)
444{
445  CERTCertDBHandle *db = CERT_GetDefaultCertDB();
446  CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0);
447  if(crl) {
448    /* CRL already cached */
449    SEC_DestroyCrl(crl);
450    SECITEM_FreeItem(crl_der, PR_TRUE);
451    return CURLE_SSL_CRL_BADFILE;
452  }
453
454  /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */
455  PR_Lock(nss_crllock);
456
457  /* store the CRL item so that we can free it in Curl_nss_cleanup() */
458  if(!Curl_llist_insert_next(nss_crl_list, nss_crl_list->tail, crl_der)) {
459    SECITEM_FreeItem(crl_der, PR_TRUE);
460    PR_Unlock(nss_crllock);
461    return CURLE_OUT_OF_MEMORY;
462  }
463
464  if(SECSuccess != CERT_CacheCRL(db, crl_der)) {
465    /* unable to cache CRL */
466    PR_Unlock(nss_crllock);
467    return CURLE_SSL_CRL_BADFILE;
468  }
469
470  /* we need to clear session cache, so that the CRL could take effect */
471  SSL_ClearSessionCache();
472  PR_Unlock(nss_crllock);
473  return CURLE_OK;
474}
475
476static CURLcode nss_load_crl(const char* crlfilename)
477{
478  PRFileDesc *infile;
479  PRFileInfo  info;
480  SECItem filedata = { 0, NULL, 0 };
481  SECItem *crl_der = NULL;
482  char *body;
483
484  infile = PR_Open(crlfilename, PR_RDONLY, 0);
485  if(!infile)
486    return CURLE_SSL_CRL_BADFILE;
487
488  if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
489    goto fail;
490
491  if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
492    goto fail;
493
494  if(info.size != PR_Read(infile, filedata.data, info.size))
495    goto fail;
496
497  crl_der = SECITEM_AllocItem(NULL, NULL, 0U);
498  if(!crl_der)
499    goto fail;
500
501  /* place a trailing zero right after the visible data */
502  body = (char*)filedata.data;
503  body[--filedata.len] = '\0';
504
505  body = strstr(body, "-----BEGIN");
506  if(body) {
507    /* assume ASCII */
508    char *trailer;
509    char *begin = PORT_Strchr(body, '\n');
510    if(!begin)
511      begin = PORT_Strchr(body, '\r');
512    if(!begin)
513      goto fail;
514
515    trailer = strstr(++begin, "-----END");
516    if(!trailer)
517      goto fail;
518
519    /* retrieve DER from ASCII */
520    *trailer = '\0';
521    if(ATOB_ConvertAsciiToItem(crl_der, begin))
522      goto fail;
523
524    SECITEM_FreeItem(&filedata, PR_FALSE);
525  }
526  else
527    /* assume DER */
528    *crl_der = filedata;
529
530  PR_Close(infile);
531  return nss_cache_crl(crl_der);
532
533fail:
534  PR_Close(infile);
535  SECITEM_FreeItem(crl_der, PR_TRUE);
536  SECITEM_FreeItem(&filedata, PR_FALSE);
537  return CURLE_SSL_CRL_BADFILE;
538}
539
540static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
541                             char *key_file)
542{
543  PK11SlotInfo *slot;
544  SECStatus status;
545  CURLcode rv;
546  struct ssl_connect_data *ssl = conn->ssl;
547  (void)sockindex; /* unused */
548
549  rv = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
550  if(CURLE_OK != rv) {
551    PR_SetError(SEC_ERROR_BAD_KEY, 0);
552    return rv;
553  }
554
555  slot = PK11_FindSlotByName("PEM Token #1");
556  if(!slot)
557    return CURLE_SSL_CERTPROBLEM;
558
559  /* This will force the token to be seen as re-inserted */
560  SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
561  PK11_IsPresent(slot);
562
563  status = PK11_Authenticate(slot, PR_TRUE,
564                             conn->data->set.str[STRING_KEY_PASSWD]);
565  PK11_FreeSlot(slot);
566  return (SECSuccess == status)
567    ? CURLE_OK
568    : CURLE_SSL_CERTPROBLEM;
569}
570
571static int display_error(struct connectdata *conn, PRInt32 err,
572                         const char *filename)
573{
574  switch(err) {
575  case SEC_ERROR_BAD_PASSWORD:
576    failf(conn->data, "Unable to load client key: Incorrect password");
577    return 1;
578  case SEC_ERROR_UNKNOWN_CERT:
579    failf(conn->data, "Unable to load certificate %s", filename);
580    return 1;
581  default:
582    break;
583  }
584  return 0; /* The caller will print a generic error */
585}
586
587static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
588                           char *cert_file, char *key_file)
589{
590  struct SessionHandle *data = conn->data;
591  CURLcode rv;
592
593  if(cert_file) {
594    rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
595    if(CURLE_OK != rv) {
596      const PRErrorCode err = PR_GetError();
597      if(!display_error(conn, err, cert_file)) {
598        const char *err_name = nss_error_to_name(err);
599        failf(data, "unable to load client cert: %d (%s)", err, err_name);
600      }
601
602      return rv;
603    }
604  }
605
606  if(key_file || (is_file(cert_file))) {
607    if(key_file)
608      rv = nss_load_key(conn, sockindex, key_file);
609    else
610      /* In case the cert file also has the key */
611      rv = nss_load_key(conn, sockindex, cert_file);
612    if(CURLE_OK != rv) {
613      const PRErrorCode err = PR_GetError();
614      if(!display_error(conn, err, key_file)) {
615        const char *err_name = nss_error_to_name(err);
616        failf(data, "unable to load client key: %d (%s)", err, err_name);
617      }
618
619      return rv;
620    }
621  }
622
623  return CURLE_OK;
624}
625
626static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
627{
628  (void)slot; /* unused */
629  if(retry || NULL == arg)
630    return NULL;
631  else
632    return (char *)PORT_Strdup((char *)arg);
633}
634
635/* bypass the default SSL_AuthCertificate() hook in case we do not want to
636 * verify peer */
637static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
638                                    PRBool isServer)
639{
640  struct connectdata *conn = (struct connectdata *)arg;
641  if(!conn->data->set.ssl.verifypeer) {
642    infof(conn->data, "skipping SSL peer certificate verification\n");
643    return SECSuccess;
644  }
645
646  return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
647}
648
649/**
650 * Inform the application that the handshake is complete.
651 */
652static void HandshakeCallback(PRFileDesc *sock, void *arg)
653{
654#ifdef USE_NGHTTP2
655  struct connectdata *conn = (struct connectdata*) arg;
656  unsigned int buflenmax = 50;
657  unsigned char buf[50];
658  unsigned int buflen;
659  SSLNextProtoState state;
660
661  if(!conn->data->set.ssl_enable_npn && !conn->data->set.ssl_enable_alpn) {
662    return;
663  }
664
665  if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) {
666
667    switch(state) {
668      case SSL_NEXT_PROTO_NO_SUPPORT:
669      case SSL_NEXT_PROTO_NO_OVERLAP:
670        infof(conn->data, "TLS, neither ALPN nor NPN succeeded\n");
671        return;
672#ifdef SSL_ENABLE_ALPN
673      case SSL_NEXT_PROTO_SELECTED:
674        infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf);
675        break;
676#endif
677      case SSL_NEXT_PROTO_NEGOTIATED:
678        infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf);
679        break;
680    }
681
682    if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN &&
683       memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)
684       == 0) {
685      conn->negnpn = NPN_HTTP2;
686    }
687    else if(buflen == ALPN_HTTP_1_1_LENGTH && memcmp(ALPN_HTTP_1_1, buf,
688                                                     ALPN_HTTP_1_1_LENGTH)) {
689      conn->negnpn = NPN_HTTP1_1;
690    }
691  }
692#else
693  (void)sock;
694  (void)arg;
695#endif
696}
697
698static void display_cert_info(struct SessionHandle *data,
699                              CERTCertificate *cert)
700{
701  char *subject, *issuer, *common_name;
702  PRExplodedTime printableTime;
703  char timeString[256];
704  PRTime notBefore, notAfter;
705
706  subject = CERT_NameToAscii(&cert->subject);
707  issuer = CERT_NameToAscii(&cert->issuer);
708  common_name = CERT_GetCommonName(&cert->subject);
709  infof(data, "\tsubject: %s\n", subject);
710
711  CERT_GetCertTimes(cert, &notBefore, &notAfter);
712  PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
713  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
714  infof(data, "\tstart date: %s\n", timeString);
715  PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
716  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
717  infof(data, "\texpire date: %s\n", timeString);
718  infof(data, "\tcommon name: %s\n", common_name);
719  infof(data, "\tissuer: %s\n", issuer);
720
721  PR_Free(subject);
722  PR_Free(issuer);
723  PR_Free(common_name);
724}
725
726static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
727{
728  SSLChannelInfo channel;
729  SSLCipherSuiteInfo suite;
730  CERTCertificate *cert;
731  CERTCertificate *cert2;
732  CERTCertificate *cert3;
733  PRTime now;
734  int i;
735
736  if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
737     SECSuccess && channel.length == sizeof channel &&
738     channel.cipherSuite) {
739    if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
740                              &suite, sizeof suite) == SECSuccess) {
741      infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
742    }
743  }
744
745  cert = SSL_PeerCertificate(sock);
746
747  if(cert) {
748    infof(conn->data, "Server certificate:\n");
749
750    if(!conn->data->set.ssl.certinfo) {
751      display_cert_info(conn->data, cert);
752      CERT_DestroyCertificate(cert);
753    }
754    else {
755      /* Count certificates in chain. */
756      now = PR_Now();
757      i = 1;
758      if(!cert->isRoot) {
759        cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
760        while(cert2) {
761          i++;
762          if(cert2->isRoot) {
763            CERT_DestroyCertificate(cert2);
764            break;
765          }
766          cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
767          CERT_DestroyCertificate(cert2);
768          cert2 = cert3;
769        }
770      }
771      Curl_ssl_init_certinfo(conn->data, i);
772      for(i = 0; cert; cert = cert2) {
773        Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data,
774                              (char *)cert->derCert.data + cert->derCert.len);
775        if(cert->isRoot) {
776          CERT_DestroyCertificate(cert);
777          break;
778        }
779        cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
780        CERT_DestroyCertificate(cert);
781      }
782    }
783  }
784
785  return;
786}
787
788static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
789{
790  struct connectdata *conn = (struct connectdata *)arg;
791  struct SessionHandle *data = conn->data;
792  PRErrorCode err = PR_GetError();
793  CERTCertificate *cert;
794
795  /* remember the cert verification result */
796  data->set.ssl.certverifyresult = err;
797
798  if(err == SSL_ERROR_BAD_CERT_DOMAIN && !data->set.ssl.verifyhost)
799    /* we are asked not to verify the host name */
800    return SECSuccess;
801
802  /* print only info about the cert, the error is printed off the callback */
803  cert = SSL_PeerCertificate(sock);
804  if(cert) {
805    infof(data, "Server certificate:\n");
806    display_cert_info(data, cert);
807    CERT_DestroyCertificate(cert);
808  }
809
810  return SECFailure;
811}
812
813/**
814 *
815 * Check that the Peer certificate's issuer certificate matches the one found
816 * by issuer_nickname.  This is not exactly the way OpenSSL and GNU TLS do the
817 * issuer check, so we provide comments that mimic the OpenSSL
818 * X509_check_issued function (in x509v3/v3_purp.c)
819 */
820static SECStatus check_issuer_cert(PRFileDesc *sock,
821                                   char *issuer_nickname)
822{
823  CERTCertificate *cert,*cert_issuer,*issuer;
824  SECStatus res=SECSuccess;
825  void *proto_win = NULL;
826
827  /*
828    PRArenaPool   *tmpArena = NULL;
829    CERTAuthKeyID *authorityKeyID = NULL;
830    SECITEM       *caname = NULL;
831  */
832
833  cert = SSL_PeerCertificate(sock);
834  cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
835
836  proto_win = SSL_RevealPinArg(sock);
837  issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
838
839  if((!cert_issuer) || (!issuer))
840    res = SECFailure;
841  else if(SECITEM_CompareItem(&cert_issuer->derCert,
842                              &issuer->derCert)!=SECEqual)
843    res = SECFailure;
844
845  CERT_DestroyCertificate(cert);
846  CERT_DestroyCertificate(issuer);
847  CERT_DestroyCertificate(cert_issuer);
848  return res;
849}
850
851/**
852 *
853 * Callback to pick the SSL client certificate.
854 */
855static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
856                                  struct CERTDistNamesStr *caNames,
857                                  struct CERTCertificateStr **pRetCert,
858                                  struct SECKEYPrivateKeyStr **pRetKey)
859{
860  struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
861  struct SessionHandle *data = connssl->data;
862  const char *nickname = connssl->client_nickname;
863
864  if(connssl->obj_clicert) {
865    /* use the cert/key provided by PEM reader */
866    static const char pem_slotname[] = "PEM Token #1";
867    SECItem cert_der = { 0, NULL, 0 };
868    void *proto_win = SSL_RevealPinArg(sock);
869    struct CERTCertificateStr *cert;
870    struct SECKEYPrivateKeyStr *key;
871
872    PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname);
873    if(NULL == slot) {
874      failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
875      return SECFailure;
876    }
877
878    if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE,
879                             &cert_der) != SECSuccess) {
880      failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
881      PK11_FreeSlot(slot);
882      return SECFailure;
883    }
884
885    cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
886    SECITEM_FreeItem(&cert_der, PR_FALSE);
887    if(NULL == cert) {
888      failf(data, "NSS: client certificate from file not found");
889      PK11_FreeSlot(slot);
890      return SECFailure;
891    }
892
893    key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
894    PK11_FreeSlot(slot);
895    if(NULL == key) {
896      failf(data, "NSS: private key from file not found");
897      CERT_DestroyCertificate(cert);
898      return SECFailure;
899    }
900
901    infof(data, "NSS: client certificate from file\n");
902    display_cert_info(data, cert);
903
904    *pRetCert = cert;
905    *pRetKey = key;
906    return SECSuccess;
907  }
908
909  /* use the default NSS hook */
910  if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
911                                          pRetCert, pRetKey)
912      || NULL == *pRetCert) {
913
914    if(NULL == nickname)
915      failf(data, "NSS: client certificate not found (nickname not "
916            "specified)");
917    else
918      failf(data, "NSS: client certificate not found: %s", nickname);
919
920    return SECFailure;
921  }
922
923  /* get certificate nickname if any */
924  nickname = (*pRetCert)->nickname;
925  if(NULL == nickname)
926    nickname = "[unknown]";
927
928  if(NULL == *pRetKey) {
929    failf(data, "NSS: private key not found for certificate: %s", nickname);
930    return SECFailure;
931  }
932
933  infof(data, "NSS: using client certificate: %s\n", nickname);
934  display_cert_info(data, *pRetCert);
935  return SECSuccess;
936}
937
938/* This function is supposed to decide, which error codes should be used
939 * to conclude server is TLS intolerant.
940 *
941 * taken from xulrunner - nsNSSIOLayer.cpp
942 */
943static PRBool
944isTLSIntoleranceError(PRInt32 err)
945{
946  switch (err) {
947  case SSL_ERROR_BAD_MAC_ALERT:
948  case SSL_ERROR_BAD_MAC_READ:
949  case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
950  case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
951  case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
952  case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
953  case SSL_ERROR_NO_CYPHER_OVERLAP:
954  case SSL_ERROR_BAD_SERVER:
955  case SSL_ERROR_BAD_BLOCK_PADDING:
956  case SSL_ERROR_UNSUPPORTED_VERSION:
957  case SSL_ERROR_PROTOCOL_VERSION_ALERT:
958  case SSL_ERROR_RX_MALFORMED_FINISHED:
959  case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
960  case SSL_ERROR_DECODE_ERROR_ALERT:
961  case SSL_ERROR_RX_UNKNOWN_ALERT:
962    return PR_TRUE;
963  default:
964    return PR_FALSE;
965  }
966}
967
968/* update blocking direction in case of PR_WOULD_BLOCK_ERROR */
969static void nss_update_connecting_state(ssl_connect_state state, void *secret)
970{
971  struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret;
972  if(PR_GetError() != PR_WOULD_BLOCK_ERROR)
973    /* an unrelated error is passing by */
974    return;
975
976  switch(connssl->connecting_state) {
977  case ssl_connect_2:
978  case ssl_connect_2_reading:
979  case ssl_connect_2_writing:
980    break;
981  default:
982    /* we are not called from an SSL handshake */
983    return;
984  }
985
986  /* update the state accordingly */
987  connssl->connecting_state = state;
988}
989
990/* recv() wrapper we use to detect blocking direction during SSL handshake */
991static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
992                            PRIntn flags, PRIntervalTime timeout)
993{
994  const PRRecvFN recv_fn = fd->lower->methods->recv;
995  const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout);
996  if(rv < 0)
997    /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
998    nss_update_connecting_state(ssl_connect_2_reading, fd->secret);
999  return rv;
1000}
1001
1002/* send() wrapper we use to detect blocking direction during SSL handshake */
1003static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
1004                            PRIntn flags, PRIntervalTime timeout)
1005{
1006  const PRSendFN send_fn = fd->lower->methods->send;
1007  const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout);
1008  if(rv < 0)
1009    /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
1010    nss_update_connecting_state(ssl_connect_2_writing, fd->secret);
1011  return rv;
1012}
1013
1014/* close() wrapper to avoid assertion failure due to fd->secret != NULL */
1015static PRStatus nspr_io_close(PRFileDesc *fd)
1016{
1017  const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close;
1018  fd->secret = NULL;
1019  return close_fn(fd);
1020}
1021
1022static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir)
1023{
1024  NSSInitParameters initparams;
1025
1026  if(nss_context != NULL)
1027    return CURLE_OK;
1028
1029  memset((void *) &initparams, '\0', sizeof(initparams));
1030  initparams.length = sizeof(initparams);
1031
1032  if(cert_dir) {
1033    const bool use_sql = NSS_VersionCheck("3.12.0");
1034    char *certpath = aprintf("%s%s", use_sql ? "sql:" : "", cert_dir);
1035    if(!certpath)
1036      return CURLE_OUT_OF_MEMORY;
1037
1038    infof(data, "Initializing NSS with certpath: %s\n", certpath);
1039    nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
1040            NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
1041    free(certpath);
1042
1043    if(nss_context != NULL)
1044      return CURLE_OK;
1045
1046    infof(data, "Unable to initialize NSS database\n");
1047  }
1048
1049  infof(data, "Initializing NSS with certpath: none\n");
1050  nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
1051         | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
1052         | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
1053  if(nss_context != NULL)
1054    return CURLE_OK;
1055
1056  infof(data, "Unable to initialize NSS\n");
1057  return CURLE_SSL_CACERT_BADFILE;
1058}
1059
1060static CURLcode nss_init(struct SessionHandle *data)
1061{
1062  char *cert_dir;
1063  struct_stat st;
1064  CURLcode rv;
1065
1066  if(initialized)
1067    return CURLE_OK;
1068
1069  /* list of all CRL items we need to destroy in Curl_nss_cleanup() */
1070  nss_crl_list = Curl_llist_alloc(nss_destroy_crl_item);
1071  if(!nss_crl_list)
1072    return CURLE_OUT_OF_MEMORY;
1073
1074  /* First we check if $SSL_DIR points to a valid dir */
1075  cert_dir = getenv("SSL_DIR");
1076  if(cert_dir) {
1077    if((stat(cert_dir, &st) != 0) ||
1078        (!S_ISDIR(st.st_mode))) {
1079      cert_dir = NULL;
1080    }
1081  }
1082
1083  /* Now we check if the default location is a valid dir */
1084  if(!cert_dir) {
1085    if((stat(SSL_DIR, &st) == 0) &&
1086        (S_ISDIR(st.st_mode))) {
1087      cert_dir = (char *)SSL_DIR;
1088    }
1089  }
1090
1091  if(nspr_io_identity == PR_INVALID_IO_LAYER) {
1092    /* allocate an identity for our own NSPR I/O layer */
1093    nspr_io_identity = PR_GetUniqueIdentity("libcurl");
1094    if(nspr_io_identity == PR_INVALID_IO_LAYER)
1095      return CURLE_OUT_OF_MEMORY;
1096
1097    /* the default methods just call down to the lower I/O layer */
1098    memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(), sizeof nspr_io_methods);
1099
1100    /* override certain methods in the table by our wrappers */
1101    nspr_io_methods.recv  = nspr_io_recv;
1102    nspr_io_methods.send  = nspr_io_send;
1103    nspr_io_methods.close = nspr_io_close;
1104  }
1105
1106  rv = nss_init_core(data, cert_dir);
1107  if(rv)
1108    return rv;
1109
1110  if(num_enabled_ciphers() == 0)
1111    NSS_SetDomesticPolicy();
1112
1113  initialized = 1;
1114  return CURLE_OK;
1115}
1116
1117/**
1118 * Global SSL init
1119 *
1120 * @retval 0 error initializing SSL
1121 * @retval 1 SSL initialized successfully
1122 */
1123int Curl_nss_init(void)
1124{
1125  /* curl_global_init() is not thread-safe so this test is ok */
1126  if(nss_initlock == NULL) {
1127    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
1128    nss_initlock = PR_NewLock();
1129    nss_crllock = PR_NewLock();
1130  }
1131
1132  /* We will actually initialize NSS later */
1133
1134  return 1;
1135}
1136
1137CURLcode Curl_nss_force_init(struct SessionHandle *data)
1138{
1139  CURLcode rv;
1140  if(!nss_initlock) {
1141    failf(data,
1142          "unable to initialize NSS, curl_global_init() should have been "
1143          "called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
1144    return CURLE_FAILED_INIT;
1145  }
1146
1147  PR_Lock(nss_initlock);
1148  rv = nss_init(data);
1149  PR_Unlock(nss_initlock);
1150  return rv;
1151}
1152
1153/* Global cleanup */
1154void Curl_nss_cleanup(void)
1155{
1156  /* This function isn't required to be threadsafe and this is only done
1157   * as a safety feature.
1158   */
1159  PR_Lock(nss_initlock);
1160  if(initialized) {
1161    /* Free references to client certificates held in the SSL session cache.
1162     * Omitting this hampers destruction of the security module owning
1163     * the certificates. */
1164    SSL_ClearSessionCache();
1165
1166    if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) {
1167      SECMOD_DestroyModule(mod);
1168      mod = NULL;
1169    }
1170    NSS_ShutdownContext(nss_context);
1171    nss_context = NULL;
1172  }
1173
1174  /* destroy all CRL items */
1175  Curl_llist_destroy(nss_crl_list, NULL);
1176  nss_crl_list = NULL;
1177
1178  PR_Unlock(nss_initlock);
1179
1180  PR_DestroyLock(nss_initlock);
1181  PR_DestroyLock(nss_crllock);
1182  nss_initlock = NULL;
1183
1184  initialized = 0;
1185}
1186
1187/*
1188 * This function uses SSL_peek to determine connection status.
1189 *
1190 * Return codes:
1191 *     1 means the connection is still in place
1192 *     0 means the connection has been closed
1193 *    -1 means the connection status is unknown
1194 */
1195int
1196Curl_nss_check_cxn(struct connectdata *conn)
1197{
1198  int rc;
1199  char buf;
1200
1201  rc =
1202    PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK,
1203            PR_SecondsToInterval(1));
1204  if(rc > 0)
1205    return 1; /* connection still in place */
1206
1207  if(rc == 0)
1208    return 0; /* connection has been closed */
1209
1210  return -1;  /* connection status unknown */
1211}
1212
1213/*
1214 * This function is called when an SSL connection is closed.
1215 */
1216void Curl_nss_close(struct connectdata *conn, int sockindex)
1217{
1218  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1219
1220  if(connssl->handle) {
1221    /* NSS closes the socket we previously handed to it, so we must mark it
1222       as closed to avoid double close */
1223    fake_sclose(conn->sock[sockindex]);
1224    conn->sock[sockindex] = CURL_SOCKET_BAD;
1225
1226    if((connssl->client_nickname != NULL) || (connssl->obj_clicert != NULL))
1227      /* A server might require different authentication based on the
1228       * particular path being requested by the client.  To support this
1229       * scenario, we must ensure that a connection will never reuse the
1230       * authentication data from a previous connection. */
1231      SSL_InvalidateSession(connssl->handle);
1232
1233    if(connssl->client_nickname != NULL) {
1234      free(connssl->client_nickname);
1235      connssl->client_nickname = NULL;
1236    }
1237    /* destroy all NSS objects in order to avoid failure of NSS shutdown */
1238    Curl_llist_destroy(connssl->obj_list, NULL);
1239    connssl->obj_list = NULL;
1240    connssl->obj_clicert = NULL;
1241
1242    PR_Close(connssl->handle);
1243    connssl->handle = NULL;
1244  }
1245}
1246
1247/*
1248 * This function is called when the 'data' struct is going away. Close
1249 * down everything and free all resources!
1250 */
1251int Curl_nss_close_all(struct SessionHandle *data)
1252{
1253  (void)data;
1254  return 0;
1255}
1256
1257/* return true if NSS can provide error code (and possibly msg) for the
1258   error */
1259static bool is_nss_error(CURLcode err)
1260{
1261  switch(err) {
1262  case CURLE_PEER_FAILED_VERIFICATION:
1263  case CURLE_SSL_CACERT:
1264  case CURLE_SSL_CERTPROBLEM:
1265  case CURLE_SSL_CONNECT_ERROR:
1266  case CURLE_SSL_ISSUER_ERROR:
1267    return true;
1268
1269  default:
1270    return false;
1271  }
1272}
1273
1274/* return true if the given error code is related to a client certificate */
1275static bool is_cc_error(PRInt32 err)
1276{
1277  switch(err) {
1278  case SSL_ERROR_BAD_CERT_ALERT:
1279  case SSL_ERROR_EXPIRED_CERT_ALERT:
1280  case SSL_ERROR_REVOKED_CERT_ALERT:
1281    return true;
1282
1283  default:
1284    return false;
1285  }
1286}
1287
1288static Curl_recv nss_recv;
1289static Curl_send nss_send;
1290
1291static CURLcode nss_load_ca_certificates(struct connectdata *conn,
1292                                         int sockindex)
1293{
1294  struct SessionHandle *data = conn->data;
1295  const char *cafile = data->set.ssl.CAfile;
1296  const char *capath = data->set.ssl.CApath;
1297
1298  if(cafile) {
1299    CURLcode rv = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
1300    if(CURLE_OK != rv)
1301      return rv;
1302  }
1303
1304  if(capath) {
1305    struct_stat st;
1306    if(stat(capath, &st) == -1)
1307      return CURLE_SSL_CACERT_BADFILE;
1308
1309    if(S_ISDIR(st.st_mode)) {
1310      PRDirEntry *entry;
1311      PRDir *dir = PR_OpenDir(capath);
1312      if(!dir)
1313        return CURLE_SSL_CACERT_BADFILE;
1314
1315      while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
1316        char *fullpath = aprintf("%s/%s", capath, entry->name);
1317        if(!fullpath) {
1318          PR_CloseDir(dir);
1319          return CURLE_OUT_OF_MEMORY;
1320        }
1321
1322        if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
1323          /* This is purposefully tolerant of errors so non-PEM files can
1324           * be in the same directory */
1325          infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
1326
1327        free(fullpath);
1328      }
1329
1330      PR_CloseDir(dir);
1331    }
1332    else
1333      infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
1334  }
1335
1336  infof(data, "  CAfile: %s\n  CApath: %s\n",
1337      cafile ? cafile : "none",
1338      capath ? capath : "none");
1339
1340  return CURLE_OK;
1341}
1342
1343static CURLcode nss_init_sslver(SSLVersionRange *sslver,
1344                                struct SessionHandle *data)
1345{
1346  switch (data->set.ssl.version) {
1347  default:
1348  case CURL_SSLVERSION_DEFAULT:
1349    sslver->min = SSL_LIBRARY_VERSION_3_0;
1350    if(data->state.ssl_connect_retry) {
1351      infof(data, "TLS disabled due to previous handshake failure\n");
1352      sslver->max = SSL_LIBRARY_VERSION_3_0;
1353      return CURLE_OK;
1354    }
1355  /* intentional fall-through to default to highest TLS version if possible */
1356
1357  case CURL_SSLVERSION_TLSv1:
1358#ifdef SSL_LIBRARY_VERSION_TLS_1_2
1359    sslver->max = SSL_LIBRARY_VERSION_TLS_1_2;
1360#elif defined SSL_LIBRARY_VERSION_TLS_1_1
1361    sslver->max = SSL_LIBRARY_VERSION_TLS_1_1;
1362#else
1363    sslver->max = SSL_LIBRARY_VERSION_TLS_1_0;
1364#endif
1365    return CURLE_OK;
1366
1367  case CURL_SSLVERSION_SSLv2:
1368    sslver->min = SSL_LIBRARY_VERSION_2;
1369    sslver->max = SSL_LIBRARY_VERSION_2;
1370    return CURLE_OK;
1371
1372  case CURL_SSLVERSION_SSLv3:
1373    sslver->min = SSL_LIBRARY_VERSION_3_0;
1374    sslver->max = SSL_LIBRARY_VERSION_3_0;
1375    return CURLE_OK;
1376
1377  case CURL_SSLVERSION_TLSv1_0:
1378    sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
1379    sslver->max = SSL_LIBRARY_VERSION_TLS_1_0;
1380    return CURLE_OK;
1381
1382  case CURL_SSLVERSION_TLSv1_1:
1383#ifdef SSL_LIBRARY_VERSION_TLS_1_1
1384    sslver->min = SSL_LIBRARY_VERSION_TLS_1_1;
1385    sslver->max = SSL_LIBRARY_VERSION_TLS_1_1;
1386    return CURLE_OK;
1387#endif
1388    break;
1389
1390  case CURL_SSLVERSION_TLSv1_2:
1391#ifdef SSL_LIBRARY_VERSION_TLS_1_2
1392    sslver->min = SSL_LIBRARY_VERSION_TLS_1_2;
1393    sslver->max = SSL_LIBRARY_VERSION_TLS_1_2;
1394    return CURLE_OK;
1395#endif
1396    break;
1397  }
1398
1399  failf(data, "TLS minor version cannot be set");
1400  return CURLE_SSL_CONNECT_ERROR;
1401}
1402
1403static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
1404                                 struct SessionHandle *data,
1405                                 CURLcode curlerr)
1406{
1407  SSLVersionRange sslver;
1408  PRErrorCode err = 0;
1409
1410  /* reset the flag to avoid an infinite loop */
1411  data->state.ssl_connect_retry = FALSE;
1412
1413  if(is_nss_error(curlerr)) {
1414    /* read NSPR error code */
1415    err = PR_GetError();
1416    if(is_cc_error(err))
1417      curlerr = CURLE_SSL_CERTPROBLEM;
1418
1419    /* print the error number and error string */
1420    infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
1421
1422    /* print a human-readable message describing the error if available */
1423    nss_print_error_message(data, err);
1424  }
1425
1426  /* cleanup on connection failure */
1427  Curl_llist_destroy(connssl->obj_list, NULL);
1428  connssl->obj_list = NULL;
1429
1430  if(connssl->handle
1431      && (SSL_VersionRangeGet(connssl->handle, &sslver) == SECSuccess)
1432      && (sslver.min == SSL_LIBRARY_VERSION_3_0)
1433      && (sslver.max != SSL_LIBRARY_VERSION_3_0)
1434      && isTLSIntoleranceError(err)) {
1435    /* schedule reconnect through Curl_retry_request() */
1436    data->state.ssl_connect_retry = TRUE;
1437    infof(data, "Error in TLS handshake, trying SSLv3...\n");
1438    return CURLE_OK;
1439  }
1440
1441  return curlerr;
1442}
1443
1444/* Switch the SSL socket into non-blocking mode. */
1445static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl,
1446                                 struct SessionHandle *data)
1447{
1448  static PRSocketOptionData sock_opt;
1449  sock_opt.option = PR_SockOpt_Nonblocking;
1450  sock_opt.value.non_blocking = PR_TRUE;
1451
1452  if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS)
1453    return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
1454
1455  return CURLE_OK;
1456}
1457
1458static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
1459{
1460  PRFileDesc *model = NULL;
1461  PRFileDesc *nspr_io = NULL;
1462  PRFileDesc *nspr_io_stub = NULL;
1463  PRBool ssl_no_cache;
1464  PRBool ssl_cbc_random_iv;
1465  struct SessionHandle *data = conn->data;
1466  curl_socket_t sockfd = conn->sock[sockindex];
1467  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1468  CURLcode curlerr;
1469
1470  SSLVersionRange sslver = {
1471    SSL_LIBRARY_VERSION_TLS_1_0,  /* min */
1472    SSL_LIBRARY_VERSION_TLS_1_0   /* max */
1473  };
1474
1475#ifdef USE_NGHTTP2
1476#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
1477  unsigned int alpn_protos_len = NGHTTP2_PROTO_VERSION_ID_LEN +
1478      ALPN_HTTP_1_1_LENGTH + 2;
1479  unsigned char alpn_protos[NGHTTP2_PROTO_VERSION_ID_LEN + ALPN_HTTP_1_1_LENGTH
1480      + 2];
1481  int cur = 0;
1482#endif
1483#endif
1484
1485
1486  if(connssl->state == ssl_connection_complete)
1487    return CURLE_OK;
1488
1489  connssl->data = data;
1490
1491  /* list of all NSS objects we need to destroy in Curl_nss_close() */
1492  connssl->obj_list = Curl_llist_alloc(nss_destroy_object);
1493  if(!connssl->obj_list)
1494    return CURLE_OUT_OF_MEMORY;
1495
1496  /* FIXME. NSS doesn't support multiple databases open at the same time. */
1497  PR_Lock(nss_initlock);
1498  curlerr = nss_init(conn->data);
1499  if(CURLE_OK != curlerr) {
1500    PR_Unlock(nss_initlock);
1501    goto error;
1502  }
1503
1504  curlerr = CURLE_SSL_CONNECT_ERROR;
1505
1506  if(!mod) {
1507    char *configstring = aprintf("library=%s name=PEM", pem_library);
1508    if(!configstring) {
1509      PR_Unlock(nss_initlock);
1510      goto error;
1511    }
1512    mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
1513    free(configstring);
1514
1515    if(!mod || !mod->loaded) {
1516      if(mod) {
1517        SECMOD_DestroyModule(mod);
1518        mod = NULL;
1519      }
1520      infof(data, "WARNING: failed to load NSS PEM library %s. Using "
1521            "OpenSSL PEM certificates will not work.\n", pem_library);
1522    }
1523  }
1524
1525  PK11_SetPasswordFunc(nss_get_password);
1526  PR_Unlock(nss_initlock);
1527
1528  model = PR_NewTCPSocket();
1529  if(!model)
1530    goto error;
1531  model = SSL_ImportFD(NULL, model);
1532
1533  if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
1534    goto error;
1535  if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
1536    goto error;
1537  if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
1538    goto error;
1539
1540  /* do not use SSL cache if disabled or we are not going to verify peer */
1541  ssl_no_cache = (conn->ssl_config.sessionid && data->set.ssl.verifypeer) ?
1542    PR_FALSE : PR_TRUE;
1543  if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
1544    goto error;
1545
1546  /* enable/disable the requested SSL version(s) */
1547  if(nss_init_sslver(&sslver, data) != CURLE_OK)
1548    goto error;
1549  if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
1550    goto error;
1551
1552  ssl_cbc_random_iv = !data->set.ssl_enable_beast;
1553#ifdef SSL_CBC_RANDOM_IV
1554  /* unless the user explicitly asks to allow the protocol vulnerability, we
1555     use the work-around */
1556  if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
1557    infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n",
1558          ssl_cbc_random_iv);
1559#else
1560  if(ssl_cbc_random_iv)
1561    infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
1562#endif
1563
1564  /* reset the flag to avoid an infinite loop */
1565  data->state.ssl_connect_retry = FALSE;
1566
1567  if(data->set.ssl.cipher_list) {
1568    if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
1569      curlerr = CURLE_SSL_CIPHER;
1570      goto error;
1571    }
1572  }
1573
1574  if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost)
1575    infof(data, "warning: ignoring value of ssl.verifyhost\n");
1576
1577  /* bypass the default SSL_AuthCertificate() hook in case we do not want to
1578   * verify peer */
1579  if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
1580    goto error;
1581
1582  data->set.ssl.certverifyresult=0; /* not checked yet */
1583  if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
1584    goto error;
1585
1586  if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess)
1587    goto error;
1588
1589  if(data->set.ssl.verifypeer) {
1590    const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
1591    if(CURLE_OK != rv) {
1592      curlerr = rv;
1593      goto error;
1594    }
1595  }
1596
1597  if(data->set.ssl.CRLfile) {
1598    const CURLcode rv = nss_load_crl(data->set.ssl.CRLfile);
1599    if(CURLE_OK != rv) {
1600      curlerr = rv;
1601      goto error;
1602    }
1603    infof(data, "  CRLfile: %s\n", data->set.ssl.CRLfile);
1604  }
1605
1606  if(data->set.str[STRING_CERT]) {
1607    char *nickname = dup_nickname(data, STRING_CERT);
1608    if(nickname) {
1609      /* we are not going to use libnsspem.so to read the client cert */
1610      connssl->obj_clicert = NULL;
1611    }
1612    else {
1613      CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
1614                               data->set.str[STRING_KEY]);
1615      if(CURLE_OK != rv) {
1616        /* failf() is already done in cert_stuff() */
1617        curlerr = rv;
1618        goto error;
1619      }
1620    }
1621
1622    /* store the nickname for SelectClientCert() called during handshake */
1623    connssl->client_nickname = nickname;
1624  }
1625  else
1626    connssl->client_nickname = NULL;
1627
1628  if(SSL_GetClientAuthDataHook(model, SelectClientCert,
1629                               (void *)connssl) != SECSuccess) {
1630    curlerr = CURLE_SSL_CERTPROBLEM;
1631    goto error;
1632  }
1633
1634  /* wrap OS file descriptor by NSPR's file descriptor abstraction */
1635  nspr_io = PR_ImportTCPSocket(sockfd);
1636  if(!nspr_io)
1637    goto error;
1638
1639  /* create our own NSPR I/O layer */
1640  nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
1641  if(!nspr_io_stub) {
1642    PR_Close(nspr_io);
1643    goto error;
1644  }
1645
1646  /* make the per-connection data accessible from NSPR I/O callbacks */
1647  nspr_io_stub->secret = (void *)connssl;
1648
1649  /* push our new layer to the NSPR I/O stack */
1650  if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
1651    PR_Close(nspr_io);
1652    PR_Close(nspr_io_stub);
1653    goto error;
1654  }
1655
1656  /* import our model socket onto the current I/O stack */
1657  connssl->handle = SSL_ImportFD(model, nspr_io);
1658  if(!connssl->handle) {
1659    PR_Close(nspr_io);
1660    goto error;
1661  }
1662
1663  PR_Close(model); /* We don't need this any more */
1664  model = NULL;
1665
1666  /* This is the password associated with the cert that we're using */
1667  if(data->set.str[STRING_KEY_PASSWD]) {
1668    SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]);
1669  }
1670
1671#ifdef USE_NGHTTP2
1672  if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
1673#ifdef SSL_ENABLE_NPN
1674    if(data->set.ssl_enable_npn) {
1675      if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, PR_TRUE) != SECSuccess)
1676        goto error;
1677    }
1678#endif
1679
1680#ifdef SSL_ENABLE_ALPN
1681    if(data->set.ssl_enable_alpn) {
1682      if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, PR_TRUE)
1683          != SECSuccess)
1684        goto error;
1685    }
1686#endif
1687
1688#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
1689    if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) {
1690      alpn_protos[cur] = NGHTTP2_PROTO_VERSION_ID_LEN;
1691      cur++;
1692      memcpy(&alpn_protos[cur], NGHTTP2_PROTO_VERSION_ID,
1693          NGHTTP2_PROTO_VERSION_ID_LEN);
1694      cur += NGHTTP2_PROTO_VERSION_ID_LEN;
1695      alpn_protos[cur] = ALPN_HTTP_1_1_LENGTH;
1696      cur++;
1697      memcpy(&alpn_protos[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
1698
1699      if(SSL_SetNextProtoNego(connssl->handle, alpn_protos, alpn_protos_len)
1700          != SECSuccess)
1701        goto error;
1702    }
1703    else {
1704      infof(data, "SSL, can't negotiate HTTP/2.0 with neither NPN nor ALPN\n");
1705    }
1706#endif
1707  }
1708#endif
1709
1710
1711  /* Force handshake on next I/O */
1712  SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
1713
1714  SSL_SetURL(connssl->handle, conn->host.name);
1715
1716  return CURLE_OK;
1717
1718error:
1719  if(model)
1720    PR_Close(model);
1721
1722  return nss_fail_connect(connssl, data, curlerr);
1723}
1724
1725static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
1726{
1727  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1728  struct SessionHandle *data = conn->data;
1729  CURLcode curlerr = CURLE_SSL_CONNECT_ERROR;
1730  PRUint32 timeout;
1731
1732  /* check timeout situation */
1733  const long time_left = Curl_timeleft(data, NULL, TRUE);
1734  if(time_left < 0L) {
1735    failf(data, "timed out before SSL handshake");
1736    curlerr = CURLE_OPERATION_TIMEDOUT;
1737    goto error;
1738  }
1739
1740  /* Force the handshake now */
1741  timeout = PR_MillisecondsToInterval((PRUint32) time_left);
1742  if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
1743    if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
1744      /* blocking direction is updated by nss_update_connecting_state() */
1745      return CURLE_AGAIN;
1746    else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
1747      curlerr = CURLE_PEER_FAILED_VERIFICATION;
1748    else if(conn->data->set.ssl.certverifyresult!=0)
1749      curlerr = CURLE_SSL_CACERT;
1750    goto error;
1751  }
1752
1753  connssl->state = ssl_connection_complete;
1754  conn->recv[sockindex] = nss_recv;
1755  conn->send[sockindex] = nss_send;
1756
1757  display_conn_info(conn, connssl->handle);
1758
1759  if(data->set.str[STRING_SSL_ISSUERCERT]) {
1760    SECStatus ret = SECFailure;
1761    char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT);
1762    if(nickname) {
1763      /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */
1764      ret = check_issuer_cert(connssl->handle, nickname);
1765      free(nickname);
1766    }
1767
1768    if(SECFailure == ret) {
1769      infof(data,"SSL certificate issuer check failed\n");
1770      curlerr = CURLE_SSL_ISSUER_ERROR;
1771      goto error;
1772    }
1773    else {
1774      infof(data, "SSL certificate issuer check ok\n");
1775    }
1776  }
1777
1778  return CURLE_OK;
1779
1780error:
1781  return nss_fail_connect(connssl, data, curlerr);
1782}
1783
1784static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
1785                                   bool *done)
1786{
1787  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1788  struct SessionHandle *data = conn->data;
1789  const bool blocking = (done == NULL);
1790  CURLcode rv;
1791
1792  if(connssl->connecting_state == ssl_connect_1) {
1793    rv = nss_setup_connect(conn, sockindex);
1794    if(rv)
1795      /* we do not expect CURLE_AGAIN from nss_setup_connect() */
1796      return rv;
1797
1798    if(!blocking) {
1799      /* in non-blocking mode, set NSS non-blocking mode before handshake */
1800      rv = nss_set_nonblock(connssl, data);
1801      if(rv)
1802        return rv;
1803    }
1804
1805    connssl->connecting_state = ssl_connect_2;
1806  }
1807
1808  rv = nss_do_connect(conn, sockindex);
1809  switch(rv) {
1810  case CURLE_OK:
1811    break;
1812  case CURLE_AGAIN:
1813    if(!blocking)
1814      /* CURLE_AGAIN in non-blocking mode is not an error */
1815      return CURLE_OK;
1816    /* fall through */
1817  default:
1818    return rv;
1819  }
1820
1821  if(blocking) {
1822    /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
1823    rv = nss_set_nonblock(connssl, data);
1824    if(rv)
1825      return rv;
1826  }
1827  else
1828    /* signal completed SSL handshake */
1829    *done = TRUE;
1830
1831  connssl->connecting_state = ssl_connect_done;
1832  return CURLE_OK;
1833}
1834
1835CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
1836{
1837  return nss_connect_common(conn, sockindex, /* blocking */ NULL);
1838}
1839
1840CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
1841                                      int sockindex, bool *done)
1842{
1843  return nss_connect_common(conn, sockindex, done);
1844}
1845
1846static ssize_t nss_send(struct connectdata *conn,  /* connection data */
1847                        int sockindex,             /* socketindex */
1848                        const void *mem,           /* send this data */
1849                        size_t len,                /* amount to write */
1850                        CURLcode *curlcode)
1851{
1852  ssize_t rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0,
1853                       PR_INTERVAL_NO_WAIT);
1854  if(rc < 0) {
1855    PRInt32 err = PR_GetError();
1856    if(err == PR_WOULD_BLOCK_ERROR)
1857      *curlcode = CURLE_AGAIN;
1858    else {
1859      /* print the error number and error string */
1860      const char *err_name = nss_error_to_name(err);
1861      infof(conn->data, "SSL write: error %d (%s)\n", err, err_name);
1862
1863      /* print a human-readable message describing the error if available */
1864      nss_print_error_message(conn->data, err);
1865
1866      *curlcode = (is_cc_error(err))
1867        ? CURLE_SSL_CERTPROBLEM
1868        : CURLE_SEND_ERROR;
1869    }
1870    return -1;
1871  }
1872  return rc; /* number of bytes */
1873}
1874
1875static ssize_t nss_recv(struct connectdata * conn, /* connection data */
1876                        int num,                   /* socketindex */
1877                        char *buf,                 /* store read data here */
1878                        size_t buffersize,         /* max amount to read */
1879                        CURLcode *curlcode)
1880{
1881  ssize_t nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0,
1882                          PR_INTERVAL_NO_WAIT);
1883  if(nread < 0) {
1884    /* failed SSL read */
1885    PRInt32 err = PR_GetError();
1886
1887    if(err == PR_WOULD_BLOCK_ERROR)
1888      *curlcode = CURLE_AGAIN;
1889    else {
1890      /* print the error number and error string */
1891      const char *err_name = nss_error_to_name(err);
1892      infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name);
1893
1894      /* print a human-readable message describing the error if available */
1895      nss_print_error_message(conn->data, err);
1896
1897      *curlcode = (is_cc_error(err))
1898        ? CURLE_SSL_CERTPROBLEM
1899        : CURLE_RECV_ERROR;
1900    }
1901    return -1;
1902  }
1903  return nread;
1904}
1905
1906size_t Curl_nss_version(char *buffer, size_t size)
1907{
1908  return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
1909}
1910
1911int Curl_nss_seed(struct SessionHandle *data)
1912{
1913  /* make sure that NSS is initialized */
1914  return !!Curl_nss_force_init(data);
1915}
1916
1917void Curl_nss_random(struct SessionHandle *data,
1918                     unsigned char *entropy,
1919                     size_t length)
1920{
1921  Curl_nss_seed(data);  /* Initiate the seed if not already done */
1922  if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length))) {
1923    /* no way to signal a failure from here, we have to abort */
1924    failf(data, "PK11_GenerateRandom() failed, calling abort()...");
1925    abort();
1926  }
1927}
1928
1929void Curl_nss_md5sum(unsigned char *tmp, /* input */
1930                     size_t tmplen,
1931                     unsigned char *md5sum, /* output */
1932                     size_t md5len)
1933{
1934  PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
1935  unsigned int MD5out;
1936  PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen));
1937  PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len));
1938  PK11_DestroyContext(MD5pw, PR_TRUE);
1939}
1940
1941#endif /* USE_NSS */
1942