ResponseCode MbedTLSConnection::ConnectInternal()

in network/MbedTLS/MbedTLSConnection.cpp [100:276]


        ResponseCode MbedTLSConnection::ConnectInternal() {
            ResponseCode rc = ResponseCode::SUCCESS;

            int ret = 0;
            const util::String pers = "aws_iot_tls_wrapper";
            char port_buf[6];
            char vrfy_buf[512];
            const char* alpn_protocol_list[] = {"x-amzn-mqtt-ca", nullptr};

            mbedtls_net_init(&server_fd_);
            mbedtls_ssl_init(&ssl_);
            mbedtls_ssl_config_init(&conf_);
            mbedtls_ctr_drbg_init(&ctr_drbg_);
            mbedtls_x509_crt_init(&cacert_);
            mbedtls_x509_crt_init(&clicert_);
            mbedtls_pk_init(&pkey_);

            if (enable_alpn_) {
#ifdef MBEDTLS_SSL_ALPN
                if (0 != mbedtls_ssl_conf_alpn_protocols(&conf_, alpn_protocol_list)) {
                    AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, " SSL INIT Failed - Unable to set ALPN options");
                    return ResponseCode::NETWORK_SSL_INIT_ERROR;
                }
#else
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, " SSL INIT Failed - No ALPN support");
                return ResponseCode::NETWORK_SSL_INIT_ERROR;
