IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params)
{
if(NULL == pNetwork)
{
return NULL_VALUE_ERROR;
}
if(NULL != params)
{
_iot_tls_set_connect_params(pNetwork, params->pRootCALocation, params->pDeviceCertLocation,
params->pDevicePrivateKeyLocation, params->pDestinationURL,
params->DestinationPort, params->timeout_ms, params->ServerVerificationFlag);
}
int ret = 0;
const char *pers = "aws_iot_tls_wrapper";
#if 0 // 2k should be large enough! Not needed anyway.
#ifdef msg_debug
unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1];
#endif
#endif // 0
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
mbedtls_platform_set_calloc_free( heap_alloc , heap_free);
mbedtls_ssl_config_init(&(tlsDataParams->conf));
mbedtls_ctr_drbg_init(&(tlsDataParams->ctr_drbg));
mbedtls_x509_crt_init(&(tlsDataParams->cacert));
mbedtls_x509_crt_init(&(tlsDataParams->clicert));
mbedtls_pk_init(&(tlsDataParams->pkey));
mbedtls_debug_set_threshold(1);
mbedtls_ssl_conf_dbg( &(tlsDataParams->conf), my_debug, stdout );
msg_debug("\n . Seeding the random number generator...");
mbedtls_entropy_init(&(tlsDataParams->entropy));
if( (ret = mbedtls_entropy_add_source( &(tlsDataParams->entropy), mbedtls_hardware_poll ,
(void*)&hrng, 1, MBEDTLS_ENTROPY_SOURCE_STRONG) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_entropy_add_source returned %d\n", ret );
return NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
}
if((ret = mbedtls_ctr_drbg_seed(&(tlsDataParams->ctr_drbg), mbedtls_entropy_func, &(tlsDataParams->entropy),
(const unsigned char *) pers, strlen(pers))) != 0)
{
msg_error(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret);
return NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
}
msg_debug(" . Loading the CA root certificate ...");
ret = mbedtls_x509_crt_parse(&(tlsDataParams->cacert), (unsigned char const *) pNetwork->tlsConnectParams.pRootCALocation, strlen(pNetwork->tlsConnectParams.pRootCALocation) + 1);
if(ret < 0)
{
msg_error(" failed\n ! mbedtls_x509_crt_parse returned -0x%x while parsing root cert\n\n", -ret);
return NETWORK_X509_ROOT_CRT_PARSE_ERROR;
}
msg_debug(" ok (%d skipped)\n", ret);
msg_debug(" . Loading the client cert. and key...");
ret = mbedtls_x509_crt_parse(&(tlsDataParams->clicert), (unsigned char const *) pNetwork->tlsConnectParams.pDeviceCertLocation, strlen(pNetwork->tlsConnectParams.pDeviceCertLocation) + 1);
if(ret != 0)
{
msg_error(" failed\n ! mbedtls_x509_crt_parse returned -0x%x while parsing device cert\n\n", -ret);
return NETWORK_X509_DEVICE_CRT_PARSE_ERROR;
}
#ifdef FIREWALL_MBEDLIB
ret = mbedtls_firewall_pk_parse_key(&(tlsDataParams->pkey), (unsigned char const *) pNetwork->tlsConnectParams.pDevicePrivateKeyLocation, (size_t) 0 , (unsigned char const *)"", 0);
/* the key is converted to an RSA structure here : pk_parse_key_pkcs1_der
the info pointer are change in pk_wrap.c*/
extern mbedtls_pk_info_t mbedtls_firewall_info;
(tlsDataParams->pkey).pk_info = &mbedtls_firewall_info;
#else
ret = mbedtls_pk_parse_key(&(tlsDataParams->pkey), (unsigned char const *) pNetwork->tlsConnectParams.pDevicePrivateKeyLocation, strlen(pNetwork->tlsConnectParams.pDevicePrivateKeyLocation) + 1, (unsigned char const *)"", 0);
#endif
if(ret != 0)
{
msg_error(" failed\n ! mbedtls_pk_parse_key returned -0x%x while parsing private key\n\n", -ret);
msg_debug(" path : %s ", pNetwork->tlsConnectParams.pDevicePrivateKeyLocation);
return NETWORK_PK_PRIVATE_KEY_PARSE_ERROR;
}
msg_debug(" ok\n");
char portBuffer[6];
snprintf(portBuffer, 6, "%d", pNetwork->tlsConnectParams.DestinationPort);
msg_debug(" . Connecting to %s/%s...", pNetwork->tlsConnectParams.pDestinationURL, portBuffer);
if( (ret = net_sock_create(hnet, (net_sockhnd_t *)&tlsDataParams->server_fd.fd, NET_PROTO_TCP)) != NET_OK )
{
msg_error(" failed to create a TCP socket ! net_sock_create %d\n", ret);
return SSL_CONNECTION_ERROR;
}
if( (ret = net_sock_setopt(tlsDataParams->server_fd.fd, "sock_noblocking", NULL, 0)) != NET_OK )
{
msg_error(" failed to set the TCP socket noblocking ! net_sock_setopt %d\n", ret);
return SSL_CONNECTION_ERROR;
}
if( (ret = net_sock_open(tlsDataParams->server_fd.fd, pNetwork->tlsConnectParams.pDestinationURL, pNetwork->tlsConnectParams.DestinationPort, 0) ) != NET_OK)
{
msg_error(" failed to connect to %s ! net_sock_open returned %d\n", pNetwork->tlsConnectParams.pDestinationURL, ret);
return SSL_CONNECTION_ERROR;
}
msg_debug(" . Setting up the SSL/TLS structure...");
if((ret = mbedtls_ssl_config_defaults(&(tlsDataParams->conf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
{
msg_error(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret);
return SSL_CONNECTION_ERROR;
}
#ifndef MOSQUITTO
mbedtls_ssl_conf_cert_profile( &(tlsDataParams->conf), &mbedtls_x509_crt_amazon_suite );
#endif
mbedtls_ssl_conf_verify(&(tlsDataParams->conf), _iot_tls_verify_cert, NULL);
if(pNetwork->tlsConnectParams.ServerVerificationFlag == true)
{
mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
}
else
{
mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_OPTIONAL);
}
mbedtls_ssl_conf_rng(&(tlsDataParams->conf), mbedtls_ctr_drbg_random, &(tlsDataParams->ctr_drbg));
mbedtls_ssl_conf_ca_chain(&(tlsDataParams->conf), &(tlsDataParams->cacert), NULL);
if((ret = mbedtls_ssl_conf_own_cert(&(tlsDataParams->conf), &(tlsDataParams->clicert), &(tlsDataParams->pkey))) !=
0)
{
msg_error(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
return SSL_CONNECTION_ERROR;
}
mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), pNetwork->tlsConnectParams.timeout_ms);
if((ret = mbedtls_ssl_setup(&(tlsDataParams->ssl), &(tlsDataParams->conf))) != 0)
{
msg_error(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret);
return SSL_CONNECTION_ERROR;
}
#ifdef MOSQUITTO
/* If the server IP address cannot be resolved from a hostname, the expected server common name must be set manually. */
char *common_name = "gnbiotsrv";
#else
char *common_name = pNetwork->tlsConnectParams.pDestinationURL;
#endif
if((ret = mbedtls_ssl_set_hostname(&(tlsDataParams->ssl), common_name )) != 0)
{
msg_error(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
return SSL_CONNECTION_ERROR;
}
msg_debug("\n\nSSL state connect : %d ", tlsDataParams->ssl.state);
mbedtls_ssl_set_bio(&(tlsDataParams->ssl), (void*) tlsDataParams->server_fd.fd, mbedtls_net_send, mbedtls_net_recv, NULL);
msg_debug(" ok\n");
msg_debug("\n\nSSL state connect : %d ", tlsDataParams->ssl.state);
msg_debug(" . Performing the SSL/TLS handshake...");
while((ret = mbedtls_ssl_handshake(&(tlsDataParams->ssl))) != 0)
{
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
{
msg_error(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n", -ret);
if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED)
{
msg_error(" Unable to verify the server's certificate. "
"Either it is invalid,\n"
" or you didn't set ca_file or ca_path "
"to an appropriate value.\n"
" Alternatively, you may want to use "
"auth_mode=optional for testing purposes.\n");
}
return SSL_CONNECTION_ERROR;
}
}
msg_debug(" ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&(tlsDataParams->ssl)),
mbedtls_ssl_get_ciphersuite(&(tlsDataParams->ssl)));
if((ret = mbedtls_ssl_get_record_expansion(&(tlsDataParams->ssl))) >= 0)
{
msg_debug(" [ Record expansion is %d ]\n", ret);
}
else
{
msg_debug(" [ Record expansion is unknown (compression) ]\n");
}
msg_debug(" . Verifying peer X.509 certificate...");
if(pNetwork->tlsConnectParams.ServerVerificationFlag == true)
{
if((tlsDataParams->flags = mbedtls_ssl_get_verify_result(&(tlsDataParams->ssl))) != 0)
{
char vrfy_buf[512];
msg_error(" failed\n");
mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", tlsDataParams->flags);
msg_error("%s\n", vrfy_buf);
ret = SSL_CONNECTION_ERROR;
}
else
{
msg_debug(" ok\n");
ret = SUCCESS;
}
}
else
{
msg_debug(" Server Verification skipped\n");
ret = SUCCESS;
}
#if 0
#ifdef msg_debug
if (mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)) != NULL)
{
msg_debug(" . Peer certificate information ...\n");
mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, " ", mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)));
msg_debug("%s\n", buf);
}
#endif
#endif // 0
mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), IOT_SSL_READ_TIMEOUT);
return (IoT_Error_t) ret;
}