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