2013-01-01 42 views
8

Tôi muốn tạo kết nối SSL với máy chủ của mình bằng chứng chỉ tự ký được gửi cùng với mã trong iOS. Bằng cách đó, tôi không phải lo lắng về những cuộc tấn công phức tạp hơn giữa những người đàn ông trung gian, nơi ai đó có quyền truy cập vào một cơ quan cấp cao "đáng tin cậy". Tôi đang gặp vấn đề khi sử dụng những gì tôi tin là cách chuẩn của Apple.Cách xác minh (và yêu cầu) chứng chỉ tự ký trong iOS

Tạo giấy chứng nhận, thông qua các thủ tục tìm thấy here

# Create root CA & private key 
openssl req -newkey rsa:4096 -sha512 -days 9999 -x509 -nodes -out root.pem.cer 
# Create a certificate signing request 
openssl req -newkey rsa:4096 -sha512 -nodes -out ssl.csr -keyout ssl.key 
# Create an OpenSSL Configuration file from http://svasey.org/projects/software-usage-notes/ssl_en.html 
vim openssl.conf 
# Create the indexes 
touch certindex 
echo 000a > certserial 
echo 000a > crlnumber 
# Generate SSL certificate 
openssl ca -batch -config openssl.conf -notext -in ssl.csr -out ssl.pem.cer 
# Create Certificate Revocation List 
openssl ca -config openssl.conf -gencrl -keyfile privkey.pem -cert root.pem.cer -out root.crl.pem 
openssl crl -inform PEM -in root.crl.pem -outform DER -out root.crl && rm root.crl.pem 

Và mã iOS:

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { 
    NSURLProtectionSpace *protectionSpace = [challenge protectionSpace]; 
    if ([protectionSpace authenticationMethod] == NSURLAuthenticationMethodServerTrust) { 
    // Load anchor cert.. also tried this with both certs and it doesn't seem to matter 
    NSString *path = [[NSBundle mainBundle] pathForResource:@"root.der" ofType:@"crt"]; 
    NSData *data = [[NSData alloc] initWithContentsOfFile:path]; 
    SecCertificateRef anchorCert = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)data); 
    CFMutableArrayRef anchorCerts = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 
    CFArrayAppendValue(anchorCerts, anchorCert); 

    // Set anchor cert 
    SecTrustRef trust = [protectionSpace serverTrust]; 
    SecTrustSetAnchorCertificates(trust, anchorCerts); 
    SecTrustSetAnchorCertificatesOnly(trust, YES); // only use that certificate 
    CFRelease(anchorCert); 
    CFRelease(anchorCerts); 

    // Validate cert 
    SecTrustResultType secresult = kSecTrustResultInvalid; 
    if (SecTrustEvaluate(trust, &secresult) != errSecSuccess) { 
     [challenge.sender cancelAuthenticationChallenge:challenge]; 
     return; 
    } 

    switch (secresult) { 
     case kSecTrustResultInvalid: 
     case kSecTrustResultDeny: 
     case kSecTrustResultFatalTrustFailure: 
     case kSecTrustResultOtherError: 
     case kSecTrustResultRecoverableTrustFailure: { 
     // !!! It's always kSecTrustResultRecoverableTrustFailure, aka 5 
     NSLog(@"Failing due to result: %lu", secresult); 
     [challenge.sender cancelAuthenticationChallenge:challenge]; 
     return; 
     } 

     case kSecTrustResultUnspecified: // The OS trusts this certificate implicitly. 
     case kSecTrustResultProceed: { // The user explicitly told the OS to trust it. 
     NSURLCredential *credential = [NSURLCredential credentialForTrust:trust]; 
     [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; 
     return; 
     } 
     default: ; 
     /* It's somebody else's key. Fall through. */ 
    } 
    /* The server sent a key other than the trusted key. */ 
    [connection cancel]; 

    // Perform other cleanup here, as needed. 
    } else { 
    NSLog(@"In weird space... not handling authentication method: %@", [protectionSpace authenticationMethod]); 
    [connection cancel]; 
    } 
} 

Tôi luôn nhận được kSecTrustResultRecoverableTrustFailure như kết quả. Tôi không nghĩ rằng đây là vấn đề localhost như tôi đã cố gắng sử dụng mã của Apple để thay đổi điều đó quá. Phải làm gì?

Cảm ơn!

+0

Bạn cần ghi đè cả 'canAuthenticateAgainstProtectionSpace' và 'didReceiveAuthenticationChallenge'. 'TrustResultRecoverableTrustFailure' có nghĩa là bạn có thể thay đổi kết quả của việc xác thực máy chủ. Cũng xem ví dụ ghim khóa công khai của OWASP tại [Khóa khóa công khai] (http://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#iOS). – jww

Trả lời

0

Hãy chắc chắn rằng chứng chỉ của bạn là hợp lệ. Tôi nghĩ tên của nó không phải là root.der.crt. Bạn có thể tìm kiếm các loại chứng chỉ từ here. Mã dưới đây dành cho chứng chỉ p12, tôi hy vọng nó sẽ giúp.

NSData *PKCS12DataQA = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"CERTIFICATE NAME" ofType:@"CERTIFICATE TYPE"]]; 

BOOL result = [self extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12DataQA]; 


- (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data 
{ 
    OSStatus securityError = errSecSuccess; 
    //testtest is the passsword for the certificate. 
    NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"testtest" forKey:(id)CFBridgingRelease(kSecImportExportPassphrase)]; 

    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); 
    securityError = SecPKCS12Import((__bridge CFDataRef)(inPKCS12Data),(CFDictionaryRef)CFBridgingRetain(optionsDictionary),&items); 

    if (securityError == 0) { 
     CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0); 
     const void *tempIdentity = NULL; 
     tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity); 
     *outIdentity = (SecIdentityRef)tempIdentity; 
     const void *tempTrust = NULL; 
     tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust); 
     *outTrust = (SecTrustRef)tempTrust; 

    } else { 
     NSLog(@"Failed with error code %d",(int)securityError); 
     return NO; 
    } 

    return YES; 
} 
Các vấn đề liên quan