在iOS库中生成CSR?

我想看看是否有可能在iOS中生成一个CSR(证书签名请求),以及是否有一个库。 我想要生成一个请求,使用一个分机的私钥签名,然后将CSR请求发送回服务器。

这是可能的,是否有一个好的图书馆呢?

谢谢

是的,这是可能的,但并不简单,因为iOS不能像你所想的那样使用标准格式的密钥

将CSR生成为PEM

我已经成功地使用这个库来生成PCKS#10格式的CSR,并在KeyChain中生成密钥并以DER格式(二进制)编码。

https://github.com/ateska/ios-csr

func createCertificationRequest(keyId: String, C: String?, CN: String?, O:String?, SERIALNAME:String? ) -> String { //Replace this with your mechanism to get the private and public key let publicKey = loadKeyStringFromKeyChainAsNSData(PUBLIC_KEY + keyId) let privateKey = loadKeySecKeyFromKeyChain(PRIVATE_KEY + keyId) //SCCSR from ios-csr library let sccsr : SCCSR = SCCSR() sccsr.commonName = CN; sccsr.organizationName = O; sccsr.countryName = C; // // aditional data you can set // sccsr.countryName = @""; // sccsr.organizationalUnitName = @""; // sccsr.subjectDER = nil; // // // let certificateRequest = sccsr.build(publicKey, privateKey: privateKey) let certificateRequestB64 = certificateRequest.base64EncodedStringWithOptions(NSDataBase64EncodingOptions()) let certificateRequestPEM = "-----BEGIN CERTIFICATE REQUEST-----\\n" + certificateRequestB64 + "\\n-----END CERTIFICATE REQUEST-----\\n" return certificateRequestPEM } 

之后,您可以将CSR以DER(格式)发送到服务器,也可以使用PEM格式(base64)进行编码,具体取决于您的服务器的function

我想你错过了最后一步,将X509从服务器返回到设备进行存储

EDITED

使用KeyChain生成密钥

我还包含了使用iOS-KeyChain帮助生成密钥的代码

 let KEY_SIZE = 2048 let PUBLIC_KEY = "mysystem.publickey." let PRIVATE_KEY = "mysystem.privatekey." // Generates a key pair in KeyChain using keyId as identifier and returns the public key // publicKey -->PUBLIC_KEY + keyId // privateKey --> PRIVATE_KEY + keyId // KEY_SIZE is stablished globally func generateKeyPairInKeyChain(keyId: String) -> String { let privateAttributes = [String(kSecAttrIsPermanent): true, String(kSecAttrApplicationTag): PRIVATE_KEY + keyId, String(kSecAttrIsPermanent): kCFBooleanTrue] let publicAttributes = [String(kSecAttrIsPermanent): true, String(kSecAttrApplicationTag): PUBLIC_KEY + keyId, String(kSecAttrIsPermanent): kCFBooleanTrue] let pairAttributes = [String(kSecAttrKeyType): kSecAttrKeyTypeRSA, String(kSecAttrKeySizeInBits): KEY_SIZE, String(kSecPublicKeyAttrs): publicAttributes, String(kSecPrivateKeyAttrs): privateAttributes] //Ensure that keychain has no key with keyId identifier deleteKeyPairFromKeyChain(keyId) var publicRef: SecKeyRef? var privateRef: SecKeyRef? //Generate the keys and recover the references in publicRef and privateRf switch SecKeyGeneratePair(pairAttributes, &publicRef, &privateRef) { case noErr: // Get the public key as a String let publicKeyStr = loadKeyStringFromKeyChain(PUBLIC_KEY + keyId) return publicKeyStr default: return "" } } 

公用事业

以下内容包括用于生成CSR或密钥的实用程序function。 你会发现,改变结果的types基本上是一样的(需要一些额外的工作来简化…)

 //Delete an existing keypair from keychain (public + private) func deleteKeyPairFromKeyChain(keyId: String) { deleteRSAKeyFromKeychain(PRIVATE_KEY + keyId) deleteRSAKeyFromKeychain(PUBLIC_KEY + keyId) } // Delete existing RSA key from keychain private func deleteRSAKeyFromKeychain(tagName: String) { let queryFilter: [String: AnyObject] = [ String(kSecClass) : kSecClassKey, String(kSecAttrKeyType) : kSecAttrKeyTypeRSA, String(kSecAttrApplicationTag): tagName ] let status: OSStatus = SecItemDelete(queryFilter) NSLog("private or public deletion result is: " + status.description) } // Finds the SecKeyRef corresponding to the parameter key and returns it as a String private func loadKeyStringFromKeyChain(key: String) -> String { let query: Dictionary<String, AnyObject> = [ String(kSecAttrKeyType): kSecAttrKeyTypeRSA, String(kSecAttrKeySizeInBits): KEY_SIZE, String(kSecClass): kSecClassKey, String(kSecAttrApplicationTag): key, kSecReturnData as String : kCFBooleanTrue ] var dataTypeRef: AnyObject? = nil var resultData: NSData? = nil let status: OSStatus = withUnsafeMutablePointer(&dataTypeRef) { SecItemCopyMatching(query as NSDictionary, UnsafeMutablePointer($0)) } NSLog("SecItemCopyMatching: " + status.description) if status == errSecSuccess { NSLog("private or public debug description is: " + dataTypeRef.debugDescription) resultData = dataTypeRef as? NSData let resultStr = resultData?.base64EncodedStringWithOptions([]) NSLog("private or public String is: " + resultStr!) return resultStr! } else { NSLog("no key found!!!!") return "" } } // Finds the SecKeyRef corresponding to the parameter key and returns it func loadKeySecKeyFromKeyChain(key: String) -> SecKeyRef { let query: Dictionary<String, AnyObject> = [ String(kSecAttrKeyType): kSecAttrKeyTypeRSA, String(kSecAttrKeySizeInBits): KEY_SIZE, String(kSecClass): kSecClassKey, String(kSecAttrApplicationTag): key, kSecReturnRef as String : kCFBooleanTrue ] var dataTypeRef: Unmanaged<AnyObject>? = nil var resultData: SecKeyRef? = nil let status: OSStatus = withUnsafeMutablePointer(&dataTypeRef) { SecItemCopyMatching(query as NSDictionary, UnsafeMutablePointer($0)) } NSLog("SecItemCopyMatching: " + status.description) if status == errSecSuccess { NSLog("private or public debug description is: " + dataTypeRef.debugDescription) resultData = (dataTypeRef!.takeRetainedValue() as! SecKeyRef) NSLog("SecItemCopyMatching returns SecKey: " + resultData.debugDescription) return resultData! } else { return resultData! } } // Finds the SecKeyRef corresponding to the parameter key and returns it as a NSData private func loadKeyStringFromKeyChainAsNSData(key: String) -> NSData { let query: Dictionary<String, AnyObject> = [ String(kSecAttrKeyType): kSecAttrKeyTypeRSA, String(kSecAttrKeySizeInBits): KEY_SIZE, String(kSecClass): kSecClassKey, String(kSecAttrApplicationTag): key, kSecReturnData as String : kCFBooleanTrue ] var dataTypeRef: AnyObject? = nil var resultData: NSData? = nil let status: OSStatus = withUnsafeMutablePointer(&dataTypeRef) { SecItemCopyMatching(query as NSDictionary, UnsafeMutablePointer($0)) } NSLog("SecItemCopyMatching: " + status.description) if status == errSecSuccess { NSLog("private or public debug description is: " + dataTypeRef.debugDescription) resultData = dataTypeRef as? NSData return resultData! } else { NSLog("no key found!!!!") return resultData! } } 

EDITED

将公共密钥导出为DER

请注意,此代码不会以DER等可读格式提供公钥

 let publicKey = loadKeyStringFromKeyChainAsNSData(PUBLIC_KEY + keyId) 

如果您需要在iOS之外使用公钥(或导入证书并获取有效密钥),则需要执行额外的操作。 使用以下项目的CryptoExportImportManager.swift支持转换密钥

https://github.com/DigitalLeaves/CryptoExportImportManager

例如

 func exportPublicKeyToDER(keyId:String) -> NSData?{ let publicKey = loadKeyStringFromKeyChainAsNSData(PUBLIC_KEY + keyId) let keyType = kSecAttrKeyTypeRSA let keySize = 2048 let exportImportManager = CryptoExportImportManager() if let exportableDERKey = exportImportManager.exportPublicKeyToDER(publicKey, keyType: keyType as String, keySize: keySize) { return exportableDERKey } else { return nil } }