2016-07-11 48 views
1

SecPKCS12Importという機能があり、p12ファイルからデータをインポートすることができます。しかし、私は逆のルートに行きたい。 SecCertificateRefと公開/私設SecKeyRefがあります。これをP12ファイルの作成に使用します。誰もがiPhoneでこれを行う方法を知っていますか?P12ファイルXcodeを生成しますか?

おかげ

答えて

2

は残念ながら、そこにCommonCryptoは(そのOSXの対応はそれを行うことができていても)PKCS12コンテナをエクスポートする任意の手段はおろか、他のエクスポート機能を提供していません。キーチェーンからSecKeyRef生データを抽出する方法がありますが、PKCS12をすべてラップする必要があります。

私たちも同様の問題に直面していて、OpenSSLに行っていました。あなたはOpenSSLのソースを自分でコンパイルしてリンクする必要があるとして、iOSの OpenSSLを統合

ためにOpenSSLのコンパイル

は仕事のビットを必要とします。幸いにも、使用可能なビルドスクリプトがいくつかありますので、自分で行う必要はありません(例:https://github.com/x2on/OpenSSL-for-iPhone)。私は、あなたがヘーゼルのビットであるMakefileのいくつかにパッチを当てる必要があるので、それらを使用することをお勧めします。これらのビルドスクリプトは、iOSとtvOSの両方の静的リンクライブラリを生成します。プロジェクトとリンクするだけで、それに応じてヘッダとライブラリの検索パスを設定するだけです。

CocoaPods

また、公式OpenSSL CocoaPodを使用することができます。これにより、プロジェクトを構成する手間が省けます。

エクスポートPKCS12

ご存知かもしれませんが、OpenSSLはC libraryです。つまり、すべてのC関数をObjective-CまたはSwiftラッパーにカプセル化したい場合があります。 PKCS12コンテナのインポ​​ートとエクスポートをサポートするオープンソースのラッパーがいくつかありますが、ドキュメントが1つしかないものは見つかりませんでした。あなたはいくつかのソースから関連するスニペットを引き出すことができるはずです。

https://github.com/microsec/MscX509Common/blob/master/src/MscPKCS12.m

あなたは、この例を見て、同様http://fm4dd.com/openssl/pkcs12test.htmを持つことができます。

希望に役立ちます!

+0

また:let data = FileManager.default.contents(atPath: path)! as NSData

を経由して、我々は、ファイルを読まなければならないiOSの機能を使ってキーストア内のデータにアクセスするために完全なソリューションは、以下に示します。 OpenSSLライブラリを使用せずに他の方法でこれを行う方法はありますか?理論的には – hockeybro

+0

、あなたが自分で実装する必要がありますキーチェーンからのNSDataとして秘密鍵と公開鍵をエクスポートしますが、追加のフォーマット、例えば、PEM、DER、X.509またはPKCS12ことができます。残念ながら、私たちはこのアプリでは動作しませんでした。あなたが興味を持っているなら、 'SecItemCopyMatching'を見ることができます。がんばろう! –

+0

は、OpenSSLからPKCS12を生成し、ちょうどこれをコピーではなく、全体のライブラリをインポートするためのコードスニペットを取得することは可能でしょうか? – hockeybro

1

このタスクはOpenSSLを使用してのみ実行できることに同意します。 iOS用にコンパイルするのはちょっと難しいですが、OpenSSL-for-iPhoneでは可能です。

#import <openssl/err.h> 
#import <openssl/pem.h> 
#import <openssl/pkcs12.h> 
#import <openssl/x509.h> 
SecCertificateから PKCS12キーストアを作成する与えられたタスクと SecKeyスウィフト3ちょうどあなたのプロジェクトに静的ライブラリ libssl.alibcrypto.aを追加し、次のブリッジのヘッダーを作成し解決するために

キーストアを作成するには、入力データをOpenSSLデータ構造に変換する必要があります。これにはいくつかの創造性が必要です。SecCertificateDERフォーマットに直接変換し、次いでX509構造に読み込むことができます。 SecKeyはさらに扱いにくいです。キーのデータを取得する唯一の可能なソリューションは、キーチェーンに書き込んで参照を取得することです。参照から、基数64の符号化された文字列を得ることができ、その後EVP_PKEY構造体に読み込むことができます。これで、キーストアを作成してファイルに保存できます。私は、証明書と秘密鍵を送信する場合は、

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() 
} 
+0

良いもの。セキュリティ上の理由から、プロダクションアプリでプライベートキーを印刷しないようにプライベートキーを印刷するコードでコメントを付けることができます。 – mbonness

+1

ありがとうございます。はい、あなたが正しいです、キーは生産中に印刷すべきではありません。私は対応する行にコメントを追加しました。 – sundance

関連する問題