Annotation of embedaddon/curl/lib/vtls/vtls.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: /* This file is for implementing all "generic" SSL functions that all libcurl
24: internals should use. It is then responsible for calling the proper
25: "backend" function.
26:
27: SSL-functions in libcurl should call functions in this source file, and not
28: to any specific SSL-layer.
29:
30: Curl_ssl_ - prefix for generic ones
31:
32: Note that this source code uses the functions of the configured SSL
33: backend via the global Curl_ssl instance.
34:
35: "SSL/TLS Strong Encryption: An Introduction"
36: https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
37: */
38:
39: #include "curl_setup.h"
40:
41: #ifdef HAVE_SYS_TYPES_H
42: #include <sys/types.h>
43: #endif
44: #ifdef HAVE_SYS_STAT_H
45: #include <sys/stat.h>
46: #endif
47: #ifdef HAVE_FCNTL_H
48: #include <fcntl.h>
49: #endif
50:
51: #include "urldata.h"
52:
53: #include "vtls.h" /* generic SSL protos etc */
54: #include "slist.h"
55: #include "sendf.h"
56: #include "strcase.h"
57: #include "url.h"
58: #include "progress.h"
59: #include "share.h"
60: #include "multiif.h"
61: #include "timeval.h"
62: #include "curl_md5.h"
63: #include "warnless.h"
64: #include "curl_base64.h"
65: #include "curl_printf.h"
66:
67: /* The last #include files should be: */
68: #include "curl_memory.h"
69: #include "memdebug.h"
70:
71: /* convenience macro to check if this handle is using a shared SSL session */
72: #define SSLSESSION_SHARED(data) (data->share && \
73: (data->share->specifier & \
74: (1<<CURL_LOCK_DATA_SSL_SESSION)))
75:
76: #define CLONE_STRING(var) \
77: if(source->var) { \
78: dest->var = strdup(source->var); \
79: if(!dest->var) \
80: return FALSE; \
81: } \
82: else \
83: dest->var = NULL;
84:
85: bool
86: Curl_ssl_config_matches(struct ssl_primary_config* data,
87: struct ssl_primary_config* needle)
88: {
89: if((data->version == needle->version) &&
90: (data->version_max == needle->version_max) &&
91: (data->verifypeer == needle->verifypeer) &&
92: (data->verifyhost == needle->verifyhost) &&
93: (data->verifystatus == needle->verifystatus) &&
94: Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
95: Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
96: Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
97: Curl_safe_strcasecompare(data->random_file, needle->random_file) &&
98: Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
99: Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) &&
100: Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) &&
101: Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key))
102: return TRUE;
103:
104: return FALSE;
105: }
106:
107: bool
108: Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
109: struct ssl_primary_config *dest)
110: {
111: dest->version = source->version;
112: dest->version_max = source->version_max;
113: dest->verifypeer = source->verifypeer;
114: dest->verifyhost = source->verifyhost;
115: dest->verifystatus = source->verifystatus;
116: dest->sessionid = source->sessionid;
117:
118: CLONE_STRING(CApath);
119: CLONE_STRING(CAfile);
120: CLONE_STRING(clientcert);
121: CLONE_STRING(random_file);
122: CLONE_STRING(egdsocket);
123: CLONE_STRING(cipher_list);
124: CLONE_STRING(cipher_list13);
125: CLONE_STRING(pinned_key);
126:
127: return TRUE;
128: }
129:
130: void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
131: {
132: Curl_safefree(sslc->CApath);
133: Curl_safefree(sslc->CAfile);
134: Curl_safefree(sslc->clientcert);
135: Curl_safefree(sslc->random_file);
136: Curl_safefree(sslc->egdsocket);
137: Curl_safefree(sslc->cipher_list);
138: Curl_safefree(sslc->cipher_list13);
139: Curl_safefree(sslc->pinned_key);
140: }
141:
142: #ifdef USE_SSL
143: static int multissl_init(const struct Curl_ssl *backend);
144: #endif
145:
146: int Curl_ssl_backend(void)
147: {
148: #ifdef USE_SSL
149: multissl_init(NULL);
150: return Curl_ssl->info.id;
151: #else
152: return (int)CURLSSLBACKEND_NONE;
153: #endif
154: }
155:
156: #ifdef USE_SSL
157:
158: /* "global" init done? */
159: static bool init_ssl = FALSE;
160:
161: /**
162: * Global SSL init
163: *
164: * @retval 0 error initializing SSL
165: * @retval 1 SSL initialized successfully
166: */
167: int Curl_ssl_init(void)
168: {
169: /* make sure this is only done once */
170: if(init_ssl)
171: return 1;
172: init_ssl = TRUE; /* never again */
173:
174: return Curl_ssl->init();
175: }
176:
177: #if defined(CURL_WITH_MULTI_SSL)
178: static const struct Curl_ssl Curl_ssl_multi;
179: #endif
180:
181: /* Global cleanup */
182: void Curl_ssl_cleanup(void)
183: {
184: if(init_ssl) {
185: /* only cleanup if we did a previous init */
186: Curl_ssl->cleanup();
187: #if defined(CURL_WITH_MULTI_SSL)
188: Curl_ssl = &Curl_ssl_multi;
189: #endif
190: init_ssl = FALSE;
191: }
192: }
193:
194: static bool ssl_prefs_check(struct Curl_easy *data)
195: {
196: /* check for CURLOPT_SSLVERSION invalid parameter value */
197: const long sslver = data->set.ssl.primary.version;
198: if((sslver < 0) || (sslver >= CURL_SSLVERSION_LAST)) {
199: failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
200: return FALSE;
201: }
202:
203: switch(data->set.ssl.primary.version_max) {
204: case CURL_SSLVERSION_MAX_NONE:
205: case CURL_SSLVERSION_MAX_DEFAULT:
206: break;
207:
208: default:
209: if((data->set.ssl.primary.version_max >> 16) < sslver) {
210: failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION");
211: return FALSE;
212: }
213: }
214:
215: return TRUE;
216: }
217:
218: static CURLcode
219: ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
220: {
221: DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
222: if(ssl_connection_complete == conn->ssl[sockindex].state &&
223: !conn->proxy_ssl[sockindex].use) {
224: struct ssl_backend_data *pbdata;
225:
226: if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
227: return CURLE_NOT_BUILT_IN;
228:
229: /* The pointers to the ssl backend data, which is opaque here, are swapped
230: rather than move the contents. */
231: pbdata = conn->proxy_ssl[sockindex].backend;
232: conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
233:
234: memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
235: memset(pbdata, 0, Curl_ssl->sizeof_ssl_backend_data);
236:
237: conn->ssl[sockindex].backend = pbdata;
238: }
239: return CURLE_OK;
240: }
241:
242: CURLcode
243: Curl_ssl_connect(struct connectdata *conn, int sockindex)
244: {
245: CURLcode result;
246:
247: if(conn->bits.proxy_ssl_connected[sockindex]) {
248: result = ssl_connect_init_proxy(conn, sockindex);
249: if(result)
250: return result;
251: }
252:
253: if(!ssl_prefs_check(conn->data))
254: return CURLE_SSL_CONNECT_ERROR;
255:
256: /* mark this is being ssl-enabled from here on. */
257: conn->ssl[sockindex].use = TRUE;
258: conn->ssl[sockindex].state = ssl_connection_negotiating;
259:
260: result = Curl_ssl->connect_blocking(conn, sockindex);
261:
262: if(!result)
263: Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
264:
265: return result;
266: }
267:
268: CURLcode
269: Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
270: bool *done)
271: {
272: CURLcode result;
273: if(conn->bits.proxy_ssl_connected[sockindex]) {
274: result = ssl_connect_init_proxy(conn, sockindex);
275: if(result)
276: return result;
277: }
278:
279: if(!ssl_prefs_check(conn->data))
280: return CURLE_SSL_CONNECT_ERROR;
281:
282: /* mark this is being ssl requested from here on. */
283: conn->ssl[sockindex].use = TRUE;
284: result = Curl_ssl->connect_nonblocking(conn, sockindex, done);
285: if(!result && *done)
286: Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
287: return result;
288: }
289:
290: /*
291: * Lock shared SSL session data
292: */
293: void Curl_ssl_sessionid_lock(struct connectdata *conn)
294: {
295: if(SSLSESSION_SHARED(conn->data))
296: Curl_share_lock(conn->data,
297: CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
298: }
299:
300: /*
301: * Unlock shared SSL session data
302: */
303: void Curl_ssl_sessionid_unlock(struct connectdata *conn)
304: {
305: if(SSLSESSION_SHARED(conn->data))
306: Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION);
307: }
308:
309: /*
310: * Check if there's a session ID for the given connection in the cache, and if
311: * there's one suitable, it is provided. Returns TRUE when no entry matched.
312: */
313: bool Curl_ssl_getsessionid(struct connectdata *conn,
314: void **ssl_sessionid,
315: size_t *idsize, /* set 0 if unknown */
316: int sockindex)
317: {
318: struct curl_ssl_session *check;
319: struct Curl_easy *data = conn->data;
320: size_t i;
321: long *general_age;
322: bool no_match = TRUE;
323:
324: const bool isProxy = CONNECT_PROXY_SSL();
325: struct ssl_primary_config * const ssl_config = isProxy ?
326: &conn->proxy_ssl_config :
327: &conn->ssl_config;
328: const char * const name = isProxy ? conn->http_proxy.host.name :
329: conn->host.name;
330: int port = isProxy ? (int)conn->port : conn->remote_port;
331: *ssl_sessionid = NULL;
332:
333: DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
334:
335: if(!SSL_SET_OPTION(primary.sessionid))
336: /* session ID re-use is disabled */
337: return TRUE;
338:
339: /* Lock if shared */
340: if(SSLSESSION_SHARED(data))
341: general_age = &data->share->sessionage;
342: else
343: general_age = &data->state.sessionage;
344:
345: for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
346: check = &data->state.session[i];
347: if(!check->sessionid)
348: /* not session ID means blank entry */
349: continue;
350: if(strcasecompare(name, check->name) &&
351: ((!conn->bits.conn_to_host && !check->conn_to_host) ||
352: (conn->bits.conn_to_host && check->conn_to_host &&
353: strcasecompare(conn->conn_to_host.name, check->conn_to_host))) &&
354: ((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
355: (conn->bits.conn_to_port && check->conn_to_port != -1 &&
356: conn->conn_to_port == check->conn_to_port)) &&
357: (port == check->remote_port) &&
358: strcasecompare(conn->handler->scheme, check->scheme) &&
359: Curl_ssl_config_matches(ssl_config, &check->ssl_config)) {
360: /* yes, we have a session ID! */
361: (*general_age)++; /* increase general age */
362: check->age = *general_age; /* set this as used in this age */
363: *ssl_sessionid = check->sessionid;
364: if(idsize)
365: *idsize = check->idsize;
366: no_match = FALSE;
367: break;
368: }
369: }
370:
371: return no_match;
372: }
373:
374: /*
375: * Kill a single session ID entry in the cache.
376: */
377: void Curl_ssl_kill_session(struct curl_ssl_session *session)
378: {
379: if(session->sessionid) {
380: /* defensive check */
381:
382: /* free the ID the SSL-layer specific way */
383: Curl_ssl->session_free(session->sessionid);
384:
385: session->sessionid = NULL;
386: session->age = 0; /* fresh */
387:
388: Curl_free_primary_ssl_config(&session->ssl_config);
389:
390: Curl_safefree(session->name);
391: Curl_safefree(session->conn_to_host);
392: }
393: }
394:
395: /*
396: * Delete the given session ID from the cache.
397: */
398: void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
399: {
400: size_t i;
401: struct Curl_easy *data = conn->data;
402:
403: for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
404: struct curl_ssl_session *check = &data->state.session[i];
405:
406: if(check->sessionid == ssl_sessionid) {
407: Curl_ssl_kill_session(check);
408: break;
409: }
410: }
411: }
412:
413: /*
414: * Store session id in the session cache. The ID passed on to this function
415: * must already have been extracted and allocated the proper way for the SSL
416: * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
417: * later on.
418: */
419: CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
420: void *ssl_sessionid,
421: size_t idsize,
422: int sockindex)
423: {
424: size_t i;
425: struct Curl_easy *data = conn->data; /* the mother of all structs */
426: struct curl_ssl_session *store = &data->state.session[0];
427: long oldest_age = data->state.session[0].age; /* zero if unused */
428: char *clone_host;
429: char *clone_conn_to_host;
430: int conn_to_port;
431: long *general_age;
432: const bool isProxy = CONNECT_PROXY_SSL();
433: struct ssl_primary_config * const ssl_config = isProxy ?
434: &conn->proxy_ssl_config :
435: &conn->ssl_config;
436:
437: DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
438:
439: clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name);
440: if(!clone_host)
441: return CURLE_OUT_OF_MEMORY; /* bail out */
442:
443: if(conn->bits.conn_to_host) {
444: clone_conn_to_host = strdup(conn->conn_to_host.name);
445: if(!clone_conn_to_host) {
446: free(clone_host);
447: return CURLE_OUT_OF_MEMORY; /* bail out */
448: }
449: }
450: else
451: clone_conn_to_host = NULL;
452:
453: if(conn->bits.conn_to_port)
454: conn_to_port = conn->conn_to_port;
455: else
456: conn_to_port = -1;
457:
458: /* Now we should add the session ID and the host name to the cache, (remove
459: the oldest if necessary) */
460:
461: /* If using shared SSL session, lock! */
462: if(SSLSESSION_SHARED(data)) {
463: general_age = &data->share->sessionage;
464: }
465: else {
466: general_age = &data->state.sessionage;
467: }
468:
469: /* find an empty slot for us, or find the oldest */
470: for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) &&
471: data->state.session[i].sessionid; i++) {
472: if(data->state.session[i].age < oldest_age) {
473: oldest_age = data->state.session[i].age;
474: store = &data->state.session[i];
475: }
476: }
477: if(i == data->set.general_ssl.max_ssl_sessions)
478: /* cache is full, we must "kill" the oldest entry! */
479: Curl_ssl_kill_session(store);
480: else
481: store = &data->state.session[i]; /* use this slot */
482:
483: /* now init the session struct wisely */
484: store->sessionid = ssl_sessionid;
485: store->idsize = idsize;
486: store->age = *general_age; /* set current age */
487: /* free it if there's one already present */
488: free(store->name);
489: free(store->conn_to_host);
490: store->name = clone_host; /* clone host name */
491: store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
492: store->conn_to_port = conn_to_port; /* connect to port number */
493: /* port number */
494: store->remote_port = isProxy ? (int)conn->port : conn->remote_port;
495: store->scheme = conn->handler->scheme;
496:
497: if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) {
498: Curl_free_primary_ssl_config(&store->ssl_config);
499: store->sessionid = NULL; /* let caller free sessionid */
500: free(clone_host);
501: free(clone_conn_to_host);
502: return CURLE_OUT_OF_MEMORY;
503: }
504:
505: return CURLE_OK;
506: }
507:
508:
509: void Curl_ssl_close_all(struct Curl_easy *data)
510: {
511: /* kill the session ID cache if not shared */
512: if(data->state.session && !SSLSESSION_SHARED(data)) {
513: size_t i;
514: for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
515: /* the single-killer function handles empty table slots */
516: Curl_ssl_kill_session(&data->state.session[i]);
517:
518: /* free the cache data */
519: Curl_safefree(data->state.session);
520: }
521:
522: Curl_ssl->close_all(data);
523: }
524:
525: #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
526: defined(USE_SECTRANSP) || defined(USE_NSS) || \
527: defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_BEARSSL)
528: int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks)
529: {
530: struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
531:
532: if(connssl->connecting_state == ssl_connect_2_writing) {
533: /* write mode */
534: socks[0] = conn->sock[FIRSTSOCKET];
535: return GETSOCK_WRITESOCK(0);
536: }
537: if(connssl->connecting_state == ssl_connect_2_reading) {
538: /* read mode */
539: socks[0] = conn->sock[FIRSTSOCKET];
540: return GETSOCK_READSOCK(0);
541: }
542:
543: return GETSOCK_BLANK;
544: }
545: #else
546: int Curl_ssl_getsock(struct connectdata *conn,
547: curl_socket_t *socks)
548: {
549: (void)conn;
550: (void)socks;
551: return GETSOCK_BLANK;
552: }
553: /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_SECTRANSP || USE_NSS */
554: #endif
555:
556: void Curl_ssl_close(struct connectdata *conn, int sockindex)
557: {
558: DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
559: Curl_ssl->close_one(conn, sockindex);
560: }
561:
562: CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
563: {
564: if(Curl_ssl->shut_down(conn, sockindex))
565: return CURLE_SSL_SHUTDOWN_FAILED;
566:
567: conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
568: conn->ssl[sockindex].state = ssl_connection_none;
569:
570: conn->recv[sockindex] = Curl_recv_plain;
571: conn->send[sockindex] = Curl_send_plain;
572:
573: return CURLE_OK;
574: }
575:
576: /* Selects an SSL crypto engine
577: */
578: CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
579: {
580: return Curl_ssl->set_engine(data, engine);
581: }
582:
583: /* Selects the default SSL crypto engine
584: */
585: CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
586: {
587: return Curl_ssl->set_engine_default(data);
588: }
589:
590: /* Return list of OpenSSL crypto engine names. */
591: struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
592: {
593: return Curl_ssl->engines_list(data);
594: }
595:
596: /*
597: * This sets up a session ID cache to the specified size. Make sure this code
598: * is agnostic to what underlying SSL technology we use.
599: */
600: CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
601: {
602: struct curl_ssl_session *session;
603:
604: if(data->state.session)
605: /* this is just a precaution to prevent multiple inits */
606: return CURLE_OK;
607:
608: session = calloc(amount, sizeof(struct curl_ssl_session));
609: if(!session)
610: return CURLE_OUT_OF_MEMORY;
611:
612: /* store the info in the SSL section */
613: data->set.general_ssl.max_ssl_sessions = amount;
614: data->state.session = session;
615: data->state.sessionage = 1; /* this is brand new */
616: return CURLE_OK;
617: }
618:
619: static size_t Curl_multissl_version(char *buffer, size_t size);
620:
621: size_t Curl_ssl_version(char *buffer, size_t size)
622: {
623: #ifdef CURL_WITH_MULTI_SSL
624: return Curl_multissl_version(buffer, size);
625: #else
626: return Curl_ssl->version(buffer, size);
627: #endif
628: }
629:
630: /*
631: * This function tries to determine connection status.
632: *
633: * Return codes:
634: * 1 means the connection is still in place
635: * 0 means the connection has been closed
636: * -1 means the connection status is unknown
637: */
638: int Curl_ssl_check_cxn(struct connectdata *conn)
639: {
640: return Curl_ssl->check_cxn(conn);
641: }
642:
643: bool Curl_ssl_data_pending(const struct connectdata *conn,
644: int connindex)
645: {
646: return Curl_ssl->data_pending(conn, connindex);
647: }
648:
649: void Curl_ssl_free_certinfo(struct Curl_easy *data)
650: {
651: struct curl_certinfo *ci = &data->info.certs;
652:
653: if(ci->num_of_certs) {
654: /* free all individual lists used */
655: int i;
656: for(i = 0; i<ci->num_of_certs; i++) {
657: curl_slist_free_all(ci->certinfo[i]);
658: ci->certinfo[i] = NULL;
659: }
660:
661: free(ci->certinfo); /* free the actual array too */
662: ci->certinfo = NULL;
663: ci->num_of_certs = 0;
664: }
665: }
666:
667: CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
668: {
669: struct curl_certinfo *ci = &data->info.certs;
670: struct curl_slist **table;
671:
672: /* Free any previous certificate information structures */
673: Curl_ssl_free_certinfo(data);
674:
675: /* Allocate the required certificate information structures */
676: table = calloc((size_t) num, sizeof(struct curl_slist *));
677: if(!table)
678: return CURLE_OUT_OF_MEMORY;
679:
680: ci->num_of_certs = num;
681: ci->certinfo = table;
682:
683: return CURLE_OK;
684: }
685:
686: /*
687: * 'value' is NOT a zero terminated string
688: */
689: CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
690: int certnum,
691: const char *label,
692: const char *value,
693: size_t valuelen)
694: {
695: struct curl_certinfo *ci = &data->info.certs;
696: char *output;
697: struct curl_slist *nl;
698: CURLcode result = CURLE_OK;
699: size_t labellen = strlen(label);
700: size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
701:
702: output = malloc(outlen);
703: if(!output)
704: return CURLE_OUT_OF_MEMORY;
705:
706: /* sprintf the label and colon */
707: msnprintf(output, outlen, "%s:", label);
708:
709: /* memcpy the value (it might not be zero terminated) */
710: memcpy(&output[labellen + 1], value, valuelen);
711:
712: /* zero terminate the output */
713: output[labellen + 1 + valuelen] = 0;
714:
715: nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
716: if(!nl) {
717: free(output);
718: curl_slist_free_all(ci->certinfo[certnum]);
719: result = CURLE_OUT_OF_MEMORY;
720: }
721:
722: ci->certinfo[certnum] = nl;
723: return result;
724: }
725:
726: /*
727: * This is a convenience function for push_certinfo_len that takes a zero
728: * terminated value.
729: */
730: CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data,
731: int certnum,
732: const char *label,
733: const char *value)
734: {
735: size_t valuelen = strlen(value);
736:
737: return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
738: }
739:
740: CURLcode Curl_ssl_random(struct Curl_easy *data,
741: unsigned char *entropy,
742: size_t length)
743: {
744: return Curl_ssl->random(data, entropy, length);
745: }
746:
747: /*
748: * Public key pem to der conversion
749: */
750:
751: static CURLcode pubkey_pem_to_der(const char *pem,
752: unsigned char **der, size_t *der_len)
753: {
754: char *stripped_pem, *begin_pos, *end_pos;
755: size_t pem_count, stripped_pem_count = 0, pem_len;
756: CURLcode result;
757:
758: /* if no pem, exit. */
759: if(!pem)
760: return CURLE_BAD_CONTENT_ENCODING;
761:
762: begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
763: if(!begin_pos)
764: return CURLE_BAD_CONTENT_ENCODING;
765:
766: pem_count = begin_pos - pem;
767: /* Invalid if not at beginning AND not directly following \n */
768: if(0 != pem_count && '\n' != pem[pem_count - 1])
769: return CURLE_BAD_CONTENT_ENCODING;
770:
771: /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
772: pem_count += 26;
773:
774: /* Invalid if not directly following \n */
775: end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
776: if(!end_pos)
777: return CURLE_BAD_CONTENT_ENCODING;
778:
779: pem_len = end_pos - pem;
780:
781: stripped_pem = malloc(pem_len - pem_count + 1);
782: if(!stripped_pem)
783: return CURLE_OUT_OF_MEMORY;
784:
785: /*
786: * Here we loop through the pem array one character at a time between the
787: * correct indices, and place each character that is not '\n' or '\r'
788: * into the stripped_pem array, which should represent the raw base64 string
789: */
790: while(pem_count < pem_len) {
791: if('\n' != pem[pem_count] && '\r' != pem[pem_count])
792: stripped_pem[stripped_pem_count++] = pem[pem_count];
793: ++pem_count;
794: }
795: /* Place the null terminator in the correct place */
796: stripped_pem[stripped_pem_count] = '\0';
797:
798: result = Curl_base64_decode(stripped_pem, der, der_len);
799:
800: Curl_safefree(stripped_pem);
801:
802: return result;
803: }
804:
805: /*
806: * Generic pinned public key check.
807: */
808:
809: CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
810: const char *pinnedpubkey,
811: const unsigned char *pubkey, size_t pubkeylen)
812: {
813: FILE *fp;
814: unsigned char *buf = NULL, *pem_ptr = NULL;
815: CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
816:
817: /* if a path wasn't specified, don't pin */
818: if(!pinnedpubkey)
819: return CURLE_OK;
820: if(!pubkey || !pubkeylen)
821: return result;
822:
823: /* only do this if pinnedpubkey starts with "sha256//", length 8 */
824: if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
825: CURLcode encode;
826: size_t encodedlen, pinkeylen;
827: char *encoded, *pinkeycopy, *begin_pos, *end_pos;
828: unsigned char *sha256sumdigest;
829:
830: if(!Curl_ssl->sha256sum) {
831: /* without sha256 support, this cannot match */
832: return result;
833: }
834:
835: /* compute sha256sum of public key */
836: sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH);
837: if(!sha256sumdigest)
838: return CURLE_OUT_OF_MEMORY;
839: encode = Curl_ssl->sha256sum(pubkey, pubkeylen,
840: sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
841:
842: if(encode != CURLE_OK)
843: return encode;
844:
845: encode = Curl_base64_encode(data, (char *)sha256sumdigest,
846: CURL_SHA256_DIGEST_LENGTH, &encoded,
847: &encodedlen);
848: Curl_safefree(sha256sumdigest);
849:
850: if(encode)
851: return encode;
852:
853: infof(data, "\t public key hash: sha256//%s\n", encoded);
854:
855: /* it starts with sha256//, copy so we can modify it */
856: pinkeylen = strlen(pinnedpubkey) + 1;
857: pinkeycopy = malloc(pinkeylen);
858: if(!pinkeycopy) {
859: Curl_safefree(encoded);
860: return CURLE_OUT_OF_MEMORY;
861: }
862: memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
863: /* point begin_pos to the copy, and start extracting keys */
864: begin_pos = pinkeycopy;
865: do {
866: end_pos = strstr(begin_pos, ";sha256//");
867: /*
868: * if there is an end_pos, null terminate,
869: * otherwise it'll go to the end of the original string
870: */
871: if(end_pos)
872: end_pos[0] = '\0';
873:
874: /* compare base64 sha256 digests, 8 is the length of "sha256//" */
875: if(encodedlen == strlen(begin_pos + 8) &&
876: !memcmp(encoded, begin_pos + 8, encodedlen)) {
877: result = CURLE_OK;
878: break;
879: }
880:
881: /*
882: * change back the null-terminator we changed earlier,
883: * and look for next begin
884: */
885: if(end_pos) {
886: end_pos[0] = ';';
887: begin_pos = strstr(end_pos, "sha256//");
888: }
889: } while(end_pos && begin_pos);
890: Curl_safefree(encoded);
891: Curl_safefree(pinkeycopy);
892: return result;
893: }
894:
895: fp = fopen(pinnedpubkey, "rb");
896: if(!fp)
897: return result;
898:
899: do {
900: long filesize;
901: size_t size, pem_len;
902: CURLcode pem_read;
903:
904: /* Determine the file's size */
905: if(fseek(fp, 0, SEEK_END))
906: break;
907: filesize = ftell(fp);
908: if(fseek(fp, 0, SEEK_SET))
909: break;
910: if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
911: break;
912:
913: /*
914: * if the size of our certificate is bigger than the file
915: * size then it can't match
916: */
917: size = curlx_sotouz((curl_off_t) filesize);
918: if(pubkeylen > size)
919: break;
920:
921: /*
922: * Allocate buffer for the pinned key
923: * With 1 additional byte for null terminator in case of PEM key
924: */
925: buf = malloc(size + 1);
926: if(!buf)
927: break;
928:
929: /* Returns number of elements read, which should be 1 */
930: if((int) fread(buf, size, 1, fp) != 1)
931: break;
932:
933: /* If the sizes are the same, it can't be base64 encoded, must be der */
934: if(pubkeylen == size) {
935: if(!memcmp(pubkey, buf, pubkeylen))
936: result = CURLE_OK;
937: break;
938: }
939:
940: /*
941: * Otherwise we will assume it's PEM and try to decode it
942: * after placing null terminator
943: */
944: buf[size] = '\0';
945: pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
946: /* if it wasn't read successfully, exit */
947: if(pem_read)
948: break;
949:
950: /*
951: * if the size of our certificate doesn't match the size of
952: * the decoded file, they can't be the same, otherwise compare
953: */
954: if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
955: result = CURLE_OK;
956: } while(0);
957:
958: Curl_safefree(buf);
959: Curl_safefree(pem_ptr);
960: fclose(fp);
961:
962: return result;
963: }
964:
965: #ifndef CURL_DISABLE_CRYPTO_AUTH
966: CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
967: size_t tmplen,
968: unsigned char *md5sum, /* output */
969: size_t md5len)
970: {
971: return Curl_ssl->md5sum(tmp, tmplen, md5sum, md5len);
972: }
973: #endif
974:
975: /*
976: * Check whether the SSL backend supports the status_request extension.
977: */
978: bool Curl_ssl_cert_status_request(void)
979: {
980: return Curl_ssl->cert_status_request();
981: }
982:
983: /*
984: * Check whether the SSL backend supports false start.
985: */
986: bool Curl_ssl_false_start(void)
987: {
988: return Curl_ssl->false_start();
989: }
990:
991: /*
992: * Check whether the SSL backend supports setting TLS 1.3 cipher suites
993: */
994: bool Curl_ssl_tls13_ciphersuites(void)
995: {
996: return Curl_ssl->supports & SSLSUPP_TLS13_CIPHERSUITES;
997: }
998:
999: /*
1000: * Default implementations for unsupported functions.
1001: */
1002:
1003: int Curl_none_init(void)
1004: {
1005: return 1;
1006: }
1007:
1008: void Curl_none_cleanup(void)
1009: { }
1010:
1011: int Curl_none_shutdown(struct connectdata *conn UNUSED_PARAM,
1012: int sockindex UNUSED_PARAM)
1013: {
1014: (void)conn;
1015: (void)sockindex;
1016: return 0;
1017: }
1018:
1019: int Curl_none_check_cxn(struct connectdata *conn UNUSED_PARAM)
1020: {
1021: (void)conn;
1022: return -1;
1023: }
1024:
1025: CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM,
1026: unsigned char *entropy UNUSED_PARAM,
1027: size_t length UNUSED_PARAM)
1028: {
1029: (void)data;
1030: (void)entropy;
1031: (void)length;
1032: return CURLE_NOT_BUILT_IN;
1033: }
1034:
1035: void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM)
1036: {
1037: (void)data;
1038: }
1039:
1040: void Curl_none_session_free(void *ptr UNUSED_PARAM)
1041: {
1042: (void)ptr;
1043: }
1044:
1045: bool Curl_none_data_pending(const struct connectdata *conn UNUSED_PARAM,
1046: int connindex UNUSED_PARAM)
1047: {
1048: (void)conn;
1049: (void)connindex;
1050: return 0;
1051: }
1052:
1053: bool Curl_none_cert_status_request(void)
1054: {
1055: return FALSE;
1056: }
1057:
1058: CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM,
1059: const char *engine UNUSED_PARAM)
1060: {
1061: (void)data;
1062: (void)engine;
1063: return CURLE_NOT_BUILT_IN;
1064: }
1065:
1066: CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM)
1067: {
1068: (void)data;
1069: return CURLE_NOT_BUILT_IN;
1070: }
1071:
1072: struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM)
1073: {
1074: (void)data;
1075: return (struct curl_slist *)NULL;
1076: }
1077:
1078: bool Curl_none_false_start(void)
1079: {
1080: return FALSE;
1081: }
1082:
1083: #ifndef CURL_DISABLE_CRYPTO_AUTH
1084: CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
1085: unsigned char *md5sum, size_t md5len UNUSED_PARAM)
1086: {
1087: MD5_context *MD5pw;
1088:
1089: (void)md5len;
1090:
1091: MD5pw = Curl_MD5_init(Curl_DIGEST_MD5);
1092: if(!MD5pw)
1093: return CURLE_OUT_OF_MEMORY;
1094: Curl_MD5_update(MD5pw, input, curlx_uztoui(inputlen));
1095: Curl_MD5_final(MD5pw, md5sum);
1096: return CURLE_OK;
1097: }
1098: #else
1099: CURLcode Curl_none_md5sum(unsigned char *input UNUSED_PARAM,
1100: size_t inputlen UNUSED_PARAM,
1101: unsigned char *md5sum UNUSED_PARAM,
1102: size_t md5len UNUSED_PARAM)
1103: {
1104: (void)input;
1105: (void)inputlen;
1106: (void)md5sum;
1107: (void)md5len;
1108: return CURLE_NOT_BUILT_IN;
1109: }
1110: #endif
1111:
1112: static int Curl_multissl_init(void)
1113: {
1114: if(multissl_init(NULL))
1115: return 1;
1116: return Curl_ssl->init();
1117: }
1118:
1119: static CURLcode Curl_multissl_connect(struct connectdata *conn, int sockindex)
1120: {
1121: if(multissl_init(NULL))
1122: return CURLE_FAILED_INIT;
1123: return Curl_ssl->connect_blocking(conn, sockindex);
1124: }
1125:
1126: static CURLcode Curl_multissl_connect_nonblocking(struct connectdata *conn,
1127: int sockindex, bool *done)
1128: {
1129: if(multissl_init(NULL))
1130: return CURLE_FAILED_INIT;
1131: return Curl_ssl->connect_nonblocking(conn, sockindex, done);
1132: }
1133:
1134: static void *Curl_multissl_get_internals(struct ssl_connect_data *connssl,
1135: CURLINFO info)
1136: {
1137: if(multissl_init(NULL))
1138: return NULL;
1139: return Curl_ssl->get_internals(connssl, info);
1140: }
1141:
1142: static void Curl_multissl_close(struct connectdata *conn, int sockindex)
1143: {
1144: if(multissl_init(NULL))
1145: return;
1146: Curl_ssl->close_one(conn, sockindex);
1147: }
1148:
1149: static const struct Curl_ssl Curl_ssl_multi = {
1150: { CURLSSLBACKEND_NONE, "multi" }, /* info */
1151: 0, /* supports nothing */
1152: (size_t)-1, /* something insanely large to be on the safe side */
1153:
1154: Curl_multissl_init, /* init */
1155: Curl_none_cleanup, /* cleanup */
1156: Curl_multissl_version, /* version */
1157: Curl_none_check_cxn, /* check_cxn */
1158: Curl_none_shutdown, /* shutdown */
1159: Curl_none_data_pending, /* data_pending */
1160: Curl_none_random, /* random */
1161: Curl_none_cert_status_request, /* cert_status_request */
1162: Curl_multissl_connect, /* connect */
1163: Curl_multissl_connect_nonblocking, /* connect_nonblocking */
1164: Curl_multissl_get_internals, /* get_internals */
1165: Curl_multissl_close, /* close_one */
1166: Curl_none_close_all, /* close_all */
1167: Curl_none_session_free, /* session_free */
1168: Curl_none_set_engine, /* set_engine */
1169: Curl_none_set_engine_default, /* set_engine_default */
1170: Curl_none_engines_list, /* engines_list */
1171: Curl_none_false_start, /* false_start */
1172: Curl_none_md5sum, /* md5sum */
1173: NULL /* sha256sum */
1174: };
1175:
1176: const struct Curl_ssl *Curl_ssl =
1177: #if defined(CURL_WITH_MULTI_SSL)
1178: &Curl_ssl_multi;
1179: #elif defined(USE_WOLFSSL)
1180: &Curl_ssl_wolfssl;
1181: #elif defined(USE_SECTRANSP)
1182: &Curl_ssl_sectransp;
1183: #elif defined(USE_GNUTLS)
1184: &Curl_ssl_gnutls;
1185: #elif defined(USE_GSKIT)
1186: &Curl_ssl_gskit;
1187: #elif defined(USE_MBEDTLS)
1188: &Curl_ssl_mbedtls;
1189: #elif defined(USE_NSS)
1190: &Curl_ssl_nss;
1191: #elif defined(USE_OPENSSL)
1192: &Curl_ssl_openssl;
1193: #elif defined(USE_SCHANNEL)
1194: &Curl_ssl_schannel;
1195: #elif defined(USE_MESALINK)
1196: &Curl_ssl_mesalink;
1197: #elif defined(USE_BEARSSL)
1198: &Curl_ssl_bearssl;
1199: #else
1200: #error "Missing struct Curl_ssl for selected SSL backend"
1201: #endif
1202:
1203: static const struct Curl_ssl *available_backends[] = {
1204: #if defined(USE_WOLFSSL)
1205: &Curl_ssl_wolfssl,
1206: #endif
1207: #if defined(USE_SECTRANSP)
1208: &Curl_ssl_sectransp,
1209: #endif
1210: #if defined(USE_GNUTLS)
1211: &Curl_ssl_gnutls,
1212: #endif
1213: #if defined(USE_GSKIT)
1214: &Curl_ssl_gskit,
1215: #endif
1216: #if defined(USE_MBEDTLS)
1217: &Curl_ssl_mbedtls,
1218: #endif
1219: #if defined(USE_NSS)
1220: &Curl_ssl_nss,
1221: #endif
1222: #if defined(USE_OPENSSL)
1223: &Curl_ssl_openssl,
1224: #endif
1225: #if defined(USE_SCHANNEL)
1226: &Curl_ssl_schannel,
1227: #endif
1228: #if defined(USE_MESALINK)
1229: &Curl_ssl_mesalink,
1230: #endif
1231: #if defined(USE_BEARSSL)
1232: &Curl_ssl_bearssl,
1233: #endif
1234: NULL
1235: };
1236:
1237: static size_t Curl_multissl_version(char *buffer, size_t size)
1238: {
1239: static const struct Curl_ssl *selected;
1240: static char backends[200];
1241: static size_t backends_len;
1242: const struct Curl_ssl *current;
1243:
1244: current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl;
1245:
1246: if(current != selected) {
1247: char *p = backends;
1248: char *end = backends + sizeof(backends);
1249: int i;
1250:
1251: selected = current;
1252:
1253: backends[0] = '\0';
1254:
1255: for(i = 0; available_backends[i]; ++i) {
1256: char vb[200];
1257: bool paren = (selected != available_backends[i]);
1258:
1259: if(available_backends[i]->version(vb, sizeof(vb))) {
1260: p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""),
1261: (paren ? "(" : ""), vb, (paren ? ")" : ""));
1262: }
1263: }
1264:
1265: backends_len = p - backends;
1266: }
1267:
1268: if(!size)
1269: return 0;
1270:
1271: if(size <= backends_len) {
1272: strncpy(buffer, backends, size - 1);
1273: buffer[size - 1] = '\0';
1274: return size - 1;
1275: }
1276:
1277: strcpy(buffer, backends);
1278: return backends_len;
1279: }
1280:
1281: static int multissl_init(const struct Curl_ssl *backend)
1282: {
1283: const char *env;
1284: char *env_tmp;
1285:
1286: if(Curl_ssl != &Curl_ssl_multi)
1287: return 1;
1288:
1289: if(backend) {
1290: Curl_ssl = backend;
1291: return 0;
1292: }
1293:
1294: if(!available_backends[0])
1295: return 1;
1296:
1297: env = env_tmp = curl_getenv("CURL_SSL_BACKEND");
1298: #ifdef CURL_DEFAULT_SSL_BACKEND
1299: if(!env)
1300: env = CURL_DEFAULT_SSL_BACKEND;
1301: #endif
1302: if(env) {
1303: int i;
1304: for(i = 0; available_backends[i]; i++) {
1305: if(strcasecompare(env, available_backends[i]->info.name)) {
1306: Curl_ssl = available_backends[i];
1307: curl_free(env_tmp);
1308: return 0;
1309: }
1310: }
1311: }
1312:
1313: /* Fall back to first available backend */
1314: Curl_ssl = available_backends[0];
1315: curl_free(env_tmp);
1316: return 0;
1317: }
1318:
1319: CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
1320: const curl_ssl_backend ***avail)
1321: {
1322: int i;
1323:
1324: if(avail)
1325: *avail = (const curl_ssl_backend **)&available_backends;
1326:
1327: if(Curl_ssl != &Curl_ssl_multi)
1328: return id == Curl_ssl->info.id ||
1329: (name && strcasecompare(name, Curl_ssl->info.name)) ?
1330: CURLSSLSET_OK :
1331: #if defined(CURL_WITH_MULTI_SSL)
1332: CURLSSLSET_TOO_LATE;
1333: #else
1334: CURLSSLSET_UNKNOWN_BACKEND;
1335: #endif
1336:
1337: for(i = 0; available_backends[i]; i++) {
1338: if(available_backends[i]->info.id == id ||
1339: (name && strcasecompare(available_backends[i]->info.name, name))) {
1340: multissl_init(available_backends[i]);
1341: return CURLSSLSET_OK;
1342: }
1343: }
1344:
1345: return CURLSSLSET_UNKNOWN_BACKEND;
1346: }
1347:
1348: #else /* USE_SSL */
1349: CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
1350: const curl_ssl_backend ***avail)
1351: {
1352: (void)id;
1353: (void)name;
1354: (void)avail;
1355: return CURLSSLSET_NO_BACKENDS;
1356: }
1357:
1358: #endif /* !USE_SSL */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>