static CURLcode darwinssl_connect_step2(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; OSStatus err; SSLCipherSuite cipher; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state); /* Here goes nothing: */ err = SSLHandshake(connssl->ssl_ctx); if(err != noErr) { switch (err) { case errSSLWouldBlock: /* they're not done with us yet */ connssl->connecting_state = connssl->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; break; case errSSLServerAuthCompleted: /* the documentation says we need to call SSLHandshake() again */ return darwinssl_connect_step2(conn, sockindex); case errSSLXCertChainInvalid: case errSSLUnknownRootCert: case errSSLNoRootCert: case errSSLCertExpired: failf(data, "SSL certificate problem: OSStatus %d", err); return CURLE_SSL_CACERT; break; default: failf(data, "Unknown SSL protocol error in connection to %s:%d", conn->host.name, err); return CURLE_SSL_CONNECT_ERROR; break; } } else { /* we have been connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; /* Informational message */ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); infof (data, "SSL connection using %s\n", CipherNameForNumber(cipher)); return CURLE_OK; } }
static CURLcode darwinssl_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode retcode; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; return CURLE_OK; } if(ssl_connect_1==connssl->connecting_state) { /* Find out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } retcode = darwinssl_connect_step1(conn, sockindex); if(retcode) return retcode; } while(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* if ssl is expecting something, check if it's available. */ if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } else if(0 == what) { if(nonblocking) { *done = FALSE; return CURLE_OK; } else { /* timeout */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } } /* socket is readable or writable */ } /* Run transaction, and return to the caller if it failed or if this * connection is done nonblocking and this loop would execute again. This * permits the owner of a multi handle to abort a connection attempt * before step2 has completed while ensuring that a client using select() * or epoll() will always have a valid fdset to wait on. */ retcode = darwinssl_connect_step2(conn, sockindex); if(retcode || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state))) return retcode; } /* repeat step2 until all transactions are done. */ if(ssl_connect_3==connssl->connecting_state) { retcode = darwinssl_connect_step3(conn, sockindex); if(retcode) return retcode; } if(ssl_connect_done==connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = darwinssl_recv; conn->send[sockindex] = darwinssl_send; *done = TRUE; } else *done = FALSE; /* Reset our connect state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; }
static CURLcode darwinssl_connect_step2(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; OSStatus err; SSLCipherSuite cipher; SSLProtocol protocol = 0; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state); /* Here goes nothing: */ err = SSLHandshake(connssl->ssl_ctx); if(err != noErr) { switch (err) { case errSSLWouldBlock: /* they're not done with us yet */ connssl->connecting_state = connssl->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; case errSSLServerAuthCompleted: /* the documentation says we need to call SSLHandshake() again */ return darwinssl_connect_step2(conn, sockindex); case errSSLXCertChainInvalid: case errSSLUnknownRootCert: case errSSLNoRootCert: case errSSLCertExpired: failf(data, "SSL certificate problem: OSStatus %d", err); return CURLE_SSL_CACERT; case errSSLHostNameMismatch: failf(data, "SSL certificate peer verification failed, the " "certificate did not match \"%s\"\n", conn->host.dispname); return CURLE_PEER_FAILED_VERIFICATION; default: failf(data, "Unknown SSL protocol error in connection to %s:%d", conn->host.name, err); return CURLE_SSL_CONNECT_ERROR; } } else { /* we have been connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; /* Informational message */ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol); switch (protocol) { case kSSLProtocol2: infof(data, "SSL 2.0 connection using %s\n", SSLCipherNameForNumber(cipher)); break; case kSSLProtocol3: infof(data, "SSL 3.0 connection using %s\n", SSLCipherNameForNumber(cipher)); break; case kTLSProtocol1: infof(data, "TLS 1.0 connection using %s\n", TLSCipherNameForNumber(cipher)); break; #if defined(__MAC_10_8) || defined(__IPHONE_5_0) case kTLSProtocol11: infof(data, "TLS 1.1 connection using %s\n", TLSCipherNameForNumber(cipher)); break; case kTLSProtocol12: infof(data, "TLS 1.2 connection using %s\n", TLSCipherNameForNumber(cipher)); break; #endif default: infof(data, "Unknown protocol connection\n"); break; } return CURLE_OK; } }