vtls.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 /* This file is for implementing all "generic" SSL functions that all libcurl
00024    internals should use. It is then responsible for calling the proper
00025    "backend" function.
00026 
00027    SSL-functions in libcurl should call functions in this source file, and not
00028    to any specific SSL-layer.
00029 
00030    Curl_ssl_ - prefix for generic ones
00031    Curl_ossl_ - prefix for OpenSSL ones
00032    Curl_gtls_ - prefix for GnuTLS ones
00033    Curl_nss_ - prefix for NSS ones
00034    Curl_gskit_ - prefix for GSKit ones
00035    Curl_polarssl_ - prefix for PolarSSL ones
00036    Curl_cyassl_ - prefix for CyaSSL ones
00037    Curl_schannel_ - prefix for Schannel SSPI ones
00038    Curl_darwinssl_ - prefix for SecureTransport (Darwin) ones
00039 
00040    Note that this source code uses curlssl_* functions, and they are all
00041    defines/macros #defined by the lib-specific header files.
00042 
00043    "SSL/TLS Strong Encryption: An Introduction"
00044    https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
00045 */
00046 
00047 #include "curl_setup.h"
00048 
00049 #ifdef HAVE_SYS_TYPES_H
00050 #include <sys/types.h>
00051 #endif
00052 #ifdef HAVE_SYS_STAT_H
00053 #include <sys/stat.h>
00054 #endif
00055 #ifdef HAVE_FCNTL_H
00056 #include <fcntl.h>
00057 #endif
00058 
00059 #include "urldata.h"
00060 
00061 #include "vtls.h" /* generic SSL protos etc */
00062 #include "slist.h"
00063 #include "sendf.h"
00064 #include "strcase.h"
00065 #include "url.h"
00066 #include "progress.h"
00067 #include "share.h"
00068 #include "multiif.h"
00069 #include "timeval.h"
00070 #include "curl_md5.h"
00071 #include "warnless.h"
00072 #include "curl_base64.h"
00073 #include "curl_printf.h"
00074 
00075 /* The last #include files should be: */
00076 #include "curl_memory.h"
00077 #include "memdebug.h"
00078 
00079 /* convenience macro to check if this handle is using a shared SSL session */
00080 #define SSLSESSION_SHARED(data) (data->share &&                        \
00081                                  (data->share->specifier &             \
00082                                   (1<<CURL_LOCK_DATA_SSL_SESSION)))
00083 
00084 #define CLONE_STRING(var)                    \
00085   if(source->var) {                          \
00086     dest->var = strdup(source->var);         \
00087     if(!dest->var)                           \
00088       return FALSE;                          \
00089   }                                          \
00090   else                                       \
00091     dest->var = NULL;
00092 
00093 bool
00094 Curl_ssl_config_matches(struct ssl_primary_config* data,
00095                         struct ssl_primary_config* needle)
00096 {
00097   if((data->version == needle->version) &&
00098      (data->verifypeer == needle->verifypeer) &&
00099      (data->verifyhost == needle->verifyhost) &&
00100      Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
00101      Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
00102      Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
00103      Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list))
00104     return TRUE;
00105 
00106   return FALSE;
00107 }
00108 
00109 bool
00110 Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
00111                               struct ssl_primary_config *dest)
00112 {
00113   dest->verifyhost = source->verifyhost;
00114   dest->verifypeer = source->verifypeer;
00115   dest->version = source->version;
00116 
00117   CLONE_STRING(CAfile);
00118   CLONE_STRING(CApath);
00119   CLONE_STRING(cipher_list);
00120   CLONE_STRING(egdsocket);
00121   CLONE_STRING(random_file);
00122   CLONE_STRING(clientcert);
00123   return TRUE;
00124 }
00125 
00126 void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
00127 {
00128   Curl_safefree(sslc->CAfile);
00129   Curl_safefree(sslc->CApath);
00130   Curl_safefree(sslc->cipher_list);
00131   Curl_safefree(sslc->egdsocket);
00132   Curl_safefree(sslc->random_file);
00133   Curl_safefree(sslc->clientcert);
00134 }
00135 
00136 int Curl_ssl_backend(void)
00137 {
00138   return (int)CURL_SSL_BACKEND;
00139 }
00140 
00141 #ifdef USE_SSL
00142 
00143 /* "global" init done? */
00144 static bool init_ssl=FALSE;
00145 
00152 int Curl_ssl_init(void)
00153 {
00154   /* make sure this is only done once */
00155   if(init_ssl)
00156     return 1;
00157   init_ssl = TRUE; /* never again */
00158 
00159   return curlssl_init();
00160 }
00161 
00162 
00163 /* Global cleanup */
00164 void Curl_ssl_cleanup(void)
00165 {
00166   if(init_ssl) {
00167     /* only cleanup if we did a previous init */
00168     curlssl_cleanup();
00169     init_ssl = FALSE;
00170   }
00171 }
00172 
00173 static bool ssl_prefs_check(struct Curl_easy *data)
00174 {
00175   /* check for CURLOPT_SSLVERSION invalid parameter value */
00176   if((data->set.ssl.primary.version < 0)
00177      || (data->set.ssl.primary.version >= CURL_SSLVERSION_LAST)) {
00178     failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
00179     return FALSE;
00180   }
00181   return TRUE;
00182 }
00183 
00184 static CURLcode
00185 ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
00186 {
00187   DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
00188   if(ssl_connection_complete == conn->ssl[sockindex].state &&
00189      !conn->proxy_ssl[sockindex].use) {
00190 #if defined(HTTPS_PROXY_SUPPORT)
00191     conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
00192     memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
00193 #else
00194     return CURLE_NOT_BUILT_IN;
00195 #endif
00196   }
00197   return CURLE_OK;
00198 }
00199 
00200 CURLcode
00201 Curl_ssl_connect(struct connectdata *conn, int sockindex)
00202 {
00203   CURLcode result;
00204 
00205   if(conn->bits.proxy_ssl_connected[sockindex]) {
00206     result = ssl_connect_init_proxy(conn, sockindex);
00207     if(result)
00208       return result;
00209   }
00210 
00211   if(!ssl_prefs_check(conn->data))
00212     return CURLE_SSL_CONNECT_ERROR;
00213 
00214   /* mark this is being ssl-enabled from here on. */
00215   conn->ssl[sockindex].use = TRUE;
00216   conn->ssl[sockindex].state = ssl_connection_negotiating;
00217 
00218   result = curlssl_connect(conn, sockindex);
00219 
00220   if(!result)
00221     Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
00222 
00223   return result;
00224 }
00225 
00226 CURLcode
00227 Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
00228                              bool *done)
00229 {
00230   CURLcode result;
00231   if(conn->bits.proxy_ssl_connected[sockindex]) {
00232     result = ssl_connect_init_proxy(conn, sockindex);
00233     if(result)
00234       return result;
00235   }
00236 
00237   if(!ssl_prefs_check(conn->data))
00238     return CURLE_SSL_CONNECT_ERROR;
00239 
00240   /* mark this is being ssl requested from here on. */
00241   conn->ssl[sockindex].use = TRUE;
00242 #ifdef curlssl_connect_nonblocking
00243   result = curlssl_connect_nonblocking(conn, sockindex, done);
00244 #else
00245   *done = TRUE; /* fallback to BLOCKING */
00246   result = curlssl_connect(conn, sockindex);
00247 #endif /* non-blocking connect support */
00248   if(!result && *done)
00249     Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
00250   return result;
00251 }
00252 
00253 /*
00254  * Lock shared SSL session data
00255  */
00256 void Curl_ssl_sessionid_lock(struct connectdata *conn)
00257 {
00258   if(SSLSESSION_SHARED(conn->data))
00259     Curl_share_lock(conn->data,
00260                     CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
00261 }
00262 
00263 /*
00264  * Unlock shared SSL session data
00265  */
00266 void Curl_ssl_sessionid_unlock(struct connectdata *conn)
00267 {
00268   if(SSLSESSION_SHARED(conn->data))
00269     Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION);
00270 }
00271 
00272 /*
00273  * Check if there's a session ID for the given connection in the cache, and if
00274  * there's one suitable, it is provided. Returns TRUE when no entry matched.
00275  */
00276 bool Curl_ssl_getsessionid(struct connectdata *conn,
00277                            void **ssl_sessionid,
00278                            size_t *idsize, /* set 0 if unknown */
00279                            int sockindex)
00280 {
00281   struct curl_ssl_session *check;
00282   struct Curl_easy *data = conn->data;
00283   size_t i;
00284   long *general_age;
00285   bool no_match = TRUE;
00286 
00287   const bool isProxy = CONNECT_PROXY_SSL();
00288   struct ssl_primary_config * const ssl_config = isProxy ?
00289                                                  &conn->proxy_ssl_config :
00290                                                  &conn->ssl_config;
00291   const char * const name = isProxy ? conn->http_proxy.host.name :
00292                                       conn->host.name;
00293   int port = isProxy ? (int)conn->port : conn->remote_port;
00294   *ssl_sessionid = NULL;
00295 
00296   DEBUGASSERT(data->set.general_ssl.sessionid);
00297 
00298   if(!data->set.general_ssl.sessionid)
00299     /* session ID re-use is disabled */
00300     return TRUE;
00301 
00302   /* Lock if shared */
00303   if(SSLSESSION_SHARED(data))
00304     general_age = &data->share->sessionage;
00305   else
00306     general_age = &data->state.sessionage;
00307 
00308   for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
00309     check = &data->state.session[i];
00310     if(!check->sessionid)
00311       /* not session ID means blank entry */
00312       continue;
00313     if(strcasecompare(name, check->name) &&
00314        ((!conn->bits.conn_to_host && !check->conn_to_host) ||
00315         (conn->bits.conn_to_host && check->conn_to_host &&
00316          strcasecompare(conn->conn_to_host.name, check->conn_to_host))) &&
00317        ((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
00318         (conn->bits.conn_to_port && check->conn_to_port != -1 &&
00319          conn->conn_to_port == check->conn_to_port)) &&
00320        (port == check->remote_port) &&
00321        strcasecompare(conn->handler->scheme, check->scheme) &&
00322        Curl_ssl_config_matches(ssl_config, &check->ssl_config)) {
00323       /* yes, we have a session ID! */
00324       (*general_age)++;          /* increase general age */
00325       check->age = *general_age; /* set this as used in this age */
00326       *ssl_sessionid = check->sessionid;
00327       if(idsize)
00328         *idsize = check->idsize;
00329       no_match = FALSE;
00330       break;
00331     }
00332   }
00333 
00334   return no_match;
00335 }
00336 
00337 /*
00338  * Kill a single session ID entry in the cache.
00339  */
00340 void Curl_ssl_kill_session(struct curl_ssl_session *session)
00341 {
00342   if(session->sessionid) {
00343     /* defensive check */
00344 
00345     /* free the ID the SSL-layer specific way */
00346     curlssl_session_free(session->sessionid);
00347 
00348     session->sessionid = NULL;
00349     session->age = 0; /* fresh */
00350 
00351     Curl_free_primary_ssl_config(&session->ssl_config);
00352 
00353     Curl_safefree(session->name);
00354     Curl_safefree(session->conn_to_host);
00355   }
00356 }
00357 
00358 /*
00359  * Delete the given session ID from the cache.
00360  */
00361 void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
00362 {
00363   size_t i;
00364   struct Curl_easy *data=conn->data;
00365 
00366   for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
00367     struct curl_ssl_session *check = &data->state.session[i];
00368 
00369     if(check->sessionid == ssl_sessionid) {
00370       Curl_ssl_kill_session(check);
00371       break;
00372     }
00373   }
00374 }
00375 
00376 /*
00377  * Store session id in the session cache. The ID passed on to this function
00378  * must already have been extracted and allocated the proper way for the SSL
00379  * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
00380  * later on.
00381  */
00382 CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
00383                                void *ssl_sessionid,
00384                                size_t idsize,
00385                                int sockindex)
00386 {
00387   size_t i;
00388   struct Curl_easy *data=conn->data; /* the mother of all structs */
00389   struct curl_ssl_session *store = &data->state.session[0];
00390   long oldest_age=data->state.session[0].age; /* zero if unused */
00391   char *clone_host;
00392   char *clone_conn_to_host;
00393   int conn_to_port;
00394   long *general_age;
00395   const bool isProxy = CONNECT_PROXY_SSL();
00396   struct ssl_primary_config * const ssl_config = isProxy ?
00397                                            &conn->proxy_ssl_config :
00398                                            &conn->ssl_config;
00399 
00400   DEBUGASSERT(data->set.general_ssl.sessionid);
00401 
00402   clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name);
00403   if(!clone_host)
00404     return CURLE_OUT_OF_MEMORY; /* bail out */
00405 
00406   if(conn->bits.conn_to_host) {
00407     clone_conn_to_host = strdup(conn->conn_to_host.name);
00408     if(!clone_conn_to_host) {
00409       free(clone_host);
00410       return CURLE_OUT_OF_MEMORY; /* bail out */
00411     }
00412   }
00413   else
00414     clone_conn_to_host = NULL;
00415 
00416   if(conn->bits.conn_to_port)
00417     conn_to_port = conn->conn_to_port;
00418   else
00419     conn_to_port = -1;
00420 
00421   /* Now we should add the session ID and the host name to the cache, (remove
00422      the oldest if necessary) */
00423 
00424   /* If using shared SSL session, lock! */
00425   if(SSLSESSION_SHARED(data)) {
00426     general_age = &data->share->sessionage;
00427   }
00428   else {
00429     general_age = &data->state.sessionage;
00430   }
00431 
00432   /* find an empty slot for us, or find the oldest */
00433   for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) &&
00434         data->state.session[i].sessionid; i++) {
00435     if(data->state.session[i].age < oldest_age) {
00436       oldest_age = data->state.session[i].age;
00437       store = &data->state.session[i];
00438     }
00439   }
00440   if(i == data->set.general_ssl.max_ssl_sessions)
00441     /* cache is full, we must "kill" the oldest entry! */
00442     Curl_ssl_kill_session(store);
00443   else
00444     store = &data->state.session[i]; /* use this slot */
00445 
00446   /* now init the session struct wisely */
00447   store->sessionid = ssl_sessionid;
00448   store->idsize = idsize;
00449   store->age = *general_age;    /* set current age */
00450     /* free it if there's one already present */
00451   free(store->name);
00452   free(store->conn_to_host);
00453   store->name = clone_host;               /* clone host name */
00454   store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
00455   store->conn_to_port = conn_to_port; /* connect to port number */
00456   /* port number */
00457   store->remote_port = isProxy ? (int)conn->port : conn->remote_port;
00458   store->scheme = conn->handler->scheme;
00459 
00460   if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) {
00461     store->sessionid = NULL; /* let caller free sessionid */
00462     free(clone_host);
00463     free(clone_conn_to_host);
00464     return CURLE_OUT_OF_MEMORY;
00465   }
00466 
00467   return CURLE_OK;
00468 }
00469 
00470 
00471 void Curl_ssl_close_all(struct Curl_easy *data)
00472 {
00473   size_t i;
00474   /* kill the session ID cache if not shared */
00475   if(data->state.session && !SSLSESSION_SHARED(data)) {
00476     for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
00477       /* the single-killer function handles empty table slots */
00478       Curl_ssl_kill_session(&data->state.session[i]);
00479 
00480     /* free the cache data */
00481     Curl_safefree(data->state.session);
00482   }
00483 
00484   curlssl_close_all(data);
00485 }
00486 
00487 #if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
00488     defined(USE_DARWINSSL) || defined(USE_NSS)
00489 /* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only. */
00490 int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks,
00491                      int numsocks)
00492 {
00493   struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
00494 
00495   if(!numsocks)
00496     return GETSOCK_BLANK;
00497 
00498   if(connssl->connecting_state == ssl_connect_2_writing) {
00499     /* write mode */
00500     socks[0] = conn->sock[FIRSTSOCKET];
00501     return GETSOCK_WRITESOCK(0);
00502   }
00503   else if(connssl->connecting_state == ssl_connect_2_reading) {
00504     /* read mode */
00505     socks[0] = conn->sock[FIRSTSOCKET];
00506     return GETSOCK_READSOCK(0);
00507   }
00508 
00509   return GETSOCK_BLANK;
00510 }
00511 #else
00512 int Curl_ssl_getsock(struct connectdata *conn,
00513                           curl_socket_t *socks,
00514                           int numsocks)
00515 {
00516   (void)conn;
00517   (void)socks;
00518   (void)numsocks;
00519   return GETSOCK_BLANK;
00520 }
00521 /* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */
00522 #endif
00523 
00524 void Curl_ssl_close(struct connectdata *conn, int sockindex)
00525 {
00526   DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
00527   curlssl_close(conn, sockindex);
00528 }
00529 
00530 CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
00531 {
00532   if(curlssl_shutdown(conn, sockindex))
00533     return CURLE_SSL_SHUTDOWN_FAILED;
00534 
00535   conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
00536   conn->ssl[sockindex].state = ssl_connection_none;
00537 
00538   conn->recv[sockindex] = Curl_recv_plain;
00539   conn->send[sockindex] = Curl_send_plain;
00540 
00541   return CURLE_OK;
00542 }
00543 
00544 /* Selects an SSL crypto engine
00545  */
00546 CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
00547 {
00548   return curlssl_set_engine(data, engine);
00549 }
00550 
00551 /* Selects the default SSL crypto engine
00552  */
00553 CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
00554 {
00555   return curlssl_set_engine_default(data);
00556 }
00557 
00558 /* Return list of OpenSSL crypto engine names. */
00559 struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
00560 {
00561   return curlssl_engines_list(data);
00562 }
00563 
00564 /*
00565  * This sets up a session ID cache to the specified size. Make sure this code
00566  * is agnostic to what underlying SSL technology we use.
00567  */
00568 CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
00569 {
00570   struct curl_ssl_session *session;
00571 
00572   if(data->state.session)
00573     /* this is just a precaution to prevent multiple inits */
00574     return CURLE_OK;
00575 
00576   session = calloc(amount, sizeof(struct curl_ssl_session));
00577   if(!session)
00578     return CURLE_OUT_OF_MEMORY;
00579 
00580   /* store the info in the SSL section */
00581   data->set.general_ssl.max_ssl_sessions = amount;
00582   data->state.session = session;
00583   data->state.sessionage = 1; /* this is brand new */
00584   return CURLE_OK;
00585 }
00586 
00587 size_t Curl_ssl_version(char *buffer, size_t size)
00588 {
00589   return curlssl_version(buffer, size);
00590 }
00591 
00592 /*
00593  * This function tries to determine connection status.
00594  *
00595  * Return codes:
00596  *     1 means the connection is still in place
00597  *     0 means the connection has been closed
00598  *    -1 means the connection status is unknown
00599  */
00600 int Curl_ssl_check_cxn(struct connectdata *conn)
00601 {
00602   return curlssl_check_cxn(conn);
00603 }
00604 
00605 bool Curl_ssl_data_pending(const struct connectdata *conn,
00606                            int connindex)
00607 {
00608   return curlssl_data_pending(conn, connindex);
00609 }
00610 
00611 void Curl_ssl_free_certinfo(struct Curl_easy *data)
00612 {
00613   int i;
00614   struct curl_certinfo *ci = &data->info.certs;
00615 
00616   if(ci->num_of_certs) {
00617     /* free all individual lists used */
00618     for(i=0; i<ci->num_of_certs; i++) {
00619       curl_slist_free_all(ci->certinfo[i]);
00620       ci->certinfo[i] = NULL;
00621     }
00622 
00623     free(ci->certinfo); /* free the actual array too */
00624     ci->certinfo = NULL;
00625     ci->num_of_certs = 0;
00626   }
00627 }
00628 
00629 CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
00630 {
00631   struct curl_certinfo *ci = &data->info.certs;
00632   struct curl_slist **table;
00633 
00634   /* Free any previous certificate information structures */
00635   Curl_ssl_free_certinfo(data);
00636 
00637   /* Allocate the required certificate information structures */
00638   table = calloc((size_t) num, sizeof(struct curl_slist *));
00639   if(!table)
00640     return CURLE_OUT_OF_MEMORY;
00641 
00642   ci->num_of_certs = num;
00643   ci->certinfo = table;
00644 
00645   return CURLE_OK;
00646 }
00647 
00648 /*
00649  * 'value' is NOT a zero terminated string
00650  */
00651 CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
00652                                     int certnum,
00653                                     const char *label,
00654                                     const char *value,
00655                                     size_t valuelen)
00656 {
00657   struct curl_certinfo *ci = &data->info.certs;
00658   char *output;
00659   struct curl_slist *nl;
00660   CURLcode result = CURLE_OK;
00661   size_t labellen = strlen(label);
00662   size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
00663 
00664   output = malloc(outlen);
00665   if(!output)
00666     return CURLE_OUT_OF_MEMORY;
00667 
00668   /* sprintf the label and colon */
00669   snprintf(output, outlen, "%s:", label);
00670 
00671   /* memcpy the value (it might not be zero terminated) */
00672   memcpy(&output[labellen+1], value, valuelen);
00673 
00674   /* zero terminate the output */
00675   output[labellen + 1 + valuelen] = 0;
00676 
00677   nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
00678   if(!nl) {
00679     free(output);
00680     curl_slist_free_all(ci->certinfo[certnum]);
00681     result = CURLE_OUT_OF_MEMORY;
00682   }
00683 
00684   ci->certinfo[certnum] = nl;
00685   return result;
00686 }
00687 
00688 /*
00689  * This is a convenience function for push_certinfo_len that takes a zero
00690  * terminated value.
00691  */
00692 CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data,
00693                                 int certnum,
00694                                 const char *label,
00695                                 const char *value)
00696 {
00697   size_t valuelen = strlen(value);
00698 
00699   return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
00700 }
00701 
00702 CURLcode Curl_ssl_random(struct Curl_easy *data,
00703                          unsigned char *entropy,
00704                          size_t length)
00705 {
00706   int rc = curlssl_random(data, entropy, length);
00707   if(rc) {
00708     failf(data, "PRNG seeding failed");
00709     return CURLE_FAILED_INIT; /* possibly weird return code */
00710   }
00711   return CURLE_OK;
00712 }
00713 
00714 /*
00715  * Public key pem to der conversion
00716  */
00717 
00718 static CURLcode pubkey_pem_to_der(const char *pem,
00719                                   unsigned char **der, size_t *der_len)
00720 {
00721   char *stripped_pem, *begin_pos, *end_pos;
00722   size_t pem_count, stripped_pem_count = 0, pem_len;
00723   CURLcode result;
00724 
00725   /* if no pem, exit. */
00726   if(!pem)
00727     return CURLE_BAD_CONTENT_ENCODING;
00728 
00729   begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
00730   if(!begin_pos)
00731     return CURLE_BAD_CONTENT_ENCODING;
00732 
00733   pem_count = begin_pos - pem;
00734   /* Invalid if not at beginning AND not directly following \n */
00735   if(0 != pem_count && '\n' != pem[pem_count - 1])
00736     return CURLE_BAD_CONTENT_ENCODING;
00737 
00738   /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
00739   pem_count += 26;
00740 
00741   /* Invalid if not directly following \n */
00742   end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
00743   if(!end_pos)
00744     return CURLE_BAD_CONTENT_ENCODING;
00745 
00746   pem_len = end_pos - pem;
00747 
00748   stripped_pem = malloc(pem_len - pem_count + 1);
00749   if(!stripped_pem)
00750     return CURLE_OUT_OF_MEMORY;
00751 
00752   /*
00753    * Here we loop through the pem array one character at a time between the
00754    * correct indices, and place each character that is not '\n' or '\r'
00755    * into the stripped_pem array, which should represent the raw base64 string
00756    */
00757   while(pem_count < pem_len) {
00758     if('\n' != pem[pem_count] && '\r' != pem[pem_count])
00759       stripped_pem[stripped_pem_count++] = pem[pem_count];
00760     ++pem_count;
00761   }
00762   /* Place the null terminator in the correct place */
00763   stripped_pem[stripped_pem_count] = '\0';
00764 
00765   result = Curl_base64_decode(stripped_pem, der, der_len);
00766 
00767   Curl_safefree(stripped_pem);
00768 
00769   return result;
00770 }
00771 
00772 /*
00773  * Generic pinned public key check.
00774  */
00775 
00776 CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
00777                               const char *pinnedpubkey,
00778                               const unsigned char *pubkey, size_t pubkeylen)
00779 {
00780   FILE *fp;
00781   unsigned char *buf = NULL, *pem_ptr = NULL;
00782   long filesize;
00783   size_t size, pem_len;
00784   CURLcode pem_read;
00785   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
00786 #ifdef curlssl_sha256sum
00787   CURLcode encode;
00788   size_t encodedlen, pinkeylen;
00789   char *encoded, *pinkeycopy, *begin_pos, *end_pos;
00790   unsigned char *sha256sumdigest = NULL;
00791 #endif
00792 
00793   /* if a path wasn't specified, don't pin */
00794   if(!pinnedpubkey)
00795     return CURLE_OK;
00796   if(!pubkey || !pubkeylen)
00797     return result;
00798 
00799   /* only do this if pinnedpubkey starts with "sha256//", length 8 */
00800   if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
00801 #ifdef curlssl_sha256sum
00802     /* compute sha256sum of public key */
00803     sha256sumdigest = malloc(SHA256_DIGEST_LENGTH);
00804     if(!sha256sumdigest)
00805       return CURLE_OUT_OF_MEMORY;
00806     curlssl_sha256sum(pubkey, pubkeylen,
00807                       sha256sumdigest, SHA256_DIGEST_LENGTH);
00808     encode = Curl_base64_encode(data, (char *)sha256sumdigest,
00809                                 SHA256_DIGEST_LENGTH, &encoded, &encodedlen);
00810     Curl_safefree(sha256sumdigest);
00811 
00812     if(encode)
00813       return encode;
00814 
00815     infof(data, "\t public key hash: sha256//%s\n", encoded);
00816 
00817     /* it starts with sha256//, copy so we can modify it */
00818     pinkeylen = strlen(pinnedpubkey) + 1;
00819     pinkeycopy = malloc(pinkeylen);
00820     if(!pinkeycopy) {
00821       Curl_safefree(encoded);
00822       return CURLE_OUT_OF_MEMORY;
00823     }
00824     memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
00825     /* point begin_pos to the copy, and start extracting keys */
00826     begin_pos = pinkeycopy;
00827     do {
00828       end_pos = strstr(begin_pos, ";sha256//");
00829       /*
00830        * if there is an end_pos, null terminate,
00831        * otherwise it'll go to the end of the original string
00832        */
00833       if(end_pos)
00834         end_pos[0] = '\0';
00835 
00836       /* compare base64 sha256 digests, 8 is the length of "sha256//" */
00837       if(encodedlen == strlen(begin_pos + 8) &&
00838          !memcmp(encoded, begin_pos + 8, encodedlen)) {
00839         result = CURLE_OK;
00840         break;
00841       }
00842 
00843       /*
00844        * change back the null-terminator we changed earlier,
00845        * and look for next begin
00846        */
00847       if(end_pos) {
00848         end_pos[0] = ';';
00849         begin_pos = strstr(end_pos, "sha256//");
00850       }
00851     } while(end_pos && begin_pos);
00852     Curl_safefree(encoded);
00853     Curl_safefree(pinkeycopy);
00854 #else
00855     /* without sha256 support, this cannot match */
00856     (void)data;
00857 #endif
00858     return result;
00859   }
00860 
00861   fp = fopen(pinnedpubkey, "rb");
00862   if(!fp)
00863     return result;
00864 
00865   do {
00866     /* Determine the file's size */
00867     if(fseek(fp, 0, SEEK_END))
00868       break;
00869     filesize = ftell(fp);
00870     if(fseek(fp, 0, SEEK_SET))
00871       break;
00872     if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
00873       break;
00874 
00875     /*
00876      * if the size of our certificate is bigger than the file
00877      * size then it can't match
00878      */
00879     size = curlx_sotouz((curl_off_t) filesize);
00880     if(pubkeylen > size)
00881       break;
00882 
00883     /*
00884      * Allocate buffer for the pinned key
00885      * With 1 additional byte for null terminator in case of PEM key
00886      */
00887     buf = malloc(size + 1);
00888     if(!buf)
00889       break;
00890 
00891     /* Returns number of elements read, which should be 1 */
00892     if((int) fread(buf, size, 1, fp) != 1)
00893       break;
00894 
00895     /* If the sizes are the same, it can't be base64 encoded, must be der */
00896     if(pubkeylen == size) {
00897       if(!memcmp(pubkey, buf, pubkeylen))
00898         result = CURLE_OK;
00899       break;
00900     }
00901 
00902     /*
00903      * Otherwise we will assume it's PEM and try to decode it
00904      * after placing null terminator
00905      */
00906     buf[size] = '\0';
00907     pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
00908     /* if it wasn't read successfully, exit */
00909     if(pem_read)
00910       break;
00911 
00912     /*
00913      * if the size of our certificate doesn't match the size of
00914      * the decoded file, they can't be the same, otherwise compare
00915      */
00916     if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
00917       result = CURLE_OK;
00918   } while(0);
00919 
00920   Curl_safefree(buf);
00921   Curl_safefree(pem_ptr);
00922   fclose(fp);
00923 
00924   return result;
00925 }
00926 
00927 #ifndef CURL_DISABLE_CRYPTO_AUTH
00928 CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
00929                          size_t tmplen,
00930                          unsigned char *md5sum, /* output */
00931                          size_t md5len)
00932 {
00933 #ifdef curlssl_md5sum
00934   curlssl_md5sum(tmp, tmplen, md5sum, md5len);
00935 #else
00936   MD5_context *MD5pw;
00937 
00938   (void) md5len;
00939 
00940   MD5pw = Curl_MD5_init(Curl_DIGEST_MD5);
00941   if(!MD5pw)
00942     return CURLE_OUT_OF_MEMORY;
00943   Curl_MD5_update(MD5pw, tmp, curlx_uztoui(tmplen));
00944   Curl_MD5_final(MD5pw, md5sum);
00945 #endif
00946   return CURLE_OK;
00947 }
00948 #endif
00949 
00950 /*
00951  * Check whether the SSL backend supports the status_request extension.
00952  */
00953 bool Curl_ssl_cert_status_request(void)
00954 {
00955 #ifdef curlssl_cert_status_request
00956   return curlssl_cert_status_request();
00957 #else
00958   return FALSE;
00959 #endif
00960 }
00961 
00962 /*
00963  * Check whether the SSL backend supports false start.
00964  */
00965 bool Curl_ssl_false_start(void)
00966 {
00967 #ifdef curlssl_false_start
00968   return curlssl_false_start();
00969 #else
00970   return FALSE;
00971 #endif
00972 }
00973 
00974 #endif /* USE_SSL */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:07