#endif
            }

            requires_free_ = true;

            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "...............................%d", MBEDTLS_SSL_MAX_CONTENT_LEN);

            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "....Seeding the random number generator...");
            mbedtls_entropy_init(&entropy_);
            if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg_, mbedtls_entropy_func, &entropy_,
                                             (const unsigned char *) (pers.c_str()), pers.length())) != 0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, " Connect Failed!!! mbedtls_ctr_drbg_seed returned -0x%x", -ret);
                return ResponseCode::NETWORK_SSL_INIT_ERROR;
            }

            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "....Loading the CA root certificate... %s", root_ca_location_.c_str());
            ret = mbedtls_x509_crt_parse_file(&cacert_, root_ca_location_.c_str());
            if (ret < 0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG,
                              "Failed!!!  mbedtls_x509_crt_parse returned -0x%x while parsing root cert\n\n",
                              -ret);
                return ResponseCode::NETWORK_SSL_ROOT_CRT_PARSE_ERROR;
            }
            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "ok (%d skipped)\n", ret);

            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "....Loading the client cert. and key...");
            ret = mbedtls_x509_crt_parse_file(&clicert_, device_cert_location_.c_str());
            if (ret != 0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG,
                              "Failed!!!  mbedtls_x509_crt_parse returned -0x%x while parsing device cert\n\n",
                              -ret);
                return ResponseCode::NETWORK_SSL_DEVICE_CRT_PARSE_ERROR;
            }

            ret = mbedtls_pk_parse_keyfile(&pkey_, device_private_key_location_.c_str(), "");
            if (ret != 0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG,
                              "Failed!!!  mbedtls_pk_parse_key returned -0x%x while parsing private key\n\n",
                              -ret);
                AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, " path : %s ", device_private_key_location_.c_str());
                return ResponseCode::NETWORK_SSL_KEY_PARSE_ERROR;
            }
            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, " ok\n");
            snprintf(port_buf, MAX_CHARS_IN_PORT_NUMBER, "%d", endpoint_port_);
            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "....Connecting to %s/%s...", endpoint_.c_str(), port_buf);
            if ((ret = mbedtls_net_connect(&server_fd_, endpoint_.c_str(), port_buf, MBEDTLS_NET_PROTO_TCP)) != 0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, "Failed!!! mbedtls_net_connect returned -0x%x\n\n", -ret);
                switch (ret) {
                    case MBEDTLS_ERR_NET_SOCKET_FAILED:
                        return ResponseCode::NETWORK_TCP_SETUP_ERROR;
                    case MBEDTLS_ERR_NET_UNKNOWN_HOST:
                        return ResponseCode::NETWORK_TCP_UNKNOWN_HOST;
                    case MBEDTLS_ERR_NET_CONNECT_FAILED:
                    default:
                        return ResponseCode::NETWORK_TCP_CONNECT_ERROR;
                };
            }

            ret = mbedtls_net_set_block(&server_fd_);
            if (ret != 0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, "Failed!!! net_set_(non)block() returned -0x%x\n\n", -ret);
                return ResponseCode::NETWORK_SSL_UNKNOWN_ERROR;
            }
            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "Ok!");

            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "....Setting up the SSL/TLS structure...");
            if ((ret = mbedtls_ssl_config_defaults(&conf_, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
                                                   MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG,
                              "Failed!!! mbedtls_ssl_config_defaults returned -0x%x\n\n",
                              -ret);
                return ResponseCode::NETWORK_SSL_UNKNOWN_ERROR;
            }

            mbedtls_ssl_conf_verify(&conf_, &MbedTLSConnection::VerifyCertificate, NULL);
            if (server_verification_flag_) {
                mbedtls_ssl_conf_authmode(&conf_, MBEDTLS_SSL_VERIFY_REQUIRED);
            } else {
                mbedtls_ssl_conf_authmode(&conf_, MBEDTLS_SSL_VERIFY_OPTIONAL);
            }
            mbedtls_ssl_conf_rng(&conf_, mbedtls_ctr_drbg_random, &ctr_drbg_);

            mbedtls_ssl_conf_ca_chain(&conf_, &cacert_, NULL);
            if ((ret = mbedtls_ssl_conf_own_cert(&conf_, &clicert_, &pkey_)) !=
                0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, "Failed!!! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
                return ResponseCode::NETWORK_SSL_UNKNOWN_ERROR;
            }

            mbedtls_ssl_conf_read_timeout(&conf_, static_cast<uint32_t>(tls_handshake_timeout_.count()));
            if ((ret = mbedtls_ssl_set_hostname(&ssl_, endpoint_.c_str())) != 0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, "Failed!!! mbedtls_ssl_set_hostname returned %d\n\n", ret);
                return ResponseCode::NETWORK_SSL_UNKNOWN_ERROR;
            }
            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "\n\nSSL state connect : %d ", ssl_.state);
            mbedtls_ssl_set_bio(&ssl_, &server_fd_, mbedtls_net_send, NULL, mbedtls_net_recv_timeout);
            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "Ok!");

            if ((ret = mbedtls_ssl_setup(&ssl_, &conf_)) != 0) {
                AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, "Failed!!! mbedtls_ssl_setup returned -0x%x\n\n", -ret);
                return ResponseCode::NETWORK_SSL_UNKNOWN_ERROR;
            }

            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "\n\nSSL state connect : %d ", ssl_.state);
            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "....Performing the SSL/TLS handshake...");
            while ((ret = mbedtls_ssl_handshake(&ssl_)) != 0) {
                if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
                    AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, "Failed!!! mbedtls_ssl_handshake returned -0x%x\n", -ret);
                    if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
                        AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, "    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 ResponseCode::NETWORK_SSL_TLS_HANDSHAKE_ERROR;
                }
            }

            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG,
                         " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
                         mbedtls_ssl_get_version(&ssl_),
                         mbedtls_ssl_get_ciphersuite(&ssl_));
            if ((ret = mbedtls_ssl_get_record_expansion(&ssl_)) >= 0) {
                AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "    [ Record expansion is %d ]\n", ret);
            } else {
                AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "    [ Record expansion is unknown (compression) ]\n");
            }

            AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, "....Verifying peer X.509 certificate...");

            if (server_verification_flag_) {
                if ((flags_ = mbedtls_ssl_get_verify_result(&ssl_)) != 0) {
                    AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, " failed\n");
                    mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags_);
                    AWS_LOG_ERROR(MBEDTLS_WRAPPER_LOG_TAG, "%s\n", vrfy_buf);
                    rc = ResponseCode::NETWORK_SSL_SERVER_VERIFICATION_ERROR;
                } else {
                    AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, " ok\n");
                    rc = ResponseCode::SUCCESS;
                }
            } else {
                AWS_LOG_INFO(MBEDTLS_WRAPPER_LOG_TAG, " Server Verification skipped\n");
                rc = ResponseCode::SUCCESS;
            }

            mbedtls_ssl_conf_read_timeout(&conf_, static_cast<uint32_t>(tls_read_timeout_.count()));
            is_connected_ = true;
            return rc;
        }