aboutsummaryrefslogtreecommitdiff
path: root/lib/ssluse.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2003-11-24 07:15:37 +0000
committerDaniel Stenberg <daniel@haxx.se>2003-11-24 07:15:37 +0000
commit1e98727c552ced5f8c7587f64ab69c6eaab743dd (patch)
tree1b685977d873fadecb1a468fc2a317ae026867b9 /lib/ssluse.c
parent1c700b5a5cd9cf9fb9d2887aa233e065e4e450ee (diff)
FTPS support added as RFC2228 and the murray-ftp-auth-ssl draft describe it
Diffstat (limited to 'lib/ssluse.c')
-rw-r--r--lib/ssluse.c163
1 files changed, 88 insertions, 75 deletions
diff --git a/lib/ssluse.c b/lib/ssluse.c
index b0203fd46..7419c4583 100644
--- a/lib/ssluse.c
+++ b/lib/ssluse.c
@@ -223,6 +223,7 @@ static int do_file_type(const char *type)
static
int cert_stuff(struct connectdata *conn,
+ SSL_CTX* ctx,
char *cert_file,
const char *cert_type,
char *key_file,
@@ -246,11 +247,11 @@ int cert_stuff(struct connectdata *conn,
/*
* We set the password in the callback userdata
*/
- SSL_CTX_set_default_passwd_cb_userdata(conn->ssl.ctx,
+ SSL_CTX_set_default_passwd_cb_userdata(ctx,
data->set.key_passwd);
#endif
/* Set passwd callback: */
- SSL_CTX_set_default_passwd_cb(conn->ssl.ctx, passwd_callback);
+ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
}
file_type = do_file_type(cert_type);
@@ -258,8 +259,8 @@ int cert_stuff(struct connectdata *conn,
switch(file_type) {
case SSL_FILETYPE_PEM:
/* SSL_CTX_use_certificate_chain_file() only works on PEM files */
- if(SSL_CTX_use_certificate_chain_file(conn->ssl.ctx,
- cert_file) != 1) {
+ if(SSL_CTX_use_certificate_chain_file(ctx,
+ cert_file) != 1) {
failf(data, "unable to set certificate file (wrong password?)");
return 0;
}
@@ -269,9 +270,9 @@ int cert_stuff(struct connectdata *conn,
/* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
we use the case above for PEM so this can only be performed with
ASN1 files. */
- if(SSL_CTX_use_certificate_file(conn->ssl.ctx,
- cert_file,
- file_type) != 1) {
+ if(SSL_CTX_use_certificate_file(ctx,
+ cert_file,
+ file_type) != 1) {
failf(data, "unable to set certificate file (wrong password?)");
return 0;
}
@@ -293,9 +294,7 @@ int cert_stuff(struct connectdata *conn,
/* cert & key can only be in PEM case in the same file */
key_file=cert_file;
case SSL_FILETYPE_ASN1:
- if(SSL_CTX_use_PrivateKey_file(conn->ssl.ctx,
- key_file,
- file_type) != 1) {
+ if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
failf(data, "unable to set private key file: '%s' type %s\n",
key_file, key_type?key_type:"PEM");
return 0;
@@ -322,7 +321,7 @@ int cert_stuff(struct connectdata *conn,
failf(data, "failed to load private key from crypto engine\n");
return 0;
}
- if(SSL_CTX_use_PrivateKey(conn->ssl.ctx, priv_key) != 1) {
+ if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
failf(data, "unable to set private key\n");
EVP_PKEY_free(priv_key);
return 0;
@@ -344,7 +343,7 @@ int cert_stuff(struct connectdata *conn,
return 0;
}
- ssl=SSL_new(conn->ssl.ctx);
+ ssl=SSL_new(ctx);
x509=SSL_get_certificate(ssl);
/* This version was provided by Evan Jordan and is supposed to not
@@ -363,7 +362,7 @@ int cert_stuff(struct connectdata *conn,
/* Now we know that a key and cert have been set against
* the SSL context */
- if(!SSL_CTX_check_private_key(conn->ssl.ctx)) {
+ if(!SSL_CTX_check_private_key(ctx)) {
failf(data, "Private key does not match the certificate public key");
return(0);
}
@@ -453,6 +452,13 @@ void Curl_SSL_cleanup(void)
#endif
}
+#ifndef USE_SSLEAY
+void Curl_SSL_Close(struct connectdata *conn)
+{
+ (void)conn;
+}
+#endif
+
#ifdef USE_SSLEAY
/*
@@ -460,7 +466,8 @@ void Curl_SSL_cleanup(void)
*/
void Curl_SSL_Close(struct connectdata *conn)
{
- if(conn->ssl.use) {
+ if(conn->ssl[FIRSTSOCKET].use) {
+ int i;
/*
ERR_remove_state() frees the error queue associated with
thread pid. If pid == 0, the current thread will have its
@@ -472,18 +479,22 @@ void Curl_SSL_Close(struct connectdata *conn)
*/
ERR_remove_state(0);
- if(conn->ssl.handle) {
- (void)SSL_shutdown(conn->ssl.handle);
- SSL_set_connect_state(conn->ssl.handle);
-
- SSL_free (conn->ssl.handle);
- conn->ssl.handle = NULL;
- }
- if(conn->ssl.ctx) {
- SSL_CTX_free (conn->ssl.ctx);
- conn->ssl.ctx = NULL;
+ for(i=0; i<2; i++) {
+ struct ssl_connect_data *connssl = &conn->ssl[i];
+
+ if(connssl->handle) {
+ (void)SSL_shutdown(connssl->handle);
+ SSL_set_connect_state(connssl->handle);
+
+ SSL_free (connssl->handle);
+ connssl->handle = NULL;
+ }
+ if(connssl->ctx) {
+ SSL_CTX_free (connssl->ctx);
+ connssl->ctx = NULL;
+ }
+ connssl->use = FALSE; /* get back to ordinary socket usage */
}
- conn->ssl.use = FALSE; /* get back to ordinary socket usage */
}
}
@@ -598,7 +609,8 @@ int Curl_SSL_Close_All(struct SessionHandle *data)
/*
* Extract the session id and store it in the session cache.
*/
-static int Store_SSL_Session(struct connectdata *conn)
+static int Store_SSL_Session(struct connectdata *conn,
+ struct ssl_connect_data *ssl)
{
SSL_SESSION *ssl_sessionid;
int i;
@@ -609,14 +621,14 @@ static int Store_SSL_Session(struct connectdata *conn)
/* ask OpenSSL, say please */
#ifdef HAVE_SSL_GET1_SESSION
- ssl_sessionid = SSL_get1_session(conn->ssl.handle);
+ ssl_sessionid = SSL_get1_session(ssl->handle);
/* SSL_get1_session() will increment the reference
count and the session will stay in memory until explicitly freed with
SSL_SESSION_free(3), regardless of its state.
This function was introduced in openssl 0.9.5a. */
#else
- ssl_sessionid = SSL_get_session(conn->ssl.handle);
+ ssl_sessionid = SSL_get_session(ssl->handle);
/* if SSL_get1_session() is unavailable, use SSL_get_session().
This is an inferior option because the session can be flushed
@@ -647,7 +659,7 @@ static int Store_SSL_Session(struct connectdata *conn)
/* now init the session struct wisely */
store->sessionid = ssl_sessionid;
- store->age = data->state.sessionage; /* set current age */
+ store->age = data->state.sessionage; /* set current age */
store->name = strdup(conn->name); /* clone host name */
store->remote_port = conn->remote_port; /* port number */
@@ -765,7 +777,8 @@ cert_hostcheck(const char *certname, const char *hostname)
in the certificate and must exactly match the IP in the URI.
*/
-static CURLcode verifyhost(struct connectdata *conn)
+static CURLcode verifyhost(struct connectdata *conn,
+ X509 *server_cert)
{
char peer_CN[257];
bool matched = FALSE; /* no alternative match yet */
@@ -793,8 +806,7 @@ static CURLcode verifyhost(struct connectdata *conn)
}
/* get a "list" of alternative names */
- altnames = X509_get_ext_d2i(conn->ssl.server_cert, NID_subject_alt_name,
- NULL, NULL);
+ altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
if(altnames) {
int hostlen;
@@ -856,7 +868,7 @@ static CURLcode verifyhost(struct connectdata *conn)
infof(data, "\t subjectAltName: %s matched\n", conn->hostname);
else {
bool obtain=FALSE;
- if(X509_NAME_get_text_by_NID(X509_get_subject_name(conn->ssl.server_cert),
+ if(X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert),
NID_commonName,
peer_CN,
sizeof(peer_CN)) < 0) {
@@ -896,7 +908,8 @@ static CURLcode verifyhost(struct connectdata *conn)
/* ====================================================== */
CURLcode
-Curl_SSLConnect(struct connectdata *conn)
+Curl_SSLConnect(struct connectdata *conn,
+ int sockindex)
{
CURLcode retcode = CURLE_OK;
@@ -908,9 +921,11 @@ Curl_SSLConnect(struct connectdata *conn)
SSL_METHOD *req_method;
SSL_SESSION *ssl_sessionid=NULL;
ASN1_TIME *certdate;
+ int sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
/* mark this is being ssl enabled from here on out. */
- conn->ssl.use = TRUE;
+ connssl->use = TRUE;
if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) {
/* Make funny stuff to get random input */
@@ -937,9 +952,9 @@ Curl_SSLConnect(struct connectdata *conn)
break;
}
- conn->ssl.ctx = SSL_CTX_new(req_method);
+ connssl->ctx = SSL_CTX_new(req_method);
- if(!conn->ssl.ctx) {
+ if(!connssl->ctx) {
failf(data, "SSL: couldn't create a context!");
return CURLE_OUT_OF_MEMORY;
}
@@ -952,10 +967,11 @@ Curl_SSLConnect(struct connectdata *conn)
implementations is desired."
*/
- SSL_CTX_set_options(conn->ssl.ctx, SSL_OP_ALL);
+ SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL);
if(data->set.cert) {
if(!cert_stuff(conn,
+ connssl->ctx,
data->set.cert,
data->set.cert_type,
data->set.key,
@@ -966,7 +982,7 @@ Curl_SSLConnect(struct connectdata *conn)
}
if(data->set.ssl.cipher_list) {
- if(!SSL_CTX_set_cipher_list(conn->ssl.ctx,
+ if(!SSL_CTX_set_cipher_list(connssl->ctx,
data->set.ssl.cipher_list)) {
failf(data, "failed setting cipher list");
return CURLE_SSL_CIPHER;
@@ -976,7 +992,7 @@ Curl_SSLConnect(struct connectdata *conn)
if (data->set.ssl.CAfile || data->set.ssl.CApath) {
/* tell SSL where to find CA certificates that are used to verify
the servers certificate. */
- if (!SSL_CTX_load_verify_locations(conn->ssl.ctx, data->set.ssl.CAfile,
+ if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile,
data->set.ssl.CApath)) {
if (data->set.ssl.verifypeer) {
/* Fail if we insist on successfully verifying the server. */
@@ -989,34 +1005,31 @@ Curl_SSLConnect(struct connectdata *conn)
else {
/* Just continue with a warning if no strict certificate verification
is required. */
- infof(data,"error setting certificate verify locations,"
+ infof(data, "error setting certificate verify locations,"
" continuing anyway:\n");
- infof(data, " CAfile: %s\n",
- data->set.ssl.CAfile ? data->set.ssl.CAfile : "none");
- infof(data, " CApath: %s\n",
- data->set.ssl.CApath ? data->set.ssl.CApath : "none");
}
}
else {
/* Everything is fine. */
- infof(data,"successfully set certificate verify locations:\n");
- infof(data, " CAfile: %s\n",
- data->set.ssl.CAfile ? data->set.ssl.CAfile : "none");
- infof(data, " CApath: %s\n",
- data->set.ssl.CApath ? data->set.ssl.CApath : "none");
+ infof(data, "successfully set certificate verify locations:\n");
}
+ infof(data,
+ " CAfile: %s\n"
+ " CApath: %s\n",
+ data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
+ data->set.ssl.CApath ? data->set.ssl.CApath : "none");
}
/* SSL always tries to verify the peer, this only says whether it should
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
- SSL_CTX_set_verify(conn->ssl.ctx,
+ SSL_CTX_set_verify(connssl->ctx,
data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
cert_verify_callback);
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
- retcode = (*data->set.ssl.fsslctx)(data, conn->ssl.ctx,
+ retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx,
data->set.ssl.fsslctxp);
if(retcode) {
failf(data,"error signaled by ssl ctx callback");
@@ -1025,24 +1038,24 @@ Curl_SSLConnect(struct connectdata *conn)
}
/* Lets make an SSL structure */
- conn->ssl.handle = SSL_new (conn->ssl.ctx);
- SSL_set_connect_state (conn->ssl.handle);
+ connssl->handle = SSL_new(connssl->ctx);
+ SSL_set_connect_state(connssl->handle);
- conn->ssl.server_cert = 0x0;
+ connssl->server_cert = 0x0;
if(!conn->bits.reuse) {
/* We're not re-using a connection, check if there's a cached ID we
can/should use here! */
if(!Get_SSL_Session(conn, &ssl_sessionid)) {
/* we got a session id, use it! */
- SSL_set_session(conn->ssl.handle, ssl_sessionid);
+ SSL_set_session(connssl->handle, ssl_sessionid);
/* Informational message */
infof (data, "SSL re-using session ID\n");
}
}
/* pass the raw socket into the SSL layers */
- SSL_set_fd(conn->ssl.handle, conn->firstsocket);
+ SSL_set_fd(connssl->handle, sockfd);
do {
fd_set writefd;
@@ -1088,18 +1101,18 @@ Curl_SSLConnect(struct connectdata *conn)
FD_ZERO(&writefd);
FD_ZERO(&readfd);
- err = SSL_connect(conn->ssl.handle);
+ err = SSL_connect(connssl->handle);
/* 1 is fine
0 is "not successful but was shut down controlled"
<0 is "handshake was not successful, because a fatal error occurred" */
if(1 != err) {
- int detail = SSL_get_error(conn->ssl.handle, err);
+ int detail = SSL_get_error(connssl->handle, err);
if(SSL_ERROR_WANT_READ == detail)
- FD_SET(conn->firstsocket, &readfd);
+ FD_SET(sockfd, &readfd);
else if(SSL_ERROR_WANT_WRITE == detail)
- FD_SET(conn->firstsocket, &writefd);
+ FD_SET(sockfd, &writefd);
else {
/* untreated error */
char error_buffer[120]; /* OpenSSL documents that this must be at least
@@ -1143,7 +1156,7 @@ Curl_SSLConnect(struct connectdata *conn)
interval.tv_usec = timeout_ms*1000;
- what = select(conn->firstsocket+1, &readfd, &writefd, NULL, &interval);
+ what = select(sockfd+1, &readfd, &writefd, NULL, &interval);
if(what > 0)
/* reabable or writable, go loop yourself */
continue;
@@ -1158,12 +1171,12 @@ Curl_SSLConnect(struct connectdata *conn)
/* Informational message */
infof (data, "SSL connection using %s\n",
- SSL_get_cipher(conn->ssl.handle));
+ SSL_get_cipher(connssl->handle));
if(!ssl_sessionid) {
/* Since this is not a cached session ID, then we want to stach this one
in the cache! */
- Store_SSL_Session(conn);
+ Store_SSL_Session(conn, connssl);
}
@@ -1173,38 +1186,38 @@ Curl_SSLConnect(struct connectdata *conn)
* attack
*/
- conn->ssl.server_cert = SSL_get_peer_certificate(conn->ssl.handle);
- if(!conn->ssl.server_cert) {
+ connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
+ if(!connssl->server_cert) {
failf(data, "SSL: couldn't get peer certificate!");
return CURLE_SSL_PEER_CERTIFICATE;
}
infof (data, "Server certificate:\n");
- str = X509_NAME_oneline(X509_get_subject_name(conn->ssl.server_cert),
+ str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert),
NULL, 0);
if(!str) {
failf(data, "SSL: couldn't get X509-subject!");
- X509_free(conn->ssl.server_cert);
+ X509_free(connssl->server_cert);
return CURLE_SSL_CONNECT_ERROR;
}
infof(data, "\t subject: %s\n", str);
CRYPTO_free(str);
- certdate = X509_get_notBefore(conn->ssl.server_cert);
+ certdate = X509_get_notBefore(connssl->server_cert);
Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate);
- certdate = X509_get_notAfter(conn->ssl.server_cert);
+ certdate = X509_get_notAfter(connssl->server_cert);
Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate);
if(data->set.ssl.verifyhost) {
- retcode = verifyhost(conn);
+ retcode = verifyhost(conn, connssl->server_cert);
if(retcode) {
- X509_free(conn->ssl.server_cert);
+ X509_free(connssl->server_cert);
return retcode;
}
}
- str = X509_NAME_oneline(X509_get_issuer_name(conn->ssl.server_cert),
+ str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert),
NULL, 0);
if(!str) {
failf(data, "SSL: couldn't get X509-issuer name!");
@@ -1217,7 +1230,7 @@ Curl_SSLConnect(struct connectdata *conn)
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
- data->set.ssl.certverifyresult=SSL_get_verify_result(conn->ssl.handle);
+ data->set.ssl.certverifyresult=SSL_get_verify_result(connssl->handle);
if(data->set.ssl.certverifyresult != X509_V_OK) {
if(data->set.ssl.verifypeer) {
/* We probably never reach this, because SSL_connect() will fail
@@ -1234,7 +1247,7 @@ Curl_SSLConnect(struct connectdata *conn)
infof(data, "SSL certificate verify ok.\n");
}
- X509_free(conn->ssl.server_cert);
+ X509_free(connssl->server_cert);
#else /* USE_SSLEAY */
/* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
(void) conn;