iOS HTTPS Quick Reference
Quick reference guide for developers and users working with HTTPS and self-signed certificates in the Krill iOS app
iOS HTTPS Quick Reference
For iOS Users
How to Trust Self-Signed Certificates
Fastest Method (Testing)
- Open Safari on your iPhone/iPad
- Go to
https://your-server-address - Tap “Show Details” → “Visit this website”
- Launch the app and connect
Proper Method (Production)
- Get the
.crtcertificate file (email/AirDrop) - Tap to install the profile
- Settings → General → VPN & Device Management → Install
- Settings → General → About → Certificate Trust Settings
- Enable trust for your certificate
For Developers
Using the iOS HTTP Client
1
2
3
4
5
6
7
8
9
// Fetch and store certificate
val url = Url("https://192.168.1.100:8443")
val success = trustHttpClient.fetchPeerCert(url)
// Certificate is stored, but user must manually trust it
// Check logs for detailed instructions
// Make HTTPS request (after user trusts cert)
val response = httpClient.get("https://192.168.1.100:8443/api/data")
Quick Test Checklist
- Certificate fetched and stored (check logs)
- User instructions displayed in logs
- Certificate installed via Settings
- Trust enabled in Certificate Trust Settings
- App restarted after enabling trust
- HTTPS connection succeeds
Common Issues
Q: Connection fails after fetching certificate
A: User must manually trust it via Settings → Certificate Trust Settings
Q: Still fails after enabling trust
A: Restart the app, verify hostname matches certificate
Q: “Certificate not trusted” in logs
A: Check Settings → VPN & Device Management → verify profile is installed
Q: Works in Safari but not in app
A: Safari’s temporary trust doesn’t apply to apps, install profile properly
Key Differences from Android/JVM
1
2
3
4
5
6
7
8
9
10
// ❌ iOS CANNOT do this (no programmatic trust)
val keyStore = KeyStore.getInstance()
keyStore.setCertificateEntry("cert", cert) // Not possible on iOS
// ✅ iOS CAN do this (system trust)
handleChallenge { _, _, challenge, completionHandler ->
if (certificateIsInSystemTrustStore) {
completionHandler(UseCredential, credential)
}
}
Files to Check
- Implementation:
krill-sdk/src/iosMain/kotlin/krill/zone/io/HttpClient.ios.kt - Client Config:
krill-sdk/src/iosMain/kotlin/krill/zone/io/HttpClientContainer.ios.kt - Full Guide: iOS HTTPS with Self-Signed Certificates
- Implementation Summary: iOS HTTP Client Implementation
Development Tips
- Test with Simulator: Use Xcode simulator for initial testing
- Check Console.app: Connect device and view detailed networking logs
- Use Safari First: Easier to see certificate details and errors
- Test on Real Device: Simulator may behave differently for certificates
- Development Signing: Dev builds may have relaxed certificate validation
Production Considerations
- ⚠️ App Store: Self-signed certificates won’t work for App Store apps
- ✅ Enterprise: Use MDM to pre-install certificates
- ✅ TestFlight: Document installation steps for beta testers
- 🔒 Security: Use proper CA-signed certificates for production
Platform Support Matrix
| Platform | Auto Trust | User Action | Status |
|---|---|---|---|
| JVM | ✅ Yes | None | ✅ Complete |
| Android | ✅ Yes | None | ✅ Complete |
| iOS | ❌ No | Install via Settings | ✅ Complete |
| WASM | N/A | Trust in Browser | ✅ Complete |
Code Examples
Certificate Fetching
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// In your connection logic
suspend fun connectToServer(hostUrl: String) {
val url = Url(hostUrl)
// First, fetch and store the certificate
val certFetched = trustHttpClient.fetchPeerCert(url)
if (certFetched) {
println("Certificate stored successfully")
println("User must now trust it via iOS Settings")
// Show UI instructions to user
} else {
println("Failed to fetch certificate")
// Handle error
}
}
Making HTTPS Requests
1
2
3
4
5
6
7
8
9
10
11
// After user has trusted the certificate
suspend fun fetchData() {
try {
val response: HttpResponse = httpClient.get("https://192.168.1.100:8443/api/data")
val data: String = response.bodyAsText()
println("Success: $data")
} catch (e: Exception) {
println("Connection failed: ${e.message}")
// May indicate certificate not trusted yet
}
}
Checking Certificate Storage
1
2
3
4
5
fun isCertificateStored(hostname: String): Boolean {
val certKey = "krill_trusted_cert_$hostname"
val cert = NSUserDefaults.standardUserDefaults.dataForKey(certKey)
return cert != null
}
Troubleshooting Flow
1
2
3
4
5
6
7
8
9
10
Connection Fails
↓
Is certificate stored?
├─ No → Run trustHttpClient.fetchPeerCert(url)
└─ Yes → Is certificate trusted in iOS Settings?
├─ No → Guide user to Settings → Certificate Trust Settings
└─ Yes → Check hostname matches certificate
├─ No → Fetch correct certificate
└─ Yes → Check network connectivity
└─ Still failing? → Check Console.app logs
Next Steps
- First Time Setup: Fetch certificate with
trustHttpClient.fetchPeerCert() - Trust Certificate: Follow instructions in device Settings
- Verify Connection: Make test HTTPS request
- Production Deploy: Use properly signed certificates
Need More Help?
- See the complete iOS HTTPS guide
- Review the implementation details
This post is licensed under CC BY 4.0 by the author.