Home | History | Annotate | Download | only in vtls
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel (at) 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    Curl_ossl_ - prefix for OpenSSL ones
     32    Curl_gtls_ - prefix for GnuTLS ones
     33    Curl_nss_ - prefix for NSS ones
     34    Curl_gskit_ - prefix for GSKit ones
     35    Curl_polarssl_ - prefix for PolarSSL ones
     36    Curl_cyassl_ - prefix for CyaSSL ones
     37    Curl_schannel_ - prefix for Schannel SSPI ones
     38    Curl_darwinssl_ - prefix for SecureTransport (Darwin) ones
     39 
     40    Note that this source code uses curlssl_* functions, and they are all
     41    defines/macros #defined by the lib-specific header files.
     42 
     43    "SSL/TLS Strong Encryption: An Introduction"
     44    https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
     45 */
     46 
     47 #include "curl_setup.h"
     48 
     49 #ifdef HAVE_SYS_TYPES_H
     50 #include <sys/types.h>
     51 #endif
     52 #ifdef HAVE_SYS_STAT_H
     53 #include <sys/stat.h>
     54 #endif
     55 #ifdef HAVE_FCNTL_H
     56 #include <fcntl.h>
     57 #endif
     58 
     59 #include "urldata.h"
     60 
     61 #include "vtls.h" /* generic SSL protos etc */
     62 #include "slist.h"
     63 #include "sendf.h"
     64 #include "strcase.h"
     65 #include "url.h"
     66 #include "progress.h"
     67 #include "share.h"
     68 #include "multiif.h"
     69 #include "timeval.h"
     70 #include "curl_md5.h"
     71 #include "warnless.h"
     72 #include "curl_base64.h"
     73 #include "curl_printf.h"
     74 
     75 /* The last #include files should be: */
     76 #include "curl_memory.h"
     77 #include "memdebug.h"
     78 
     79 /* convenience macro to check if this handle is using a shared SSL session */
     80 #define SSLSESSION_SHARED(data) (data->share &&                        \
     81                                  (data->share->specifier &             \
     82                                   (1<<CURL_LOCK_DATA_SSL_SESSION)))
     83 
     84 #define CLONE_STRING(var)                    \
     85   if(source->var) {                          \
     86     dest->var = strdup(source->var);         \
     87     if(!dest->var)                           \
     88       return FALSE;                          \
     89   }                                          \
     90   else                                       \
     91     dest->var = NULL;
     92 
     93 bool
     94 Curl_ssl_config_matches(struct ssl_primary_config* data,
     95                         struct ssl_primary_config* needle)
     96 {
     97   if((data->version == needle->version) &&
     98      (data->verifypeer == needle->verifypeer) &&
     99      (data->verifyhost == needle->verifyhost) &&
    100      Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
    101      Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
    102      Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
    103      Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list))
    104     return TRUE;
    105 
    106   return FALSE;
    107 }
    108 
    109 bool
    110 Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
    111                               struct ssl_primary_config *dest)
    112 {
    113   dest->verifyhost = source->verifyhost;
    114   dest->verifypeer = source->verifypeer;
    115   dest->version = source->version;
    116 
    117   CLONE_STRING(CAfile);
    118   CLONE_STRING(CApath);
    119   CLONE_STRING(cipher_list);
    120   CLONE_STRING(egdsocket);
    121   CLONE_STRING(random_file);
    122   CLONE_STRING(clientcert);
    123   return TRUE;
    124 }
    125 
    126 void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
    127 {
    128   Curl_safefree(sslc->CAfile);
    129   Curl_safefree(sslc->CApath);
    130   Curl_safefree(sslc->cipher_list);
    131   Curl_safefree(sslc->egdsocket);
    132   Curl_safefree(sslc->random_file);
    133   Curl_safefree(sslc->clientcert);
    134 }
    135 
    136 int Curl_ssl_backend(void)
    137 {
    138   return (int)CURL_SSL_BACKEND;
    139 }
    140 
    141 #ifdef USE_SSL
    142 
    143 /* "global" init done? */
    144 static bool init_ssl=FALSE;
    145 
    146 /**
    147  * Global SSL init
    148  *
    149  * @retval 0 error initializing SSL
    150  * @retval 1 SSL initialized successfully
    151  */
    152 int Curl_ssl_init(void)
    153 {
    154   /* make sure this is only done once */
    155   if(init_ssl)
    156     return 1;
    157   init_ssl = TRUE; /* never again */
    158 
    159   return curlssl_init();
    160 }
    161 
    162 
    163 /* Global cleanup */
    164 void Curl_ssl_cleanup(void)
    165 {
    166   if(init_ssl) {
    167     /* only cleanup if we did a previous init */
    168     curlssl_cleanup();
    169     init_ssl = FALSE;
    170   }
    171 }
    172 
    173 static bool ssl_prefs_check(struct Curl_easy *data)
    174 {
    175   /* check for CURLOPT_SSLVERSION invalid parameter value */
    176   if((data->set.ssl.primary.version < 0)
    177      || (data->set.ssl.primary.version >= CURL_SSLVERSION_LAST)) {
    178     failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
    179     return FALSE;
    180   }
    181   return TRUE;
    182 }
    183 
    184 static CURLcode
    185 ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
    186 {
    187   DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
    188   if(ssl_connection_complete == conn->ssl[sockindex].state &&
    189      !conn->proxy_ssl[sockindex].use) {
    190 #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_NSS) ||  \
    191   defined(USE_GSKIT)
    192     conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
    193     memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
    194 #else
    195     return CURLE_NOT_BUILT_IN;
    196 #endif
    197   }
    198   return CURLE_OK;
    199 }
    200 
    201 CURLcode
    202 Curl_ssl_connect(struct connectdata *conn, int sockindex)
    203 {
    204   CURLcode result;
    205 
    206   if(conn->bits.proxy_ssl_connected[sockindex]) {
    207     result = ssl_connect_init_proxy(conn, sockindex);
    208     if(result)
    209       return result;
    210   }
    211 
    212   if(!ssl_prefs_check(conn->data))
    213     return CURLE_SSL_CONNECT_ERROR;
    214 
    215   /* mark this is being ssl-enabled from here on. */
    216   conn->ssl[sockindex].use = TRUE;
    217   conn->ssl[sockindex].state = ssl_connection_negotiating;
    218 
    219   result = curlssl_connect(conn, sockindex);
    220 
    221   if(!result)
    222     Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
    223 
    224   return result;
    225 }
    226 
    227 CURLcode
    228 Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
    229                              bool *done)
    230 {
    231   CURLcode result;
    232   if(conn->bits.proxy_ssl_connected[sockindex]) {
    233     result = ssl_connect_init_proxy(conn, sockindex);
    234     if(result)
    235       return result;
    236   }
    237 
    238   if(!ssl_prefs_check(conn->data))
    239     return CURLE_SSL_CONNECT_ERROR;
    240 
    241   /* mark this is being ssl requested from here on. */
    242   conn->ssl[sockindex].use = TRUE;
    243 #ifdef curlssl_connect_nonblocking
    244   result = curlssl_connect_nonblocking(conn, sockindex, done);
    245 #else
    246   *done = TRUE; /* fallback to BLOCKING */
    247   result = curlssl_connect(conn, sockindex);
    248 #endif /* non-blocking connect support */
    249   if(!result && *done)
    250     Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
    251   return result;
    252 }
    253 
    254 /*
    255  * Lock shared SSL session data
    256  */
    257 void Curl_ssl_sessionid_lock(struct connectdata *conn)
    258 {
    259   if(SSLSESSION_SHARED(conn->data))
    260     Curl_share_lock(conn->data,
    261                     CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
    262 }
    263 
    264 /*
    265  * Unlock shared SSL session data
    266  */
    267 void Curl_ssl_sessionid_unlock(struct connectdata *conn)
    268 {
    269   if(SSLSESSION_SHARED(conn->data))
    270     Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION);
    271 }
    272 
    273 /*
    274  * Check if there's a session ID for the given connection in the cache, and if
    275  * there's one suitable, it is provided. Returns TRUE when no entry matched.
    276  */
    277 bool Curl_ssl_getsessionid(struct connectdata *conn,
    278                            void **ssl_sessionid,
    279                            size_t *idsize, /* set 0 if unknown */
    280                            int sockindex)
    281 {
    282   struct curl_ssl_session *check;
    283   struct Curl_easy *data = conn->data;
    284   size_t i;
    285   long *general_age;
    286   bool no_match = TRUE;
    287 
    288   const bool isProxy = CONNECT_PROXY_SSL();
    289   struct ssl_primary_config * const ssl_config = isProxy ?
    290                                                  &conn->proxy_ssl_config :
    291                                                  &conn->ssl_config;
    292   const char * const name = isProxy ? conn->http_proxy.host.name :
    293                                       conn->host.name;
    294   int port = isProxy ? (int)conn->port : conn->remote_port;
    295   *ssl_sessionid = NULL;
    296 
    297   DEBUGASSERT(data->set.general_ssl.sessionid);
    298 
    299   if(!data->set.general_ssl.sessionid)
    300     /* session ID re-use is disabled */
    301     return TRUE;
    302 
    303   /* Lock if shared */
    304   if(SSLSESSION_SHARED(data))
    305     general_age = &data->share->sessionage;
    306   else
    307     general_age = &data->state.sessionage;
    308 
    309   for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
    310     check = &data->state.session[i];
    311     if(!check->sessionid)
    312       /* not session ID means blank entry */
    313       continue;
    314     if(strcasecompare(name, check->name) &&
    315        ((!conn->bits.conn_to_host && !check->conn_to_host) ||
    316         (conn->bits.conn_to_host && check->conn_to_host &&
    317          strcasecompare(conn->conn_to_host.name, check->conn_to_host))) &&
    318        ((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
    319         (conn->bits.conn_to_port && check->conn_to_port != -1 &&
    320          conn->conn_to_port == check->conn_to_port)) &&
    321        (port == check->remote_port) &&
    322        strcasecompare(conn->handler->scheme, check->scheme) &&
    323        Curl_ssl_config_matches(ssl_config, &check->ssl_config)) {
    324       /* yes, we have a session ID! */
    325       (*general_age)++;          /* increase general age */
    326       check->age = *general_age; /* set this as used in this age */
    327       *ssl_sessionid = check->sessionid;
    328       if(idsize)
    329         *idsize = check->idsize;
    330       no_match = FALSE;
    331       break;
    332     }
    333   }
    334 
    335   return no_match;
    336 }
    337 
    338 /*
    339  * Kill a single session ID entry in the cache.
    340  */
    341 void Curl_ssl_kill_session(struct curl_ssl_session *session)
    342 {
    343   if(session->sessionid) {
    344     /* defensive check */
    345 
    346     /* free the ID the SSL-layer specific way */
    347     curlssl_session_free(session->sessionid);
    348 
    349     session->sessionid = NULL;
    350     session->age = 0; /* fresh */
    351 
    352     Curl_free_primary_ssl_config(&session->ssl_config);
    353 
    354     Curl_safefree(session->name);
    355     Curl_safefree(session->conn_to_host);
    356   }
    357 }
    358 
    359 /*
    360  * Delete the given session ID from the cache.
    361  */
    362 void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
    363 {
    364   size_t i;
    365   struct Curl_easy *data=conn->data;
    366 
    367   for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
    368     struct curl_ssl_session *check = &data->state.session[i];
    369 
    370     if(check->sessionid == ssl_sessionid) {
    371       Curl_ssl_kill_session(check);
    372       break;
    373     }
    374   }
    375 }
    376 
    377 /*
    378  * Store session id in the session cache. The ID passed on to this function
    379  * must already have been extracted and allocated the proper way for the SSL
    380  * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
    381  * later on.
    382  */
    383 CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
    384                                void *ssl_sessionid,
    385                                size_t idsize,
    386                                int sockindex)
    387 {
    388   size_t i;
    389   struct Curl_easy *data=conn->data; /* the mother of all structs */
    390   struct curl_ssl_session *store = &data->state.session[0];
    391   long oldest_age=data->state.session[0].age; /* zero if unused */
    392   char *clone_host;
    393   char *clone_conn_to_host;
    394   int conn_to_port;
    395   long *general_age;
    396   const bool isProxy = CONNECT_PROXY_SSL();
    397   struct ssl_primary_config * const ssl_config = isProxy ?
    398                                            &conn->proxy_ssl_config :
    399                                            &conn->ssl_config;
    400 
    401   DEBUGASSERT(data->set.general_ssl.sessionid);
    402 
    403   clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name);
    404   if(!clone_host)
    405     return CURLE_OUT_OF_MEMORY; /* bail out */
    406 
    407   if(conn->bits.conn_to_host) {
    408     clone_conn_to_host = strdup(conn->conn_to_host.name);
    409     if(!clone_conn_to_host) {
    410       free(clone_host);
    411       return CURLE_OUT_OF_MEMORY; /* bail out */
    412     }
    413   }
    414   else
    415     clone_conn_to_host = NULL;
    416 
    417   if(conn->bits.conn_to_port)
    418     conn_to_port = conn->conn_to_port;
    419   else
    420     conn_to_port = -1;
    421 
    422   /* Now we should add the session ID and the host name to the cache, (remove
    423      the oldest if necessary) */
    424 
    425   /* If using shared SSL session, lock! */
    426   if(SSLSESSION_SHARED(data)) {
    427     general_age = &data->share->sessionage;
    428   }
    429   else {
    430     general_age = &data->state.sessionage;
    431   }
    432 
    433   /* find an empty slot for us, or find the oldest */
    434   for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) &&
    435         data->state.session[i].sessionid; i++) {
    436     if(data->state.session[i].age < oldest_age) {
    437       oldest_age = data->state.session[i].age;
    438       store = &data->state.session[i];
    439     }
    440   }
    441   if(i == data->set.general_ssl.max_ssl_sessions)
    442     /* cache is full, we must "kill" the oldest entry! */
    443     Curl_ssl_kill_session(store);
    444   else
    445     store = &data->state.session[i]; /* use this slot */
    446 
    447   /* now init the session struct wisely */
    448   store->sessionid = ssl_sessionid;
    449   store->idsize = idsize;
    450   store->age = *general_age;    /* set current age */
    451     /* free it if there's one already present */
    452   free(store->name);
    453   free(store->conn_to_host);
    454   store->name = clone_host;               /* clone host name */
    455   store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
    456   store->conn_to_port = conn_to_port; /* connect to port number */
    457   /* port number */
    458   store->remote_port = isProxy ? (int)conn->port : conn->remote_port;
    459   store->scheme = conn->handler->scheme;
    460 
    461   if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) {
    462     store->sessionid = NULL; /* let caller free sessionid */
    463     free(clone_host);
    464     free(clone_conn_to_host);
    465     return CURLE_OUT_OF_MEMORY;
    466   }
    467 
    468   return CURLE_OK;
    469 }
    470 
    471 
    472 void Curl_ssl_close_all(struct Curl_easy *data)
    473 {
    474   size_t i;
    475   /* kill the session ID cache if not shared */
    476   if(data->state.session && !SSLSESSION_SHARED(data)) {
    477     for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
    478       /* the single-killer function handles empty table slots */
    479       Curl_ssl_kill_session(&data->state.session[i]);
    480 
    481     /* free the cache data */
    482     Curl_safefree(data->state.session);
    483   }
    484 
    485   curlssl_close_all(data);
    486 }
    487 
    488 #if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
    489     defined(USE_DARWINSSL) || defined(USE_NSS)
    490 /* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only. */
    491 int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks,
    492                      int numsocks)
    493 {
    494   struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
    495 
    496   if(!numsocks)
    497     return GETSOCK_BLANK;
    498 
    499   if(connssl->connecting_state == ssl_connect_2_writing) {
    500     /* write mode */
    501     socks[0] = conn->sock[FIRSTSOCKET];
    502     return GETSOCK_WRITESOCK(0);
    503   }
    504   else if(connssl->connecting_state == ssl_connect_2_reading) {
    505     /* read mode */
    506     socks[0] = conn->sock[FIRSTSOCKET];
    507     return GETSOCK_READSOCK(0);
    508   }
    509 
    510   return GETSOCK_BLANK;
    511 }
    512 #else
    513 int Curl_ssl_getsock(struct connectdata *conn,
    514                           curl_socket_t *socks,
    515                           int numsocks)
    516 {
    517   (void)conn;
    518   (void)socks;
    519   (void)numsocks;
    520   return GETSOCK_BLANK;
    521 }
    522 /* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */
    523 #endif
    524 
    525 void Curl_ssl_close(struct connectdata *conn, int sockindex)
    526 {
    527   DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
    528   curlssl_close(conn, sockindex);
    529 }
    530 
    531 CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
    532 {
    533   if(curlssl_shutdown(conn, sockindex))
    534     return CURLE_SSL_SHUTDOWN_FAILED;
    535 
    536   conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
    537   conn->ssl[sockindex].state = ssl_connection_none;
    538 
    539   conn->recv[sockindex] = Curl_recv_plain;
    540   conn->send[sockindex] = Curl_send_plain;
    541 
    542   return CURLE_OK;
    543 }
    544 
    545 /* Selects an SSL crypto engine
    546  */
    547 CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
    548 {
    549   return curlssl_set_engine(data, engine);
    550 }
    551 
    552 /* Selects the default SSL crypto engine
    553  */
    554 CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
    555 {
    556   return curlssl_set_engine_default(data);
    557 }
    558 
    559 /* Return list of OpenSSL crypto engine names. */
    560 struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
    561 {
    562   return curlssl_engines_list(data);
    563 }
    564 
    565 /*
    566  * This sets up a session ID cache to the specified size. Make sure this code
    567  * is agnostic to what underlying SSL technology we use.
    568  */
    569 CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
    570 {
    571   struct curl_ssl_session *session;
    572 
    573   if(data->state.session)
    574     /* this is just a precaution to prevent multiple inits */
    575     return CURLE_OK;
    576 
    577   session = calloc(amount, sizeof(struct curl_ssl_session));
    578   if(!session)
    579     return CURLE_OUT_OF_MEMORY;
    580 
    581   /* store the info in the SSL section */
    582   data->set.general_ssl.max_ssl_sessions = amount;
    583   data->state.session = session;
    584   data->state.sessionage = 1; /* this is brand new */
    585   return CURLE_OK;
    586 }
    587 
    588 size_t Curl_ssl_version(char *buffer, size_t size)
    589 {
    590   return curlssl_version(buffer, size);
    591 }
    592 
    593 /*
    594  * This function tries to determine connection status.
    595  *
    596  * Return codes:
    597  *     1 means the connection is still in place
    598  *     0 means the connection has been closed
    599  *    -1 means the connection status is unknown
    600  */
    601 int Curl_ssl_check_cxn(struct connectdata *conn)
    602 {
    603   return curlssl_check_cxn(conn);
    604 }
    605 
    606 bool Curl_ssl_data_pending(const struct connectdata *conn,
    607                            int connindex)
    608 {
    609   return curlssl_data_pending(conn, connindex);
    610 }
    611 
    612 void Curl_ssl_free_certinfo(struct Curl_easy *data)
    613 {
    614   int i;
    615   struct curl_certinfo *ci = &data->info.certs;
    616 
    617   if(ci->num_of_certs) {
    618     /* free all individual lists used */
    619     for(i=0; i<ci->num_of_certs; i++) {
    620       curl_slist_free_all(ci->certinfo[i]);
    621       ci->certinfo[i] = NULL;
    622     }
    623 
    624     free(ci->certinfo); /* free the actual array too */
    625     ci->certinfo = NULL;
    626     ci->num_of_certs = 0;
    627   }
    628 }
    629 
    630 CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
    631 {
    632   struct curl_certinfo *ci = &data->info.certs;
    633   struct curl_slist **table;
    634 
    635   /* Free any previous certificate information structures */
    636   Curl_ssl_free_certinfo(data);
    637 
    638   /* Allocate the required certificate information structures */
    639   table = calloc((size_t) num, sizeof(struct curl_slist *));
    640   if(!table)
    641     return CURLE_OUT_OF_MEMORY;
    642 
    643   ci->num_of_certs = num;
    644   ci->certinfo = table;
    645 
    646   return CURLE_OK;
    647 }
    648 
    649 /*
    650  * 'value' is NOT a zero terminated string
    651  */
    652 CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
    653                                     int certnum,
    654                                     const char *label,
    655                                     const char *value,
    656                                     size_t valuelen)
    657 {
    658   struct curl_certinfo *ci = &data->info.certs;
    659   char *output;
    660   struct curl_slist *nl;
    661   CURLcode result = CURLE_OK;
    662   size_t labellen = strlen(label);
    663   size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
    664 
    665   output = malloc(outlen);
    666   if(!output)
    667     return CURLE_OUT_OF_MEMORY;
    668 
    669   /* sprintf the label and colon */
    670   snprintf(output, outlen, "%s:", label);
    671 
    672   /* memcpy the value (it might not be zero terminated) */
    673   memcpy(&output[labellen+1], value, valuelen);
    674 
    675   /* zero terminate the output */
    676   output[labellen + 1 + valuelen] = 0;
    677 
    678   nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
    679   if(!nl) {
    680     free(output);
    681     curl_slist_free_all(ci->certinfo[certnum]);
    682     result = CURLE_OUT_OF_MEMORY;
    683   }
    684 
    685   ci->certinfo[certnum] = nl;
    686   return result;
    687 }
    688 
    689 /*
    690  * This is a convenience function for push_certinfo_len that takes a zero
    691  * terminated value.
    692  */
    693 CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data,
    694                                 int certnum,
    695                                 const char *label,
    696                                 const char *value)
    697 {
    698   size_t valuelen = strlen(value);
    699 
    700   return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
    701 }
    702 
    703 CURLcode Curl_ssl_random(struct Curl_easy *data,
    704                          unsigned char *entropy,
    705                          size_t length)
    706 {
    707   int rc = curlssl_random(data, entropy, length);
    708   if(rc) {
    709     failf(data, "PRNG seeding failed");
    710     return CURLE_FAILED_INIT; /* possibly weird return code */
    711   }
    712   return CURLE_OK;
    713 }
    714 
    715 /*
    716  * Public key pem to der conversion
    717  */
    718 
    719 static CURLcode pubkey_pem_to_der(const char *pem,
    720                                   unsigned char **der, size_t *der_len)
    721 {
    722   char *stripped_pem, *begin_pos, *end_pos;
    723   size_t pem_count, stripped_pem_count = 0, pem_len;
    724   CURLcode result;
    725 
    726   /* if no pem, exit. */
    727   if(!pem)
    728     return CURLE_BAD_CONTENT_ENCODING;
    729 
    730   begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
    731   if(!begin_pos)
    732     return CURLE_BAD_CONTENT_ENCODING;
    733 
    734   pem_count = begin_pos - pem;
    735   /* Invalid if not at beginning AND not directly following \n */
    736   if(0 != pem_count && '\n' != pem[pem_count - 1])
    737     return CURLE_BAD_CONTENT_ENCODING;
    738 
    739   /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
    740   pem_count += 26;
    741 
    742   /* Invalid if not directly following \n */
    743   end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
    744   if(!end_pos)
    745     return CURLE_BAD_CONTENT_ENCODING;
    746 
    747   pem_len = end_pos - pem;
    748 
    749   stripped_pem = malloc(pem_len - pem_count + 1);
    750   if(!stripped_pem)
    751     return CURLE_OUT_OF_MEMORY;
    752 
    753   /*
    754    * Here we loop through the pem array one character at a time between the
    755    * correct indices, and place each character that is not '\n' or '\r'
    756    * into the stripped_pem array, which should represent the raw base64 string
    757    */
    758   while(pem_count < pem_len) {
    759     if('\n' != pem[pem_count] && '\r' != pem[pem_count])
    760       stripped_pem[stripped_pem_count++] = pem[pem_count];
    761     ++pem_count;
    762   }
    763   /* Place the null terminator in the correct place */
    764   stripped_pem[stripped_pem_count] = '\0';
    765 
    766   result = Curl_base64_decode(stripped_pem, der, der_len);
    767 
    768   Curl_safefree(stripped_pem);
    769 
    770   return result;
    771 }
    772 
    773 /*
    774  * Generic pinned public key check.
    775  */
    776 
    777 CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
    778                               const char *pinnedpubkey,
    779                               const unsigned char *pubkey, size_t pubkeylen)
    780 {
    781   FILE *fp;
    782   unsigned char *buf = NULL, *pem_ptr = NULL;
    783   long filesize;
    784   size_t size, pem_len;
    785   CURLcode pem_read;
    786   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
    787 #ifdef curlssl_sha256sum
    788   CURLcode encode;
    789   size_t encodedlen, pinkeylen;
    790   char *encoded, *pinkeycopy, *begin_pos, *end_pos;
    791   unsigned char *sha256sumdigest = NULL;
    792 #endif
    793 
    794   /* if a path wasn't specified, don't pin */
    795   if(!pinnedpubkey)
    796     return CURLE_OK;
    797   if(!pubkey || !pubkeylen)
    798     return result;
    799 
    800   /* only do this if pinnedpubkey starts with "sha256//", length 8 */
    801   if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
    802 #ifdef curlssl_sha256sum
    803     /* compute sha256sum of public key */
    804     sha256sumdigest = malloc(SHA256_DIGEST_LENGTH);
    805     if(!sha256sumdigest)
    806       return CURLE_OUT_OF_MEMORY;
    807     curlssl_sha256sum(pubkey, pubkeylen,
    808                       sha256sumdigest, SHA256_DIGEST_LENGTH);
    809     encode = Curl_base64_encode(data, (char *)sha256sumdigest,
    810                                 SHA256_DIGEST_LENGTH, &encoded, &encodedlen);
    811     Curl_safefree(sha256sumdigest);
    812 
    813     if(encode)
    814       return encode;
    815 
    816     infof(data, "\t public key hash: sha256//%s\n", encoded);
    817 
    818     /* it starts with sha256//, copy so we can modify it */
    819     pinkeylen = strlen(pinnedpubkey) + 1;
    820     pinkeycopy = malloc(pinkeylen);
    821     if(!pinkeycopy) {
    822       Curl_safefree(encoded);
    823       return CURLE_OUT_OF_MEMORY;
    824     }
    825     memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
    826     /* point begin_pos to the copy, and start extracting keys */
    827     begin_pos = pinkeycopy;
    828     do {
    829       end_pos = strstr(begin_pos, ";sha256//");
    830       /*
    831        * if there is an end_pos, null terminate,
    832        * otherwise it'll go to the end of the original string
    833        */
    834       if(end_pos)
    835         end_pos[0] = '\0';
    836 
    837       /* compare base64 sha256 digests, 8 is the length of "sha256//" */
    838       if(encodedlen == strlen(begin_pos + 8) &&
    839          !memcmp(encoded, begin_pos + 8, encodedlen)) {
    840         result = CURLE_OK;
    841         break;
    842       }
    843 
    844       /*
    845        * change back the null-terminator we changed earlier,
    846        * and look for next begin
    847        */
    848       if(end_pos) {
    849         end_pos[0] = ';';
    850         begin_pos = strstr(end_pos, "sha256//");
    851       }
    852     } while(end_pos && begin_pos);
    853     Curl_safefree(encoded);
    854     Curl_safefree(pinkeycopy);
    855 #else
    856     /* without sha256 support, this cannot match */
    857     (void)data;
    858 #endif
    859     return result;
    860   }
    861 
    862   fp = fopen(pinnedpubkey, "rb");
    863   if(!fp)
    864     return result;
    865 
    866   do {
    867     /* Determine the file's size */
    868     if(fseek(fp, 0, SEEK_END))
    869       break;
    870     filesize = ftell(fp);
    871     if(fseek(fp, 0, SEEK_SET))
    872       break;
    873     if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
    874       break;
    875 
    876     /*
    877      * if the size of our certificate is bigger than the file
    878      * size then it can't match
    879      */
    880     size = curlx_sotouz((curl_off_t) filesize);
    881     if(pubkeylen > size)
    882       break;
    883 
    884     /*
    885      * Allocate buffer for the pinned key
    886      * With 1 additional byte for null terminator in case of PEM key
    887      */
    888     buf = malloc(size + 1);
    889     if(!buf)
    890       break;
    891 
    892     /* Returns number of elements read, which should be 1 */
    893     if((int) fread(buf, size, 1, fp) != 1)
    894       break;
    895 
    896     /* If the sizes are the same, it can't be base64 encoded, must be der */
    897     if(pubkeylen == size) {
    898       if(!memcmp(pubkey, buf, pubkeylen))
    899         result = CURLE_OK;
    900       break;
    901     }
    902 
    903     /*
    904      * Otherwise we will assume it's PEM and try to decode it
    905      * after placing null terminator
    906      */
    907     buf[size] = '\0';
    908     pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
    909     /* if it wasn't read successfully, exit */
    910     if(pem_read)
    911       break;
    912 
    913     /*
    914      * if the size of our certificate doesn't match the size of
    915      * the decoded file, they can't be the same, otherwise compare
    916      */
    917     if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
    918       result = CURLE_OK;
    919   } while(0);
    920 
    921   Curl_safefree(buf);
    922   Curl_safefree(pem_ptr);
    923   fclose(fp);
    924 
    925   return result;
    926 }
    927 
    928 #ifndef CURL_DISABLE_CRYPTO_AUTH
    929 CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
    930                          size_t tmplen,
    931                          unsigned char *md5sum, /* output */
    932                          size_t md5len)
    933 {
    934 #ifdef curlssl_md5sum
    935   curlssl_md5sum(tmp, tmplen, md5sum, md5len);
    936 #else
    937   MD5_context *MD5pw;
    938 
    939   (void) md5len;
    940 
    941   MD5pw = Curl_MD5_init(Curl_DIGEST_MD5);
    942   if(!MD5pw)
    943     return CURLE_OUT_OF_MEMORY;
    944   Curl_MD5_update(MD5pw, tmp, curlx_uztoui(tmplen));
    945   Curl_MD5_final(MD5pw, md5sum);
    946 #endif
    947   return CURLE_OK;
    948 }
    949 #endif
    950 
    951 /*
    952  * Check whether the SSL backend supports the status_request extension.
    953  */
    954 bool Curl_ssl_cert_status_request(void)
    955 {
    956 #ifdef curlssl_cert_status_request
    957   return curlssl_cert_status_request();
    958 #else
    959   return FALSE;
    960 #endif
    961 }
    962 
    963 /*
    964  * Check whether the SSL backend supports false start.
    965  */
    966 bool Curl_ssl_false_start(void)
    967 {
    968 #ifdef curlssl_false_start
    969   return curlssl_false_start();
    970 #else
    971   return FALSE;
    972 #endif
    973 }
    974 
    975 #endif /* USE_SSL */
    976