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