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