2016-07-11 1 views
1

SecPKCS12Import이라는 기능이있어 p12 파일에서 데이터를 가져올 수 있습니다. 그러나 나는 반대 방향으로 가고 싶다. 나는 SecCertificateRef과 공공/전용 SecKeyRef을 가지고 있는데, P12 파일을 만드는데 사용하고 싶습니다. 누구든지 iPhone에서이 작업을 수행하는 방법을 알고 있습니까?P12 파일 Xcode를 생성 하시겠습니까?

감사

답변

2

불행하게도, CommonCrypto은 (는 OSX의 대응이 그렇게 할 수 있지만) PKCS12 컨테이너 혼자 다른 내보내기 기능을하게 내보낼 수있는 수단이 제공하지 않습니다. 키 체인에서 SecKeyRef 원시 데이터를 추출하는 방법이 있지만 그 다음에는 모든 PKCS12를 직접 작성해야합니다.

비슷한 문제가 발생하여 OpenSSL을 사용했습니다. 당신이 컴파일하고 OpenSSL이 자신을 소싱 연결 필요로하는 아이폰 OS OpenSSL을 통합

을 위해 OpenSSL을 컴파일

는 약간의 작업이 필요합니다. 다행히도 빌드 스크립트가 있으므로 사용할 필요가 없습니다 (예 : https://github.com/x2on/OpenSSL-for-iPhone). 약간의 개암 (hazel) 인 Makefile을 패치해야 할 때 사용하는 것이 좋습니다. 이러한 빌드 스크립트는 iOS와 tvOS 모두를위한 정적 링크 라이브러리를 생성합니다. 프로젝트에 링크를 연결하고 그에 따라 헤더 및 라이브러리 검색 경로를 설정하면됩니다.

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을 볼 수있다.

희망 하시겠습니까?

+0

을 또한, 나는이에 대한 인증서와 개인 키를 보내려면 서버, OpenSSL 라이브러리를 사용하지 않고 다른 방법으로 그것을 할 수 있습니까? – hockeybro

+0

이론적으로 비공개 및 공개 키는 키 체인에서 NSData로 내보낼 수 있지만 직접 구현해야하는 PEM, DER, X.509 또는 PKCS12와 같은 추가 형식을 내보낼 수 있습니다. 불행히도, 우리는이 앱에서 결코 작동하지 않습니다. 관심이 있으시면'SecItemCopyMatching'을보세요. 행운을 빕니다! –

+0

OpenSSL에서 PKCS12를 생성하고 전체 라이브러리를 가져 오는 대신이 코드를 복사하는 코드 스 니펫을 얻을 수 있습니까? – hockeybro

1

이 작업은 OpenSSL을 통해서만 수행 할 수 있다는 것에 동의합니다. iOS 용으로 컴파일하는 것은 약간 까다 롭지 만, OpenSSL-for-iPhone을 사용하는 것은 가능합니다.

SecCertificate에서 PKCS12 키 스토어 및 프로젝트에 스위프트 3 단지 추가 정적 라이브러리 libssl.aSecKeylibcrypto.a을 만드는 주어진 과제를 해결하고 다음 브리지 헤더를 만들려면 :

#import <openssl/err.h> 
#import <openssl/pem.h> 
#import <openssl/pkcs12.h> 
#import <openssl/x509.h> 

키 스토어를 만들려면 입력 데이터를 OpenSSL 데이터 구조로 변환해야하며 이는 약간의 창의성을 필요로합니다.SecCertificateDER 형식으로 직접 변환 한 다음 X509 구조로 읽을 수 있습니다. SecKey은 처리하기가 훨씬 더 어렵습니다. 키의 데이터를 얻는 유일한 방법은 키 체인에 데이터를 쓰고 참조를 얻는 것입니다. 참조에서 기본 64 인코딩 된 문자열을 가져올 수 있으며이 문자열은 EVP_PKEY 구조로 읽을 수 있습니다. 이제 키 스토어를 만들어 파일에 저장할 수 있습니다. 아이폰 OS 기능을 통해 키 스토어의 데이터에 액세스하기 위해 우리는 전체 솔루션은 다음과 같다 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() 
} 
+0

좋은 물건. 보안상의 이유로 프로덕션 응용 프로그램에서 개인 키를 인쇄하지 않는 코드를 주석으로 표시 할 수 있습니다. – mbonness

+1

감사합니다. 네, 맞습니다. 열쇠를 생산 현장에 인쇄해서는 안됩니다. 해당 줄에 주석을 추가했습니다. – sundance

관련 문제