Annotation of embedaddon/curl/lib/vtls/nss.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, 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 https://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 "strcase.h"
38: #include "select.h"
39: #include "vtls.h"
40: #include "llist.h"
41: #include "multiif.h"
42: #include "curl_printf.h"
43: #include "nssg.h"
44: #include <nspr.h>
45: #include <nss.h>
46: #include <ssl.h>
47: #include <sslerr.h>
48: #include <secerr.h>
49: #include <secmod.h>
50: #include <sslproto.h>
51: #include <prtypes.h>
52: #include <pk11pub.h>
53: #include <prio.h>
54: #include <secitem.h>
55: #include <secport.h>
56: #include <certdb.h>
57: #include <base64.h>
58: #include <cert.h>
59: #include <prerror.h>
60: #include <keyhi.h> /* for SECKEY_DestroyPublicKey() */
61: #include <private/pprio.h> /* for PR_ImportTCPSocket */
62:
63: #define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH)
64:
65: #if NSSVERNUM >= 0x030f00 /* 3.15.0 */
66: #include <ocsp.h>
67: #endif
68:
69: #include "strcase.h"
70: #include "warnless.h"
71: #include "x509asn1.h"
72:
73: /* The last #include files should be: */
74: #include "curl_memory.h"
75: #include "memdebug.h"
76:
77: #define SSL_DIR "/etc/pki/nssdb"
78:
79: /* enough to fit the string "PEM Token #[0|1]" */
80: #define SLOTSIZE 13
81:
82: struct ssl_backend_data {
83: PRFileDesc *handle;
84: char *client_nickname;
85: struct Curl_easy *data;
86: struct curl_llist obj_list;
87: PK11GenericObject *obj_clicert;
88: };
89:
90: static PRLock *nss_initlock = NULL;
91: static PRLock *nss_crllock = NULL;
92: static PRLock *nss_findslot_lock = NULL;
93: static PRLock *nss_trustload_lock = NULL;
94: static struct curl_llist nss_crl_list;
95: static NSSInitContext *nss_context = NULL;
96: static volatile int initialized = 0;
97:
98: /* type used to wrap pointers as list nodes */
99: struct ptr_list_wrap {
100: void *ptr;
101: struct curl_llist_element node;
102: };
103:
104: typedef struct {
105: const char *name;
106: int num;
107: } cipher_s;
108:
109: #define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \
110: CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \
111: ptr->type = (_type); \
112: ptr->pValue = (_val); \
113: ptr->ulValueLen = (_len); \
114: } while(0)
115:
116: #define CERT_NewTempCertificate __CERT_NewTempCertificate
117:
118: #define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
119: static const cipher_s cipherlist[] = {
120: /* SSL2 cipher suites */
121: {"rc4", SSL_EN_RC4_128_WITH_MD5},
122: {"rc4-md5", SSL_EN_RC4_128_WITH_MD5},
123: {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5},
124: {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5},
125: {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
126: {"des", SSL_EN_DES_64_CBC_WITH_MD5},
127: {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
128: /* SSL3/TLS cipher suites */
129: {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5},
130: {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA},
131: {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA},
132: {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA},
133: {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5},
134: {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
135: {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5},
136: {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA},
137: {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
138: {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA},
139: {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
140: {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
141: {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
142: /* TLS 1.0: Exportable 56-bit Cipher Suites. */
143: {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
144: {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
145: /* AES ciphers. */
146: {"dhe_dss_aes_128_cbc_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA},
147: {"dhe_dss_aes_256_cbc_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA},
148: {"dhe_rsa_aes_128_cbc_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
149: {"dhe_rsa_aes_256_cbc_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
150: {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA},
151: {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA},
152: /* ECC ciphers. */
153: {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA},
154: {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA},
155: {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA},
156: {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA},
157: {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA},
158: {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA},
159: {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
160: {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA},
161: {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
162: {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
163: {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA},
164: {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA},
165: {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA},
166: {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA},
167: {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA},
168: {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA},
169: {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
170: {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
171: {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
172: {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
173: {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA},
174: {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA},
175: {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA},
176: {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA},
177: {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA},
178: #ifdef TLS_RSA_WITH_NULL_SHA256
179: /* new HMAC-SHA256 cipher suites specified in RFC */
180: {"rsa_null_sha_256", TLS_RSA_WITH_NULL_SHA256},
181: {"rsa_aes_128_cbc_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256},
182: {"rsa_aes_256_cbc_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256},
183: {"dhe_rsa_aes_128_cbc_sha_256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
184: {"dhe_rsa_aes_256_cbc_sha_256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
185: {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
186: {"ecdhe_rsa_aes_128_cbc_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
187: #endif
188: #ifdef TLS_RSA_WITH_AES_128_GCM_SHA256
189: /* AES GCM cipher suites in RFC 5288 and RFC 5289 */
190: {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256},
191: {"dhe_rsa_aes_128_gcm_sha_256", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
192: {"dhe_dss_aes_128_gcm_sha_256", TLS_DHE_DSS_WITH_AES_128_GCM_SHA256},
193: {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
194: {"ecdh_ecdsa_aes_128_gcm_sha_256", TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256},
195: {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
196: {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256},
197: #endif
198: #ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
199: /* cipher suites using SHA384 */
200: {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384},
201: {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
202: {"dhe_dss_aes_256_gcm_sha_384", TLS_DHE_DSS_WITH_AES_256_GCM_SHA384},
203: {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
204: {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
205: {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
206: {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
207: #endif
208: #ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
209: /* chacha20-poly1305 cipher suites */
210: {"ecdhe_rsa_chacha20_poly1305_sha_256",
211: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
212: {"ecdhe_ecdsa_chacha20_poly1305_sha_256",
213: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
214: {"dhe_rsa_chacha20_poly1305_sha_256",
215: TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
216: #endif
217: #ifdef TLS_AES_256_GCM_SHA384
218: {"aes_128_gcm_sha_256", TLS_AES_128_GCM_SHA256},
219: {"aes_256_gcm_sha_384", TLS_AES_256_GCM_SHA384},
220: {"chacha20_poly1305_sha_256", TLS_CHACHA20_POLY1305_SHA256},
221: #endif
222: };
223:
224: #if defined(WIN32)
225: static const char *pem_library = "nsspem.dll";
226: static const char *trust_library = "nssckbi.dll";
227: #elif defined(__APPLE__)
228: static const char *pem_library = "libnsspem.dylib";
229: static const char *trust_library = "libnssckbi.dylib";
230: #else
231: static const char *pem_library = "libnsspem.so";
232: static const char *trust_library = "libnssckbi.so";
233: #endif
234:
235: static SECMODModule *pem_module = NULL;
236: static SECMODModule *trust_module = NULL;
237:
238: /* NSPR I/O layer we use to detect blocking direction during SSL handshake */
239: static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
240: static PRIOMethods nspr_io_methods;
241:
242: static const char *nss_error_to_name(PRErrorCode code)
243: {
244: const char *name = PR_ErrorToName(code);
245: if(name)
246: return name;
247:
248: return "unknown error";
249: }
250:
251: static void nss_print_error_message(struct Curl_easy *data, PRUint32 err)
252: {
253: failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
254: }
255:
256: static char *nss_sslver_to_name(PRUint16 nssver)
257: {
258: switch(nssver) {
259: case SSL_LIBRARY_VERSION_2:
260: return strdup("SSLv2");
261: case SSL_LIBRARY_VERSION_3_0:
262: return strdup("SSLv3");
263: case SSL_LIBRARY_VERSION_TLS_1_0:
264: return strdup("TLSv1.0");
265: #ifdef SSL_LIBRARY_VERSION_TLS_1_1
266: case SSL_LIBRARY_VERSION_TLS_1_1:
267: return strdup("TLSv1.1");
268: #endif
269: #ifdef SSL_LIBRARY_VERSION_TLS_1_2
270: case SSL_LIBRARY_VERSION_TLS_1_2:
271: return strdup("TLSv1.2");
272: #endif
273: #ifdef SSL_LIBRARY_VERSION_TLS_1_3
274: case SSL_LIBRARY_VERSION_TLS_1_3:
275: return strdup("TLSv1.3");
276: #endif
277: default:
278: return curl_maprintf("0x%04x", nssver);
279: }
280: }
281:
282: static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
283: char *cipher_list)
284: {
285: unsigned int i;
286: PRBool cipher_state[NUM_OF_CIPHERS];
287: PRBool found;
288: char *cipher;
289:
290: /* use accessors to avoid dynamic linking issues after an update of NSS */
291: const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers();
292: const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers();
293: if(!implemented_ciphers)
294: return SECFailure;
295:
296: /* First disable all ciphers. This uses a different max value in case
297: * NSS adds more ciphers later we don't want them available by
298: * accident
299: */
300: for(i = 0; i < num_implemented_ciphers; i++) {
301: SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE);
302: }
303:
304: /* Set every entry in our list to false */
305: for(i = 0; i < NUM_OF_CIPHERS; i++) {
306: cipher_state[i] = PR_FALSE;
307: }
308:
309: cipher = cipher_list;
310:
311: while(cipher_list && (cipher_list[0])) {
312: while((*cipher) && (ISSPACE(*cipher)))
313: ++cipher;
314:
315: cipher_list = strchr(cipher, ',');
316: if(cipher_list) {
317: *cipher_list++ = '\0';
318: }
319:
320: found = PR_FALSE;
321:
322: for(i = 0; i<NUM_OF_CIPHERS; i++) {
323: if(strcasecompare(cipher, cipherlist[i].name)) {
324: cipher_state[i] = PR_TRUE;
325: found = PR_TRUE;
326: break;
327: }
328: }
329:
330: if(found == PR_FALSE) {
331: failf(data, "Unknown cipher in list: %s", cipher);
332: return SECFailure;
333: }
334:
335: if(cipher_list) {
336: cipher = cipher_list;
337: }
338: }
339:
340: /* Finally actually enable the selected ciphers */
341: for(i = 0; i<NUM_OF_CIPHERS; i++) {
342: if(!cipher_state[i])
343: continue;
344:
345: if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) {
346: failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name);
347: return SECFailure;
348: }
349: }
350:
351: return SECSuccess;
352: }
353:
354: /*
355: * Return true if at least one cipher-suite is enabled. Used to determine
356: * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
357: */
358: static bool any_cipher_enabled(void)
359: {
360: unsigned int i;
361:
362: for(i = 0; i<NUM_OF_CIPHERS; i++) {
363: PRInt32 policy = 0;
364: SSL_CipherPolicyGet(cipherlist[i].num, &policy);
365: if(policy)
366: return TRUE;
367: }
368:
369: return FALSE;
370: }
371:
372: /*
373: * Determine whether the nickname passed in is a filename that needs to
374: * be loaded as a PEM or a regular NSS nickname.
375: *
376: * returns 1 for a file
377: * returns 0 for not a file (NSS nickname)
378: */
379: static int is_file(const char *filename)
380: {
381: struct_stat st;
382:
383: if(filename == NULL)
384: return 0;
385:
386: if(stat(filename, &st) == 0)
387: if(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISCHR(st.st_mode))
388: return 1;
389:
390: return 0;
391: }
392:
393: /* Check if the given string is filename or nickname of a certificate. If the
394: * given string is recognized as filename, return NULL. If the given string is
395: * recognized as nickname, return a duplicated string. The returned string
396: * should be later deallocated using free(). If the OOM failure occurs, we
397: * return NULL, too.
398: */
399: static char *dup_nickname(struct Curl_easy *data, const char *str)
400: {
401: const char *n;
402:
403: if(!is_file(str))
404: /* no such file exists, use the string as nickname */
405: return strdup(str);
406:
407: /* search the first slash; we require at least one slash in a file name */
408: n = strchr(str, '/');
409: if(!n) {
410: infof(data, "warning: certificate file name \"%s\" handled as nickname; "
411: "please use \"./%s\" to force file name\n", str, str);
412: return strdup(str);
413: }
414:
415: /* we'll use the PEM reader to read the certificate from file */
416: return NULL;
417: }
418:
419: /* Lock/unlock wrapper for PK11_FindSlotByName() to work around race condition
420: * in nssSlot_IsTokenPresent() causing spurious SEC_ERROR_NO_TOKEN. For more
421: * details, go to <https://bugzilla.mozilla.org/1297397>.
422: */
423: static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name)
424: {
425: PK11SlotInfo *slot;
426: PR_Lock(nss_findslot_lock);
427: slot = PK11_FindSlotByName(slot_name);
428: PR_Unlock(nss_findslot_lock);
429: return slot;
430: }
431:
432: /* wrap 'ptr' as list node and tail-insert into 'list' */
433: static CURLcode insert_wrapped_ptr(struct curl_llist *list, void *ptr)
434: {
435: struct ptr_list_wrap *wrap = malloc(sizeof(*wrap));
436: if(!wrap)
437: return CURLE_OUT_OF_MEMORY;
438:
439: wrap->ptr = ptr;
440: Curl_llist_insert_next(list, list->tail, wrap, &wrap->node);
441: return CURLE_OK;
442: }
443:
444: /* Call PK11_CreateGenericObject() with the given obj_class and filename. If
445: * the call succeeds, append the object handle to the list of objects so that
446: * the object can be destroyed in Curl_nss_close(). */
447: static CURLcode nss_create_object(struct ssl_connect_data *connssl,
448: CK_OBJECT_CLASS obj_class,
449: const char *filename, bool cacert)
450: {
451: PK11SlotInfo *slot;
452: PK11GenericObject *obj;
453: CK_BBOOL cktrue = CK_TRUE;
454: CK_BBOOL ckfalse = CK_FALSE;
455: CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
456: int attr_cnt = 0;
457: CURLcode result = (cacert)
458: ? CURLE_SSL_CACERT_BADFILE
459: : CURLE_SSL_CERTPROBLEM;
460:
461: const int slot_id = (cacert) ? 0 : 1;
462: char *slot_name = aprintf("PEM Token #%d", slot_id);
463: struct ssl_backend_data *backend = connssl->backend;
464: if(!slot_name)
465: return CURLE_OUT_OF_MEMORY;
466:
467: slot = nss_find_slot_by_name(slot_name);
468: free(slot_name);
469: if(!slot)
470: return result;
471:
472: PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
473: PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
474: PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
475: (CK_ULONG)strlen(filename) + 1);
476:
477: if(CKO_CERTIFICATE == obj_class) {
478: CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
479: PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
480: }
481:
482: /* PK11_CreateManagedGenericObject() was introduced in NSS 3.34 because
483: * PK11_DestroyGenericObject() does not release resources allocated by
484: * PK11_CreateGenericObject() early enough. */
485: obj =
486: #ifdef HAVE_PK11_CREATEMANAGEDGENERICOBJECT
487: PK11_CreateManagedGenericObject
488: #else
489: PK11_CreateGenericObject
490: #endif
491: (slot, attrs, attr_cnt, PR_FALSE);
492:
493: PK11_FreeSlot(slot);
494: if(!obj)
495: return result;
496:
497: if(insert_wrapped_ptr(&backend->obj_list, obj) != CURLE_OK) {
498: PK11_DestroyGenericObject(obj);
499: return CURLE_OUT_OF_MEMORY;
500: }
501:
502: if(!cacert && CKO_CERTIFICATE == obj_class)
503: /* store reference to a client certificate */
504: backend->obj_clicert = obj;
505:
506: return CURLE_OK;
507: }
508:
509: /* Destroy the NSS object whose handle is given by ptr. This function is
510: * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
511: * NSS objects in Curl_nss_close() */
512: static void nss_destroy_object(void *user, void *ptr)
513: {
514: struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
515: PK11GenericObject *obj = (PK11GenericObject *) wrap->ptr;
516: (void) user;
517: PK11_DestroyGenericObject(obj);
518: free(wrap);
519: }
520:
521: /* same as nss_destroy_object() but for CRL items */
522: static void nss_destroy_crl_item(void *user, void *ptr)
523: {
524: struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
525: SECItem *crl_der = (SECItem *) wrap->ptr;
526: (void) user;
527: SECITEM_FreeItem(crl_der, PR_TRUE);
528: free(wrap);
529: }
530:
531: static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
532: const char *filename, PRBool cacert)
533: {
534: CURLcode result = (cacert)
535: ? CURLE_SSL_CACERT_BADFILE
536: : CURLE_SSL_CERTPROBLEM;
537:
538: /* libnsspem.so leaks memory if the requested file does not exist. For more
539: * details, go to <https://bugzilla.redhat.com/734760>. */
540: if(is_file(filename))
541: result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
542:
543: if(!result && !cacert) {
544: /* we have successfully loaded a client certificate */
545: CERTCertificate *cert;
546: char *nickname = NULL;
547: char *n = strrchr(filename, '/');
548: if(n)
549: n++;
550:
551: /* The following undocumented magic helps to avoid a SIGSEGV on call
552: * of PK11_ReadRawAttribute() from SelectClientCert() when using an
553: * immature version of libnsspem.so. For more details, go to
554: * <https://bugzilla.redhat.com/733685>. */
555: nickname = aprintf("PEM Token #1:%s", n);
556: if(nickname) {
557: cert = PK11_FindCertFromNickname(nickname, NULL);
558: if(cert)
559: CERT_DestroyCertificate(cert);
560:
561: free(nickname);
562: }
563: }
564:
565: return result;
566: }
567:
568: /* add given CRL to cache if it is not already there */
569: static CURLcode nss_cache_crl(SECItem *crl_der)
570: {
571: CERTCertDBHandle *db = CERT_GetDefaultCertDB();
572: CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0);
573: if(crl) {
574: /* CRL already cached */
575: SEC_DestroyCrl(crl);
576: SECITEM_FreeItem(crl_der, PR_TRUE);
577: return CURLE_OK;
578: }
579:
580: /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */
581: PR_Lock(nss_crllock);
582:
583: if(SECSuccess != CERT_CacheCRL(db, crl_der)) {
584: /* unable to cache CRL */
585: SECITEM_FreeItem(crl_der, PR_TRUE);
586: PR_Unlock(nss_crllock);
587: return CURLE_SSL_CRL_BADFILE;
588: }
589:
590: /* store the CRL item so that we can free it in Curl_nss_cleanup() */
591: if(insert_wrapped_ptr(&nss_crl_list, crl_der) != CURLE_OK) {
592: if(SECSuccess == CERT_UncacheCRL(db, crl_der))
593: SECITEM_FreeItem(crl_der, PR_TRUE);
594: PR_Unlock(nss_crllock);
595: return CURLE_OUT_OF_MEMORY;
596: }
597:
598: /* we need to clear session cache, so that the CRL could take effect */
599: SSL_ClearSessionCache();
600: PR_Unlock(nss_crllock);
601: return CURLE_OK;
602: }
603:
604: static CURLcode nss_load_crl(const char *crlfilename)
605: {
606: PRFileDesc *infile;
607: PRFileInfo info;
608: SECItem filedata = { 0, NULL, 0 };
609: SECItem *crl_der = NULL;
610: char *body;
611:
612: infile = PR_Open(crlfilename, PR_RDONLY, 0);
613: if(!infile)
614: return CURLE_SSL_CRL_BADFILE;
615:
616: if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
617: goto fail;
618:
619: if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
620: goto fail;
621:
622: if(info.size != PR_Read(infile, filedata.data, info.size))
623: goto fail;
624:
625: crl_der = SECITEM_AllocItem(NULL, NULL, 0U);
626: if(!crl_der)
627: goto fail;
628:
629: /* place a trailing zero right after the visible data */
630: body = (char *)filedata.data;
631: body[--filedata.len] = '\0';
632:
633: body = strstr(body, "-----BEGIN");
634: if(body) {
635: /* assume ASCII */
636: char *trailer;
637: char *begin = PORT_Strchr(body, '\n');
638: if(!begin)
639: begin = PORT_Strchr(body, '\r');
640: if(!begin)
641: goto fail;
642:
643: trailer = strstr(++begin, "-----END");
644: if(!trailer)
645: goto fail;
646:
647: /* retrieve DER from ASCII */
648: *trailer = '\0';
649: if(ATOB_ConvertAsciiToItem(crl_der, begin))
650: goto fail;
651:
652: SECITEM_FreeItem(&filedata, PR_FALSE);
653: }
654: else
655: /* assume DER */
656: *crl_der = filedata;
657:
658: PR_Close(infile);
659: return nss_cache_crl(crl_der);
660:
661: fail:
662: PR_Close(infile);
663: SECITEM_FreeItem(crl_der, PR_TRUE);
664: SECITEM_FreeItem(&filedata, PR_FALSE);
665: return CURLE_SSL_CRL_BADFILE;
666: }
667:
668: static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
669: char *key_file)
670: {
671: PK11SlotInfo *slot, *tmp;
672: SECStatus status;
673: CURLcode result;
674: struct ssl_connect_data *ssl = conn->ssl;
675: struct Curl_easy *data = conn->data;
676:
677: (void)sockindex; /* unused */
678:
679: result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
680: if(result) {
681: PR_SetError(SEC_ERROR_BAD_KEY, 0);
682: return result;
683: }
684:
685: slot = nss_find_slot_by_name("PEM Token #1");
686: if(!slot)
687: return CURLE_SSL_CERTPROBLEM;
688:
689: /* This will force the token to be seen as re-inserted */
690: tmp = SECMOD_WaitForAnyTokenEvent(pem_module, 0, 0);
691: if(tmp)
692: PK11_FreeSlot(tmp);
693: if(!PK11_IsPresent(slot)) {
694: PK11_FreeSlot(slot);
695: return CURLE_SSL_CERTPROBLEM;
696: }
697:
698: status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd));
699: PK11_FreeSlot(slot);
700:
701: return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
702: }
703:
704: static int display_error(struct connectdata *conn, PRInt32 err,
705: const char *filename)
706: {
707: switch(err) {
708: case SEC_ERROR_BAD_PASSWORD:
709: failf(conn->data, "Unable to load client key: Incorrect password");
710: return 1;
711: case SEC_ERROR_UNKNOWN_CERT:
712: failf(conn->data, "Unable to load certificate %s", filename);
713: return 1;
714: default:
715: break;
716: }
717: return 0; /* The caller will print a generic error */
718: }
719:
720: static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
721: char *cert_file, char *key_file)
722: {
723: struct Curl_easy *data = conn->data;
724: CURLcode result;
725:
726: if(cert_file) {
727: result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
728: if(result) {
729: const PRErrorCode err = PR_GetError();
730: if(!display_error(conn, err, cert_file)) {
731: const char *err_name = nss_error_to_name(err);
732: failf(data, "unable to load client cert: %d (%s)", err, err_name);
733: }
734:
735: return result;
736: }
737: }
738:
739: if(key_file || (is_file(cert_file))) {
740: if(key_file)
741: result = nss_load_key(conn, sockindex, key_file);
742: else
743: /* In case the cert file also has the key */
744: result = nss_load_key(conn, sockindex, cert_file);
745: if(result) {
746: const PRErrorCode err = PR_GetError();
747: if(!display_error(conn, err, key_file)) {
748: const char *err_name = nss_error_to_name(err);
749: failf(data, "unable to load client key: %d (%s)", err, err_name);
750: }
751:
752: return result;
753: }
754: }
755:
756: return CURLE_OK;
757: }
758:
759: static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
760: {
761: (void)slot; /* unused */
762:
763: if(retry || NULL == arg)
764: return NULL;
765: else
766: return (char *)PORT_Strdup((char *)arg);
767: }
768:
769: /* bypass the default SSL_AuthCertificate() hook in case we do not want to
770: * verify peer */
771: static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
772: PRBool isServer)
773: {
774: struct connectdata *conn = (struct connectdata *)arg;
775:
776: #ifdef SSL_ENABLE_OCSP_STAPLING
777: if(SSL_CONN_CONFIG(verifystatus)) {
778: SECStatus cacheResult;
779:
780: const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
781: if(!csa) {
782: failf(conn->data, "Invalid OCSP response");
783: return SECFailure;
784: }
785:
786: if(csa->len == 0) {
787: failf(conn->data, "No OCSP response received");
788: return SECFailure;
789: }
790:
791: cacheResult = CERT_CacheOCSPResponseFromSideChannel(
792: CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd),
793: PR_Now(), &csa->items[0], arg
794: );
795:
796: if(cacheResult != SECSuccess) {
797: failf(conn->data, "Invalid OCSP response");
798: return cacheResult;
799: }
800: }
801: #endif
802:
803: if(!SSL_CONN_CONFIG(verifypeer)) {
804: infof(conn->data, "skipping SSL peer certificate verification\n");
805: return SECSuccess;
806: }
807:
808: return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
809: }
810:
811: /**
812: * Inform the application that the handshake is complete.
813: */
814: static void HandshakeCallback(PRFileDesc *sock, void *arg)
815: {
816: struct connectdata *conn = (struct connectdata*) arg;
817: unsigned int buflenmax = 50;
818: unsigned char buf[50];
819: unsigned int buflen;
820: SSLNextProtoState state;
821:
822: if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) {
823: return;
824: }
825:
826: if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) {
827:
828: switch(state) {
829: #if NSSVERNUM >= 0x031a00 /* 3.26.0 */
830: /* used by NSS internally to implement 0-RTT */
831: case SSL_NEXT_PROTO_EARLY_VALUE:
832: /* fall through! */
833: #endif
834: case SSL_NEXT_PROTO_NO_SUPPORT:
835: case SSL_NEXT_PROTO_NO_OVERLAP:
836: infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n");
837: return;
838: #ifdef SSL_ENABLE_ALPN
839: case SSL_NEXT_PROTO_SELECTED:
840: infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf);
841: break;
842: #endif
843: case SSL_NEXT_PROTO_NEGOTIATED:
844: infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf);
845: break;
846: }
847:
848: #ifdef USE_NGHTTP2
849: if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN &&
850: !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) {
851: conn->negnpn = CURL_HTTP_VERSION_2;
852: }
853: else
854: #endif
855: if(buflen == ALPN_HTTP_1_1_LENGTH &&
856: !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) {
857: conn->negnpn = CURL_HTTP_VERSION_1_1;
858: }
859: Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
860: BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
861: }
862: }
863:
864: #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
865: static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
866: PRBool *canFalseStart)
867: {
868: struct connectdata *conn = client_data;
869: struct Curl_easy *data = conn->data;
870:
871: SSLChannelInfo channelInfo;
872: SSLCipherSuiteInfo cipherInfo;
873:
874: SECStatus rv;
875: PRBool negotiatedExtension;
876:
877: *canFalseStart = PR_FALSE;
878:
879: if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess)
880: return SECFailure;
881:
882: if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
883: sizeof(cipherInfo)) != SECSuccess)
884: return SECFailure;
885:
886: /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
887: * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310
888: */
889: if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2)
890: goto end;
891:
892: /* Only allow ECDHE key exchange algorithm.
893: * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */
894: if(cipherInfo.keaType != ssl_kea_ecdh)
895: goto end;
896:
897: /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
898: * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
899: * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */
900: if(cipherInfo.symCipher != ssl_calg_aes_gcm)
901: goto end;
902:
903: /* Enforce ALPN or NPN to do False Start, as an indicator of server
904: * compatibility. */
905: rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn,
906: &negotiatedExtension);
907: if(rv != SECSuccess || !negotiatedExtension) {
908: rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn,
909: &negotiatedExtension);
910: }
911:
912: if(rv != SECSuccess || !negotiatedExtension)
913: goto end;
914:
915: *canFalseStart = PR_TRUE;
916:
917: infof(data, "Trying TLS False Start\n");
918:
919: end:
920: return SECSuccess;
921: }
922: #endif
923:
924: static void display_cert_info(struct Curl_easy *data,
925: CERTCertificate *cert)
926: {
927: char *subject, *issuer, *common_name;
928: PRExplodedTime printableTime;
929: char timeString[256];
930: PRTime notBefore, notAfter;
931:
932: subject = CERT_NameToAscii(&cert->subject);
933: issuer = CERT_NameToAscii(&cert->issuer);
934: common_name = CERT_GetCommonName(&cert->subject);
935: infof(data, "\tsubject: %s\n", subject);
936:
937: CERT_GetCertTimes(cert, ¬Before, ¬After);
938: PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
939: PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
940: infof(data, "\tstart date: %s\n", timeString);
941: PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
942: PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
943: infof(data, "\texpire date: %s\n", timeString);
944: infof(data, "\tcommon name: %s\n", common_name);
945: infof(data, "\tissuer: %s\n", issuer);
946:
947: PR_Free(subject);
948: PR_Free(issuer);
949: PR_Free(common_name);
950: }
951:
952: static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock)
953: {
954: CURLcode result = CURLE_OK;
955: SSLChannelInfo channel;
956: SSLCipherSuiteInfo suite;
957: CERTCertificate *cert;
958: CERTCertificate *cert2;
959: CERTCertificate *cert3;
960: PRTime now;
961: int i;
962:
963: if(SSL_GetChannelInfo(sock, &channel, sizeof(channel)) ==
964: SECSuccess && channel.length == sizeof(channel) &&
965: channel.cipherSuite) {
966: if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
967: &suite, sizeof(suite)) == SECSuccess) {
968: infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
969: }
970: }
971:
972: cert = SSL_PeerCertificate(sock);
973: if(cert) {
974: infof(conn->data, "Server certificate:\n");
975:
976: if(!conn->data->set.ssl.certinfo) {
977: display_cert_info(conn->data, cert);
978: CERT_DestroyCertificate(cert);
979: }
980: else {
981: /* Count certificates in chain. */
982: now = PR_Now();
983: i = 1;
984: if(!cert->isRoot) {
985: cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
986: while(cert2) {
987: i++;
988: if(cert2->isRoot) {
989: CERT_DestroyCertificate(cert2);
990: break;
991: }
992: cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
993: CERT_DestroyCertificate(cert2);
994: cert2 = cert3;
995: }
996: }
997:
998: result = Curl_ssl_init_certinfo(conn->data, i);
999: if(!result) {
1000: for(i = 0; cert; cert = cert2) {
1001: result = Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data,
1002: (char *)cert->derCert.data +
1003: cert->derCert.len);
1004: if(result)
1005: break;
1006:
1007: if(cert->isRoot) {
1008: CERT_DestroyCertificate(cert);
1009: break;
1010: }
1011:
1012: cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
1013: CERT_DestroyCertificate(cert);
1014: }
1015: }
1016: }
1017: }
1018:
1019: return result;
1020: }
1021:
1022: static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
1023: {
1024: struct connectdata *conn = (struct connectdata *)arg;
1025: struct Curl_easy *data = conn->data;
1026: PRErrorCode err = PR_GetError();
1027: CERTCertificate *cert;
1028:
1029: /* remember the cert verification result */
1030: if(SSL_IS_PROXY())
1031: data->set.proxy_ssl.certverifyresult = err;
1032: else
1033: data->set.ssl.certverifyresult = err;
1034:
1035: if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
1036: /* we are asked not to verify the host name */
1037: return SECSuccess;
1038:
1039: /* print only info about the cert, the error is printed off the callback */
1040: cert = SSL_PeerCertificate(sock);
1041: if(cert) {
1042: infof(data, "Server certificate:\n");
1043: display_cert_info(data, cert);
1044: CERT_DestroyCertificate(cert);
1045: }
1046:
1047: return SECFailure;
1048: }
1049:
1050: /**
1051: *
1052: * Check that the Peer certificate's issuer certificate matches the one found
1053: * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
1054: * issuer check, so we provide comments that mimic the OpenSSL
1055: * X509_check_issued function (in x509v3/v3_purp.c)
1056: */
1057: static SECStatus check_issuer_cert(PRFileDesc *sock,
1058: char *issuer_nickname)
1059: {
1060: CERTCertificate *cert, *cert_issuer, *issuer;
1061: SECStatus res = SECSuccess;
1062: void *proto_win = NULL;
1063:
1064: cert = SSL_PeerCertificate(sock);
1065: cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner);
1066:
1067: proto_win = SSL_RevealPinArg(sock);
1068: issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
1069:
1070: if((!cert_issuer) || (!issuer))
1071: res = SECFailure;
1072: else if(SECITEM_CompareItem(&cert_issuer->derCert,
1073: &issuer->derCert) != SECEqual)
1074: res = SECFailure;
1075:
1076: CERT_DestroyCertificate(cert);
1077: CERT_DestroyCertificate(issuer);
1078: CERT_DestroyCertificate(cert_issuer);
1079: return res;
1080: }
1081:
1082: static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
1083: const char *pinnedpubkey)
1084: {
1085: CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1086: struct ssl_backend_data *backend = connssl->backend;
1087: struct Curl_easy *data = backend->data;
1088: CERTCertificate *cert;
1089:
1090: if(!pinnedpubkey)
1091: /* no pinned public key specified */
1092: return CURLE_OK;
1093:
1094: /* get peer certificate */
1095: cert = SSL_PeerCertificate(backend->handle);
1096: if(cert) {
1097: /* extract public key from peer certificate */
1098: SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
1099: if(pubkey) {
1100: /* encode the public key as DER */
1101: SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
1102: if(cert_der) {
1103: /* compare the public key with the pinned public key */
1104: result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data,
1105: cert_der->len);
1106: SECITEM_FreeItem(cert_der, PR_TRUE);
1107: }
1108: SECKEY_DestroyPublicKey(pubkey);
1109: }
1110: CERT_DestroyCertificate(cert);
1111: }
1112:
1113: /* report the resulting status */
1114: switch(result) {
1115: case CURLE_OK:
1116: infof(data, "pinned public key verified successfully!\n");
1117: break;
1118: case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
1119: failf(data, "failed to verify pinned public key");
1120: break;
1121: default:
1122: /* OOM, etc. */
1123: break;
1124: }
1125:
1126: return result;
1127: }
1128:
1129: /**
1130: *
1131: * Callback to pick the SSL client certificate.
1132: */
1133: static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
1134: struct CERTDistNamesStr *caNames,
1135: struct CERTCertificateStr **pRetCert,
1136: struct SECKEYPrivateKeyStr **pRetKey)
1137: {
1138: struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
1139: struct ssl_backend_data *backend = connssl->backend;
1140: struct Curl_easy *data = backend->data;
1141: const char *nickname = backend->client_nickname;
1142: static const char pem_slotname[] = "PEM Token #1";
1143:
1144: if(backend->obj_clicert) {
1145: /* use the cert/key provided by PEM reader */
1146: SECItem cert_der = { 0, NULL, 0 };
1147: void *proto_win = SSL_RevealPinArg(sock);
1148: struct CERTCertificateStr *cert;
1149: struct SECKEYPrivateKeyStr *key;
1150:
1151: PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
1152: if(NULL == slot) {
1153: failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
1154: return SECFailure;
1155: }
1156:
1157: if(PK11_ReadRawAttribute(PK11_TypeGeneric, backend->obj_clicert, CKA_VALUE,
1158: &cert_der) != SECSuccess) {
1159: failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
1160: PK11_FreeSlot(slot);
1161: return SECFailure;
1162: }
1163:
1164: cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
1165: SECITEM_FreeItem(&cert_der, PR_FALSE);
1166: if(NULL == cert) {
1167: failf(data, "NSS: client certificate from file not found");
1168: PK11_FreeSlot(slot);
1169: return SECFailure;
1170: }
1171:
1172: key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
1173: PK11_FreeSlot(slot);
1174: if(NULL == key) {
1175: failf(data, "NSS: private key from file not found");
1176: CERT_DestroyCertificate(cert);
1177: return SECFailure;
1178: }
1179:
1180: infof(data, "NSS: client certificate from file\n");
1181: display_cert_info(data, cert);
1182:
1183: *pRetCert = cert;
1184: *pRetKey = key;
1185: return SECSuccess;
1186: }
1187:
1188: /* use the default NSS hook */
1189: if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
1190: pRetCert, pRetKey)
1191: || NULL == *pRetCert) {
1192:
1193: if(NULL == nickname)
1194: failf(data, "NSS: client certificate not found (nickname not "
1195: "specified)");
1196: else
1197: failf(data, "NSS: client certificate not found: %s", nickname);
1198:
1199: return SECFailure;
1200: }
1201:
1202: /* get certificate nickname if any */
1203: nickname = (*pRetCert)->nickname;
1204: if(NULL == nickname)
1205: nickname = "[unknown]";
1206:
1207: if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
1208: failf(data, "NSS: refusing previously loaded certificate from file: %s",
1209: nickname);
1210: return SECFailure;
1211: }
1212:
1213: if(NULL == *pRetKey) {
1214: failf(data, "NSS: private key not found for certificate: %s", nickname);
1215: return SECFailure;
1216: }
1217:
1218: infof(data, "NSS: using client certificate: %s\n", nickname);
1219: display_cert_info(data, *pRetCert);
1220: return SECSuccess;
1221: }
1222:
1223: /* update blocking direction in case of PR_WOULD_BLOCK_ERROR */
1224: static void nss_update_connecting_state(ssl_connect_state state, void *secret)
1225: {
1226: struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret;
1227: if(PR_GetError() != PR_WOULD_BLOCK_ERROR)
1228: /* an unrelated error is passing by */
1229: return;
1230:
1231: switch(connssl->connecting_state) {
1232: case ssl_connect_2:
1233: case ssl_connect_2_reading:
1234: case ssl_connect_2_writing:
1235: break;
1236: default:
1237: /* we are not called from an SSL handshake */
1238: return;
1239: }
1240:
1241: /* update the state accordingly */
1242: connssl->connecting_state = state;
1243: }
1244:
1245: /* recv() wrapper we use to detect blocking direction during SSL handshake */
1246: static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
1247: PRIntn flags, PRIntervalTime timeout)
1248: {
1249: const PRRecvFN recv_fn = fd->lower->methods->recv;
1250: const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout);
1251: if(rv < 0)
1252: /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
1253: nss_update_connecting_state(ssl_connect_2_reading, fd->secret);
1254: return rv;
1255: }
1256:
1257: /* send() wrapper we use to detect blocking direction during SSL handshake */
1258: static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
1259: PRIntn flags, PRIntervalTime timeout)
1260: {
1261: const PRSendFN send_fn = fd->lower->methods->send;
1262: const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout);
1263: if(rv < 0)
1264: /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
1265: nss_update_connecting_state(ssl_connect_2_writing, fd->secret);
1266: return rv;
1267: }
1268:
1269: /* close() wrapper to avoid assertion failure due to fd->secret != NULL */
1270: static PRStatus nspr_io_close(PRFileDesc *fd)
1271: {
1272: const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close;
1273: fd->secret = NULL;
1274: return close_fn(fd);
1275: }
1276:
1277: /* load a PKCS #11 module */
1278: static CURLcode nss_load_module(SECMODModule **pmod, const char *library,
1279: const char *name)
1280: {
1281: char *config_string;
1282: SECMODModule *module = *pmod;
1283: if(module)
1284: /* already loaded */
1285: return CURLE_OK;
1286:
1287: config_string = aprintf("library=%s name=%s", library, name);
1288: if(!config_string)
1289: return CURLE_OUT_OF_MEMORY;
1290:
1291: module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE);
1292: free(config_string);
1293:
1294: if(module && module->loaded) {
1295: /* loaded successfully */
1296: *pmod = module;
1297: return CURLE_OK;
1298: }
1299:
1300: if(module)
1301: SECMOD_DestroyModule(module);
1302: return CURLE_FAILED_INIT;
1303: }
1304:
1305: /* unload a PKCS #11 module */
1306: static void nss_unload_module(SECMODModule **pmod)
1307: {
1308: SECMODModule *module = *pmod;
1309: if(!module)
1310: /* not loaded */
1311: return;
1312:
1313: if(SECMOD_UnloadUserModule(module) != SECSuccess)
1314: /* unload failed */
1315: return;
1316:
1317: SECMOD_DestroyModule(module);
1318: *pmod = NULL;
1319: }
1320:
1321: /* data might be NULL */
1322: static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
1323: {
1324: NSSInitParameters initparams;
1325: PRErrorCode err;
1326: const char *err_name;
1327:
1328: if(nss_context != NULL)
1329: return CURLE_OK;
1330:
1331: memset((void *) &initparams, '\0', sizeof(initparams));
1332: initparams.length = sizeof(initparams);
1333:
1334: if(cert_dir) {
1335: char *certpath = aprintf("sql:%s", cert_dir);
1336: if(!certpath)
1337: return CURLE_OUT_OF_MEMORY;
1338:
1339: infof(data, "Initializing NSS with certpath: %s\n", certpath);
1340: nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
1341: NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
1342: free(certpath);
1343:
1344: if(nss_context != NULL)
1345: return CURLE_OK;
1346:
1347: err = PR_GetError();
1348: err_name = nss_error_to_name(err);
1349: infof(data, "Unable to initialize NSS database: %d (%s)\n", err, err_name);
1350: }
1351:
1352: infof(data, "Initializing NSS with certpath: none\n");
1353: nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
1354: | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
1355: | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
1356: if(nss_context != NULL)
1357: return CURLE_OK;
1358:
1359: err = PR_GetError();
1360: err_name = nss_error_to_name(err);
1361: failf(data, "Unable to initialize NSS: %d (%s)", err, err_name);
1362: return CURLE_SSL_CACERT_BADFILE;
1363: }
1364:
1365: /* data might be NULL */
1366: static CURLcode nss_init(struct Curl_easy *data)
1367: {
1368: char *cert_dir;
1369: struct_stat st;
1370: CURLcode result;
1371:
1372: if(initialized)
1373: return CURLE_OK;
1374:
1375: /* list of all CRL items we need to destroy in Curl_nss_cleanup() */
1376: Curl_llist_init(&nss_crl_list, nss_destroy_crl_item);
1377:
1378: /* First we check if $SSL_DIR points to a valid dir */
1379: cert_dir = getenv("SSL_DIR");
1380: if(cert_dir) {
1381: if((stat(cert_dir, &st) != 0) ||
1382: (!S_ISDIR(st.st_mode))) {
1383: cert_dir = NULL;
1384: }
1385: }
1386:
1387: /* Now we check if the default location is a valid dir */
1388: if(!cert_dir) {
1389: if((stat(SSL_DIR, &st) == 0) &&
1390: (S_ISDIR(st.st_mode))) {
1391: cert_dir = (char *)SSL_DIR;
1392: }
1393: }
1394:
1395: if(nspr_io_identity == PR_INVALID_IO_LAYER) {
1396: /* allocate an identity for our own NSPR I/O layer */
1397: nspr_io_identity = PR_GetUniqueIdentity("libcurl");
1398: if(nspr_io_identity == PR_INVALID_IO_LAYER)
1399: return CURLE_OUT_OF_MEMORY;
1400:
1401: /* the default methods just call down to the lower I/O layer */
1402: memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(),
1403: sizeof(nspr_io_methods));
1404:
1405: /* override certain methods in the table by our wrappers */
1406: nspr_io_methods.recv = nspr_io_recv;
1407: nspr_io_methods.send = nspr_io_send;
1408: nspr_io_methods.close = nspr_io_close;
1409: }
1410:
1411: result = nss_init_core(data, cert_dir);
1412: if(result)
1413: return result;
1414:
1415: if(!any_cipher_enabled())
1416: NSS_SetDomesticPolicy();
1417:
1418: initialized = 1;
1419:
1420: return CURLE_OK;
1421: }
1422:
1423: /**
1424: * Global SSL init
1425: *
1426: * @retval 0 error initializing SSL
1427: * @retval 1 SSL initialized successfully
1428: */
1429: static int Curl_nss_init(void)
1430: {
1431: /* curl_global_init() is not thread-safe so this test is ok */
1432: if(nss_initlock == NULL) {
1433: PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
1434: nss_initlock = PR_NewLock();
1435: nss_crllock = PR_NewLock();
1436: nss_findslot_lock = PR_NewLock();
1437: nss_trustload_lock = PR_NewLock();
1438: }
1439:
1440: /* We will actually initialize NSS later */
1441:
1442: return 1;
1443: }
1444:
1445: /* data might be NULL */
1446: CURLcode Curl_nss_force_init(struct Curl_easy *data)
1447: {
1448: CURLcode result;
1449: if(!nss_initlock) {
1450: if(data)
1451: failf(data, "unable to initialize NSS, curl_global_init() should have "
1452: "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
1453: return CURLE_FAILED_INIT;
1454: }
1455:
1456: PR_Lock(nss_initlock);
1457: result = nss_init(data);
1458: PR_Unlock(nss_initlock);
1459:
1460: return result;
1461: }
1462:
1463: /* Global cleanup */
1464: static void Curl_nss_cleanup(void)
1465: {
1466: /* This function isn't required to be threadsafe and this is only done
1467: * as a safety feature.
1468: */
1469: PR_Lock(nss_initlock);
1470: if(initialized) {
1471: /* Free references to client certificates held in the SSL session cache.
1472: * Omitting this hampers destruction of the security module owning
1473: * the certificates. */
1474: SSL_ClearSessionCache();
1475:
1476: nss_unload_module(&pem_module);
1477: nss_unload_module(&trust_module);
1478: NSS_ShutdownContext(nss_context);
1479: nss_context = NULL;
1480: }
1481:
1482: /* destroy all CRL items */
1483: Curl_llist_destroy(&nss_crl_list, NULL);
1484:
1485: PR_Unlock(nss_initlock);
1486:
1487: PR_DestroyLock(nss_initlock);
1488: PR_DestroyLock(nss_crllock);
1489: PR_DestroyLock(nss_findslot_lock);
1490: PR_DestroyLock(nss_trustload_lock);
1491: nss_initlock = NULL;
1492:
1493: initialized = 0;
1494: }
1495:
1496: /*
1497: * This function uses SSL_peek to determine connection status.
1498: *
1499: * Return codes:
1500: * 1 means the connection is still in place
1501: * 0 means the connection has been closed
1502: * -1 means the connection status is unknown
1503: */
1504: static int Curl_nss_check_cxn(struct connectdata *conn)
1505: {
1506: struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
1507: struct ssl_backend_data *backend = connssl->backend;
1508: int rc;
1509: char buf;
1510:
1511: rc =
1512: PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK,
1513: PR_SecondsToInterval(1));
1514: if(rc > 0)
1515: return 1; /* connection still in place */
1516:
1517: if(rc == 0)
1518: return 0; /* connection has been closed */
1519:
1520: return -1; /* connection status unknown */
1521: }
1522:
1523: static void nss_close(struct ssl_connect_data *connssl)
1524: {
1525: /* before the cleanup, check whether we are using a client certificate */
1526: struct ssl_backend_data *backend = connssl->backend;
1527: const bool client_cert = (backend->client_nickname != NULL)
1528: || (backend->obj_clicert != NULL);
1529:
1530: free(backend->client_nickname);
1531: backend->client_nickname = NULL;
1532:
1533: /* destroy all NSS objects in order to avoid failure of NSS shutdown */
1534: Curl_llist_destroy(&backend->obj_list, NULL);
1535: backend->obj_clicert = NULL;
1536:
1537: if(backend->handle) {
1538: if(client_cert)
1539: /* A server might require different authentication based on the
1540: * particular path being requested by the client. To support this
1541: * scenario, we must ensure that a connection will never reuse the
1542: * authentication data from a previous connection. */
1543: SSL_InvalidateSession(backend->handle);
1544:
1545: PR_Close(backend->handle);
1546: backend->handle = NULL;
1547: }
1548: }
1549:
1550: /*
1551: * This function is called when an SSL connection is closed.
1552: */
1553: static void Curl_nss_close(struct connectdata *conn, int sockindex)
1554: {
1555: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1556: struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
1557: struct ssl_backend_data *backend = connssl->backend;
1558:
1559: if(backend->handle || connssl_proxy->backend->handle) {
1560: /* NSS closes the socket we previously handed to it, so we must mark it
1561: as closed to avoid double close */
1562: fake_sclose(conn->sock[sockindex]);
1563: conn->sock[sockindex] = CURL_SOCKET_BAD;
1564: }
1565:
1566: if(backend->handle)
1567: /* nss_close(connssl) will transitively close also
1568: connssl_proxy->backend->handle if both are used. Clear it to avoid
1569: a double close leading to crash. */
1570: connssl_proxy->backend->handle = NULL;
1571:
1572: nss_close(connssl);
1573: nss_close(connssl_proxy);
1574: }
1575:
1576: /* return true if NSS can provide error code (and possibly msg) for the
1577: error */
1578: static bool is_nss_error(CURLcode err)
1579: {
1580: switch(err) {
1581: case CURLE_PEER_FAILED_VERIFICATION:
1582: case CURLE_SSL_CERTPROBLEM:
1583: case CURLE_SSL_CONNECT_ERROR:
1584: case CURLE_SSL_ISSUER_ERROR:
1585: return true;
1586:
1587: default:
1588: return false;
1589: }
1590: }
1591:
1592: /* return true if the given error code is related to a client certificate */
1593: static bool is_cc_error(PRInt32 err)
1594: {
1595: switch(err) {
1596: case SSL_ERROR_BAD_CERT_ALERT:
1597: case SSL_ERROR_EXPIRED_CERT_ALERT:
1598: case SSL_ERROR_REVOKED_CERT_ALERT:
1599: return true;
1600:
1601: default:
1602: return false;
1603: }
1604: }
1605:
1606: static Curl_recv nss_recv;
1607: static Curl_send nss_send;
1608:
1609: static CURLcode nss_load_ca_certificates(struct connectdata *conn,
1610: int sockindex)
1611: {
1612: struct Curl_easy *data = conn->data;
1613: const char *cafile = SSL_CONN_CONFIG(CAfile);
1614: const char *capath = SSL_CONN_CONFIG(CApath);
1615: bool use_trust_module;
1616: CURLcode result = CURLE_OK;
1617:
1618: /* treat empty string as unset */
1619: if(cafile && !cafile[0])
1620: cafile = NULL;
1621: if(capath && !capath[0])
1622: capath = NULL;
1623:
1624: infof(data, " CAfile: %s\n CApath: %s\n",
1625: cafile ? cafile : "none",
1626: capath ? capath : "none");
1627:
1628: /* load libnssckbi.so if no other trust roots were specified */
1629: use_trust_module = !cafile && !capath;
1630:
1631: PR_Lock(nss_trustload_lock);
1632: if(use_trust_module && !trust_module) {
1633: /* libnssckbi.so needed but not yet loaded --> load it! */
1634: result = nss_load_module(&trust_module, trust_library, "trust");
1635: infof(data, "%s %s\n", (result) ? "failed to load" : "loaded",
1636: trust_library);
1637: if(result == CURLE_FAILED_INIT)
1638: /* If libnssckbi.so is not available (or fails to load), one can still
1639: use CA certificates stored in NSS database. Ignore the failure. */
1640: result = CURLE_OK;
1641: }
1642: else if(!use_trust_module && trust_module) {
1643: /* libnssckbi.so not needed but already loaded --> unload it! */
1644: infof(data, "unloading %s\n", trust_library);
1645: nss_unload_module(&trust_module);
1646: }
1647: PR_Unlock(nss_trustload_lock);
1648:
1649: if(cafile)
1650: result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
1651:
1652: if(result)
1653: return result;
1654:
1655: if(capath) {
1656: struct_stat st;
1657: if(stat(capath, &st) == -1)
1658: return CURLE_SSL_CACERT_BADFILE;
1659:
1660: if(S_ISDIR(st.st_mode)) {
1661: PRDirEntry *entry;
1662: PRDir *dir = PR_OpenDir(capath);
1663: if(!dir)
1664: return CURLE_SSL_CACERT_BADFILE;
1665:
1666: while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
1667: char *fullpath = aprintf("%s/%s", capath, entry->name);
1668: if(!fullpath) {
1669: PR_CloseDir(dir);
1670: return CURLE_OUT_OF_MEMORY;
1671: }
1672:
1673: if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
1674: /* This is purposefully tolerant of errors so non-PEM files can
1675: * be in the same directory */
1676: infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
1677:
1678: free(fullpath);
1679: }
1680:
1681: PR_CloseDir(dir);
1682: }
1683: else
1684: infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
1685: }
1686:
1687: return CURLE_OK;
1688: }
1689:
1690: static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
1691: {
1692: switch(version) {
1693: case CURL_SSLVERSION_SSLv2:
1694: *nssver = SSL_LIBRARY_VERSION_2;
1695: return CURLE_OK;
1696:
1697: case CURL_SSLVERSION_SSLv3:
1698: *nssver = SSL_LIBRARY_VERSION_3_0;
1699: return CURLE_OK;
1700:
1701: case CURL_SSLVERSION_TLSv1_0:
1702: *nssver = SSL_LIBRARY_VERSION_TLS_1_0;
1703: return CURLE_OK;
1704:
1705: case CURL_SSLVERSION_TLSv1_1:
1706: #ifdef SSL_LIBRARY_VERSION_TLS_1_1
1707: *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
1708: return CURLE_OK;
1709: #else
1710: return CURLE_SSL_CONNECT_ERROR;
1711: #endif
1712:
1713: case CURL_SSLVERSION_TLSv1_2:
1714: #ifdef SSL_LIBRARY_VERSION_TLS_1_2
1715: *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
1716: return CURLE_OK;
1717: #else
1718: return CURLE_SSL_CONNECT_ERROR;
1719: #endif
1720:
1721: case CURL_SSLVERSION_TLSv1_3:
1722: #ifdef SSL_LIBRARY_VERSION_TLS_1_3
1723: *nssver = SSL_LIBRARY_VERSION_TLS_1_3;
1724: return CURLE_OK;
1725: #else
1726: return CURLE_SSL_CONNECT_ERROR;
1727: #endif
1728:
1729: default:
1730: return CURLE_SSL_CONNECT_ERROR;
1731: }
1732: }
1733:
1734: static CURLcode nss_init_sslver(SSLVersionRange *sslver,
1735: struct Curl_easy *data,
1736: struct connectdata *conn)
1737: {
1738: CURLcode result;
1739: const long min = SSL_CONN_CONFIG(version);
1740: const long max = SSL_CONN_CONFIG(version_max);
1741: SSLVersionRange vrange;
1742:
1743: switch(min) {
1744: case CURL_SSLVERSION_TLSv1:
1745: case CURL_SSLVERSION_DEFAULT:
1746: /* Bump our minimum TLS version if NSS has stricter requirements. */
1747: if(SSL_VersionRangeGetDefault(ssl_variant_stream, &vrange) != SECSuccess)
1748: return CURLE_SSL_CONNECT_ERROR;
1749: if(sslver->min < vrange.min)
1750: sslver->min = vrange.min;
1751: break;
1752: default:
1753: result = nss_sslver_from_curl(&sslver->min, min);
1754: if(result) {
1755: failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
1756: return result;
1757: }
1758: }
1759:
1760: switch(max) {
1761: case CURL_SSLVERSION_MAX_NONE:
1762: case CURL_SSLVERSION_MAX_DEFAULT:
1763: break;
1764: default:
1765: result = nss_sslver_from_curl(&sslver->max, max >> 16);
1766: if(result) {
1767: failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
1768: return result;
1769: }
1770: }
1771:
1772: return CURLE_OK;
1773: }
1774:
1775: static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
1776: struct Curl_easy *data,
1777: CURLcode curlerr)
1778: {
1779: PRErrorCode err = 0;
1780: struct ssl_backend_data *backend = connssl->backend;
1781:
1782: if(is_nss_error(curlerr)) {
1783: /* read NSPR error code */
1784: err = PR_GetError();
1785: if(is_cc_error(err))
1786: curlerr = CURLE_SSL_CERTPROBLEM;
1787:
1788: /* print the error number and error string */
1789: infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
1790:
1791: /* print a human-readable message describing the error if available */
1792: nss_print_error_message(data, err);
1793: }
1794:
1795: /* cleanup on connection failure */
1796: Curl_llist_destroy(&backend->obj_list, NULL);
1797:
1798: return curlerr;
1799: }
1800:
1801: /* Switch the SSL socket into blocking or non-blocking mode. */
1802: static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
1803: struct Curl_easy *data,
1804: bool blocking)
1805: {
1806: static PRSocketOptionData sock_opt;
1807: struct ssl_backend_data *backend = connssl->backend;
1808: sock_opt.option = PR_SockOpt_Nonblocking;
1809: sock_opt.value.non_blocking = !blocking;
1810:
1811: if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS)
1812: return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
1813:
1814: return CURLE_OK;
1815: }
1816:
1817: static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
1818: {
1819: PRFileDesc *model = NULL;
1820: PRFileDesc *nspr_io = NULL;
1821: PRFileDesc *nspr_io_stub = NULL;
1822: PRBool ssl_no_cache;
1823: PRBool ssl_cbc_random_iv;
1824: struct Curl_easy *data = conn->data;
1825: curl_socket_t sockfd = conn->sock[sockindex];
1826: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1827: struct ssl_backend_data *backend = connssl->backend;
1828: CURLcode result;
1829: bool second_layer = FALSE;
1830: SSLVersionRange sslver_supported;
1831:
1832: SSLVersionRange sslver = {
1833: SSL_LIBRARY_VERSION_TLS_1_0, /* min */
1834: #ifdef SSL_LIBRARY_VERSION_TLS_1_3
1835: SSL_LIBRARY_VERSION_TLS_1_3 /* max */
1836: #elif defined SSL_LIBRARY_VERSION_TLS_1_2
1837: SSL_LIBRARY_VERSION_TLS_1_2
1838: #elif defined SSL_LIBRARY_VERSION_TLS_1_1
1839: SSL_LIBRARY_VERSION_TLS_1_1
1840: #else
1841: SSL_LIBRARY_VERSION_TLS_1_0
1842: #endif
1843: };
1844:
1845: backend->data = data;
1846:
1847: /* list of all NSS objects we need to destroy in Curl_nss_close() */
1848: Curl_llist_init(&backend->obj_list, nss_destroy_object);
1849:
1850: PR_Lock(nss_initlock);
1851: result = nss_init(conn->data);
1852: if(result) {
1853: PR_Unlock(nss_initlock);
1854: goto error;
1855: }
1856:
1857: PK11_SetPasswordFunc(nss_get_password);
1858:
1859: result = nss_load_module(&pem_module, pem_library, "PEM");
1860: PR_Unlock(nss_initlock);
1861: if(result == CURLE_FAILED_INIT)
1862: infof(data, "WARNING: failed to load NSS PEM library %s. Using "
1863: "OpenSSL PEM certificates will not work.\n", pem_library);
1864: else if(result)
1865: goto error;
1866:
1867: result = CURLE_SSL_CONNECT_ERROR;
1868:
1869: model = PR_NewTCPSocket();
1870: if(!model)
1871: goto error;
1872: model = SSL_ImportFD(NULL, model);
1873:
1874: if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
1875: goto error;
1876: if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
1877: goto error;
1878: if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
1879: goto error;
1880:
1881: /* do not use SSL cache if disabled or we are not going to verify peer */
1882: ssl_no_cache = (SSL_SET_OPTION(primary.sessionid)
1883: && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
1884: if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
1885: goto error;
1886:
1887: /* enable/disable the requested SSL version(s) */
1888: if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
1889: goto error;
1890: if(SSL_VersionRangeGetSupported(ssl_variant_stream,
1891: &sslver_supported) != SECSuccess)
1892: goto error;
1893: if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) {
1894: char *sslver_req_str, *sslver_supp_str;
1895: sslver_req_str = nss_sslver_to_name(sslver.max);
1896: sslver_supp_str = nss_sslver_to_name(sslver_supported.max);
1897: if(sslver_req_str && sslver_supp_str)
1898: infof(data, "Falling back from %s to max supported SSL version (%s)\n",
1899: sslver_req_str, sslver_supp_str);
1900: free(sslver_req_str);
1901: free(sslver_supp_str);
1902: sslver.max = sslver_supported.max;
1903: }
1904: if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
1905: goto error;
1906:
1907: ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
1908: #ifdef SSL_CBC_RANDOM_IV
1909: /* unless the user explicitly asks to allow the protocol vulnerability, we
1910: use the work-around */
1911: if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
1912: infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n",
1913: ssl_cbc_random_iv);
1914: #else
1915: if(ssl_cbc_random_iv)
1916: infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
1917: #endif
1918:
1919: if(SSL_CONN_CONFIG(cipher_list)) {
1920: if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
1921: result = CURLE_SSL_CIPHER;
1922: goto error;
1923: }
1924: }
1925:
1926: if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
1927: infof(data, "warning: ignoring value of ssl.verifyhost\n");
1928:
1929: /* bypass the default SSL_AuthCertificate() hook in case we do not want to
1930: * verify peer */
1931: if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
1932: goto error;
1933:
1934: /* not checked yet */
1935: if(SSL_IS_PROXY())
1936: data->set.proxy_ssl.certverifyresult = 0;
1937: else
1938: data->set.ssl.certverifyresult = 0;
1939:
1940: if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
1941: goto error;
1942:
1943: if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess)
1944: goto error;
1945:
1946: {
1947: const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
1948: if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
1949: /* not a fatal error because we are not going to verify the peer */
1950: infof(data, "warning: CA certificates failed to load\n");
1951: else if(rv) {
1952: result = rv;
1953: goto error;
1954: }
1955: }
1956:
1957: if(SSL_SET_OPTION(CRLfile)) {
1958: const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile));
1959: if(rv) {
1960: result = rv;
1961: goto error;
1962: }
1963: infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile));
1964: }
1965:
1966: if(SSL_SET_OPTION(cert)) {
1967: char *nickname = dup_nickname(data, SSL_SET_OPTION(cert));
1968: if(nickname) {
1969: /* we are not going to use libnsspem.so to read the client cert */
1970: backend->obj_clicert = NULL;
1971: }
1972: else {
1973: CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert),
1974: SSL_SET_OPTION(key));
1975: if(rv) {
1976: /* failf() is already done in cert_stuff() */
1977: result = rv;
1978: goto error;
1979: }
1980: }
1981:
1982: /* store the nickname for SelectClientCert() called during handshake */
1983: backend->client_nickname = nickname;
1984: }
1985: else
1986: backend->client_nickname = NULL;
1987:
1988: if(SSL_GetClientAuthDataHook(model, SelectClientCert,
1989: (void *)connssl) != SECSuccess) {
1990: result = CURLE_SSL_CERTPROBLEM;
1991: goto error;
1992: }
1993:
1994: if(conn->proxy_ssl[sockindex].use) {
1995: DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
1996: DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL);
1997: nspr_io = conn->proxy_ssl[sockindex].backend->handle;
1998: second_layer = TRUE;
1999: }
2000: else {
2001: /* wrap OS file descriptor by NSPR's file descriptor abstraction */
2002: nspr_io = PR_ImportTCPSocket(sockfd);
2003: if(!nspr_io)
2004: goto error;
2005: }
2006:
2007: /* create our own NSPR I/O layer */
2008: nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
2009: if(!nspr_io_stub) {
2010: if(!second_layer)
2011: PR_Close(nspr_io);
2012: goto error;
2013: }
2014:
2015: /* make the per-connection data accessible from NSPR I/O callbacks */
2016: nspr_io_stub->secret = (void *)connssl;
2017:
2018: /* push our new layer to the NSPR I/O stack */
2019: if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
2020: if(!second_layer)
2021: PR_Close(nspr_io);
2022: PR_Close(nspr_io_stub);
2023: goto error;
2024: }
2025:
2026: /* import our model socket onto the current I/O stack */
2027: backend->handle = SSL_ImportFD(model, nspr_io);
2028: if(!backend->handle) {
2029: if(!second_layer)
2030: PR_Close(nspr_io);
2031: goto error;
2032: }
2033:
2034: PR_Close(model); /* We don't need this any more */
2035: model = NULL;
2036:
2037: /* This is the password associated with the cert that we're using */
2038: if(SSL_SET_OPTION(key_passwd)) {
2039: SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd));
2040: }
2041:
2042: #ifdef SSL_ENABLE_OCSP_STAPLING
2043: if(SSL_CONN_CONFIG(verifystatus)) {
2044: if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
2045: != SECSuccess)
2046: goto error;
2047: }
2048: #endif
2049:
2050: #ifdef SSL_ENABLE_NPN
2051: if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
2052: ? PR_TRUE : PR_FALSE) != SECSuccess)
2053: goto error;
2054: #endif
2055:
2056: #ifdef SSL_ENABLE_ALPN
2057: if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
2058: ? PR_TRUE : PR_FALSE) != SECSuccess)
2059: goto error;
2060: #endif
2061:
2062: #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
2063: if(data->set.ssl.falsestart) {
2064: if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
2065: != SECSuccess)
2066: goto error;
2067:
2068: if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback,
2069: conn) != SECSuccess)
2070: goto error;
2071: }
2072: #endif
2073:
2074: #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
2075: if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) {
2076: int cur = 0;
2077: unsigned char protocols[128];
2078:
2079: #ifdef USE_NGHTTP2
2080: if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
2081: (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
2082: protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
2083: memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
2084: NGHTTP2_PROTO_VERSION_ID_LEN);
2085: cur += NGHTTP2_PROTO_VERSION_ID_LEN;
2086: }
2087: #endif
2088: protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
2089: memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
2090: cur += ALPN_HTTP_1_1_LENGTH;
2091:
2092: if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess)
2093: goto error;
2094: }
2095: #endif
2096:
2097:
2098: /* Force handshake on next I/O */
2099: if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE)
2100: != SECSuccess)
2101: goto error;
2102:
2103: /* propagate hostname to the TLS layer */
2104: if(SSL_SetURL(backend->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name :
2105: conn->host.name) != SECSuccess)
2106: goto error;
2107:
2108: /* prevent NSS from re-using the session for a different hostname */
2109: if(SSL_SetSockPeerID(backend->handle, SSL_IS_PROXY() ?
2110: conn->http_proxy.host.name : conn->host.name)
2111: != SECSuccess)
2112: goto error;
2113:
2114: return CURLE_OK;
2115:
2116: error:
2117: if(model)
2118: PR_Close(model);
2119:
2120: return nss_fail_connect(connssl, data, result);
2121: }
2122:
2123: static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
2124: {
2125: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2126: struct ssl_backend_data *backend = connssl->backend;
2127: struct Curl_easy *data = conn->data;
2128: CURLcode result = CURLE_SSL_CONNECT_ERROR;
2129: PRUint32 timeout;
2130: long * const certverifyresult = SSL_IS_PROXY() ?
2131: &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
2132: const char * const pinnedpubkey = SSL_IS_PROXY() ?
2133: data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
2134: data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
2135:
2136:
2137: /* check timeout situation */
2138: const timediff_t time_left = Curl_timeleft(data, NULL, TRUE);
2139: if(time_left < 0) {
2140: failf(data, "timed out before SSL handshake");
2141: result = CURLE_OPERATION_TIMEDOUT;
2142: goto error;
2143: }
2144:
2145: /* Force the handshake now */
2146: timeout = PR_MillisecondsToInterval((PRUint32) time_left);
2147: if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) {
2148: if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
2149: /* blocking direction is updated by nss_update_connecting_state() */
2150: return CURLE_AGAIN;
2151: else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
2152: result = CURLE_PEER_FAILED_VERIFICATION;
2153: else if(*certverifyresult != 0)
2154: result = CURLE_PEER_FAILED_VERIFICATION;
2155: goto error;
2156: }
2157:
2158: result = display_conn_info(conn, backend->handle);
2159: if(result)
2160: goto error;
2161:
2162: if(SSL_SET_OPTION(issuercert)) {
2163: SECStatus ret = SECFailure;
2164: char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert));
2165: if(nickname) {
2166: /* we support only nicknames in case of issuercert for now */
2167: ret = check_issuer_cert(backend->handle, nickname);
2168: free(nickname);
2169: }
2170:
2171: if(SECFailure == ret) {
2172: infof(data, "SSL certificate issuer check failed\n");
2173: result = CURLE_SSL_ISSUER_ERROR;
2174: goto error;
2175: }
2176: else {
2177: infof(data, "SSL certificate issuer check ok\n");
2178: }
2179: }
2180:
2181: result = cmp_peer_pubkey(connssl, pinnedpubkey);
2182: if(result)
2183: /* status already printed */
2184: goto error;
2185:
2186: return CURLE_OK;
2187:
2188: error:
2189: return nss_fail_connect(connssl, data, result);
2190: }
2191:
2192: static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
2193: bool *done)
2194: {
2195: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2196: struct Curl_easy *data = conn->data;
2197: const bool blocking = (done == NULL);
2198: CURLcode result;
2199:
2200: if(connssl->state == ssl_connection_complete) {
2201: if(!blocking)
2202: *done = TRUE;
2203: return CURLE_OK;
2204: }
2205:
2206: if(connssl->connecting_state == ssl_connect_1) {
2207: result = nss_setup_connect(conn, sockindex);
2208: if(result)
2209: /* we do not expect CURLE_AGAIN from nss_setup_connect() */
2210: return result;
2211:
2212: connssl->connecting_state = ssl_connect_2;
2213: }
2214:
2215: /* enable/disable blocking mode before handshake */
2216: result = nss_set_blocking(connssl, data, blocking);
2217: if(result)
2218: return result;
2219:
2220: result = nss_do_connect(conn, sockindex);
2221: switch(result) {
2222: case CURLE_OK:
2223: break;
2224: case CURLE_AGAIN:
2225: if(!blocking)
2226: /* CURLE_AGAIN in non-blocking mode is not an error */
2227: return CURLE_OK;
2228: /* FALLTHROUGH */
2229: default:
2230: return result;
2231: }
2232:
2233: if(blocking) {
2234: /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
2235: result = nss_set_blocking(connssl, data, /* blocking */ FALSE);
2236: if(result)
2237: return result;
2238: }
2239: else
2240: /* signal completed SSL handshake */
2241: *done = TRUE;
2242:
2243: connssl->state = ssl_connection_complete;
2244: conn->recv[sockindex] = nss_recv;
2245: conn->send[sockindex] = nss_send;
2246:
2247: /* ssl_connect_done is never used outside, go back to the initial state */
2248: connssl->connecting_state = ssl_connect_1;
2249:
2250: return CURLE_OK;
2251: }
2252:
2253: static CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
2254: {
2255: return nss_connect_common(conn, sockindex, /* blocking */ NULL);
2256: }
2257:
2258: static CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
2259: int sockindex, bool *done)
2260: {
2261: return nss_connect_common(conn, sockindex, done);
2262: }
2263:
2264: static ssize_t nss_send(struct connectdata *conn, /* connection data */
2265: int sockindex, /* socketindex */
2266: const void *mem, /* send this data */
2267: size_t len, /* amount to write */
2268: CURLcode *curlcode)
2269: {
2270: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2271: struct ssl_backend_data *backend = connssl->backend;
2272: ssize_t rc;
2273:
2274: /* The SelectClientCert() hook uses this for infof() and failf() but the
2275: handle stored in nss_setup_connect() could have already been freed. */
2276: backend->data = conn->data;
2277:
2278: rc = PR_Send(backend->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT);
2279: if(rc < 0) {
2280: PRInt32 err = PR_GetError();
2281: if(err == PR_WOULD_BLOCK_ERROR)
2282: *curlcode = CURLE_AGAIN;
2283: else {
2284: /* print the error number and error string */
2285: const char *err_name = nss_error_to_name(err);
2286: infof(conn->data, "SSL write: error %d (%s)\n", err, err_name);
2287:
2288: /* print a human-readable message describing the error if available */
2289: nss_print_error_message(conn->data, err);
2290:
2291: *curlcode = (is_cc_error(err))
2292: ? CURLE_SSL_CERTPROBLEM
2293: : CURLE_SEND_ERROR;
2294: }
2295:
2296: return -1;
2297: }
2298:
2299: return rc; /* number of bytes */
2300: }
2301:
2302: static ssize_t nss_recv(struct connectdata *conn, /* connection data */
2303: int sockindex, /* socketindex */
2304: char *buf, /* store read data here */
2305: size_t buffersize, /* max amount to read */
2306: CURLcode *curlcode)
2307: {
2308: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2309: struct ssl_backend_data *backend = connssl->backend;
2310: ssize_t nread;
2311:
2312: /* The SelectClientCert() hook uses this for infof() and failf() but the
2313: handle stored in nss_setup_connect() could have already been freed. */
2314: backend->data = conn->data;
2315:
2316: nread = PR_Recv(backend->handle, buf, (int)buffersize, 0,
2317: PR_INTERVAL_NO_WAIT);
2318: if(nread < 0) {
2319: /* failed SSL read */
2320: PRInt32 err = PR_GetError();
2321:
2322: if(err == PR_WOULD_BLOCK_ERROR)
2323: *curlcode = CURLE_AGAIN;
2324: else {
2325: /* print the error number and error string */
2326: const char *err_name = nss_error_to_name(err);
2327: infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name);
2328:
2329: /* print a human-readable message describing the error if available */
2330: nss_print_error_message(conn->data, err);
2331:
2332: *curlcode = (is_cc_error(err))
2333: ? CURLE_SSL_CERTPROBLEM
2334: : CURLE_RECV_ERROR;
2335: }
2336:
2337: return -1;
2338: }
2339:
2340: return nread;
2341: }
2342:
2343: static size_t Curl_nss_version(char *buffer, size_t size)
2344: {
2345: return msnprintf(buffer, size, "NSS/%s", NSS_VERSION);
2346: }
2347:
2348: /* data might be NULL */
2349: static int Curl_nss_seed(struct Curl_easy *data)
2350: {
2351: /* make sure that NSS is initialized */
2352: return !!Curl_nss_force_init(data);
2353: }
2354:
2355: /* data might be NULL */
2356: static CURLcode Curl_nss_random(struct Curl_easy *data,
2357: unsigned char *entropy,
2358: size_t length)
2359: {
2360: Curl_nss_seed(data); /* Initiate the seed if not already done */
2361:
2362: if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length)))
2363: /* signal a failure */
2364: return CURLE_FAILED_INIT;
2365:
2366: return CURLE_OK;
2367: }
2368:
2369: static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */
2370: size_t tmplen,
2371: unsigned char *md5sum, /* output */
2372: size_t md5len)
2373: {
2374: PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
2375: unsigned int MD5out;
2376:
2377: if(!MD5pw)
2378: return CURLE_NOT_BUILT_IN;
2379:
2380: PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen));
2381: PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len));
2382: PK11_DestroyContext(MD5pw, PR_TRUE);
2383:
2384: return CURLE_OK;
2385: }
2386:
2387: static CURLcode Curl_nss_sha256sum(const unsigned char *tmp, /* input */
2388: size_t tmplen,
2389: unsigned char *sha256sum, /* output */
2390: size_t sha256len)
2391: {
2392: PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256);
2393: unsigned int SHA256out;
2394:
2395: if(!SHA256pw)
2396: return CURLE_NOT_BUILT_IN;
2397:
2398: PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen));
2399: PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len));
2400: PK11_DestroyContext(SHA256pw, PR_TRUE);
2401:
2402: return CURLE_OK;
2403: }
2404:
2405: static bool Curl_nss_cert_status_request(void)
2406: {
2407: #ifdef SSL_ENABLE_OCSP_STAPLING
2408: return TRUE;
2409: #else
2410: return FALSE;
2411: #endif
2412: }
2413:
2414: static bool Curl_nss_false_start(void)
2415: {
2416: #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
2417: return TRUE;
2418: #else
2419: return FALSE;
2420: #endif
2421: }
2422:
2423: static void *Curl_nss_get_internals(struct ssl_connect_data *connssl,
2424: CURLINFO info UNUSED_PARAM)
2425: {
2426: struct ssl_backend_data *backend = connssl->backend;
2427: (void)info;
2428: return backend->handle;
2429: }
2430:
2431: const struct Curl_ssl Curl_ssl_nss = {
2432: { CURLSSLBACKEND_NSS, "nss" }, /* info */
2433:
2434: SSLSUPP_CA_PATH |
2435: SSLSUPP_CERTINFO |
2436: SSLSUPP_PINNEDPUBKEY |
2437: SSLSUPP_HTTPS_PROXY,
2438:
2439: sizeof(struct ssl_backend_data),
2440:
2441: Curl_nss_init, /* init */
2442: Curl_nss_cleanup, /* cleanup */
2443: Curl_nss_version, /* version */
2444: Curl_nss_check_cxn, /* check_cxn */
2445: /* NSS has no shutdown function provided and thus always fail */
2446: Curl_none_shutdown, /* shutdown */
2447: Curl_none_data_pending, /* data_pending */
2448: Curl_nss_random, /* random */
2449: Curl_nss_cert_status_request, /* cert_status_request */
2450: Curl_nss_connect, /* connect */
2451: Curl_nss_connect_nonblocking, /* connect_nonblocking */
2452: Curl_nss_get_internals, /* get_internals */
2453: Curl_nss_close, /* close_one */
2454: Curl_none_close_all, /* close_all */
2455: /* NSS has its own session ID cache */
2456: Curl_none_session_free, /* session_free */
2457: Curl_none_set_engine, /* set_engine */
2458: Curl_none_set_engine_default, /* set_engine_default */
2459: Curl_none_engines_list, /* engines_list */
2460: Curl_nss_false_start, /* false_start */
2461: Curl_nss_md5sum, /* md5sum */
2462: Curl_nss_sha256sum /* sha256sum */
2463: };
2464:
2465: #endif /* USE_NSS */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>