1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2010, DirecTV
9 * contact: Eric Hu <ehu@directv.com>
11 * This software is licensed as described in the file COPYING, which
12 * you should have received as part of this distribution. The terms
13 * are also available at http://curl.haxx.se/docs/copyright.html.
15 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16 * copies of the Software, and permit persons to whom the Software is
17 * furnished to do so, under the terms of the COPYING file.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ***************************************************************************/
25 * Source file for all axTLS-specific code for the TLS/SSL layer. No code
26 * but sslgen.c should ever call or use these functions.
29 #include "curl_setup.h"
32 #include <axTLS/ssl.h>
36 #include "inet_pton.h"
38 #include "parsedate.h"
39 #include "connect.h" /* for the connect timeout */
41 #define _MPRINTF_REPLACE /* use our functions only */
42 #include <curl/mprintf.h>
43 #include "curl_memory.h"
45 /* The last #include file should be: */
47 #include "hostcheck.h"
50 /* Global axTLS init, called from Curl_ssl_init() */
51 int Curl_axtls_init(void)
53 /* axTLS has no global init. Everything is done through SSL and SSL_CTX
54 * structs stored in connectdata structure. Perhaps can move to axtls.h.
59 int Curl_axtls_cleanup(void)
61 /* axTLS has no global cleanup. Perhaps can move this to axtls.h. */
65 static CURLcode map_error_to_curl(int axtls_err)
68 case SSL_ERROR_NOT_SUPPORTED:
69 case SSL_ERROR_INVALID_VERSION:
70 case -70: /* protocol version alert from server */
71 return CURLE_UNSUPPORTED_PROTOCOL;
73 case SSL_ERROR_NO_CIPHER:
74 return CURLE_SSL_CIPHER;
76 case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */
77 case SSL_ERROR_NO_CERT_DEFINED:
78 case -42: /* bad certificate alert from server */
79 case -43: /* unsupported cert alert from server */
80 case -44: /* cert revoked alert from server */
81 case -45: /* cert expired alert from server */
82 case -46: /* cert unknown alert from server */
83 return CURLE_SSL_CERTPROBLEM;
85 case SSL_X509_ERROR(X509_NOT_OK):
86 case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT):
87 case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE):
88 case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID):
89 case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED):
90 case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED):
91 case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN):
92 case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST):
93 case SSL_X509_ERROR(X509_INVALID_PRIV_KEY):
94 return CURLE_PEER_FAILED_VERIFICATION;
96 case -48: /* unknown ca alert from server */
97 return CURLE_SSL_CACERT;
99 case -49: /* access denied alert from server */
100 return CURLE_REMOTE_ACCESS_DENIED;
102 case SSL_ERROR_CONN_LOST:
103 case SSL_ERROR_SOCK_SETUP_FAILURE:
104 case SSL_ERROR_INVALID_HANDSHAKE:
105 case SSL_ERROR_INVALID_PROT_MSG:
106 case SSL_ERROR_INVALID_HMAC:
107 case SSL_ERROR_INVALID_SESSION:
108 case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */
109 case SSL_ERROR_FINISHED_INVALID:
110 case SSL_ERROR_NO_CLIENT_RENOG:
112 return CURLE_SSL_CONNECT_ERROR;
117 static Curl_recv axtls_recv;
118 static Curl_send axtls_send;
120 static void free_ssl_structs(struct ssl_connect_data *connssl)
123 ssl_free (connssl->ssl);
126 if(connssl->ssl_ctx) {
127 ssl_ctx_free(connssl->ssl_ctx);
128 connssl->ssl_ctx = NULL;
133 * For both blocking and non-blocking connects, this function sets up the
134 * ssl context and state. This function is called after the TCP connect
137 static CURLcode connect_prep(struct connectdata *conn, int sockindex)
139 struct SessionHandle *data = conn->data;
142 int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0};
143 int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0};
144 int i, ssl_fcn_return;
145 const uint8_t *ssl_sessionid;
148 /* Assuming users will not compile in custom key/cert to axTLS.
149 * Also, even for blocking connects, use axTLS non-blocking feature.
151 uint32_t client_option = SSL_NO_DEFAULT_KEY |
152 SSL_SERVER_VERIFY_LATER |
153 SSL_CONNECT_IN_PARTS;
155 if(conn->ssl[sockindex].state == ssl_connection_complete)
156 /* to make us tolerant against being called more than once for the
160 /* axTLS only supports TLSv1 */
161 /* check to see if we've been told to use an explicit SSL/TLS version */
162 switch(data->set.ssl.version) {
163 case CURL_SSLVERSION_DEFAULT:
164 case CURL_SSLVERSION_TLSv1:
167 failf(data, "axTLS only supports TLSv1");
168 return CURLE_SSL_CONNECT_ERROR;
172 client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS;
173 #endif /* AXTLSDEBUG */
175 /* Allocate an SSL_CTX struct */
176 ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS);
177 if(ssl_ctx == NULL) {
178 failf(data, "unable to create client SSL context");
179 return CURLE_SSL_CONNECT_ERROR;
182 conn->ssl[sockindex].ssl_ctx = ssl_ctx;
183 conn->ssl[sockindex].ssl = NULL;
185 /* Load the trusted CA cert bundle file */
186 if(data->set.ssl.CAfile) {
187 if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL)
189 infof(data, "error reading ca cert file %s \n",
190 data->set.ssl.CAfile);
191 if(data->set.ssl.verifypeer) {
192 return CURLE_SSL_CACERT_BADFILE;
196 infof(data, "found certificates in %s\n", data->set.ssl.CAfile);
199 /* gtls.c tasks we're skipping for now:
200 * 1) certificate revocation list checking
201 * 2) dns name assignment to host
202 * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore
203 * 4) set certificate priority. axTLS ignores type and sends certs in
204 * order added. can probably ignore this.
207 /* Load client certificate */
208 if(data->set.str[STRING_CERT]) {
210 /* Instead of trying to analyze cert type here, let axTLS try them all. */
211 while(cert_types[i] != 0) {
212 ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i],
213 data->set.str[STRING_CERT], NULL);
214 if(ssl_fcn_return == SSL_OK) {
215 infof(data, "successfully read cert file %s \n",
216 data->set.str[STRING_CERT]);
221 /* Tried all cert types, none worked. */
222 if(cert_types[i] == 0) {
223 failf(data, "%s is not x509 or pkcs12 format",
224 data->set.str[STRING_CERT]);
225 return CURLE_SSL_CERTPROBLEM;
230 If a pkcs12 file successfully loaded a cert, then there's nothing to do
231 because the key has already been loaded. */
232 if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) {
234 /* Instead of trying to analyze key type here, let axTLS try them all. */
235 while(key_types[i] != 0) {
236 ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i],
237 data->set.str[STRING_KEY], NULL);
238 if(ssl_fcn_return == SSL_OK) {
239 infof(data, "successfully read key file %s \n",
240 data->set.str[STRING_KEY]);
245 /* Tried all key types, none worked. */
246 if(key_types[i] == 0) {
247 failf(data, "Failure: %s is not a supported key file",
248 data->set.str[STRING_KEY]);
249 return CURLE_SSL_CONNECT_ERROR;
253 /* gtls.c does more here that is being left out for now
254 * 1) set session credentials. can probably ignore since axtls puts this
255 * info in the ssl_ctx struct
256 * 2) setting up callbacks. these seem gnutls specific
259 /* In axTLS, handshaking happens inside ssl_client_new. */
260 if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) {
261 /* we got a session id, use it! */
262 infof (data, "SSL re-using session ID\n");
263 ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
264 ssl_sessionid, (uint8_t)ssl_idsize);
267 ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0);
269 conn->ssl[sockindex].ssl = ssl;
274 * For both blocking and non-blocking connects, this function finalizes the
277 static CURLcode connect_finish(struct connectdata *conn, int sockindex)
279 struct SessionHandle *data = conn->data;
280 SSL *ssl = conn->ssl[sockindex].ssl;
281 const uint8_t *ssl_sessionid;
284 uint32_t dns_altname_index;
285 const char *dns_altname;
286 int8_t found_subject_alt_names = 0;
287 int8_t found_subject_alt_name_matching_conn = 0;
289 /* Here, gtls.c gets the peer certificates and fails out depending on
290 * settings in "data." axTLS api doesn't have get cert chain fcn, so omit?
293 /* Verify server's certificate */
294 if(data->set.ssl.verifypeer) {
295 if(ssl_verify_cert(ssl) != SSL_OK) {
296 Curl_axtls_close(conn, sockindex);
297 failf(data, "server cert verify failed");
298 return CURLE_PEER_FAILED_VERIFICATION;
302 infof(data, "\t server certificate verification SKIPPED\n");
304 /* Here, gtls.c does issuer verification. axTLS has no straightforward
305 * equivalent, so omitting for now.*/
307 /* Here, gtls.c does the following
308 * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but
309 * it seems useful. This is now implemented, by Oscar Koeroo
310 * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert
311 * 3) displays a bunch of cert information. axTLS doesn't support most of
312 * this, but a couple fields are available.
315 /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a
316 risk of an inifite loop */
317 for(dns_altname_index = 0; ; dns_altname_index++) {
318 dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index);
319 if(dns_altname == NULL) {
322 found_subject_alt_names = 1;
324 infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n",
325 dns_altname, conn->host.name);
326 if(Curl_cert_hostcheck(dns_altname, conn->host.name)) {
327 found_subject_alt_name_matching_conn = 1;
333 if(found_subject_alt_names && !found_subject_alt_name_matching_conn) {
334 if(data->set.ssl.verifyhost) {
335 /* Break connection ! */
336 Curl_axtls_close(conn, sockindex);
337 failf(data, "\tsubjectAltName(s) do not match %s\n",
338 conn->host.dispname);
339 return CURLE_PEER_FAILED_VERIFICATION;
342 infof(data, "\tsubjectAltName(s) do not match %s\n",
343 conn->host.dispname);
345 else if(found_subject_alt_names == 0) {
346 /* Per RFC2818, when no Subject Alt Names were available, examine the peer
347 CN as a legacy fallback */
348 peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
349 if(peer_CN == NULL) {
350 if(data->set.ssl.verifyhost) {
351 Curl_axtls_close(conn, sockindex);
352 failf(data, "unable to obtain common name from peer certificate");
353 return CURLE_PEER_FAILED_VERIFICATION;
356 infof(data, "unable to obtain common name from peer certificate");
359 if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
360 if(data->set.ssl.verifyhost) {
361 /* Break connection ! */
362 Curl_axtls_close(conn, sockindex);
363 failf(data, "\tcommon name \"%s\" does not match \"%s\"\n",
364 peer_CN, conn->host.dispname);
365 return CURLE_PEER_FAILED_VERIFICATION;
368 infof(data, "\tcommon name \"%s\" does not match \"%s\"\n",
369 peer_CN, conn->host.dispname);
374 /* General housekeeping */
375 conn->ssl[sockindex].state = ssl_connection_complete;
376 conn->recv[sockindex] = axtls_recv;
377 conn->send[sockindex] = axtls_send;
379 /* Put our freshly minted SSL session in cache */
380 ssl_idsize = ssl_get_session_id_size(ssl);
381 ssl_sessionid = ssl_get_session_id(ssl);
382 if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize)
384 infof (data, "failed to add session to cache\n");
390 * Use axTLS's non-blocking connection feature to open an SSL connection.
391 * This is called after a TCP connection is already established.
393 CURLcode Curl_axtls_connect_nonblocking(
394 struct connectdata *conn,
402 /* connectdata is calloc'd and connecting_state is only changed in this
403 function, so this is safe, as the state is effectively initialized. */
404 if(conn->ssl[sockindex].connecting_state == ssl_connect_1) {
405 conn_step = connect_prep(conn, sockindex);
406 if(conn_step != CURLE_OK) {
407 Curl_axtls_close(conn, sockindex);
410 conn->ssl[sockindex].connecting_state = ssl_connect_2;
413 if(conn->ssl[sockindex].connecting_state == ssl_connect_2) {
414 /* Check to make sure handshake was ok. */
415 if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) {
416 ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL);
417 if(ssl_fcn_return < 0) {
418 Curl_axtls_close(conn, sockindex);
419 ssl_display_error(ssl_fcn_return); /* goes to stdout. */
420 return map_error_to_curl(ssl_fcn_return);
423 return CURLE_OK; /* Return control to caller for retries */
426 infof (conn->data, "handshake completed successfully\n");
427 conn->ssl[sockindex].connecting_state = ssl_connect_3;
430 if(conn->ssl[sockindex].connecting_state == ssl_connect_3) {
431 conn_step = connect_finish(conn, sockindex);
432 if(conn_step != CURLE_OK) {
433 Curl_axtls_close(conn, sockindex);
437 /* Reset connect state */
438 conn->ssl[sockindex].connecting_state = ssl_connect_1;
444 /* Unrecognized state. Things are very bad. */
445 conn->ssl[sockindex].state = ssl_connection_none;
446 conn->ssl[sockindex].connecting_state = ssl_connect_1;
447 /* Return value perhaps not strictly correct, but distinguishes the issue.*/
448 return CURLE_BAD_FUNCTION_ARGUMENT;
453 * This function is called after the TCP connect has completed. Setup the TLS
454 * layer and do all necessary magic for a blocking connect.
457 Curl_axtls_connect(struct connectdata *conn,
461 CURLcode conn_step = connect_prep(conn, sockindex);
463 SSL *ssl = conn->ssl[sockindex].ssl;
465 if(conn_step != CURLE_OK) {
466 Curl_axtls_close(conn, sockindex);
470 /* Check to make sure handshake was ok. */
471 while(ssl_handshake_status(ssl) != SSL_OK) {
472 ssl_fcn_return = ssl_read(ssl, NULL);
473 if(ssl_fcn_return < 0) {
474 Curl_axtls_close(conn, sockindex);
475 ssl_display_error(ssl_fcn_return); /* goes to stdout. */
476 return map_error_to_curl(ssl_fcn_return);
480 infof (conn->data, "handshake completed successfully\n");
482 conn_step = connect_finish(conn, sockindex);
483 if(conn_step != CURLE_OK) {
484 Curl_axtls_close(conn, sockindex);
491 /* return number of sent (non-SSL) bytes */
492 static ssize_t axtls_send(struct connectdata *conn,
498 /* ssl_write() returns 'int' while write() and send() returns 'size_t' */
499 int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len);
501 infof(conn->data, " axtls_send\n");
504 *err = map_error_to_curl(rc);
505 rc = -1; /* generic error code for send failure */
512 void Curl_axtls_close_all(struct SessionHandle *data)
515 infof(data, " Curl_axtls_close_all\n");
518 void Curl_axtls_close(struct connectdata *conn, int sockindex)
520 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
522 infof(conn->data, " Curl_axtls_close\n");
524 /* line from ssluse.c: (void)SSL_shutdown(connssl->ssl);
525 axTLS compat layer does nothing for SSL_shutdown */
527 /* The following line is from ssluse.c. There seems to be no axTLS
528 equivalent. ssl_free and ssl_ctx_free close things.
529 SSL_set_connect_state(connssl->handle); */
531 free_ssl_structs(connssl);
535 * This function is called to shut down the SSL layer but keep the
536 * socket open (CCC - Clear Command Channel)
538 int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
540 /* Outline taken from ssluse.c since functions are in axTLS compat layer.
541 axTLS's error set is much smaller, so a lot of error-handling was removed.
544 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
545 struct SessionHandle *data = conn->data;
549 infof(conn->data, " Curl_axtls_shutdown\n");
551 /* This has only been tested on the proftpd server, and the mod_tls code
552 sends a close notify alert without waiting for a close notify alert in
553 response. Thus we wait for a close notify alert from the server, but
554 we do not send one. Let's hope other servers do the same... */
556 /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too
557 if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
558 (void)SSL_shutdown(connssl->ssl);
562 int what = Curl_socket_ready(conn->sock[sockindex],
563 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
565 /* Something to read, let's do it and hope that it is the close
566 notify alert from the server. buf is managed internally by
567 axTLS and will be released upon calling ssl_free via
569 nread = (ssize_t)ssl_read(connssl->ssl, &buf);
572 failf(data, "close notify alert not received during shutdown");
578 failf(data, "SSL shutdown timeout");
581 /* anything that gets here is fatally bad */
582 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
586 free_ssl_structs(connssl);
591 static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
592 int num, /* socketindex */
593 char *buf, /* store read data here */
594 size_t buffersize, /* max amount to read */
597 struct ssl_connect_data *connssl = &conn->ssl[num];
601 infof(conn->data, " axtls_recv\n");
605 ret = ssl_read(connssl->ssl, &read_buf);
607 /* ssl_read returns SSL_OK if there is more data to read, so if it is
608 larger, then all data has been read already. */
609 memcpy(buf, read_buf,
610 (size_t)ret > buffersize ? buffersize : (size_t)ret);
612 else if(ret == SSL_OK) {
613 /* more data to be read, signal caller to call again */
618 /* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS
619 team approves proposed fix. */
620 Curl_axtls_close(conn, num);
623 failf(conn->data, "axTLS recv error (%d)", ret);
624 *err = map_error_to_curl(ret);
634 * 1 means the connection is still in place
635 * 0 means the connection has been closed
636 * -1 means the connection status is unknown
638 int Curl_axtls_check_cxn(struct connectdata *conn)
640 /* ssluse.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1);
641 axTLS compat layer always returns the last argument, so connection is
644 infof(conn->data, " Curl_axtls_check_cxn\n");
645 return 1; /* connection still in place */
648 void Curl_axtls_session_free(void *ptr)
652 /* both ssluse.c and gtls.c do something here, but axTLS's OpenSSL
653 compatibility layer does nothing, so we do nothing too. */
656 size_t Curl_axtls_version(char *buffer, size_t size)
658 return snprintf(buffer, size, "axTLS/%s", ssl_version());
661 #endif /* USE_AXTLS */