Swift 3/4:如何从椭圆曲线密钥对生成SecCertificate?
Hey! Great job getting your EC key pair set up in the iOS keychain already. Generating a SecCertificate from those keys boils down to creating a self-signed certificate (since you're using your own key pair) and optionally storing it back in the keychain. Let's walk through this with working code examples.
First: Complete Your EC Key Pair Generation Code
It looks like your key generation code was cut off, so here's the full, working version to ensure your keys are properly stored in the keychain:
import Security // Define unique tags to identify your keys in the keychain let privateKeyTag = "com.yourapp.identifier.private.ec.key" let publicKeyTag = "com.yourapp.identifier.public.ec.key" /// Generates and stores an EC (P-256) key pair in the iOS keychain func generateAndStoreECKeyPair() throws -> (privateKey: SecKey, publicKey: SecKey) { // Private key attributes (stored permanently in keychain) let privateKeyAttrs: [String: Any] = [ kSecAttrIsPermanent as String: true, kSecAttrApplicationTag as String: privateKeyTag, kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly ] // Public key attributes (stored permanently in keychain) let publicKeyAttrs: [String: Any] = [ kSecAttrIsPermanent as String: true, kSecAttrApplicationTag as String: publicKeyTag, kSecAttrAccessible as String: kSecAttrAccessibleAlways ] // Key generation query let keyGenQuery: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeySizeInBits as String: 256, // Uses the widely supported P-256 curve kSecPrivateKeyAttrs as String: privateKeyAttrs, kSecPublicKeyAttrs as String: publicKeyAttrs, kSecAttrKeyClass as String: kSecAttrKeyClassAsymmetric ] var generatedPublicKey: SecKey? var generatedPrivateKey: SecKey? let status = SecKeyGeneratePair(keyGenQuery as CFDictionary, &generatedPublicKey, &generatedPrivateKey) guard status == errSecSuccess, let pubKey = generatedPublicKey, let privKey = generatedPrivateKey else { throw NSError(domain: NSOSStatusErrorDomain, code: Int(status), userInfo: [NSLocalizedDescriptionKey: "Failed to generate EC key pair"]) } return (privKey, pubKey) }
Step 2: Generate a Self-Signed SecCertificate
Starting with your existing key pair, we'll use SecKeyCreateSelfSignedCertificate (iOS 13+/macOS 10.15+) to create a valid X.509 certificate. This API simplifies the process significantly compared to manually constructing ASN.1 data for older OS versions.
/// Creates a self-signed SecCertificate from an existing EC key pair func generateSelfSignedECCertificate(privateKey: SecKey, publicKey: SecKey) throws -> SecCertificate { // Define certificate subject/issuer details (self-signed, so they match) let certificateSubject: [CFString: Any] = [ kSecOIDCommonName: "Your App Self-Signed EC Cert", kSecOIDCountryName: "US", kSecOIDOrganization: "Your App Organization" ] // Set certificate validity (10 years from now) let currentDate = Date() let expiryDate = Calendar.current.date(byAdding: .year, value: 10, to: currentDate)! let validityPeriod = SecKeyValidity(notBefore: currentDate, notAfter: expiryDate) // Certificate generation parameters let certGenParams: [CFString: Any] = [ kSecAttrKey: publicKey, kSecAttrSubject: certificateSubject, kSecAttrIssuer: certificateSubject, // Self-signed: issuer = subject kSecAttrValidity: validityPeriod, kSecAttrSignatureAlgorithm: kSecKeyAlgorithmECDSA_SHA256 // Matches EC key type ] var generatedCertificate: SecCertificate? let status = SecKeyCreateSelfSignedCertificate(nil, certGenParams as CFDictionary, &generatedCertificate) guard status == errSecSuccess, let certificate = generatedCertificate else { throw NSError(domain: NSOSStatusErrorDomain, code: Int(status), userInfo: [NSLocalizedDescriptionKey: "Failed to generate self-signed certificate"]) } return certificate }
Step 3: Use the Certificate (and Store It in Keychain if Needed)
Put it all together, and optionally store the generated certificate in the keychain for later use:
do { // Generate/receive your EC key pair (skip this if you already have them retrieved from keychain) let (privateKey, publicKey) = try generateAndStoreECKeyPair() // Create the self-signed certificate let certificate = try generateSelfSignedECCertificate(privateKey: privateKey, publicKey: publicKey) // Optional: Store the certificate in the keychain let addCertQuery: [String: Any] = [ kSecClass as String: kSecClassCertificate, kSecValueRef as String: certificate, kSecAttrAccessible as String: kSecAttrAccessibleAlways ] let addStatus = SecItemAdd(addCertQuery as CFDictionary, nil) if addStatus == errSecSuccess { print("Self-signed certificate stored in keychain successfully!") } else if addStatus == errSecDuplicateItem { print("Certificate already exists in keychain.") } } catch { print("Error during certificate generation: \(error.localizedDescription)") }
Important Notes
- OS Version Support:
SecKeyCreateSelfSignedCertificaterequires iOS 13 or later. If you need to support older versions, you'll have to manually construct the X.509 certificate's ASN.1 DER data and useSecCertificateCreateWithDatato create theSecCertificateinstance—this is more complex, so prioritize using the modern API if possible. - Production Use: Self-signed certificates are great for testing, but for production, you'll want to get a certificate signed by a trusted Certificate Authority (CA). To do this, you'd first generate a Certificate Signing Request (CSR) with your private key, send it to the CA, and then import the CA-signed certificate using
SecCertificateCreateWithData.
内容的提问来源于stack exchange,提问作者Creative crypter

