
* 0.3.4 * Add `RequestOptions` for per-request customization with headers and timeouts - Introduced the `RequestOptions` struct for flexible HTTP request configurations. - Added `request_with_options` and `post_with_options` methods. - Deprecated `request` and `post` in favor of the new methods. - Updated examples and tests to reflect the new API. * run cargo fmt * Update HTTP client methods to use `request_with_options` for improved flexibility. Adjusted related test cases and examples accordingly. * Format `request_with_options` calls for improved readability. * - Downgrade `edition` from 2024 to 2021 in Cargo.toml files for compatibility. - Fix nested `if let` statements to improve readability and correctness. - Reorganize imports for consistency and structure. * Restore github old workflows * update ci --------- Co-authored-by: geoffsee <>
hyper-custom-cert
A small, ergonomic HTTP client wrapper around hyper with optional support for custom Root CAs and a dev-only insecure mode for self-signed certificates.
Features
- Secure by Default: Uses the operating system's native trust store via
native-tls
- Custom CA Support: Optional
rustls
feature for connecting to services with custom Certificate Authorities - Development Mode: Optional
insecure-dangerous
feature for testing with self-signed certificates (⚠️ NEVER use in production) - WebAssembly Compatible: Proper WASM support with appropriate security constraints
- Certificate Pinning: Advanced security feature for production environments
- Builder Pattern: Ergonomic configuration with sensible defaults
Quick Start
cargo add hyper-custom-cert
Basic Usage (Secure Default)
use hyper_custom_cert::HttpClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Uses OS trust store by default - secure for public HTTPS endpoints
let client = HttpClient::new();
// Make requests to publicly trusted endpoints
client.request("https://httpbin.org/get").await?;
Ok(())
}
Custom Root CA (Production)
For connecting to services with custom/private Certificate Authorities:
[dependencies]
hyper-custom-cert = { version = "<latest>", features = ["rustls"] }
use hyper_custom_cert::HttpClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load your organization's Root CA
let client = HttpClient::builder()
.with_root_ca_file("path/to/your-org-root-ca.pem")
.build();
// Now you can connect to services signed by your custom CA
client.request("https://internal.your-org.com/api").await?;
Ok(())
}
Certificate Pinning (Enhanced Security)
For high-security environments where you want to pin specific certificates:
use hyper_custom_cert::HttpClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// SHA-256 fingerprints of certificates you want to accept
let pin1 = [0x12, 0x34, /* ... 30 more bytes */];
let pin2 = [0xab, 0xcd, /* ... 30 more bytes */];
let client = HttpClient::builder()
.with_pinned_cert_sha256(vec![pin1, pin2])
.build();
// Only accepts connections to certificates matching the pins
client.request("https://secure-api.example.com").await?;
Ok(())
}
Development/Testing Only (⚠️ Dangerous)
WARNING: This mode disables certificate validation. Only use for local development and testing.
[dependencies]
hyper-custom-cert = { version = "0.1.0", features = ["insecure-dangerous"] }
use hyper_custom_cert::HttpClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// ⚠️ EXTREMELY DANGEROUS - Only for local development
let client = HttpClient::builder()
.insecure_accept_invalid_certs(true)
.build();
// Can connect to self-signed certificates (NOT for production!)
client.request("https://localhost:8443").await?;
Ok(())
}
Configuration Options
Builder Methods
use hyper_custom_cert::HttpClient;
use std::time::Duration;
use std::collections::HashMap;
let mut headers = HashMap::new();
headers.insert("User-Agent".to_string(), "MyApp/1.0".to_string());
let client = HttpClient::builder()
.with_timeout(Duration::from_secs(30))
.with_default_headers(headers)
.with_root_ca_file("custom-ca.pem") // Requires 'rustls' feature
.build();
Available Methods
Method | Feature Required | Description |
---|---|---|
new() |
None | Creates client with OS trust store (secure default) |
builder() |
None | Returns a builder for custom configuration |
with_timeout(Duration) |
None | Sets request timeout |
with_default_headers(HashMap) |
None | Sets default headers for all requests |
with_root_ca_pem(&[u8]) |
rustls |
Adds custom CA from PEM bytes |
with_root_ca_file(Path) |
rustls |
Adds custom CA from PEM file |
with_pinned_cert_sha256(Vec<[u8; 32]>) |
rustls |
Enables certificate pinning |
insecure_accept_invalid_certs(bool) |
insecure-dangerous |
⚠️ Disables certificate validation |
with_self_signed_certs() |
insecure-dangerous |
⚠️ Convenience for self-signed certs |
Feature Flags
native-tls
(Default)
- Default: ✅ Enabled
- Security: ✅ Secure - Uses OS trust store
- Use Case: Public HTTPS endpoints with standard certificates
- Dependencies:
hyper-tls
,native-tls
rustls
- Default: ❌ Disabled
- Security: ✅ Secure - Custom CA validation
- Use Case: Private/custom Certificate Authorities
- Dependencies:
hyper-rustls
,rustls-pemfile
- Enables:
with_root_ca_pem()
,with_root_ca_file()
,with_pinned_cert_sha256()
insecure-dangerous
- Default: ❌ Disabled
- Security: ❌ EXTREMELY DANGEROUS
- Use Case: Development/testing ONLY
- Warning: NEVER enable in production
- Enables:
insecure_accept_invalid_certs()
,with_self_signed_certs()
WebAssembly (WASM) Support
This crate supports WebAssembly targets with important security considerations:
// WASM builds will compile, but certain operations are restricted
#[cfg(target_arch = "wasm32")]
{
let client = HttpClient::new(); // ✅ Works
// Custom CA operations may return WasmNotImplemented errors
}
WASM Limitations:
- Custom Root CA installation requires browser/OS-level certificate management
- Some TLS configuration options may not be available
- Certificate pinning may be limited by browser security policies
Browser Certificate Installation:
- Download your organization's Root CA certificate
- Install it in your browser's certificate store
- Mark it as trusted for websites
- Your WASM application will then trust endpoints signed by that CA
Error Handling
use hyper_custom_cert::{HttpClient, ClientError};
match client.request("https://example.com").await {
Ok(_) => println!("Request successful"),
Err(ClientError::WasmNotImplemented) => {
println!("This operation isn't supported in WASM");
}
Err(e) => {
println!("Request failed: {}", e);
}
}
Security Best Practices
Production Recommendations
- Use Default Mode: Stick with
native-tls
for public endpoints - Custom CA Only When Needed: Only use
rustls
feature when connecting to private CAs - Never Use
insecure-dangerous
: This feature should never be enabled in production - Keep Dependencies Updated: Monitor for security advisories
- Certificate Pinning: Consider pinning for high-security applications
Development vs Production
// ✅ GOOD: Production configuration
#[cfg(not(debug_assertions))]
let client = HttpClient::new(); // Uses OS trust store
// ✅ GOOD: Development configuration
#[cfg(debug_assertions)]
let client = HttpClient::builder()
.insecure_accept_invalid_certs(true) // Only in debug builds
.build();
Examples
See the examples/
directory for complete working examples:
examples/self-signed-certs/
- Comprehensive examples for all modes- Example of connecting to public endpoints (default mode)
- Example of using custom Root CA for private services
- Example of development mode with self-signed certificates
Testing
# Test with default features
cargo test
# Test with rustls features
cargo test --features rustls
# Test with all features (for development)
cargo test --features rustls,insecure-dangerous
# Test WASM compatibility
cargo test --target wasm32-unknown-unknown
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass:
cargo test --all-features
- Submit a pull request
License
This project is licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.
Security Policy
For security vulnerabilities, please see SECURITY.md for our responsible disclosure policy.
Remember: This library prioritizes security by default. The insecure-dangerous
feature exists solely for development convenience and should never be used in production environments.