从Android迁移到iOS AWS IoT:iOS SDK类似密钥库方法咨询
Great question! The AWS IoT SDK for iOS doesn’t include direct equivalents to AWSIotKeystoreHelper.saveCertificateAndPrivateKey() or AWSIotKeystoreHelper.getIotKeystore() from Android, but you can replicate this functionality by manually parsing your PEM files and managing entries in the iOS Keychain. Here’s a step-by-step breakdown:
1. Parse PEM Format Certificate and Private Key
First, convert your PEM strings into native iOS security objects (SecCertificate for certificates, SecKey for private keys):
Parsing the PEM Certificate
func parsePEMCertificate(pemString: String) -> SecCertificate? { // Strip PEM headers/footers and clean whitespace let cleanedPEM = pemString .replacingOccurrences(of: "-----BEGIN CERTIFICATE-----", with: "") .replacingOccurrences(of: "-----END CERTIFICATE-----", with: "") .trimmingCharacters(in: .whitespacesAndNewlines) guard let data = Data(base64Encoded: cleanedPEM) else { print("Failed to base64 decode certificate PEM") return nil } return SecCertificateCreateWithData(nil, data as CFData) }
Parsing the PEM Private Key
Parsing PEM private keys requires a bit more work since iOS’s Security framework lacks a direct helper. For RSA keys, use this approach:
func parsePEMPrivateKey(pemString: String) -> SecKey? { let cleanedPEM = pemString .replacingOccurrences(of: "-----BEGIN PRIVATE KEY-----", with: "") .replacingOccurrences(of: "-----END PRIVATE KEY-----", with: "") .trimmingCharacters(in: .whitespacesAndNewlines) guard let data = Data(base64Encoded: cleanedPEM) else { print("Failed to base64 decode private key PEM") return nil } let attributes: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate ] var error: Unmanaged<CFError>? guard let secKey = SecKeyCreateWithData(data as CFData, attributes as CFDictionary, &error) else { print("Failed to create SecKey: \(error?.takeRetainedValue() ?? "Unknown error")") return nil } return secKey }
Note: For EC (Elliptic Curve) keys, update kSecAttrKeyType to kSecAttrKeyTypeEC.
2. Save Certificate and Private Key to Keychain
Persist these security objects to the Keychain for cross-launch access:
Saving the Certificate
func saveCertificateToKeychain(_ certificate: SecCertificate, withLabel label: String) -> Bool { let query: [CFString: Any] = [ kSecClass: kSecClassCertificate, kSecAttrLabel: label, kSecValueRef: certificate, kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly ] // Delete existing entry with the same label first SecItemDelete(query as CFDictionary) let status = SecItemAdd(query as CFDictionary, nil) return status == errSecSuccess }
Saving the Private Key
func savePrivateKeyToKeychain(_ privateKey: SecKey, withLabel label: String) -> Bool { let query: [CFString: Any] = [ kSecClass: kSecClassKey, kSecAttrLabel: label, kSecValueRef: privateKey, kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, kSecAttrKeyClass: kSecAttrKeyClassPrivate ] // Clean up existing entries SecItemDelete(query as CFDictionary) let status = SecItemAdd(query as CFDictionary, nil) return status == errSecSuccess }
3. Retrieve Keychain Entries for AWS IoT
Fetch stored items when initializing your AWS IoT connection:
Fetching the Certificate
func getCertificateFromKeychain(withLabel label: String) -> SecCertificate? { let query: [CFString: Any] = [ kSecClass: kSecClassCertificate, kSecAttrLabel: label, kSecReturnRef: kCFBooleanTrue!, kSecMatchLimit: kSecMatchLimitOne ] var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) guard status == errSecSuccess, let certificate = result as? SecCertificate else { print("Failed to fetch certificate from Keychain: \(status)") return nil } return certificate }
Fetching the Private Key
func getPrivateKeyFromKeychain(withLabel label: String) -> SecKey? { let query: [CFString: Any] = [ kSecClass: kSecClassKey, kSecAttrLabel: label, kSecReturnRef: kCFBooleanTrue!, kSecMatchLimit: kSecMatchLimitOne, kSecAttrKeyClass: kSecAttrKeyClassPrivate ] var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) guard status == errSecSuccess, let privateKey = result as? SecKey else { print("Failed to fetch private key from Keychain: \(status)") return nil } return privateKey }
4. Configure AWS IoT Client
Use the retrieved Keychain items to set up your MQTT client:
guard let certificate = getCertificateFromKeychain(withLabel: "MyIoTCertificate"), let privateKey = getPrivateKeyFromKeychain(withLabel: "MyIoTPrivateKey") else { print("Missing certificate or private key") return } let configuration = AWSMQTTConfiguration( clientId: "your-unique-client-id", endpoint: "your-iot-endpoint.amazonaws.com", certificate: certificate, privateKey: privateKey ) let mqttClient = AWSMQTTClient(configuration: configuration) // Proceed with connecting and using the client
Key Notes
- Accessibility: Choose
kSecAttrAccessiblevalues carefully based on your app’s needs.kSecAttrAccessibleAfterFirstUnlockThisDeviceOnlybalances security and background access. - Error Handling: Expand the basic logging in examples for production to handle cases like Keychain access denial.
内容的提问来源于stack exchange,提问作者Pavle Joksović




