diff options
Diffstat (limited to 'plugins/FTPFileYM/curl/lib/ssluse.c')
| -rw-r--r-- | plugins/FTPFileYM/curl/lib/ssluse.c | 272 | 
1 files changed, 121 insertions, 151 deletions
diff --git a/plugins/FTPFileYM/curl/lib/ssluse.c b/plugins/FTPFileYM/curl/lib/ssluse.c index 4a0dba734d..c747420f60 100644 --- a/plugins/FTPFileYM/curl/lib/ssluse.c +++ b/plugins/FTPFileYM/curl/lib/ssluse.c @@ -43,6 +43,7 @@  #include "inet_pton.h"  #include "ssluse.h"  #include "connect.h" +#include "slist.h"  #include "strequal.h"  #include "select.h"  #include "sslgen.h" @@ -236,27 +237,12 @@ static int ossl_seed(struct SessionHandle *data)    /* If we get here, it means we need to seed the PRNG using a "silly"       approach! */ -  { -    int len; -    char *area; - -    /* Changed call to RAND_seed to use the underlying RAND_add implementation -     * directly.  Do this in a loop, with the amount of additional entropy -     * being dependent upon the algorithm used by Curl_FormBoundary(): N bytes -     * of a 7-bit ascii set. -- Richard Gorton, March 11 2003. -     */ - -    do { -      area = Curl_FormBoundary(); -      if(!area) -        return 3; /* out of memory */ - -      len = curlx_uztosi(strlen(area)); -      RAND_add(area, len, (len >> 1)); - -      free(area); /* now remove the random junk */ -    } while(!RAND_status()); -  } +  do { +    unsigned char randb[64]; +    int len = sizeof(randb); +    RAND_bytes(randb, len); +    RAND_add(randb, len, (len >> 1)); +  } while(!RAND_status());    /* generates a default path for the random seed file */    buf[0]=0; /* blank it first */ @@ -308,6 +294,49 @@ static int do_file_type(const char *type)    return -1;  } +#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_LOAD_FOUR_ARGS) +/* + * Supply default password to the engine user interface conversation. + * The password is passed by OpenSSL engine from ENGINE_load_private_key() + * last argument to the ui and can be obtained by UI_get0_user_data(ui) here. + */ +static int ssl_ui_reader(UI *ui, UI_STRING *uis) +{ +  const char *password; +  switch(UI_get_string_type(uis)) { +  case UIT_PROMPT: +  case UIT_VERIFY: +    password = (const char*)UI_get0_user_data(ui); +    if(NULL != password && +       UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD) { +      UI_set_result(ui, uis, password); +      return 1; +    } +  default: +    break; +  } +  return (UI_method_get_reader(UI_OpenSSL()))(ui, uis); +} + +/* + * Suppress interactive request for a default password if available. + */ +static int ssl_ui_writer(UI *ui, UI_STRING *uis) +{ +  switch(UI_get_string_type(uis)) { +  case UIT_PROMPT: +  case UIT_VERIFY: +    if(NULL != UI_get0_user_data(ui) && +       UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD) { +      return 1; +    } +  default: +    break; +  } +  return (UI_method_get_writer(UI_OpenSSL()))(ui, uis); +} +#endif +  static  int cert_stuff(struct connectdata *conn,                 SSL_CTX* ctx, @@ -450,7 +479,7 @@ int cert_stuff(struct connectdata *conn,        PKCS12_PBE_add();        if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509, -                        &ca)) { +                       &ca)) {          failf(data,                "could not parse PKCS12 file, check password, OpenSSL error %s",                ERR_error_string(ERR_get_error(), NULL) ); @@ -462,54 +491,53 @@ int cert_stuff(struct connectdata *conn,        if(SSL_CTX_use_certificate(ctx, x509) != 1) {          failf(data, SSL_CLIENT_CERT_ERR); -        EVP_PKEY_free(pri); -        X509_free(x509); -        sk_X509_pop_free(ca, X509_free); -        return 0; +        goto fail;        }        if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {          failf(data, "unable to use private key from PKCS12 file '%s'",                cert_file); -        EVP_PKEY_free(pri); -        X509_free(x509); -        sk_X509_pop_free(ca, X509_free); -        return 0; +        goto fail;        }        if(!SSL_CTX_check_private_key (ctx)) {          failf(data, "private key from PKCS12 file '%s' "                "does not match certificate in same file", cert_file); -        EVP_PKEY_free(pri); -        X509_free(x509); -        sk_X509_pop_free(ca, X509_free); -        return 0; +        goto fail;        }        /* Set Certificate Verification chain */        if(ca && sk_X509_num(ca)) {          for(i = 0; i < sk_X509_num(ca); i++) { -          if(!SSL_CTX_add_extra_chain_cert(ctx,sk_X509_value(ca, i))) { +          /* +           * Note that sk_X509_pop() is used below to make sure the cert is +           * removed from the stack properly before getting passed to +           * SSL_CTX_add_extra_chain_cert(). Previously we used +           * sk_X509_value() instead, but then we'd clean it in the subsequent +           * sk_X509_pop_free() call. +           */ +          X509 *x = sk_X509_pop(ca); +          if(!SSL_CTX_add_extra_chain_cert(ctx, x)) {              failf(data, "cannot add certificate to certificate chain"); -            EVP_PKEY_free(pri); -            X509_free(x509); -            sk_X509_pop_free(ca, X509_free); -            return 0; +            goto fail;            } -          if(!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i))) { +          /* SSL_CTX_add_client_CA() seems to work with either sk_* function, +           * presumably because it duplicates what we pass to it. +           */ +          if(!SSL_CTX_add_client_CA(ctx, x)) {              failf(data, "cannot add certificate to client CA list"); -            EVP_PKEY_free(pri); -            X509_free(x509); -            sk_X509_pop_free(ca, X509_free); -            return 0; +            goto fail;            }          }        } +      cert_done = 1; +  fail:        EVP_PKEY_free(pri);        X509_free(x509);        sk_X509_pop_free(ca, X509_free); -      cert_done = 1; -      break; + +      if(!cert_done) +        return 0; /* failure! */  #else        failf(data, "file type P12 for certificate not supported");        return 0; @@ -542,7 +570,16 @@ int cert_stuff(struct connectdata *conn,          EVP_PKEY *priv_key = NULL;          if(data->state.engine) {  #ifdef HAVE_ENGINE_LOAD_FOUR_ARGS -          UI_METHOD *ui_method = UI_OpenSSL(); +          UI_METHOD *ui_method = +            UI_create_method((char *)"cURL user interface"); +          if(NULL == ui_method) { +            failf(data, "unable do create OpenSSL user-interface method"); +            return 0; +          } +          UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); +          UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); +          UI_method_set_reader(ui_method, ssl_ui_reader); +          UI_method_set_writer(ui_method, ssl_ui_writer);  #endif            /* the typecast below was added to please mingw32 */            priv_key = (EVP_PKEY *) @@ -551,6 +588,9 @@ int cert_stuff(struct connectdata *conn,                                      ui_method,  #endif                                      data->set.str[STRING_KEY_PASSWD]); +#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS +          UI_destroy_method(ui_method); +#endif            if(!priv_key) {              failf(data, "failed to load private key from crypto engine");              return 0; @@ -1152,6 +1192,8 @@ static CURLcode verifyhost(struct connectdata *conn,      /* an alternative name field existed, but didn't match and then         we MUST fail */      infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname); +    failf(data, "SSL: no alternative certificate subject name matches " +          "target host name '%s'", conn->host.dispname);      res = CURLE_PEER_FAILED_VERIFICATION;    }    else { @@ -1770,7 +1812,7 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)         */        if(CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {          failf(data, "Unknown SSL protocol error in connection to %s:%ld ", -              conn->host.name, conn->port); +              conn->host.name, conn->remote_port);          return rc;        }        /* Could be a CERT problem */ @@ -1806,60 +1848,6 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)    return 0;  } -static CURLcode push_certinfo_len(struct SessionHandle *data, -                                  int certnum, -                                  const char *label, -                                  const char *value, -                                  size_t valuelen) -{ -  struct curl_certinfo *ci = &data->info.certs; -  char *output; -  struct curl_slist *nl; -  CURLcode res = CURLE_OK; -  size_t labellen = strlen(label); -  size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ - -  output = malloc(outlen); -  if(!output) -    return CURLE_OUT_OF_MEMORY; - -  /* sprintf the label and colon */ -  snprintf(output, outlen, "%s:", label); - -  /* memcpy the value (it might not be zero terminated) */ -  memcpy(&output[labellen+1], value, valuelen); - -  /* zero terminate the output */ -  output[labellen + 1 + valuelen] = 0; - -  /* TODO: we should rather introduce an internal API that can do the -     equivalent of curl_slist_append but doesn't strdup() the given data as -     like in this place the extra malloc/free is totally pointless */ -  nl = curl_slist_append(ci->certinfo[certnum], output); -  free(output); -  if(!nl) { -    curl_slist_free_all(ci->certinfo[certnum]); -    ci->certinfo[certnum] = NULL; -    res = CURLE_OUT_OF_MEMORY; -  } -  else -    ci->certinfo[certnum] = nl; - -  return res; -} - -/* this is a convenience function for push_certinfo_len that takes a zero -   terminated value */ -static CURLcode push_certinfo(struct SessionHandle *data, -                              int certnum, -                              const char *label, -                              const char *value) -{ -  size_t valuelen = strlen(value); - -  return push_certinfo_len(data, certnum, label, value, valuelen); -} -  static void pubkey_show(struct SessionHandle *data,                          int num,                          const char *type, @@ -1883,7 +1871,7 @@ static void pubkey_show(struct SessionHandle *data,        left -= 3;      }      infof(data, "   %s: %s\n", namebuf, buffer); -    push_certinfo(data, num, namebuf, buffer); +    Curl_ssl_push_certinfo(data, num, namebuf, buffer);      free(buffer);    }  } @@ -1952,7 +1940,7 @@ static int X509V3_ext(struct SessionHandle *data,      }      infof(data, "  %s\n", buf); -    push_certinfo(data, certnum, namebuf, buf); +    Curl_ssl_push_certinfo(data, certnum, namebuf, buf);      BIO_free(bio_out); @@ -1972,7 +1960,7 @@ static void X509_signature(struct SessionHandle *data,      ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]);    infof(data, " Signature: %s\n", buf); -  push_certinfo(data, numcert, "Signature", buf); +  Curl_ssl_push_certinfo(data, numcert, "Signature", buf);  }  static void dumpcert(struct SessionHandle *data, X509 *x, int numcert) @@ -1988,30 +1976,13 @@ static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)    infof(data, "%s\n", biomem->data); -  push_certinfo_len(data, numcert, "Cert", biomem->data, biomem->length); +  Curl_ssl_push_certinfo_len(data, numcert, +                             "Cert", biomem->data, biomem->length);    BIO_free(bio_out);  } - -static int init_certinfo(struct SessionHandle *data, -                         int num) -{ -  struct curl_certinfo *ci = &data->info.certs; -  struct curl_slist **table; - -  Curl_ssl_free_certinfo(data); - -  ci->num_of_certs = num; -  table = calloc((size_t)num, sizeof(struct curl_slist *)); -  if(!table) -    return 1; - -  ci->certinfo = table; -  return 0; -} -  /*   * This size was previously 512 which has been reported "too small" without   * any specifics, so it was enlarged to allow more data to get shown uncut. @@ -2040,7 +2011,7 @@ static CURLcode get_cert_chain(struct connectdata *conn,    }    numcerts = sk_X509_num(sk); -  if(init_certinfo(data, numcerts)) { +  if(Curl_ssl_init_certinfo(data, numcerts)) {      free(bufp);      return CURLE_OUT_OF_MEMORY;    } @@ -2065,16 +2036,16 @@ static CURLcode get_cert_chain(struct connectdata *conn,      (void)x509_name_oneline(X509_get_subject_name(x), bufp, CERTBUFFERSIZE);      infof(data, "%2d Subject: %s\n", i, bufp); -    push_certinfo(data, i, "Subject", bufp); +    Curl_ssl_push_certinfo(data, i, "Subject", bufp);      (void)x509_name_oneline(X509_get_issuer_name(x), bufp, CERTBUFFERSIZE);      infof(data, "   Issuer: %s\n", bufp); -    push_certinfo(data, i, "Issuer", bufp); +    Curl_ssl_push_certinfo(data, i, "Issuer", bufp);      value = X509_get_version(x);      infof(data, "   Version: %lu (0x%lx)\n", value+1, value);      snprintf(bufp, CERTBUFFERSIZE, "%lx", value); -    push_certinfo(data, i, "Version", bufp); /* hex */ +    Curl_ssl_push_certinfo(data, i, "Version", bufp); /* hex */      num=X509_get_serialNumber(x);      if(num->length <= 4) { @@ -2103,30 +2074,30 @@ static CURLcode get_cert_chain(struct connectdata *conn,          bufp[0]=0;      }      if(bufp[0]) -      push_certinfo(data, i, "Serial Number", bufp); /* hex */ +      Curl_ssl_push_certinfo(data, i, "Serial Number", bufp); /* hex */      cinf = x->cert_info;      j = asn1_object_dump(cinf->signature->algorithm, bufp, CERTBUFFERSIZE);      if(!j) {        infof(data, "   Signature Algorithm: %s\n", bufp); -      push_certinfo(data, i, "Signature Algorithm", bufp); +      Curl_ssl_push_certinfo(data, i, "Signature Algorithm", bufp);      }      certdate = X509_get_notBefore(x);      asn1_output(certdate, bufp, CERTBUFFERSIZE);      infof(data, "   Start date: %s\n", bufp); -    push_certinfo(data, i, "Start date", bufp); +    Curl_ssl_push_certinfo(data, i, "Start date", bufp);      certdate = X509_get_notAfter(x);      asn1_output(certdate, bufp, CERTBUFFERSIZE);      infof(data, "   Expire date: %s\n", bufp); -    push_certinfo(data, i, "Expire date", bufp); +    Curl_ssl_push_certinfo(data, i, "Expire date", bufp);      j = asn1_object_dump(cinf->key->algor->algorithm, bufp, CERTBUFFERSIZE);      if(!j) {        infof(data, "   Public Key Algorithm: %s\n", bufp); -      push_certinfo(data, i, "Public Key Algorithm", bufp); +      Curl_ssl_push_certinfo(data, i, "Public Key Algorithm", bufp);      }      pubkey = X509_get_pubkey(x); @@ -2138,7 +2109,7 @@ static CURLcode get_cert_chain(struct connectdata *conn,          infof(data,  "   RSA Public Key (%d bits)\n",                BN_num_bits(pubkey->pkey.rsa->n));          snprintf(bufp, CERTBUFFERSIZE, "%d", BN_num_bits(pubkey->pkey.rsa->n)); -        push_certinfo(data, i, "RSA Public Key", bufp); +        Curl_ssl_push_certinfo(data, i, "RSA Public Key", bufp);          print_pubkey_BN(rsa, n, i);          print_pubkey_BN(rsa, e, i); @@ -2220,14 +2191,7 @@ static CURLcode servercert(struct connectdata *conn,    rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),                           buffer, BUFSIZE); -  if(rc) { -    if(strict) -      failf(data, "SSL: couldn't get X509-subject!"); -    X509_free(connssl->server_cert); -    connssl->server_cert = NULL; -    return CURLE_SSL_CONNECT_ERROR; -  } -  infof(data, "\t subject: %s\n", buffer); +  infof(data, "\t subject: %s\n", rc?"[NONE]":buffer);    certdate = X509_get_notBefore(connssl->server_cert);    asn1_output(certdate, buffer, BUFSIZE); @@ -2389,7 +2353,7 @@ ossl_connect_step3(struct connectdata *conn,     * operations.     */ -  if(!data->set.ssl.verifypeer) +  if(!data->set.ssl.verifypeer && !data->set.ssl.verifyhost)      (void)servercert(conn, connssl, FALSE);    else      retcode = servercert(conn, connssl, TRUE); @@ -2568,7 +2532,7 @@ static ssize_t ossl_send(struct connectdata *conn,    memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;    rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen); -  if(rc < 0) { +  if(rc <= 0) {      err = SSL_get_error(conn->ssl[sockindex].handle, rc);      switch(err) { @@ -2617,7 +2581,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */    buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;    nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize); -  if(nread < 0) { +  if(nread <= 0) {      /* failed SSL_read */      int err = SSL_get_error(conn->ssl[num].handle, (int)nread); @@ -2631,13 +2595,19 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */        *curlcode = CURLE_AGAIN;        return -1;      default: -      /* openssl/ssl.h says "look at error stack/return value/errno" */ +      /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return +         value/errno" */ +      /* http://www.openssl.org/docs/crypto/ERR_get_error.html */        sslerror = ERR_get_error(); -      failf(conn->data, "SSL read: %s, errno %d", -            ERR_error_string(sslerror, error_buffer), -            SOCKERRNO); -      *curlcode = CURLE_RECV_ERROR; -      return -1; +      if((nread < 0) || sslerror) { +        /* If the return code was negative or there actually is an error in the +           queue */ +        failf(conn->data, "SSL read: %s, errno %d", +              ERR_error_string(sslerror, error_buffer), +              SOCKERRNO); +        *curlcode = CURLE_RECV_ERROR; +        return -1; +      }      }    }    return nread;  | 
