2013-01-01 107 views
8

我想使用iOS中的代碼附帶的自簽名證書來創建與我的服務器的SSL連接。這樣我就不用擔心有人可以訪問高級「可信」證書頒發機構的更復雜的中間人攻擊。我在使用我認爲是Apple的標準方式的問題時遇到了問題。如何驗證(並要求)iOS中的自簽名證書

生成證書,通過程序中發現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 

和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]; 
    } 
} 

我一直都想與kSecTrustResultRecoverableTrustFailure作爲結果。我不認爲這是本地主機問題,因爲我試圖使用Apple的代碼來改變它。該怎麼辦?

謝謝!

+0

您需要覆蓋'canAuthenticateAgainstProtectionSpace'和'didReceiveAuthenticationChallenge'。 'TrustResultRecoverableTrustFailure'意味着你可以改變服務器驗證的結果。另請參閱OWASP的iOS公共密鑰固定示例(http://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#iOS)。 – jww

回答

0

請確保您的證書是有效的。我認爲它的名字不應該是root.der.crt。您可以查看here的證書類型。下面的代碼是爲p12證書,我希望它會有所幫助。

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; 
}