Loading lib/axtls.c +362 −14 Original line number Diff line number Diff line Loading @@ -50,17 +50,93 @@ /* The last #include file should be: */ #include "memdebug.h" /* SSL_read is opied from axTLS compat layer */ static int SSL_read(SSL *ssl, void *buf, int num) { uint8_t *read_buf; int ret; while((ret = ssl_read(ssl, &read_buf)) == SSL_OK); if(ret > SSL_OK){ memcpy(buf, read_buf, ret > num ? num : ret); } return ret; } /* Global axTLS init, called from Curl_ssl_init() */ int Curl_axtls_init(void) { /* axTLS has no global init. Everything is done through SSL and SSL_CTX * structs stored in connectdata structure. Perhaps can move to axtls.h. */ return 1; } int Curl_axtls_cleanup(void) { /* axTLS has no global cleanup. Perhaps can move this to axtls.h. */ return 1; } static CURLcode map_error_to_curl(int axtls_err) { switch (axtls_err) { case SSL_ERROR_NOT_SUPPORTED: case SSL_ERROR_INVALID_VERSION: case -70: /* protocol version alert from server */ return CURLE_UNSUPPORTED_PROTOCOL; break; case SSL_ERROR_NO_CIPHER: return CURLE_SSL_CIPHER; break; case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */ case SSL_ERROR_NO_CERT_DEFINED: case -42: /* bad certificate alert from server */ case -43: /* unsupported cert alert from server */ case -44: /* cert revoked alert from server */ case -45: /* cert expired alert from server */ case -46: /* cert unknown alert from server */ return CURLE_SSL_CERTPROBLEM; break; case SSL_X509_ERROR(X509_NOT_OK): case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT): case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE): case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID): case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED): case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED): case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN): case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST): case SSL_X509_ERROR(X509_INVALID_PRIV_KEY): return CURLE_PEER_FAILED_VERIFICATION; break; case -48: /* unknown ca alert from server */ return CURLE_SSL_CACERT; break; case -49: /* access denied alert from server */ return CURLE_REMOTE_ACCESS_DENIED; break; case SSL_ERROR_CONN_LOST: case SSL_ERROR_SOCK_SETUP_FAILURE: case SSL_ERROR_INVALID_HANDSHAKE: case SSL_ERROR_INVALID_PROT_MSG: case SSL_ERROR_INVALID_HMAC: case SSL_ERROR_INVALID_SESSION: case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */ case SSL_ERROR_FINISHED_INVALID: case SSL_ERROR_NO_CLIENT_RENOG: default: return CURLE_SSL_CONNECT_ERROR; break; } return CURLE_SSL_CONNECT_ERROR; /* catch-all for non-easily-mapped errors */ } static Curl_recv axtls_recv; static Curl_send axtls_send; /* * This function is called after the TCP connect has completed. Setup the TLS * layer and do all necessary magic. Loading @@ -70,25 +146,232 @@ Curl_axtls_connect(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; SSL_CTX *ssl_ctx; SSL *ssl; int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0}; int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0}; int i, ssl_fcn_return; const uint8_t *ssl_sessionid; size_t ssl_idsize; const char *x509; /* Assuming users will not compile in custom key/cert to axTLS */ uint32_t client_option = SSL_NO_DEFAULT_KEY; if(conn->ssl[sockindex].state == ssl_connection_complete) /* to make us tolerant against being called more than once for the same connection */ return CURLE_OK; /* axTLS only supports TLSv1 */ if(data->set.ssl.version != CURL_SSLVERSION_TLSv1) { failf(data, "axTLS only supports TLSv1"); return CURLE_SSL_CONNECT_ERROR; } #ifdef AXTLSDEBUG client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS; #endif /* AXTLSDEBUG */ /* Allocate an SSL_CTX struct */ ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS); if(ssl_ctx == NULL) { failf(data, "unable to create client SSL context"); return CURLE_SSL_CONNECT_ERROR; } /* Load the trusted CA cert bundle file */ if(data->set.ssl.CAfile) { if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL) \ != SSL_OK){ infof(data, "error reading ca cert file %s \n", data->set.ssl.CAfile); if(data->set.ssl.verifypeer){ Curl_axtls_close(conn, sockindex); return CURLE_SSL_CACERT_BADFILE; } } else infof(data, "found certificates in %s\n", data->set.ssl.CAfile); } /* gtls.c tasks we're skipping for now: * 1) certificate revocation list checking * 2) dns name assignment to host * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore * 4) set certificate priority. axTLS ignores type and sends certs in * order added. can probably ignore this. */ /* Load client certificate */ if(data->set.str[STRING_CERT]){ i=0; /* Instead of trying to analyze cert type here, let axTLS try them all. */ while(cert_types[i] != 0){ ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], \ data->set.str[STRING_CERT], NULL); if(ssl_fcn_return == SSL_OK){ infof(data, "successfully read cert file %s \n", \ data->set.str[STRING_CERT]); break; } i++; } /* Tried all cert types, none worked. */ if(cert_types[i] == 0){ failf(data, "%s is not x509 or pkcs12 format", \ data->set.str[STRING_CERT]); Curl_axtls_close(conn, sockindex); return CURLE_SSL_CERTPROBLEM; } } /* Load client key. If a pkcs12 file successfully loaded a cert, then there's nothing to do because the key has already been loaded. */ if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12){ i=0; /* Instead of trying to analyze key type here, let axTLS try them all. */ while(key_types[i] != 0){ ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], \ data->set.str[STRING_KEY], NULL); if(ssl_fcn_return == SSL_OK){ infof(data, "successfully read key file %s \n", \ data->set.str[STRING_KEY]); break; } i++; } /* Tried all key types, none worked. */ if(key_types[i] == 0){ failf(data, "Failure: %s is not a supported key file", \ data->set.str[STRING_KEY]); Curl_axtls_close(conn, sockindex); return CURLE_SSL_CONNECT_ERROR; } } /* gtls.c does more here that is being left out for now * 1) set session credentials. can probably ignore since axtls puts this * info in the ssl_ctx struct * 2) setting up callbacks. these seem gnutls specific */ /* In axTLS, handshaking happens inside ssl_client_new. */ if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)){ /* we got a session id, use it! */ infof (data, "SSL re-using session ID\n"); ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], \ ssl_sessionid, ssl_idsize); } else ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0); /* Check to make sure handshake was ok. */ ssl_fcn_return = ssl_handshake_status(ssl); if(ssl_fcn_return != SSL_OK){ Curl_axtls_close(conn, sockindex); ssl_display_error(ssl_fcn_return); /* goes to stdout. */ return map_error_to_curl(ssl_fcn_return); } infof (data, "handshake completed successfully\n"); /* Here, gtls.c gets the peer certificates and fails out depending on * settings in "data." axTLS api doesn't have get cert chain fcn, so omit? */ /* Verify server's certificate */ if(data->set.ssl.verifypeer){ if(ssl_verify_cert(ssl) != SSL_OK){ Curl_axtls_close(conn, sockindex); failf(data, "server cert verify failed"); return CURLE_SSL_CONNECT_ERROR; } } else infof(data, "\t server certificate verification SKIPPED\n"); /* Here, gtls.c does issuer verfication. axTLS has no straightforward * equivalent, so omitting for now.*/ /* See if common name was set in server certificate */ x509 = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME); if(x509 == NULL) infof(data, "error fetching CN from cert\n"); /* Here, gtls.c does the following * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but * it seems useful. Omitting for now. * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert * 3) displays a bunch of cert information. axTLS doesn't support most of * this, but a couple fields are available. */ /* General housekeeping */ conn->ssl[sockindex].state = ssl_connection_complete; conn->ssl[sockindex].ssl = ssl; conn->ssl[sockindex].ssl_ctx = ssl_ctx; conn->recv[sockindex] = axtls_recv; conn->send[sockindex] = axtls_send; /* Put our freshly minted SSL session in cache */ ssl_idsize = ssl_get_session_id_size(ssl); ssl_sessionid = ssl_get_session_id(ssl); if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize) \ != CURLE_OK) infof (data, "failed to add session to cache\n"); return CURLE_OK; } /* return number of sent (non-SSL) bytes */ ssize_t Curl_axtls_send(struct connectdata *conn, static ssize_t axtls_send(struct connectdata *conn, int sockindex, const void *mem, size_t len) size_t len, CURLcode *err) { return 0; /* ssl_write() returns 'int' while write() and send() returns 'size_t' */ char error_buffer[120]; /* Comply with OpenSSL, which documents that this must be at least 120 bytes long. */ int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len); if(rc < 0 ) { *err = map_error_to_curl(rc); rc = -1; /* generic error code for send failure */ } *err = CURLE_OK; return rc; } void Curl_axtls_close_all(struct SessionHandle *data) { (void)data; } void Curl_axtls_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(connssl->ssl) { /* line from ssluse.c: (void)SSL_shutdown(connssl->ssl); axTLS compat layer does nothing for SSL_shutdown */ /* The following line is from ssluse.c. There seems to be no axTLS equivalent. ssl_free and ssl_ctx_free close things. SSL_set_connect_state(connssl->handle); */ ssl_free (connssl->ssl); connssl->ssl = NULL; } if(connssl->ssl_ctx) { ssl_ctx_free (connssl->ssl_ctx); connssl->ssl_ctx = NULL; } } /* Loading @@ -97,7 +380,54 @@ void Curl_axtls_close(struct connectdata *conn, int sockindex) */ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) { return 0; /* Outline taken from ssluse.c since functions are in axTLS compat layer. axTLS's error set is much smaller, so a lot of error-handling was removed. */ int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; char buf[120]; /* We will use this for the OpenSSL error buffer, so it has to be at least 120 bytes long. */ ssize_t nread; /* This has only been tested on the proftpd server, and the mod_tls code sends a close notify alert without waiting for a close notify alert in response. Thus we wait for a close notify alert from the server, but we do not send one. Let's hope other servers do the same... */ /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) (void)SSL_shutdown(connssl->ssl); */ if(connssl->ssl) { int what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server */ nread = (ssize_t)SSL_read(conn->ssl[sockindex].ssl, buf, sizeof(buf)); if (nread < SSL_OK){ failf(data, "close notify alert not received during shutdown"); retval = -1; } } else if(0 == what) { /* timeout */ failf(data, "SSL shutdown timeout"); } else { /* anything that gets here is fatally bad */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); retval = -1; } ssl_free (connssl->ssl); connssl->ssl = NULL; } return retval; } /* Loading @@ -105,13 +435,24 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) * Otherwise we return the amount of data read. Other errors should return -1 * and set 'wouldblock' to FALSE. */ ssize_t Curl_axtls_recv(struct connectdata *conn, /* connection data */ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ int num, /* socketindex */ char *buf, /* store read data here */ size_t buffersize, /* max amount to read */ bool *wouldblock) CURLcode *err) { return 0; ssize_t ret = (ssize_t)SSL_read(conn->ssl[num].ssl, buf, (int)buffersize); /* axTLS isn't terribly generous about error reporting */ if(ret < 0) { failf(conn->data, "axTLS recv error (%d)", (int)ret); *err = map_error_to_curl(ret); return -1; } *err = CURLE_OK; return ret; } /* Loading @@ -124,16 +465,23 @@ ssize_t Curl_axtls_recv(struct connectdata *conn, /* connection data */ */ int Curl_axtls_check_cxn(struct connectdata *conn) { return 0; /* ssluse.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1); axTLS compat layer always returns the last argument, so connection is always alive? */ return 1; /* connection still in place */ } void Curl_axtls_session_free(void *ptr) { /* free the ID */ /* both ssluse.c and gtls.c do something here, but axTLS's OpenSSL compatibility layer does nothing, so we do nothing too. */ } size_t Curl_axtls_version(char *buffer, size_t size) { return snprintf(buffer, size, "axTLS/1.2.7"); return snprintf(buffer, size, "axTLS/%s", ssl_version()); } #endif /* USE_AXTLS */ lib/axtls.h +0 −10 Original line number Diff line number Diff line Loading @@ -38,14 +38,6 @@ void Curl_axtls_close_all(struct SessionHandle *data); /* close a SSL connection */ void Curl_axtls_close(struct connectdata *conn, int sockindex); /* return number of sent (non-SSL) bytes */ ssize_t Curl_axtls_send(struct connectdata *conn, int sockindex, const void *mem, size_t len); ssize_t Curl_axtls_recv(struct connectdata *conn, /* connection data */ int num, /* socketindex */ char *buf, /* store read data here */ size_t buffersize, /* max amount to read */ bool *wouldblock); void Curl_axtls_session_free(void *ptr); size_t Curl_axtls_version(char *buffer, size_t size); int Curl_axtls_shutdown(struct connectdata *conn, int sockindex); Loading @@ -62,8 +54,6 @@ int Curl_axtls_check_cxn(struct connectdata *conn); #define curlssl_set_engine(x,y) (x=x, y=y, CURLE_FAILED_INIT) #define curlssl_set_engine_default(x) (x=x, CURLE_FAILED_INIT) #define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) #define curlssl_send Curl_axtls_send #define curlssl_recv Curl_axtls_recv #define curlssl_version Curl_axtls_version #define curlssl_check_cxn(x) Curl_axtls_check_cxn(x) #define curlssl_data_pending(x,y) (x=x, y=y, 0) Loading tests/runtests.pl +12 −0 Original line number Diff line number Diff line Loading @@ -207,6 +207,7 @@ my $has_gnutls; # built with GnuTLS my $has_nss; # built with NSS my $has_yassl; # built with yassl my $has_polarssl;# built with polarssl my $has_axtls; # built with axTLS my $has_shared; # built shared Loading Loading @@ -696,6 +697,7 @@ sub verifyhttp { $flags .= "--silent "; $flags .= "--verbose "; $flags .= "--globoff "; $flags .= "-1 " if($has_axtls == 1); $flags .= "--insecure " if($proto eq 'https'); $flags .= "\"$proto://$ip:$port/${bonus}verifiedserver\""; Loading Loading @@ -1950,6 +1952,10 @@ sub checksystem { $has_openssl=1; $ssllib="polarssl"; } elsif ($libcurl =~ /axtls/i) { $has_axtls=1; $ssllib="axTLS"; } } elsif($_ =~ /^Protocols: (.*)/i) { # these are the protocols compiled in to this libcurl Loading Loading @@ -2297,6 +2303,11 @@ sub singletest { next; } } elsif($f eq "axTLS") { if($has_axtls) { next; } } elsif($f eq "netrc_debug") { if($debug_build) { next; Loading Loading @@ -2548,6 +2559,7 @@ sub singletest { if($curl_debug) { unlink($memdump); } $cmd = "-1 ".$cmd if(exists $feature{"SSL"} && $has_axtls == 1); # create a (possibly-empty) file before starting the test my @inputfile=getpart("client", "file"); Loading Loading
lib/axtls.c +362 −14 Original line number Diff line number Diff line Loading @@ -50,17 +50,93 @@ /* The last #include file should be: */ #include "memdebug.h" /* SSL_read is opied from axTLS compat layer */ static int SSL_read(SSL *ssl, void *buf, int num) { uint8_t *read_buf; int ret; while((ret = ssl_read(ssl, &read_buf)) == SSL_OK); if(ret > SSL_OK){ memcpy(buf, read_buf, ret > num ? num : ret); } return ret; } /* Global axTLS init, called from Curl_ssl_init() */ int Curl_axtls_init(void) { /* axTLS has no global init. Everything is done through SSL and SSL_CTX * structs stored in connectdata structure. Perhaps can move to axtls.h. */ return 1; } int Curl_axtls_cleanup(void) { /* axTLS has no global cleanup. Perhaps can move this to axtls.h. */ return 1; } static CURLcode map_error_to_curl(int axtls_err) { switch (axtls_err) { case SSL_ERROR_NOT_SUPPORTED: case SSL_ERROR_INVALID_VERSION: case -70: /* protocol version alert from server */ return CURLE_UNSUPPORTED_PROTOCOL; break; case SSL_ERROR_NO_CIPHER: return CURLE_SSL_CIPHER; break; case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */ case SSL_ERROR_NO_CERT_DEFINED: case -42: /* bad certificate alert from server */ case -43: /* unsupported cert alert from server */ case -44: /* cert revoked alert from server */ case -45: /* cert expired alert from server */ case -46: /* cert unknown alert from server */ return CURLE_SSL_CERTPROBLEM; break; case SSL_X509_ERROR(X509_NOT_OK): case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT): case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE): case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID): case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED): case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED): case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN): case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST): case SSL_X509_ERROR(X509_INVALID_PRIV_KEY): return CURLE_PEER_FAILED_VERIFICATION; break; case -48: /* unknown ca alert from server */ return CURLE_SSL_CACERT; break; case -49: /* access denied alert from server */ return CURLE_REMOTE_ACCESS_DENIED; break; case SSL_ERROR_CONN_LOST: case SSL_ERROR_SOCK_SETUP_FAILURE: case SSL_ERROR_INVALID_HANDSHAKE: case SSL_ERROR_INVALID_PROT_MSG: case SSL_ERROR_INVALID_HMAC: case SSL_ERROR_INVALID_SESSION: case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */ case SSL_ERROR_FINISHED_INVALID: case SSL_ERROR_NO_CLIENT_RENOG: default: return CURLE_SSL_CONNECT_ERROR; break; } return CURLE_SSL_CONNECT_ERROR; /* catch-all for non-easily-mapped errors */ } static Curl_recv axtls_recv; static Curl_send axtls_send; /* * This function is called after the TCP connect has completed. Setup the TLS * layer and do all necessary magic. Loading @@ -70,25 +146,232 @@ Curl_axtls_connect(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; SSL_CTX *ssl_ctx; SSL *ssl; int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0}; int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0}; int i, ssl_fcn_return; const uint8_t *ssl_sessionid; size_t ssl_idsize; const char *x509; /* Assuming users will not compile in custom key/cert to axTLS */ uint32_t client_option = SSL_NO_DEFAULT_KEY; if(conn->ssl[sockindex].state == ssl_connection_complete) /* to make us tolerant against being called more than once for the same connection */ return CURLE_OK; /* axTLS only supports TLSv1 */ if(data->set.ssl.version != CURL_SSLVERSION_TLSv1) { failf(data, "axTLS only supports TLSv1"); return CURLE_SSL_CONNECT_ERROR; } #ifdef AXTLSDEBUG client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS; #endif /* AXTLSDEBUG */ /* Allocate an SSL_CTX struct */ ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS); if(ssl_ctx == NULL) { failf(data, "unable to create client SSL context"); return CURLE_SSL_CONNECT_ERROR; } /* Load the trusted CA cert bundle file */ if(data->set.ssl.CAfile) { if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL) \ != SSL_OK){ infof(data, "error reading ca cert file %s \n", data->set.ssl.CAfile); if(data->set.ssl.verifypeer){ Curl_axtls_close(conn, sockindex); return CURLE_SSL_CACERT_BADFILE; } } else infof(data, "found certificates in %s\n", data->set.ssl.CAfile); } /* gtls.c tasks we're skipping for now: * 1) certificate revocation list checking * 2) dns name assignment to host * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore * 4) set certificate priority. axTLS ignores type and sends certs in * order added. can probably ignore this. */ /* Load client certificate */ if(data->set.str[STRING_CERT]){ i=0; /* Instead of trying to analyze cert type here, let axTLS try them all. */ while(cert_types[i] != 0){ ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], \ data->set.str[STRING_CERT], NULL); if(ssl_fcn_return == SSL_OK){ infof(data, "successfully read cert file %s \n", \ data->set.str[STRING_CERT]); break; } i++; } /* Tried all cert types, none worked. */ if(cert_types[i] == 0){ failf(data, "%s is not x509 or pkcs12 format", \ data->set.str[STRING_CERT]); Curl_axtls_close(conn, sockindex); return CURLE_SSL_CERTPROBLEM; } } /* Load client key. If a pkcs12 file successfully loaded a cert, then there's nothing to do because the key has already been loaded. */ if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12){ i=0; /* Instead of trying to analyze key type here, let axTLS try them all. */ while(key_types[i] != 0){ ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], \ data->set.str[STRING_KEY], NULL); if(ssl_fcn_return == SSL_OK){ infof(data, "successfully read key file %s \n", \ data->set.str[STRING_KEY]); break; } i++; } /* Tried all key types, none worked. */ if(key_types[i] == 0){ failf(data, "Failure: %s is not a supported key file", \ data->set.str[STRING_KEY]); Curl_axtls_close(conn, sockindex); return CURLE_SSL_CONNECT_ERROR; } } /* gtls.c does more here that is being left out for now * 1) set session credentials. can probably ignore since axtls puts this * info in the ssl_ctx struct * 2) setting up callbacks. these seem gnutls specific */ /* In axTLS, handshaking happens inside ssl_client_new. */ if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)){ /* we got a session id, use it! */ infof (data, "SSL re-using session ID\n"); ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], \ ssl_sessionid, ssl_idsize); } else ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0); /* Check to make sure handshake was ok. */ ssl_fcn_return = ssl_handshake_status(ssl); if(ssl_fcn_return != SSL_OK){ Curl_axtls_close(conn, sockindex); ssl_display_error(ssl_fcn_return); /* goes to stdout. */ return map_error_to_curl(ssl_fcn_return); } infof (data, "handshake completed successfully\n"); /* Here, gtls.c gets the peer certificates and fails out depending on * settings in "data." axTLS api doesn't have get cert chain fcn, so omit? */ /* Verify server's certificate */ if(data->set.ssl.verifypeer){ if(ssl_verify_cert(ssl) != SSL_OK){ Curl_axtls_close(conn, sockindex); failf(data, "server cert verify failed"); return CURLE_SSL_CONNECT_ERROR; } } else infof(data, "\t server certificate verification SKIPPED\n"); /* Here, gtls.c does issuer verfication. axTLS has no straightforward * equivalent, so omitting for now.*/ /* See if common name was set in server certificate */ x509 = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME); if(x509 == NULL) infof(data, "error fetching CN from cert\n"); /* Here, gtls.c does the following * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but * it seems useful. Omitting for now. * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert * 3) displays a bunch of cert information. axTLS doesn't support most of * this, but a couple fields are available. */ /* General housekeeping */ conn->ssl[sockindex].state = ssl_connection_complete; conn->ssl[sockindex].ssl = ssl; conn->ssl[sockindex].ssl_ctx = ssl_ctx; conn->recv[sockindex] = axtls_recv; conn->send[sockindex] = axtls_send; /* Put our freshly minted SSL session in cache */ ssl_idsize = ssl_get_session_id_size(ssl); ssl_sessionid = ssl_get_session_id(ssl); if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize) \ != CURLE_OK) infof (data, "failed to add session to cache\n"); return CURLE_OK; } /* return number of sent (non-SSL) bytes */ ssize_t Curl_axtls_send(struct connectdata *conn, static ssize_t axtls_send(struct connectdata *conn, int sockindex, const void *mem, size_t len) size_t len, CURLcode *err) { return 0; /* ssl_write() returns 'int' while write() and send() returns 'size_t' */ char error_buffer[120]; /* Comply with OpenSSL, which documents that this must be at least 120 bytes long. */ int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len); if(rc < 0 ) { *err = map_error_to_curl(rc); rc = -1; /* generic error code for send failure */ } *err = CURLE_OK; return rc; } void Curl_axtls_close_all(struct SessionHandle *data) { (void)data; } void Curl_axtls_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(connssl->ssl) { /* line from ssluse.c: (void)SSL_shutdown(connssl->ssl); axTLS compat layer does nothing for SSL_shutdown */ /* The following line is from ssluse.c. There seems to be no axTLS equivalent. ssl_free and ssl_ctx_free close things. SSL_set_connect_state(connssl->handle); */ ssl_free (connssl->ssl); connssl->ssl = NULL; } if(connssl->ssl_ctx) { ssl_ctx_free (connssl->ssl_ctx); connssl->ssl_ctx = NULL; } } /* Loading @@ -97,7 +380,54 @@ void Curl_axtls_close(struct connectdata *conn, int sockindex) */ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) { return 0; /* Outline taken from ssluse.c since functions are in axTLS compat layer. axTLS's error set is much smaller, so a lot of error-handling was removed. */ int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; char buf[120]; /* We will use this for the OpenSSL error buffer, so it has to be at least 120 bytes long. */ ssize_t nread; /* This has only been tested on the proftpd server, and the mod_tls code sends a close notify alert without waiting for a close notify alert in response. Thus we wait for a close notify alert from the server, but we do not send one. Let's hope other servers do the same... */ /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) (void)SSL_shutdown(connssl->ssl); */ if(connssl->ssl) { int what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server */ nread = (ssize_t)SSL_read(conn->ssl[sockindex].ssl, buf, sizeof(buf)); if (nread < SSL_OK){ failf(data, "close notify alert not received during shutdown"); retval = -1; } } else if(0 == what) { /* timeout */ failf(data, "SSL shutdown timeout"); } else { /* anything that gets here is fatally bad */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); retval = -1; } ssl_free (connssl->ssl); connssl->ssl = NULL; } return retval; } /* Loading @@ -105,13 +435,24 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) * Otherwise we return the amount of data read. Other errors should return -1 * and set 'wouldblock' to FALSE. */ ssize_t Curl_axtls_recv(struct connectdata *conn, /* connection data */ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ int num, /* socketindex */ char *buf, /* store read data here */ size_t buffersize, /* max amount to read */ bool *wouldblock) CURLcode *err) { return 0; ssize_t ret = (ssize_t)SSL_read(conn->ssl[num].ssl, buf, (int)buffersize); /* axTLS isn't terribly generous about error reporting */ if(ret < 0) { failf(conn->data, "axTLS recv error (%d)", (int)ret); *err = map_error_to_curl(ret); return -1; } *err = CURLE_OK; return ret; } /* Loading @@ -124,16 +465,23 @@ ssize_t Curl_axtls_recv(struct connectdata *conn, /* connection data */ */ int Curl_axtls_check_cxn(struct connectdata *conn) { return 0; /* ssluse.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1); axTLS compat layer always returns the last argument, so connection is always alive? */ return 1; /* connection still in place */ } void Curl_axtls_session_free(void *ptr) { /* free the ID */ /* both ssluse.c and gtls.c do something here, but axTLS's OpenSSL compatibility layer does nothing, so we do nothing too. */ } size_t Curl_axtls_version(char *buffer, size_t size) { return snprintf(buffer, size, "axTLS/1.2.7"); return snprintf(buffer, size, "axTLS/%s", ssl_version()); } #endif /* USE_AXTLS */
lib/axtls.h +0 −10 Original line number Diff line number Diff line Loading @@ -38,14 +38,6 @@ void Curl_axtls_close_all(struct SessionHandle *data); /* close a SSL connection */ void Curl_axtls_close(struct connectdata *conn, int sockindex); /* return number of sent (non-SSL) bytes */ ssize_t Curl_axtls_send(struct connectdata *conn, int sockindex, const void *mem, size_t len); ssize_t Curl_axtls_recv(struct connectdata *conn, /* connection data */ int num, /* socketindex */ char *buf, /* store read data here */ size_t buffersize, /* max amount to read */ bool *wouldblock); void Curl_axtls_session_free(void *ptr); size_t Curl_axtls_version(char *buffer, size_t size); int Curl_axtls_shutdown(struct connectdata *conn, int sockindex); Loading @@ -62,8 +54,6 @@ int Curl_axtls_check_cxn(struct connectdata *conn); #define curlssl_set_engine(x,y) (x=x, y=y, CURLE_FAILED_INIT) #define curlssl_set_engine_default(x) (x=x, CURLE_FAILED_INIT) #define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) #define curlssl_send Curl_axtls_send #define curlssl_recv Curl_axtls_recv #define curlssl_version Curl_axtls_version #define curlssl_check_cxn(x) Curl_axtls_check_cxn(x) #define curlssl_data_pending(x,y) (x=x, y=y, 0) Loading
tests/runtests.pl +12 −0 Original line number Diff line number Diff line Loading @@ -207,6 +207,7 @@ my $has_gnutls; # built with GnuTLS my $has_nss; # built with NSS my $has_yassl; # built with yassl my $has_polarssl;# built with polarssl my $has_axtls; # built with axTLS my $has_shared; # built shared Loading Loading @@ -696,6 +697,7 @@ sub verifyhttp { $flags .= "--silent "; $flags .= "--verbose "; $flags .= "--globoff "; $flags .= "-1 " if($has_axtls == 1); $flags .= "--insecure " if($proto eq 'https'); $flags .= "\"$proto://$ip:$port/${bonus}verifiedserver\""; Loading Loading @@ -1950,6 +1952,10 @@ sub checksystem { $has_openssl=1; $ssllib="polarssl"; } elsif ($libcurl =~ /axtls/i) { $has_axtls=1; $ssllib="axTLS"; } } elsif($_ =~ /^Protocols: (.*)/i) { # these are the protocols compiled in to this libcurl Loading Loading @@ -2297,6 +2303,11 @@ sub singletest { next; } } elsif($f eq "axTLS") { if($has_axtls) { next; } } elsif($f eq "netrc_debug") { if($debug_build) { next; Loading Loading @@ -2548,6 +2559,7 @@ sub singletest { if($curl_debug) { unlink($memdump); } $cmd = "-1 ".$cmd if(exists $feature{"SSL"} && $has_axtls == 1); # create a (possibly-empty) file before starting the test my @inputfile=getpart("client", "file"); Loading