生成P12文件Xcode?
Generate a P12 file Xcode?
我知道有一个名为 SecPKCS12Import
的函数可以让您从 p12 文件导入数据。但是,我想走相反的路。我有一个 SecCertificateRef
和一个 public/private SecKeyRef
,我想用它们来创建 P12 文件。有谁知道如何在 iPhone 上执行此操作?
谢谢
不幸的是,CommonCrypto 不提供任何导出 PKCS12 容器的方法,更不用说任何其他导出功能了(尽管它的 OSX 对应物可以做到这一点)。有多种方法可以从密钥链中提取 SecKeyRef 原始数据,但您仍然需要自己编写所有 PKCS12 包装。
我们遇到了类似的问题,因此选择了 OpenSSL。
为 iOS
编译 OpenSSL
集成 OpenSSL 需要一些工作,因为您需要自己编译 link OpenSSL 源代码。幸运的是,有一些可用的构建脚本,因此您不必自己动手,例如 https://github.com/x2on/OpenSSL-for-iPhone 。我建议您使用它们,因为您需要修补一些有点淡褐色的 Makefile。这些构建脚本为 iOS 和 tvOS 生成静态 linked 库。您只需要根据您的项目 link 它们并相应地设置 Header 和库搜索路径。
CocoaPods
你也可以使用官方的OpenSSL CocoaPod。这样就省去了配置项目的麻烦。
导出 PKCS12
您可能知道,OpenSSL 是 C library。这意味着您可能希望将所有 C 函数封装到 Objective-C 或 Swift 包装器中。有一些支持导入和导出 PKCS12 容器的开源包装器,但我还没有找到一个具有良好文档的包装器。不过,您应该能够从某些来源中获取相关片段。
https://github.com/microsec/MscX509Common/blob/master/src/MscPKCS12.m
你也可以看看这个例子http://fm4dd.com/openssl/pkcs12test.htm。
希望对您有所帮助!
我同意只能使用 OpenSSL 执行此任务。为 iOS 编译它有点棘手,但使用 OpenSSL-for-iPhone 是很有可能的。
解决从 SecCertificate
和 SecKey
和 Swift 创建 PKCS12 密钥库的给定任务3 只需将静态库 libssl.a
和 libcrypto.a
添加到您的项目并创建以下桥接 header:
#import <openssl/err.h>
#import <openssl/pem.h>
#import <openssl/pkcs12.h>
#import <openssl/x509.h>
要创建密钥库,必须将输入数据转换为 OpenSSL 数据结构,这需要一些创造力。 SecCertificate
可以直接转换为DER格式,然后读入X509结构。 SecKey
更难处理。获取密钥数据的唯一可能解决方案是将其写入钥匙串并获取引用。从参考中我们可以得到base 64编码的字符串,然后可以将其读入EVP_PKEY
结构。现在,我们可以创建密钥库并将其保存到文件中。要通过 iOS 函数访问密钥库中的数据,我们必须通过 let data = FileManager.default.contents(atPath: path)! as NSData
读取文件
完整的解决方案如下:
func createP12(secCertificate: SecCertificate, secPrivateKey: SecKey) {
// Read certificate
// Convert sec certificate to DER certificate
let derCertificate = SecCertificateCopyData(secCertificate)
// Create strange pointer to read DER certificate with OpenSSL
// data must be a two-dimensional array containing the pointer to the DER certificate as single element at position [0][0]
let certificatePointer = CFDataGetBytePtr(derCertificate)
let certificateLength = CFDataGetLength(derCertificate)
let certificateData = UnsafeMutablePointer<UnsafePointer<UInt8>?>.allocate(capacity: 1)
certificateData.pointee = certificatePointer
// Read DER certificate
let certificate = d2i_X509(nil, certificateData, certificateLength)
// Print certificate
X509_print_fp(stdout, certificate)
// Read private key
// Convert sec key to PEM key
let tempTag = "bundle.temp"
let tempAttributes = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: tempTag,
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecValueRef: secPrivateKey,
kSecReturnData: kCFBooleanTrue
] as NSDictionary
var privateKeyRef: AnyObject?
// Store private key in keychain
SecItemDelete(tempAttributes)
guard SecItemAdd(tempAttributes, &privateKeyRef) == noErr else {
NSLog("Cannot store private key")
return
}
// Get private key data
guard let privateKeyData = privateKeyRef as? Data else {
NSLog("Cannot get private key data")
return
}
let pemPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n\(privateKeyData.base64EncodedString())\n-----END RSA PRIVATE KEY-----\n"
// Delete private key in keychain
SecItemDelete(tempAttributes)
let privateKeyBuffer = BIO_new(BIO_s_mem())
pemPrivateKey.data(using: .utf8)!.withUnsafeBytes({ (bytes: UnsafePointer<Int8>) -> Void in
BIO_puts(privateKeyBuffer, bytes)
})
let privateKey = PEM_read_bio_PrivateKey(privateKeyBuffer, nil, nil, nil)
// !!! Remove in production: Print private key
PEM_write_PrivateKey(stdout, privateKey, nil, nil, 0, nil, nil)
// Check if private key matches certificate
guard X509_check_private_key(certificate, privateKey) == 1 else {
NSLog("Private key does not match certificate")
return
}
// Set OpenSSL parameters
OPENSSL_add_all_algorithms_noconf()
ERR_load_crypto_strings()
// Create P12 keystore
let passPhrase = UnsafeMutablePointer(mutating: ("" as NSString).utf8String)
let name = UnsafeMutablePointer(mutating: ("SSL Certificate" as NSString).utf8String)
guard let p12 = PKCS12_create(passPhrase, name, privateKey, certificate, nil, 0, 0, 0, 0, 0) else {
NSLog("Cannot create P12 keystore:")
ERR_print_errors_fp(stderr)
return
}
// Save P12 keystore
let fileManager = FileManager.default
let tempDirectory = NSTemporaryDirectory() as NSString
let path = tempDirectory.appendingPathComponent("ssl.p12")
fileManager.createFile(atPath: path, contents: nil, attributes: nil)
guard let fileHandle = FileHandle(forWritingAtPath: path) else {
NSLog("Cannot open file handle: \(path)")
return
}
let p12File = fdopen(fileHandle.fileDescriptor, "w")
i2d_PKCS12_fp(p12File, p12)
fclose(p12File)
fileHandle.closeFile()
}
我知道有一个名为 SecPKCS12Import
的函数可以让您从 p12 文件导入数据。但是,我想走相反的路。我有一个 SecCertificateRef
和一个 public/private SecKeyRef
,我想用它们来创建 P12 文件。有谁知道如何在 iPhone 上执行此操作?
谢谢
不幸的是,CommonCrypto 不提供任何导出 PKCS12 容器的方法,更不用说任何其他导出功能了(尽管它的 OSX 对应物可以做到这一点)。有多种方法可以从密钥链中提取 SecKeyRef 原始数据,但您仍然需要自己编写所有 PKCS12 包装。
我们遇到了类似的问题,因此选择了 OpenSSL。
为 iOS
编译 OpenSSL集成 OpenSSL 需要一些工作,因为您需要自己编译 link OpenSSL 源代码。幸运的是,有一些可用的构建脚本,因此您不必自己动手,例如 https://github.com/x2on/OpenSSL-for-iPhone 。我建议您使用它们,因为您需要修补一些有点淡褐色的 Makefile。这些构建脚本为 iOS 和 tvOS 生成静态 linked 库。您只需要根据您的项目 link 它们并相应地设置 Header 和库搜索路径。
CocoaPods
你也可以使用官方的OpenSSL CocoaPod。这样就省去了配置项目的麻烦。
导出 PKCS12
您可能知道,OpenSSL 是 C library。这意味着您可能希望将所有 C 函数封装到 Objective-C 或 Swift 包装器中。有一些支持导入和导出 PKCS12 容器的开源包装器,但我还没有找到一个具有良好文档的包装器。不过,您应该能够从某些来源中获取相关片段。
https://github.com/microsec/MscX509Common/blob/master/src/MscPKCS12.m
你也可以看看这个例子http://fm4dd.com/openssl/pkcs12test.htm。
希望对您有所帮助!
我同意只能使用 OpenSSL 执行此任务。为 iOS 编译它有点棘手,但使用 OpenSSL-for-iPhone 是很有可能的。
解决从 SecCertificate
和 SecKey
和 Swift 创建 PKCS12 密钥库的给定任务3 只需将静态库 libssl.a
和 libcrypto.a
添加到您的项目并创建以下桥接 header:
#import <openssl/err.h>
#import <openssl/pem.h>
#import <openssl/pkcs12.h>
#import <openssl/x509.h>
要创建密钥库,必须将输入数据转换为 OpenSSL 数据结构,这需要一些创造力。 SecCertificate
可以直接转换为DER格式,然后读入X509结构。 SecKey
更难处理。获取密钥数据的唯一可能解决方案是将其写入钥匙串并获取引用。从参考中我们可以得到base 64编码的字符串,然后可以将其读入EVP_PKEY
结构。现在,我们可以创建密钥库并将其保存到文件中。要通过 iOS 函数访问密钥库中的数据,我们必须通过 let data = FileManager.default.contents(atPath: path)! as NSData
完整的解决方案如下:
func createP12(secCertificate: SecCertificate, secPrivateKey: SecKey) {
// Read certificate
// Convert sec certificate to DER certificate
let derCertificate = SecCertificateCopyData(secCertificate)
// Create strange pointer to read DER certificate with OpenSSL
// data must be a two-dimensional array containing the pointer to the DER certificate as single element at position [0][0]
let certificatePointer = CFDataGetBytePtr(derCertificate)
let certificateLength = CFDataGetLength(derCertificate)
let certificateData = UnsafeMutablePointer<UnsafePointer<UInt8>?>.allocate(capacity: 1)
certificateData.pointee = certificatePointer
// Read DER certificate
let certificate = d2i_X509(nil, certificateData, certificateLength)
// Print certificate
X509_print_fp(stdout, certificate)
// Read private key
// Convert sec key to PEM key
let tempTag = "bundle.temp"
let tempAttributes = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: tempTag,
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecValueRef: secPrivateKey,
kSecReturnData: kCFBooleanTrue
] as NSDictionary
var privateKeyRef: AnyObject?
// Store private key in keychain
SecItemDelete(tempAttributes)
guard SecItemAdd(tempAttributes, &privateKeyRef) == noErr else {
NSLog("Cannot store private key")
return
}
// Get private key data
guard let privateKeyData = privateKeyRef as? Data else {
NSLog("Cannot get private key data")
return
}
let pemPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n\(privateKeyData.base64EncodedString())\n-----END RSA PRIVATE KEY-----\n"
// Delete private key in keychain
SecItemDelete(tempAttributes)
let privateKeyBuffer = BIO_new(BIO_s_mem())
pemPrivateKey.data(using: .utf8)!.withUnsafeBytes({ (bytes: UnsafePointer<Int8>) -> Void in
BIO_puts(privateKeyBuffer, bytes)
})
let privateKey = PEM_read_bio_PrivateKey(privateKeyBuffer, nil, nil, nil)
// !!! Remove in production: Print private key
PEM_write_PrivateKey(stdout, privateKey, nil, nil, 0, nil, nil)
// Check if private key matches certificate
guard X509_check_private_key(certificate, privateKey) == 1 else {
NSLog("Private key does not match certificate")
return
}
// Set OpenSSL parameters
OPENSSL_add_all_algorithms_noconf()
ERR_load_crypto_strings()
// Create P12 keystore
let passPhrase = UnsafeMutablePointer(mutating: ("" as NSString).utf8String)
let name = UnsafeMutablePointer(mutating: ("SSL Certificate" as NSString).utf8String)
guard let p12 = PKCS12_create(passPhrase, name, privateKey, certificate, nil, 0, 0, 0, 0, 0) else {
NSLog("Cannot create P12 keystore:")
ERR_print_errors_fp(stderr)
return
}
// Save P12 keystore
let fileManager = FileManager.default
let tempDirectory = NSTemporaryDirectory() as NSString
let path = tempDirectory.appendingPathComponent("ssl.p12")
fileManager.createFile(atPath: path, contents: nil, attributes: nil)
guard let fileHandle = FileHandle(forWritingAtPath: path) else {
NSLog("Cannot open file handle: \(path)")
return
}
let p12File = fdopen(fileHandle.fileDescriptor, "w")
i2d_PKCS12_fp(p12File, p12)
fclose(p12File)
fileHandle.closeFile()
}