簡體   English   中英

在企業 iOS 應用程序中使用來自 .mobileconfig 的客戶端 SSL 證書

[英]Using Client SSL Certificate from .mobileconfig within Enterprise iOS app

我們正在嘗試在企業 iOS 應用程序中使用客戶端 SSL 證書進行用戶身份驗證。

  • 我們可以在服務器上生成客戶端ssl證書
  • 用戶可以通過 .mobileconfig 安裝它
  • Safari 中對 Web 服務器的身份驗證與已安裝的證書一起使用。
  • 從 iOS 應用程序內部發出 http 請求失敗(未使用證書)。

我們如何讓它發揮作用? 謝謝!

概述:

您已在設備鑰匙串上安裝了客戶端 SSL 證書。

Safari.app 和 Mail.app 可以訪問此鑰匙串,而 iOS 應用程序則不能。

原因是我們開發的應用程序是沙盒的,在非越獄設備中沒有任何訪問權限。

由於 safari 可以訪問它,因此連接和驗證服務器挑戰沒有問題。

解決方案:

將導出的 P12 文件包含在 App 包中,並參考它以找到服務器正在尋找的正確客戶端證書。這實際上是一種解決方法。 硬編碼是獲取 P12 文件的可靠方法。

執行:

有問題的方法是NSURLConenction delegate willSendRequestForAuthenticationChallenge 您需要考慮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

希望這可以幫助

我創建了一個包來處理 TLS 套接字/iOS/Obj-C。 我將它連接到節點服務器,但它可能與其他人一起工作。 更重要的是,鑒於最近的 iOS 13 TLS 限制,我提供了有關正確創建證書的重要資源的鏈接。 我希望它可以有點幫助:

https://github.com/eamonwhiter73/IOSObjCWebSockets/tree/master

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM