2016-09-29 3 views
1

iOS (iPhone/iPhone 시뮬레이터)에 SSL 인증서를 프로그래밍 방식으로 설치하려고합니다. this small guide을 사용하여 .crt을 만들고 설치했습니다! 그러나 얻은 server.crtserver.der으로 변환하려고 시도 할 때 프로그래밍 방식으로 설치하면 CFNetwork SSLHandshake failed (-9807)이 표시됩니다. iOS에서는 .der 버전을 사용하고 OS X openssl 서버에서는 .crt 버전을 사용합니다. 아이폰 OS에iOS에 프로그래밍 방식으로 .der 인증서를 설치할 수 없습니다.

openssl s_server -key server.key -cert server.crt -accept 1678

설치 및 전송 :는 OS X에 수신

openssl x509 -outform der -in server.crt -out server.der

:

변환

NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 
    NSData *iosTrustedCertDerData = 
    [NSData dataWithContentsOfFile:[bundle pathForResource:@"certificate" 
                ofType:@"der"]]; 

    OSStatus   err = noErr; 
    SecCertificateRef cert; 

    cert = SecCertificateCreateWithData(NULL, (CFDataRef) iosTrustedCertDerData); 
    assert(cert != NULL); 

    CFTypeRef result; 

    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: 
          (id)kSecClassCertificate, kSecClass, 
          cert, kSecValueRef, 
          nil]; 

    err = SecItemAdd((CFDictionaryRef)dict, &result); 
    assert(err == noErr || err == errSecDuplicateItem); 

    printf("adding finished \n"); 


    if ((err == noErr) || 
     (err == errSecDuplicateItem)) { 

     printf("success \n"); 

     CFReadStreamRef readStream; 
     CFWriteStreamRef writeStream; 
     CFStreamCreatePairWithSocketToHost(NULL, 
              (CFStringRef)@"localhost", 
              1678, 
              &readStream, 
              &writeStream); 
     CFReadStreamSetProperty(readStream, 
           kCFStreamPropertySocketSecurityLevel, 
           kCFStreamSocketSecurityLevelTLSv1); 
     CFReadStreamOpen(readStream); 
     CFWriteStreamOpen(writeStream); 

     UInt8 buf[] = "Hello from iOS\n"; 
     int bytesWritten = CFWriteStreamWrite(writeStream, buf, strlen((char*)buf)); 
} 

을 그래서, 내가 어떻게 변환 할 수 있습니다를 설치하십시오.iOS의 인증서가 올바 릅니까?

UPD :

NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 

    NSString *resourcePath = [bundle pathForResource:@"certificate" ofType:@"der"]; 

    NSData *certData = [NSData dataWithContentsOfFile:resourcePath]; 

    NSString* publickKeyRef = @"certificate_der"; 

    NSData* headerStrippedData = [self stripPublicKeyHeader:certData]; 
    [self addPeerPublicKey:publickKeyRef keyBits:headerStrippedData]; 

    SecKeyRef ref= [self getPublicKeyReference:publickKeyRef]; 

    printf("adding finished \n"); 


    CFReadStreamRef readStream; 
    CFWriteStreamRef writeStream; 
    CFStreamCreatePairWithSocketToHost(NULL, 
             (CFStringRef)@"localhost", 
             1678, 
             &readStream, 
             &writeStream); 
    CFReadStreamSetProperty(readStream, 
          kCFStreamPropertySocketSecurityLevel, 
          kCFStreamSocketSecurityLevelTLSv1); 
    CFReadStreamOpen(readStream); 
    CFWriteStreamOpen(writeStream); 

예외는이 라인에 발생

[self addPeerPublicKey:publickKeyRef keyBits:headerStrippedData]; 

예외 :

아이폰 OS에서
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** setObjectForKey: object cannot be nil (key: v_Data)' 
*** First throw call stack: 
(
    0 CoreFoundation      0x00a81a14 __exceptionPreprocess + 180 
    1 libobjc.A.dylib      0x00540e02 objc_exception_throw + 50 
    2 CoreFoundation      0x0096a174 -[__NSDictionaryM setObject:forKey:] + 948 
    3 ssl2        0x0006d8eb -[ViewController addPeerPublicKey:keyBits:] + 491 
    4 ssl2        0x0006e2dd -[ViewController viewDidLoad] + 397 
    5 UIKit        0x010932ae -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 44 
    6 UIKit        0x01097dce -[UIViewController loadViewIfRequired] + 1384 
    7 UIKit        0x010981ed -[UIViewController view] + 35 
    8 UIKit        0x00f45f94 -[UIWindow addRootViewControllerViewIfPossible] + 69 
    9 UIKit        0x00f466b1 -[UIWindow _setHidden:forced:] + 304 
    10 UIKit        0x00f46a67 -[UIWindow _orderFrontWithoutMakingKey] + 49 
    11 UIKit        0x00f5a118 -[UIWindow makeKeyAndVisible] + 80 
    12 UIKit        0x00ec26e7 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4190 
    13 UIKit        0x00ec9cd6 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1989 
    14 UIKit        0x00eeeee5 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke3218 + 68 
    15 UIKit        0x00ec6966 -[UIApplication workspaceDidEndTransaction:] + 163 
    16 FrontBoardServices     0x0373fc76 __37-[FBSWorkspace clientEndTransaction:]_block_invoke_2 + 71 
    17 FrontBoardServices     0x0373f74d __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 54 
    18 FrontBoardServices     0x0375d173 -[FBSSerialQueue _performNext] + 184 
    19 FrontBoardServices     0x0375d5aa -[FBSSerialQueue _performNextFromRunLoopSource] + 52 
    20 FrontBoardServices     0x0375c8a6 FBSSerialQueueRunLoopSourceHandler + 33 
    21 CoreFoundation      0x0099b6ff __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15 
    22 CoreFoundation      0x0099138b __CFRunLoopDoSources0 + 523 
    23 CoreFoundation      0x009907a8 __CFRunLoopRun + 1032 
    24 CoreFoundation      0x009900e6 CFRunLoopRunSpecific + 470 
    25 CoreFoundation      0x0098fefb CFRunLoopRunInMode + 123 
    26 UIKit        0x00ec6206 -[UIApplication _run] + 540 
    27 UIKit        0x00ecbbfa UIApplicationMain + 160 
    28 ssl2        0x0006e91a main + 138 
    29 libdyld.dylib      0x0310ba21 start + 1 
) 
libc++abi.dylib: terminating with uncaught exception of type NSException 
+0

인증서를 만드는 방법이 올바르지 않을 수 있습니다. ***'CN = example.com' *** 아마 잘못되었습니다. 호스트 이름은 항상 * SAN *에 있습니다. * CN *에있는 경우, * SAN *에도 있어야합니다 (이 경우 두 번 나열해야합니다). 자세한 규칙 및 이유는 [인증 기관의 인증서 서명 요청 서명 방법] (http://stackoverflow.com/a/21340898/608639) 및 [openssl을 사용하여 자체 서명 된 인증서를 만드는 방법] (http://stackoverflow.com/q/10175812/608639) – jww

+0

@jww 이미이 도구를 사용해 보았습니다. [이 항목 확인] (http://stackoverflow.com/questions/39239817/cfnetwork-sslhandshake-failed-9807-on 시뮬레이터와 로컬 호스트). –

답변

2

는 그 조금 다른, 당신은이를 추가해야 .der 파일을 키 체인에 연결 한 다음 참조하십시오. 다시 열쇠 고리에서. 내가 추가하고 다시 키 체인

에서
- (void)addPeerPublicKey:(NSString *)peerName keyBits:(NSData *)publicKeyData { 

    OSStatus sanityCheck = noErr; 
    CFTypeRef persistPeer = NULL; 
    [self removePeerPublicKey:peerName]; 

    NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]]; 
    NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init]; 
    [peerPublicKeyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass]; 
    [peerPublicKeyAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType]; 
    [peerPublicKeyAttr setObject:peerTag forKey:(id)kSecAttrApplicationTag]; 
    [peerPublicKeyAttr setObject:publicKeyData forKey:(id)kSecValueData]; 
    [peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnData]; 
    sanityCheck = SecItemAdd((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&persistPeer); 

    if(sanityCheck == errSecDuplicateItem) 
    { 
     NSLog(@"HanselErrorCode: -1"); 
    } 

    persistPeer = NULL; 
    [peerPublicKeyAttr removeObjectForKey:(id)kSecValueData]; 
    sanityCheck = SecItemCopyMatching((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef*)&persistPeer); 

    if (persistPeer) CFRelease(persistPeer); 
} 

-(SecKeyRef)getPublicKeyReference:(NSString*)peerName 
{ 
    OSStatus sanityCheck = noErr; 

    SecKeyRef pubKeyRefData = NULL; 
    NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]]; 
    NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init]; 

    [peerPublicKeyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass]; 
    [peerPublicKeyAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType]; 
    [peerPublicKeyAttr setObject:peerTag forKey:(id)kSecAttrApplicationTag]; 
    [peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:  (id)kSecReturnRef]; 
    sanityCheck = SecItemCopyMatching((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef*)&pubKeyRefData); 

    if(pubKeyRefData) 
    { 
     return pubKeyRefData; 
    } 
    else 
    { 
     return nil; 
    } 
} 

- (NSData *)stripPublicKeyHeader:(NSData *)d_key 
{ 
    // Skip ASN.1 public key header 
    if (d_key == nil) return(nil); 

    unsigned int len = (unsigned int)[d_key length]; 
    if (!len) return(nil); 

    unsigned char *c_key = (unsigned char *)[d_key bytes]; 
    unsigned int idx = 0; 

    if (c_key[idx++] != 0x30) return(nil); 

    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 
    else idx++; 

    // PKCS #1 rsaEncryption szOID_RSA_RSA 
    static unsigned char seqiod[] = 
    { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 
     0x01, 0x05, 0x00 }; 
    if (memcmp(&c_key[idx], seqiod, 15)) return(nil); 

    idx += 15; 

    if (c_key[idx++] != 0x03) return(nil); 

    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 
    else idx++; 

    if (c_key[idx++] != '\0') return(nil); 

    // Now make a new NSData from this buffer 
    return([NSData dataWithBytes:&c_key[idx] length:len - idx]); 

} 


- (void)removePeerPublicKey:(NSString *)peerName 
{ 
    OSStatus sanityCheck = noErr; 

    NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]]; 
    NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init]; 

    [peerPublicKeyAttr setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass]; 
    [peerPublicKeyAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; 
    [peerPublicKeyAttr setObject:peerTag forKey:(__bridge id)kSecAttrApplicationTag]; 

    sanityCheck = SecItemDelete((__bridge CFDictionaryRef) peerPublicKeyAttr); 
} 

을 얻을 그리고이 키를 사용하려면

NSString *resourcePath = [bundle pathForResource:@"publickey" ofType:@"der"]; 
    NSData *certData = [NSData dataWithContentsOfFile:resourcePath]; 

    NSData* headerStrippedData = [self stripPublicKeyHeader:certData]; 
    [self addPeerPublicKey:publickKeyRef keyBits:headerStrippedData]; 

    SecKeyRef ref= [self getPublicKeyReference:publickKeyRef]; 

이하로 할 마지막으로 모든 용도에 ref을 사용해야합니다 아래의 코드를 제공하고 있습니다.

NSString* publickKeyRef = @"key_name_against_which_you_want_to_save_your_der";

이 코드

당신에게, 추가 다시 얻고 그것을 사용하는 방법을 보여줍니다. 몇 달 전에이 코드를 인터넷에서 가져 왔습니다. 소스를 찾으면 소스에 대한 링크를 추가하십시오. Xcode8에서는 기능 섹션에서이 der 파일을 사용할 키 체인 이름 ( publickKeyRef)을 추가해야합니다.

+0

답변 해 주셔서 감사합니다. 나는 단지 한가지를 이해하지 못한다 : 나는 'publickKeyRef'로 사용해야 할 필요가 있는가? 미안하지만 분명하다면 - iOS의 초보자입니다. –

+0

좋아요, 이제 질문을 받고 내 대답을 변경했습니다. – prabodhprakash

+0

그게 도움이 @ don-prog 않았다? – prabodhprakash

관련 문제