在 iOS 库中生成 CSR?
Generate a CSR in iOS Library?
我想看看是否可以在 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)编码,具体取决于您的服务能力
我猜你错过了最后一步,将 X509 从服务器返回到设备进行存储
已编辑
使用 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 或密钥的实用函数。你会看到基本上是相同的改变结果的类型(需要一些额外的工作来简化......)
//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([=12=])) }
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([=12=])) }
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([=12=])) }
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!
}
}
已编辑
将 public 密钥导出为 DER
请注意,此代码不会以 DER
等可读格式提供 public 密钥
let publicKey = loadKeyStringFromKeyChainAsNSData(PUBLIC_KEY + keyId)
如果您需要在 iOS 之外使用 public 密钥(或导入证书并获取有效密钥),则需要额外的操作。使用以下项目
的 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
}
}
我想看看是否可以在 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)编码,具体取决于您的服务能力
我猜你错过了最后一步,将 X509 从服务器返回到设备进行存储
已编辑
使用 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 或密钥的实用函数。你会看到基本上是相同的改变结果的类型(需要一些额外的工作来简化......)
//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([=12=])) }
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([=12=])) }
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([=12=])) }
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!
}
}
已编辑
将 public 密钥导出为 DER
请注意,此代码不会以 DER
等可读格式提供 public 密钥let publicKey = loadKeyStringFromKeyChainAsNSData(PUBLIC_KEY + keyId)
如果您需要在 iOS 之外使用 public 密钥(或导入证书并获取有效密钥),则需要额外的操作。使用以下项目
的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
}
}