Conversation
There was a problem hiding this comment.
Hello @tavdog, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
Summary of Changes
This pull request introduces a mechanism to skip SSL certificate verification when the application is running on a local network. The primary motivation, as stated in the PR description, is to simplify the development experience for users who primarily use tronbyt locally. This is achieved by adding a new function is_local_address that checks if a given URL points to a local address. If it does, the crt_bundle_attach option is not set in the HTTP client configuration, effectively skipping certificate verification. Additionally, the sdkconfig.defaults file is modified to enable insecure TLS settings by default.
Highlights
- Skip Certificate Verification: Introduces a mechanism to bypass SSL certificate verification for local network addresses.
- Local Address Detection: Implements the
is_local_addressfunction to identify URLs pointing to local resources based on prefixes like '10.', '192.168.', '172.', '127.', and '.local'. - Default Insecure TLS Settings: Enables insecure TLS settings by default in
sdkconfig.defaultsfor local development.
Changelog
- sdkconfig.defaults
- Enabled
CONFIG_ESP_TLS_INSECUREandCONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFYby default.
- Enabled
- src/remote.c
- Added declaration of
is_local_addressfunction. - Conditionally attaches the certificate bundle based on whether the URL is a local address.
- Implemented the
is_local_addressfunction to determine if a URL is local.
- Added declaration of
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
For local dev's ease,
Cert checks we now appease,
A quick, simple test,
To put minds at rest,
No HTTPS, if you please.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Code Review
This pull request aims to skip certificate verification when connecting to a local address. The implementation adds a is_local_address function to check the URL and modifies the remote_get function to conditionally skip certificate verification. While the core functionality seems sound, there are some areas for improvement regarding security, maintainability, and error handling.
Summary of Findings
- Security Risk: Insecure Certificate Handling: Skipping certificate verification introduces a significant security risk. Malicious actors could intercept communication if the connection isn't truly local. Consider alternative approaches to identify local connections that don't compromise security.
- Maintainability: Function Clarity and Documentation: The
is_local_addressfunction could benefit from more detailed comments explaining the logic behind the IP address range checks and the rationale for including specific prefixes. Adding a clear description of the function's purpose and parameters would enhance maintainability. - Error Handling: Missing Error Checks: The
is_local_addressfunction lacks error handling for potential issues like buffer overflows instrncpyandstrtol. Adding checks for these conditions would improve robustness. - Efficiency: Redundant String Operations: The
is_local_addressfunction repeatedly callsstrlenandstrncmp. Consider optimizing these operations to improve efficiency.
Merge Readiness
This pull request introduces a significant security vulnerability by disabling certificate verification. I strongly recommend not merging this pull request until the security concerns are addressed. Even after addressing the security and maintainability issues, further review and approval from other reviewers are required before merging. I cannot approve this pull request under any circumstances.
| CONFIG_ESP_TLS_INSECURE=y | ||
| CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y |
There was a problem hiding this comment.
Setting CONFIG_ESP_TLS_INSECURE=y and CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y globally is a major security risk. This should not be done globally. Consider using environment variables or build flags to control this setting for specific builds or configurations. How will this be controlled in production?
There was a problem hiding this comment.
of course it's gonna say that.
There was a problem hiding this comment.
I tested it with just CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y and it still fails to fetch https over LAN.
| if (is_local_address(url)) { | ||
| ESP_LOGI(TAG, "local address, skipping cert validation"); | ||
| } else { | ||
| config.crt_bundle_attach = esp_crt_bundle_attach; | ||
| } |
There was a problem hiding this comment.
While the conditional check for local addresses is a step in the right direction, simply skipping certificate verification is still insecure. Explore alternative, secure methods for identifying local connections. For example, you could check for a specific local IP address range or use a more robust method to verify the identity of the server. What are the implications of this approach in a production environment?
| if (is_local_address(url)) { | |
| ESP_LOGI(TAG, "local address, skipping cert validation"); | |
| } else { | |
| config.crt_bundle_attach = esp_crt_bundle_attach; | |
| } | |
| if (is_local_address(url)) { | |
| ESP_LOGI(TAG, "local address, using secure local connection method"); | |
| // Implement secure local connection method here | |
| } else { | |
| config.crt_bundle_attach = esp_crt_bundle_attach; | |
| } |
| bool is_local_address(const char* url) { | ||
| // Skip protocol prefix if present | ||
| const char* http_prefix = "http://"; | ||
| const char* https_prefix = "https://"; | ||
|
|
||
| if (strncmp(url, http_prefix, strlen(http_prefix)) == 0) { | ||
| url += strlen(http_prefix); | ||
| } else if (strncmp(url, https_prefix, strlen(https_prefix)) == 0) { | ||
| url += strlen(https_prefix); | ||
| } | ||
|
|
||
| // Make a copy of the host part (without the port) | ||
| char host[256]; | ||
| strncpy(host, url, sizeof(host) - 1); | ||
| host[sizeof(host) - 1] = '\0'; | ||
|
|
||
| // Remove port number if present | ||
| char* port = strchr(host, ':'); | ||
| if (port != NULL) { | ||
| *port = '\0'; // Terminate string at the colon | ||
| } | ||
|
|
||
| // Check for .local TLD | ||
| size_t len = strlen(host); | ||
| if (len >= 6 && strcmp(host + len - 6, ".local") == 0) { | ||
| return true; | ||
| } | ||
|
|
||
| // Check if starts with common local IP prefixes | ||
| if (strncmp(host, "10.", 3) == 0) { | ||
| return true; | ||
| } | ||
|
|
||
| if (strncmp(host, "192.168.", 8) == 0) { | ||
| return true; | ||
| } | ||
|
|
||
| if (strncmp(host, "172.", 4) == 0) { | ||
| // Check for 172.16.0.0 to 172.31.255.255 range | ||
| char* end; | ||
| long second_octet = strtol(host + 4, &end, 10); | ||
| if (*end == '.' && second_octet >= 16 && second_octet <= 31) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| if (strncmp(host, "127.", 4) == 0) { | ||
| return true; | ||
| } | ||
|
|
||
| return false; | ||
| } |
There was a problem hiding this comment.
The is_local_address function needs more robust error handling and clearer documentation. The strncpy function should check for potential buffer overflows. The strtol function should also be checked for errors. Add comments to explain the logic and the rationale behind the IP address ranges used. Consider using a more efficient approach to avoid redundant string operations.
bool is_local_address(const char* url) {
// Skip protocol prefix if present
const char* http_prefix = "http://";
const char* https_prefix = "https://";
if (strncmp(url, http_prefix, strlen(http_prefix)) == 0) {
url += strlen(http_prefix);
} else if (strncmp(url, https_prefix, strlen(https_prefix)) == 0) {
url += strlen(https_prefix);
}
// Make a copy of the host part (without the port)
char host[256];
if (strncpy(host, url, sizeof(host) - 1) == NULL) { //Error check
ESP_LOGE(TAG, "strncpy failed");
return false;
}
host[sizeof(host) - 1] = '\0';
// Remove port number if present
char* port = strchr(host, ':');
if (port != NULL) {
*port = '\0'; // Terminate string at the colon
}
// Check for .local TLD
size_t len = strlen(host);
if (len >= 6 && strcmp(host + len - 6, ".local") == 0) {
return true;
}
// Check if starts with common local IP prefixes
char *end;
long ip_num = strtol(host, &end, 10);
if (*end != '.' || errno == ERANGE) { //Error check
ESP_LOGE(TAG, "strtol failed");
return false;
}
// ... (rest of the IP address checks with error handling)
return false;
}| CONFIG_ESP_TLS_INSECURE=y | ||
| CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y |
| } | ||
|
|
||
| // Check if starts with common local IP prefixes | ||
| if (strncmp(host, "10.", 3) == 0) { |
There was a problem hiding this comment.
TLS certificates for local IP addresses? This doesn't make a lot of sense.
Certificates technically can be issued for IP addresses instead of FQDNs, but this is rare and it's only for public addresses.
There was a problem hiding this comment.
yeah, any ip should just return true i guess.
There was a problem hiding this comment.
Huh? You want is_local_address to return true for publicly routable IP addresses? I really don't think this is worth spending time on. Disabling TLS verification is worse than just not using it because it gives some false sense of security.
There was a problem hiding this comment.
I understand that, but that flag is still only meant for testing and should not be set by default.
There's no good way to determine whether a given hostname is "local" or not. .local is not a TLD (https://en.wikipedia.org/wiki/.local) and only used for mDNS in a local network, but there can be infinitely other local domains (.lan is common, mine is .localdomain) or just plain hostnames resolved against a search domain delivered via DHCP.
Even if you resolve the hostname via DNS and look at whether the resulting IP (v4 and/or v6) are local, it's vulnerable to DNS spoofing.
Because there's no good way to do that, you can't decider when to supply the default CAs and when to skip verification.
There was a problem hiding this comment.
so what's the solution for someone who wants to use https on a local address ?
There was a problem hiding this comment.
Either use a valid certificate from a default CA (e.g. using the DNS-01 challenge), provide a custom CA certificate to the firmware, or use HTTP (without the S).
I personally use the first option, for example.

if the majority of users will using tronbyt locally then it makes sense to allow for skiping cert when on local network.