2015-04-20 47 views
12

我们正在尝试在企业iOS应用程序中将客户端SSL证书用于用户身份验证。在Enterprise iOS应用程序中使用.mobileconfig的客户端SSL证书

  • 我们可以生成服务器
  • 在客户端的SSL证书的用户可以通过.mobileconfig
  • 验证安装这在Safari与安装证书工作的Web服务器。
  • 从iOS应用程序内发出http请求失败(不使用证书)。

我们如何得到这个工作?谢谢!

+0

是否使用自签名证书的HTTPS保护您的网站和服务?或者您是否尝试使用证书作为身份验证的手段而不是使用用户名和密码? –

+1

我们想使用证书来验证用户(而不是使用用户名/密码)。 –

+0

您用于Web应用程序的现有解决方案NTLM或Kerberos身份验证是什么? –

回答

8

概述:

您已经安装了客户端SSL证书上的设备钥匙串。

Safari.app和Mail.app可以访问这个钥匙串,而iOS应用不可以。

原因是我们开发的应用程序是沙盒,并且在非越狱设备中没有任何访问权限。

由于safari有权访问它,因此在连接和验证服务器挑战时没有问题。

解决方案:

包括与应用程序捆绑导出P12文件,并指它来寻找正确的客户端证书的服务器一直在寻找for.It实际上是一个解决办法。硬编码是获取P12文件的可靠方法。

实现:在问题

方法是NSURLConenction delegatewillSendRequestForAuthenticationChallenge。您需要考虑NSURLAuthenticationMethodClientCertificate挑战类型以处理服务器挑战。这是我们实施魔术的地方,可以从嵌入式P12文件中提取正确的证书标识。代码如下

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { 
    if ([challenge previousFailureCount] > 0) { 
     //this will cause an authentication failure 
      [[challenge sender] cancelAuthenticationChallenge:challenge]; 
       NSLog(@"Bad Username Or Password");        
     return; 
    } 



    //this is checking the server certificate 
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 
            SecTrustResultType result; 
            //This takes the serverTrust object and checkes it against your keychain 
            SecTrustEvaluate(challenge.protectionSpace.serverTrust, &result); 

      //if we want to ignore invalid server for certificates, we just accept the server 
            if (kSPAllowInvalidServerCertificates) { 
                [challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge]; 
       return; 
            } else if(result == kSecTrustResultProceed || result == kSecTrustResultConfirm ||  result == kSecTrustResultUnspecified) { 
       //When testing this against a trusted server I got kSecTrustResultUnspecified every time. But the other two match the description of a trusted server 
                [challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge]; 
       return; 
            } 
        } else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) { 
       //this handles authenticating the client certificate 

     /* 
What we need to do here is get the certificate and an an identity so we can do this: 
    NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:myCerts persistence:NSURLCredentialPersistencePermanent]; 
    [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; 

    It's easy to load the certificate using the code in -installCertificate 
    It's more difficult to get the identity. 
    We can get it from a .p12 file, but you need a passphrase: 
    */ 

    NSString *p12Path = [[BundleManager bundleForCurrentSkin] pathForResource:kP12FileName ofType:@"p12"]; 
    NSData *p12Data = [[NSData alloc] initWithContentsOfFile:p12Path]; 

    CFStringRef password = CFSTR("PASSWORD"); 
    const void *keys[] = { kSecImportExportPassphrase }; 
    const void *values[] = { password }; 
    CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); 
    CFArrayRef p12Items; 

    OSStatus result = SecPKCS12Import((CFDataRef)p12Data, optionsDictionary, &p12Items); 

    if(result == noErr) { 
             CFDictionaryRef identityDict = CFArrayGetValueAtIndex(p12Items, 0); 
             SecIdentityRef identityApp =(SecIdentityRef)CFDictionaryGetValue(identityDict,kSecImportItemIdentity); 

             SecCertificateRef certRef; 
             SecIdentityCopyCertificate(identityApp, &certRef); 

             SecCertificateRef certArray[1] = { certRef }; 
             CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL); 
             CFRelease(certRef); 

             NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identityApp certificates:(NSArray *)myCerts persistence:NSURLCredentialPersistencePermanent]; 
             CFRelease(myCerts); 

             [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; 
         } 
    } else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault || [[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodNTLM) { 
    // For normal authentication based on username and password. This could be NTLM or Default. 

     DAVCredentials *cred = _parentSession.credentials; 
        NSURLCredential *credential = [NSURLCredential credentialWithUser:cred.username password:cred.password persistence:NSURLCredentialPersistenceForSession]; 
    [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; 
    } else { 
     //If everything fails, we cancel the challenge. 
     [[challenge sender] cancelAuthenticationChallenge:challenge]; 
    } 
} 

参考: Ref1Ref2Ref3

希望这有助于

+0

@Christopher Stott - 试试这个,让我知道。如果你仍然面临问题请随时发表评论。 –

+0

我读过其他地方有私人方法来访问设备证书。由于我正在构建通过企业商店分发的应用,所以我不在乎App Store的拒绝。 –

相关问题