static CURLcode polarssl_connect_step2(struct connectdata *conn, int sockindex) { int ret; struct SessionHandle *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; char buffer[1024]; char errorbuf[128]; memset(errorbuf, 0, sizeof(errorbuf)); conn->recv[sockindex] = polarssl_recv; conn->send[sockindex] = polarssl_send; for(;;) { if(!(ret = ssl_handshake(&connssl->ssl))) break; else if(ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE) { #ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* POLARSSL_ERROR_C */ failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; } else { if(ret == POLARSSL_ERR_NET_WANT_READ) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } if(ret == POLARSSL_ERR_NET_WANT_WRITE) { connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } failf(data, "SSL_connect failed with error %d.", ret); return CURLE_SSL_CONNECT_ERROR; } } infof(data, "PolarSSL: Handshake complete, cipher is %s\n", #if POLARSSL_VERSION_NUMBER<0x01000000 ssl_get_cipher(&conn->ssl[sockindex].ssl) #elif POLARSSL_VERSION_NUMBER >= 0x01010000 ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) #else ssl_get_ciphersuite_name(&conn->ssl[sockindex].ssl) #endif ); ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); if(ret && data->set.ssl.verifypeer) { if(ret & BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED"); if(ret & BADCERT_REVOKED) { failf(data, "Cert verify failed: BADCERT_REVOKED"); return CURLE_SSL_CACERT; } if(ret & BADCERT_CN_MISMATCH) failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); if(ret & BADCERT_NOT_TRUSTED) failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); return CURLE_PEER_FAILED_VERIFICATION; } /* PolarSSL SVN revision r1316 to r1317, matching <1.2.0 is to cover Ubuntu's 1.1.4 version and the like */ #if POLARSSL_VERSION_NUMBER<0x01020000 if(conn->ssl[sockindex].ssl.peer_cert) { #else if(ssl_get_peer_cert(&(connssl->ssl))) { #endif /* If the session was resumed, there will be no peer certs */ memset(buffer, 0, sizeof(buffer)); /* PolarSSL SVN revision r1316 to r1317, matching <1.2.0 is to cover Ubuntu's 1.1.4 version and the like */ #if POLARSSL_VERSION_NUMBER<0x01020000 if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ", conn->ssl[sockindex].ssl.peer_cert) != -1) #else if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ", ssl_get_peer_cert(&(connssl->ssl))) != -1) #endif infof(data, "Dumping cert info:\n%s\n", buffer); } connssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); return CURLE_OK; } static CURLcode polarssl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; void *old_ssl_sessionid = NULL; ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn ; int incache; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); /* Save the current session data for possible re-use */ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); if(incache) { if(old_ssl_sessionid != our_ssl_sessionid) { infof(data, "old SSL session ID is stale, removing\n"); Curl_ssl_delsessionid(conn, old_ssl_sessionid); incache = FALSE; } } if(!incache) { void *new_session = malloc(sizeof(ssl_session)); if(new_session) { memcpy(new_session, our_ssl_sessionid, sizeof(ssl_session)); retcode = Curl_ssl_addsessionid(conn, new_session, sizeof(ssl_session)); } else { retcode = CURLE_OUT_OF_MEMORY; } if(retcode) { failf(data, "failed to store ssl session"); return retcode; } } connssl->connecting_state = ssl_connect_done; return CURLE_OK; }
int ssl_derive_keys(ssl_context * ssl) { size_t i; md5_context md5; sha1_context sha1; uint8_t tmp[64]; uint8_t padding[16]; uint8_t sha1sum[20]; uint8_t keyblk[256]; uint8_t *key1; uint8_t *key2; SSL_DEBUG_MSG(2, ("=> derive keys")); /* * SSLv3: * master = * MD5( premaster + SHA1( 'A' + premaster + randbytes ) ) + * MD5( premaster + SHA1( 'BB' + premaster + randbytes ) ) + * MD5( premaster + SHA1( 'CCC' + premaster + randbytes ) ) * * TLSv1: * master = PRF( premaster, "master secret", randbytes )[0..47] */ if (ssl->resume == 0) { size_t len = ssl->pmslen; SSL_DEBUG_BUF(3, "premaster secret", ssl->premaster, len); if (ssl->minor_ver == SSL_MINOR_VERSION_0) { for (i = 0; i < 3; i++) { memset(padding, 'A' + i, 1 + i); sha1_starts(&sha1); sha1_update(&sha1, padding, 1 + i); sha1_update(&sha1, ssl->premaster, len); sha1_update(&sha1, ssl->randbytes, 64); sha1_finish(&sha1, sha1sum); md5_starts(&md5); md5_update(&md5, ssl->premaster, len); md5_update(&md5, sha1sum, 20); md5_finish(&md5, ssl->session->master + i * 16); } } else tls1_prf(ssl->premaster, len, "master secret", ssl->randbytes, 64, ssl->session->master, 48); memset(ssl->premaster, 0, sizeof(ssl->premaster)); } else SSL_DEBUG_MSG(3, ("no premaster (session resumed)")); /* * Swap the client and server random values. */ memcpy(tmp, ssl->randbytes, 64); memcpy(ssl->randbytes, tmp + 32, 32); memcpy(ssl->randbytes + 32, tmp, 32); memset(tmp, 0, sizeof(tmp)); /* * SSLv3: * key block = * MD5( master + SHA1( 'A' + master + randbytes ) ) + * MD5( master + SHA1( 'BB' + master + randbytes ) ) + * MD5( master + SHA1( 'CCC' + master + randbytes ) ) + * MD5( master + SHA1( 'DDDD' + master + randbytes ) ) + * ... * * TLSv1: * key block = PRF( master, "key expansion", randbytes ) */ if (ssl->minor_ver == SSL_MINOR_VERSION_0) { for (i = 0; i < 16; i++) { memset(padding, 'A' + i, 1 + i); sha1_starts(&sha1); sha1_update(&sha1, padding, 1 + i); sha1_update(&sha1, ssl->session->master, 48); sha1_update(&sha1, ssl->randbytes, 64); sha1_finish(&sha1, sha1sum); md5_starts(&md5); md5_update(&md5, ssl->session->master, 48); md5_update(&md5, sha1sum, 20); md5_finish(&md5, keyblk + i * 16); } memset(&md5, 0, sizeof(md5)); memset(&sha1, 0, sizeof(sha1)); memset(padding, 0, sizeof(padding)); memset(sha1sum, 0, sizeof(sha1sum)); } else tls1_prf(ssl->session->master, 48, "key expansion", ssl->randbytes, 64, keyblk, 256); SSL_DEBUG_MSG(3, ("cipher = %s", ssl_get_cipher(ssl))); SSL_DEBUG_BUF(3, "master secret", ssl->session->master, 48); SSL_DEBUG_BUF(4, "random bytes", ssl->randbytes, 64); SSL_DEBUG_BUF(4, "key block", keyblk, 256); memset(ssl->randbytes, 0, sizeof(ssl->randbytes)); /* * Determine the appropriate key, IV and MAC length. */ switch (ssl->session->cipher) { #if defined(TROPICSSL_ARC4) case TLS_RSA_WITH_RC4_128_MD5: ssl->keylen = 16; ssl->minlen = 16; ssl->ivlen = 0; ssl->maclen = 16; break; case TLS_RSA_WITH_RC4_128_SHA: ssl->keylen = 16; ssl->minlen = 20; ssl->ivlen = 0; ssl->maclen = 20; break; #endif #if defined(TROPICSSL_DES) case TLS_RSA_WITH_3DES_EDE_CBC_SHA: case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: ssl->keylen = 24; ssl->minlen = 24; ssl->ivlen = 8; ssl->maclen = 20; break; #endif #if defined(TROPICSSL_AES) case TLS_RSA_WITH_AES_128_CBC_SHA: ssl->keylen = 16; ssl->minlen = 32; ssl->ivlen = 16; ssl->maclen = 20; break; case TLS_RSA_WITH_AES_256_CBC_SHA: case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: ssl->keylen = 32; ssl->minlen = 32; ssl->ivlen = 16; ssl->maclen = 20; break; #endif #if defined(TROPICSSL_CAMELLIA) case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: ssl->keylen = 16; ssl->minlen = 32; ssl->ivlen = 16; ssl->maclen = 20; break; case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: ssl->keylen = 32; ssl->minlen = 32; ssl->ivlen = 16; ssl->maclen = 20; break; #endif default: SSL_DEBUG_MSG(1, ("cipher %s is not available", ssl_get_cipher(ssl))); return (TROPICSSL_ERR_SSL_FEATURE_UNAVAILABLE); } SSL_DEBUG_MSG(3, ("keylen: %d, minlen: %d, ivlen: %d, maclen: %d", ssl->keylen, ssl->minlen, ssl->ivlen, ssl->maclen)); /* * Finally setup the cipher contexts, IVs and MAC secrets. */ if (ssl->endpoint == SSL_IS_CLIENT) { key1 = keyblk + ssl->maclen * 2; key2 = keyblk + ssl->maclen * 2 + ssl->keylen; memcpy(ssl->mac_enc, keyblk, ssl->maclen); memcpy(ssl->mac_dec, keyblk + ssl->maclen, ssl->maclen); memcpy(ssl->iv_enc, key2 + ssl->keylen, ssl->ivlen); memcpy(ssl->iv_dec, key2 + ssl->keylen + ssl->ivlen, ssl->ivlen); } else { key1 = keyblk + ssl->maclen * 2 + ssl->keylen; key2 = keyblk + ssl->maclen * 2; memcpy(ssl->mac_dec, keyblk, ssl->maclen); memcpy(ssl->mac_enc, keyblk + ssl->maclen, ssl->maclen); memcpy(ssl->iv_dec, key1 + ssl->keylen, ssl->ivlen); memcpy(ssl->iv_enc, key1 + ssl->keylen + ssl->ivlen, ssl->ivlen); } switch (ssl->session->cipher) { #if defined(TROPICSSL_ARC4) case TLS_RSA_WITH_RC4_128_MD5: case TLS_RSA_WITH_RC4_128_SHA: arc4_setup((arc4_context *) ssl->ctx_enc, key1, ssl->keylen); arc4_setup((arc4_context *) ssl->ctx_dec, key2, ssl->keylen); break; #endif #if defined(TROPICSSL_DES) case TLS_RSA_WITH_3DES_EDE_CBC_SHA: case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: des3_set3key_enc((des3_context *) ssl->ctx_enc, key1); des3_set3key_dec((des3_context *) ssl->ctx_dec, key2); break; #endif #if defined(TROPICSSL_AES) case TLS_RSA_WITH_AES_128_CBC_SHA: aes_setkey_enc((aes_context *) ssl->ctx_enc, key1, 128); aes_setkey_dec((aes_context *) ssl->ctx_dec, key2, 128); break; case TLS_RSA_WITH_AES_256_CBC_SHA: case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: aes_setkey_enc((aes_context *) ssl->ctx_enc, key1, 256); aes_setkey_dec((aes_context *) ssl->ctx_dec, key2, 256); break; #endif #if defined(TROPICSSL_CAMELLIA) case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: camellia_setkey_enc((camellia_context *) ssl->ctx_enc, key1, 128); camellia_setkey_dec((camellia_context *) ssl->ctx_dec, key2, 128); break; case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: camellia_setkey_enc((camellia_context *) ssl->ctx_enc, key1, 256); camellia_setkey_dec((camellia_context *) ssl->ctx_dec, key2, 256); break; #endif default: return (TROPICSSL_ERR_SSL_FEATURE_UNAVAILABLE); } memset(keyblk, 0, sizeof(keyblk)); SSL_DEBUG_MSG(2, ("<= derive keys")); return (0); }
int main( void ) { int ret, len; int listen_fd; int client_fd; unsigned char buf[1024]; havege_state hs; ssl_context ssl; ssl_session ssn; x509_cert srvcert; rsa_context rsa; /* * 1. Load the certificates and private RSA key */ printf( "\n . Loading the server cert. and key..." ); fflush( stdout ); memset( &srvcert, 0, sizeof( x509_cert ) ); /* * This demonstration program uses embedded test certificates. * Instead, you may want to use x509parse_crtfile() to read the * server and CA certificates, as well as x509parse_keyfile(). */ ret = x509parse_crt( &srvcert, (unsigned char *) test_srv_crt, strlen( test_srv_crt ) ); if( ret != 0 ) { printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); goto exit; } ret = x509parse_crt( &srvcert, (unsigned char *) test_ca_crt, strlen( test_ca_crt ) ); if( ret != 0 ) { printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); goto exit; } ret = x509parse_key( &rsa, (unsigned char *) test_srv_key, strlen( test_srv_key ), NULL, 0 ); if( ret != 0 ) { printf( " failed\n ! x509parse_key returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 2. Setup the listening TCP socket */ printf( " . Bind on https://localhost:4433/ ..." ); fflush( stdout ); if( ( ret = net_bind( &listen_fd, NULL, 4433 ) ) != 0 ) { printf( " failed\n ! net_bind returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 3. Wait until a client connects */ #ifdef WIN32 ShellExecute( NULL, "open", "https://localhost:4433/", NULL, NULL, SW_SHOWNORMAL ); #endif client_fd = -1; memset( &ssl, 0, sizeof( ssl ) ); accept: net_close( client_fd ); ssl_free( &ssl ); printf( " . Waiting for a remote connection ..." ); fflush( stdout ); if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 ) { printf( " failed\n ! net_accept returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 4. Setup stuff */ printf( " . Setting up the RNG and SSL data...." ); fflush( stdout ); havege_init( &hs ); if( ( ret = ssl_init( &ssl ) ) != 0 ) { printf( " failed\n ! ssl_init returned %d\n\n", ret ); goto accept; } printf( " ok\n" ); ssl_set_endpoint( &ssl, SSL_IS_SERVER ); ssl_set_authmode( &ssl, SSL_VERIFY_NONE ); ssl_set_rng( &ssl, havege_rand, &hs ); ssl_set_dbg( &ssl, my_debug, stdout ); ssl_set_bio( &ssl, net_recv, &client_fd, net_send, &client_fd ); ssl_set_scb( &ssl, my_get_session, my_set_session ); ssl_set_ciphers( &ssl, my_ciphers ); ssl_set_session( &ssl, 1, 0, &ssn ); memset( &ssn, 0, sizeof( ssl_session ) ); ssl_set_ca_chain( &ssl, srvcert.next, NULL, NULL ); ssl_set_own_cert( &ssl, &srvcert, &rsa ); ssl_set_dh_param( &ssl, my_dhm_P, my_dhm_G ); /* * 5. Handshake */ printf( " . Performing the SSL/TLS handshake..." ); fflush( stdout ); while( ( ret = ssl_handshake( &ssl ) ) != 0 ) { if( ret != POLARSSL_ERR_NET_TRY_AGAIN ) { printf( " failed\n ! ssl_handshake returned %d\n\n", ret ); goto accept; } } printf( " ok\n" ); /* * 6. Read the HTTP Request */ printf( " < Read from client:" ); fflush( stdout ); do { len = sizeof( buf ) - 1; memset( buf, 0, sizeof( buf ) ); ret = ssl_read( &ssl, buf, len ); if( ret == POLARSSL_ERR_NET_TRY_AGAIN ) continue; if( ret <= 0 ) { switch( ret ) { case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY: printf( " connection was closed gracefully\n" ); break; case POLARSSL_ERR_NET_CONN_RESET: printf( " connection was reset by peer\n" ); break; default: printf( " ssl_read returned %d\n", ret ); break; } break; } len = ret; printf( " %d bytes read\n\n%s", len, (char *) buf ); } while( 0 ); /* * 7. Write the 200 Response */ printf( " > Write to client:" ); fflush( stdout ); len = sprintf( (char *) buf, HTTP_RESPONSE, ssl_get_cipher( &ssl ) ); while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 ) { if( ret == POLARSSL_ERR_NET_CONN_RESET ) { printf( " failed\n ! peer closed the connection\n\n" ); goto accept; } if( ret != POLARSSL_ERR_NET_TRY_AGAIN ) { printf( " failed\n ! ssl_write returned %d\n\n", ret ); goto exit; } } len = ret; printf( " %d bytes written\n\n%s\n", len, (char *) buf ); ssl_close_notify( &ssl ); goto accept; exit: net_close( client_fd ); x509_free( &srvcert ); rsa_free( &rsa ); ssl_free( &ssl ); cur = s_list_1st; while( cur != NULL ) { prv = cur; cur = cur->next; memset( prv, 0, sizeof( ssl_session ) ); free( prv ); } memset( &ssl, 0, sizeof( ssl_context ) ); #ifdef WIN32 printf( " Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif return( ret ); }
/* * This function loads all the client/CA certificates and CRLs. Setup the TLS * layer and do all necessary magic. */ CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; bool sni = TRUE; /* default is SNI enabled */ int ret = -1; #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif void *old_session = NULL; size_t old_session_size = 0; char buffer[1024]; if(conn->ssl[sockindex].state == ssl_connection_complete) return CURLE_OK; /* PolarSSL only supports SSLv3 and TLSv1 */ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { failf(data, "PolarSSL does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) sni = FALSE; /* SSLv3 has no SNI */ havege_init(&conn->ssl[sockindex].hs); /* Load the trusted CA */ memset(&conn->ssl[sockindex].cacert, 0, sizeof(x509_cert)); if(data->set.str[STRING_SSL_CAFILE]) { ret = x509parse_crtfile(&conn->ssl[sockindex].cacert, data->set.str[STRING_SSL_CAFILE]); if(ret) { failf(data, "Error reading ca cert file %s: -0x%04X", data->set.str[STRING_SSL_CAFILE], -ret); if(data->set.ssl.verifypeer) return CURLE_SSL_CACERT_BADFILE; } } /* Load the client certificate */ memset(&conn->ssl[sockindex].clicert, 0, sizeof(x509_cert)); if(data->set.str[STRING_CERT]) { ret = x509parse_crtfile(&conn->ssl[sockindex].clicert, data->set.str[STRING_CERT]); if(ret) { failf(data, "Error reading client cert file %s: -0x%04X", data->set.str[STRING_CERT], -ret); return CURLE_SSL_CERTPROBLEM; } } /* Load the client private key */ if(data->set.str[STRING_KEY]) { ret = x509parse_keyfile(&conn->ssl[sockindex].rsa, data->set.str[STRING_KEY], data->set.str[STRING_KEY_PASSWD]); if(ret) { failf(data, "Error reading private key %s: -0x%04X", data->set.str[STRING_KEY], -ret); return CURLE_SSL_CERTPROBLEM; } } /* Load the CRL */ memset(&conn->ssl[sockindex].crl, 0, sizeof(x509_crl)); if(data->set.str[STRING_SSL_CRLFILE]) { ret = x509parse_crlfile(&conn->ssl[sockindex].crl, data->set.str[STRING_SSL_CRLFILE]); if(ret) { failf(data, "Error reading CRL file %s: -0x%04X", data->set.str[STRING_SSL_CRLFILE], -ret); return CURLE_SSL_CRL_BADFILE; } } infof(data, "PolarSSL: Connected to %s:%d\n", conn->host.name, conn->remote_port); havege_init(&conn->ssl[sockindex].hs); if(ssl_init(&conn->ssl[sockindex].ssl)) { failf(data, "PolarSSL: ssl_init failed"); return CURLE_SSL_CONNECT_ERROR; } ssl_set_endpoint(&conn->ssl[sockindex].ssl, SSL_IS_CLIENT); ssl_set_authmode(&conn->ssl[sockindex].ssl, SSL_VERIFY_OPTIONAL); ssl_set_rng(&conn->ssl[sockindex].ssl, havege_rand, &conn->ssl[sockindex].hs); ssl_set_bio(&conn->ssl[sockindex].ssl, net_recv, &conn->sock[sockindex], net_send, &conn->sock[sockindex]); ssl_set_ciphers(&conn->ssl[sockindex].ssl, ssl_default_ciphers); if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) { memcpy(&conn->ssl[sockindex].ssn, old_session, old_session_size); infof(data, "PolarSSL re-using session\n"); } ssl_set_session(&conn->ssl[sockindex].ssl, 1, 600, &conn->ssl[sockindex].ssn); ssl_set_ca_chain(&conn->ssl[sockindex].ssl, &conn->ssl[sockindex].cacert, &conn->ssl[sockindex].crl, conn->host.name); ssl_set_own_cert(&conn->ssl[sockindex].ssl, &conn->ssl[sockindex].clicert, &conn->ssl[sockindex].rsa); if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) && #ifdef ENABLE_IPV6 !Curl_inet_pton(AF_INET6, conn->host.name, &addr) && #endif sni && ssl_set_hostname(&conn->ssl[sockindex].ssl, conn->host.name)) { infof(data, "WARNING: failed to configure " "server name indication (SNI) TLS extension\n"); } infof(data, "PolarSSL: performing SSL/TLS handshake...\n"); #ifdef POLARSSL_DEBUG ssl_set_dbg(&conn->ssl[sockindex].ssl, polarssl_debug, data); #endif for(;;) { if(!(ret = ssl_handshake(&conn->ssl[sockindex].ssl))) break; else if(ret != POLARSSL_ERR_NET_TRY_AGAIN) { failf(data, "ssl_handshake returned -0x%04X", -ret); return CURLE_SSL_CONNECT_ERROR; } else { /* wait for data from server... */ long timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } switch(Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, timeout_ms)) { case 0: failf(data, "SSL handshake timeout"); return CURLE_OPERATION_TIMEDOUT; break; case CURL_CSELECT_IN: continue; break; default: return CURLE_SSL_CONNECT_ERROR; break; } } } infof(data, "PolarSSL: Handshake complete, cipher is %s\n", ssl_get_cipher(&conn->ssl[sockindex].ssl)); ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); if(ret && data->set.ssl.verifypeer) { if(ret & BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED\n"); if(ret & BADCERT_REVOKED) failf(data, "Cert verify failed: BADCERT_REVOKED"); if(ret & BADCERT_CN_MISMATCH) failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); if(ret & BADCERT_NOT_TRUSTED) failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); return CURLE_SSL_CACERT; } if(conn->ssl[sockindex].ssl.peer_cert) { /* If the session was resumed, there will be no peer certs */ memset(buffer, 0, sizeof(buffer)); if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ", conn->ssl[sockindex].ssl.peer_cert) != -1) infof(data, "Dumping cert info:\n%s\n", buffer); } conn->ssl[sockindex].state = ssl_connection_complete; conn->recv[sockindex] = polarssl_recv; conn->send[sockindex] = polarssl_send; /* Save the current session data for possible re-use */ { void *new_session = malloc(sizeof(conn->ssl[sockindex].ssn)); if(new_session) { memcpy(new_session, &conn->ssl[sockindex].ssn, sizeof(conn->ssl[sockindex].ssn)); if(old_session) Curl_ssl_delsessionid(conn, old_session); return Curl_ssl_addsessionid(conn, new_session, sizeof(conn->ssl[sockindex].ssn)); } } return CURLE_OK; }
static CURLcode polarssl_connect_step2(struct connectdata *conn, int sockindex) { int ret; struct SessionHandle *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; char buffer[1024]; conn->recv[sockindex] = polarssl_recv; conn->send[sockindex] = polarssl_send; for(;;) { if(!(ret = ssl_handshake(&connssl->ssl))) break; else if(ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE) { failf(data, "ssl_handshake returned -0x%04X", -ret); return CURLE_SSL_CONNECT_ERROR; } else { if(ret == POLARSSL_ERR_NET_WANT_READ) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } if(ret == POLARSSL_ERR_NET_WANT_WRITE) { connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } failf(data, "SSL_connect failed with error %d.", ret); return CURLE_SSL_CONNECT_ERROR; } } infof(data, "PolarSSL: Handshake complete, cipher is %s\n", #if POLARSSL_VERSION_NUMBER<0x01000000 ssl_get_cipher(&conn->ssl[sockindex].ssl) #elif POLARSSL_VERSION_NUMBER >= 0x01010000 ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) #else ssl_get_ciphersuite_name(&conn->ssl[sockindex].ssl) #endif ); ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); if(ret && data->set.ssl.verifypeer) { if(ret & BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED"); if(ret & BADCERT_REVOKED) { failf(data, "Cert verify failed: BADCERT_REVOKED"); return CURLE_SSL_CACERT; } if(ret & BADCERT_CN_MISMATCH) failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); if(ret & BADCERT_NOT_TRUSTED) failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); return CURLE_PEER_FAILED_VERIFICATION; } if(conn->ssl[sockindex].ssl.peer_cert) { /* If the session was resumed, there will be no peer certs */ memset(buffer, 0, sizeof(buffer)); if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ", conn->ssl[sockindex].ssl.peer_cert) != -1) infof(data, "Dumping cert info:\n%s\n", buffer); } connssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); return CURLE_OK; }
int main( void ) { int ret, len, server_fd; unsigned char buf[1024]; havege_state hs; ssl_context ssl; ssl_session ssn; x509_cert cacert; x509_cert clicert; rsa_context rsa; /* * 0. Initialize the RNG and the session data */ havege_init( &hs ); memset( &ssn, 0, sizeof( ssl_session ) ); /* * 1.1. Load the trusted CA */ printf( "\n . Loading the CA root certificate ..." ); fflush( stdout ); memset( &cacert, 0, sizeof( x509_cert ) ); /* * Alternatively, you may load the CA certificates from a .pem or * .crt file by calling x509parse_crtfile( &cacert, "myca.crt" ). */ ret = x509parse_crt( &cacert, (unsigned char *) xyssl_ca_crt, strlen( xyssl_ca_crt ) ); if( ret != 0 ) { printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 1.2. Load own certificate and private key * * (can be skipped if client authentication is not required) */ printf( " . Loading the client cert. and key..." ); fflush( stdout ); memset( &clicert, 0, sizeof( x509_cert ) ); ret = x509parse_crt( &clicert, (unsigned char *) test_cli_crt, strlen( test_cli_crt ) ); if( ret != 0 ) { printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); goto exit; } ret = x509parse_key( &rsa, (unsigned char *) test_cli_key, strlen( test_cli_key ), NULL, 0 ); if( ret != 0 ) { printf( " failed\n ! x509parse_key returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 2. Start the connection */ printf( " . Connecting to tcp/%s/%-4d...", SERVER_NAME, SERVER_PORT ); fflush( stdout ); if( ( ret = net_connect( &server_fd, SERVER_NAME, SERVER_PORT ) ) != 0 ) { printf( " failed\n ! net_connect returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 3. Setup stuff */ printf( " . Setting up the SSL/TLS structure..." ); fflush( stdout ); havege_init( &hs ); if( ( ret = ssl_init( &ssl ) ) != 0 ) { printf( " failed\n ! ssl_init returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); ssl_set_endpoint( &ssl, SSL_IS_CLIENT ); ssl_set_authmode( &ssl, SSL_VERIFY_OPTIONAL ); ssl_set_rng( &ssl, havege_rand, &hs ); ssl_set_bio( &ssl, net_recv, &server_fd, net_send, &server_fd ); ssl_set_ciphers( &ssl, ssl_default_ciphers ); ssl_set_session( &ssl, 1, 600, &ssn ); ssl_set_ca_chain( &ssl, &cacert, SERVER_NAME ); ssl_set_own_cert( &ssl, &clicert, &rsa ); ssl_set_hostname( &ssl, SERVER_NAME ); /* * 4. Handshake */ printf( " . Performing the SSL/TLS handshake..." ); fflush( stdout ); while( ( ret = ssl_handshake( &ssl ) ) != 0 ) { if( ret != POLARSSL_ERR_NET_TRY_AGAIN ) { printf( " failed\n ! ssl_handshake returned %d\n\n", ret ); goto exit; } } printf( " ok\n [ Cipher is %s ]\n", ssl_get_cipher( &ssl ) ); /* * 5. Verify the server certificate */ printf( " . Verifying peer X.509 certificate..." ); if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 ) { printf( " failed\n" ); if( ( ret & BADCERT_EXPIRED ) != 0 ) printf( " ! server certificate has expired\n" ); if( ( ret & BADCERT_REVOKED ) != 0 ) printf( " ! server certificate has been revoked\n" ); if( ( ret & BADCERT_CN_MISMATCH ) != 0 ) printf( " ! CN mismatch (expected CN=%s)\n", SERVER_NAME ); if( ( ret & BADCERT_NOT_TRUSTED ) != 0 ) printf( " ! self-signed or not signed by a trusted CA\n" ); printf( "\n" ); } else printf( " ok\n" ); printf( " . Peer certificate information ...\n" ); printf( "%s", x509parse_cert_info( " ", ssl.peer_cert ) ); /* * 6. Write the GET request */ printf( " > Write to server:" ); fflush( stdout ); len = sprintf( (char *) buf, GET_REQUEST ); while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 ) { if( ret != POLARSSL_ERR_NET_TRY_AGAIN ) { printf( " failed\n ! ssl_write returned %d\n\n", ret ); goto exit; } } len = ret; printf( " %d bytes written\n\n%s", len, (char *) buf ); /* * 7. Read the HTTP response */ printf( " < Read from server:" ); fflush( stdout ); do { len = sizeof( buf ) - 1; memset( buf, 0, sizeof( buf ) ); ret = ssl_read( &ssl, buf, len ); if( ret == POLARSSL_ERR_NET_TRY_AGAIN ) continue; if( ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY ) break; if( ret <= 0 ) { printf( "failed\n ! ssl_read returned %d\n\n", ret ); break; } len = ret; printf( " %d bytes read\n\n%s", len, (char *) buf ); } while( 0 ); ssl_close_notify( &ssl ); exit: net_close( server_fd ); x509_free( &clicert ); x509_free( &cacert ); rsa_free( &rsa ); ssl_free( &ssl ); memset( &ssl, 0, sizeof( ssl ) ); #ifdef WIN32 printf( " + Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif return( ret ); }