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; |