Ich stimme zu, dass diese Aufgabe nur mit OpenSSL ausgeführt werden kann. Es ist ein bisschen schwierig, es für iOS zu kompilieren, aber mit OpenSSL-for-iPhone ist es durchaus möglich.
Um die gegebene Aufgabe der Schaffung eines PKCS12 Schlüsselspeicher von einem SecCertificate
und SecKey
mit Swift 3 fügen Sie einfach den statischen Bibliotheken libssl.a
und libcrypto.a
zu einem Projekt zu lösen und die folgende Überbrückung Header erstellen:
#import <openssl/err.h>
#import <openssl/pem.h>
#import <openssl/pkcs12.h>
#import <openssl/x509.h>
Um den Keystore zu erstellen, müssen die Eingabedaten in OpenSSL-Datenstrukturen konvertiert werden, was etwas Kreativität erfordert.Die SecCertificate
kann direkt in das Format DER konvertiert und dann in eine X509 Struktur eingelesen werden. Die SecKey
ist noch schlechter zu handhaben. Die einzige mögliche Lösung, um die Daten des Schlüssels zu erhalten, besteht darin, sie in den Schlüsselbund zu schreiben und die Referenz zu erhalten. Aus der Referenz können wir die Base 64 codierte Zeichenfolge erhalten, die dann in eine EVP_PKEY
Struktur gelesen werden kann. Jetzt können wir den Keystore erstellen und in einer Datei speichern. Um die Daten in den Schlüsselspeicher über iOS-Funktionen zugreifen, müssen wir die Datei über let data = FileManager.default.contents(atPath: path)! as NSData
Die vollständige Lösung wird gezeigt in der folgenden lesen:
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()
}
Auch, wenn ich ein Zertifikat und einen privaten Schlüssel zu einem schicken möchten Server, gibt es eine andere Möglichkeit, dies zu tun, ohne die OpenSSL-Bibliothek zu verwenden? – hockeybro
Theoretisch können Sie die privaten und öffentlichen Schlüssel als NSData aus dem Schlüsselbund exportieren, aber jede zusätzliche Formatierung, z. B. PEM, DER, X.509 oder PKCS12, die Sie selbst implementieren müssen. Leider haben wir das nie in unserer App funktionieren lassen. Wenn Sie interessiert sind, können Sie sich "SecItemCopyMatching" anschauen. Viel Glück! –
Wäre es möglich, Codeschnipsel zu erhalten, um eine PKCS12 von OpenSSL zu erzeugen, und kopieren Sie diese einfach hinein, anstatt die gesamte Bibliothek zu importieren? – hockeybro