web-dev-qa-db-ja.com

iOSクライアント証明書とモバイルデバイス管理

お客様は、特定の企業Webサービスへのアクセスを企業デバイスのみに制限するために、MDM(モバイルデバイス管理)ソリューション(MobileIron)を使用してクライアント証明書を企業iOSデバイスにインストールすることを望んでいます。

MobileIronはクライアント証明書を設定>一般>プロファイルにインストールします。これはiOSの証明書のデフォルトの場所であり、Safariは企業がこの証明書で応答できます。 Webサービスは1つに挑戦します。

しかし、カスタムアプリ内から同じことが起こる必要があります。アプリが証明書を要求された場合、設定>一般>プロファイルから証明書で応答できる必要があります。アプリにバンドルされている証明書と、アプリが独自のキーチェーン内に保存している証明書で応答する例がありますが、私はしません[設定]> [一般]> [プロファイル]に、デバイスにインストールされている証明書を使用して応答する例があります。

NSURLAuthenticationChallengeSenderプロトコルメソッド-performDefaultHandlingForAuthenticationChallenge:の機能について誰かが私にもっと説明できますか? デフォルトの処理は、iOSがアプリに代わってチャレンジに効果的に応答することを意味しますか?この応答には、設定>一般>プロファイルに保存されているクライアント証明書を含めることができますか?

更新

MDMがクライアント証明書をアプリのキーチェーンにインストールできれば、それは完璧です。

15
Brett Donald

Appleのテクニカルサポートは、それに応じて次のテクニカルノートを指摘してくれました。

https://developer.Apple.com/library/ios/qa/qa1745/_index.html

要約すると、私たちがやりたいことはサポートされていません。

7
Brett Donald

MobileIronの AppConnect 2.1アップデートはこの問題を解決し、特別なコードは必要ありません。 X.509証明書は、AppConnect構成を使用してプッシュでき、AppConnectフレームワークは、適格な証明書で応答できる場合、 認証チャレンジ をインターセプトします。証明書は、最初の起動時にオンザフライで作成し、後で取り消すことができ、ユーザーごとまたはデバイスごとにカスタマイズできます。また、URLごとに異なる証明書を使用できます。

誰かがこのページのコードスニペットを使用している場合は、停止してください。必要ありません。変更されていないアプリをラップするか、AppConnectフレームワークにリンクした後、証明書登録構成(SCEP、Entrust、Symantec PKI、PIV-Dなど)を指すMI_AC_CLIENT_CERT_1キーをAppConnect構成に追加します。 URLを含むMI_AC_CLIENT_1_RULEキーを追加します(オプションのワイルドカードを使用)。手順3はありません。アプリは認証に証明書を自動的に使用するようになります。

詳細については、MobileIronのAppConnectおよびAppTunnelガイドのドキュメントの「AppConnectアプリからエンタープライズサービスへの証明書認証」を参照してください。

2
Cliff Tuel

MobileIronを使用していて、これを実行しようとしている顧客のオンサイトから戻ってきたところです。 MobileIron開発サポートは、MobileIronのCoreConfigテクノロジーを介してAppConnectWrapperによって提供された証明書をインポートするこのコードスニペットを提供してくれました。

それはきれいではありませんが、彼らによって提供されたので、私はそれを変更することを許可されませんでした。それでも動作します!これをAppDelegate.hに挿入します。

- (NSString *)appConnectConfigChangedTo:(NSDictionary *)newConfig;

そして、これをAppDelegate.mに、前述のプラグママークの直後に追加します。

#pragma mark UIApplicationDelegate implementation                                
- (NSString *)appConnectConfigChangedTo:(NSDictionary *)newConfig{
        //NSLog(@"New config: %@", newConfig);                                          //unsecure
        NSLog(@"New config retrieved");                                                 //confirm we got a new config
        NSString *certStr       = [newConfig valueForKey:@"kUserCert"];                 //Store certificate as String
        NSString *certPassword  = [newConfig valueForKey:@"kUserCert_MI_CERT_PW"];      //Store certificate password as string
        NSData *cert = [[NSData alloc] initWithBase64EncodedString:certStr options:0];  //only for iOS7+, decodes base64 encoded certificate
        CFDataRef pkcs12Data = (__bridge CFDataRef)cert;                                //Extract identity & certificate objects from
        CFStringRef password = (__bridge CFStringRef)certPassword;                      //the cert data Identity
        SecIdentityRef myIdentity = nil;                                                //Initialize variable for identity
        SecCertificateRef myCertificate = nil;                                          //Initialize variable for certificate
        OSStatus status = extractIdentityAndTrust(pkcs12Data, password, &myIdentity, nil); //Use Apple-provided method for extracting Identity and Trust
        if (status != errSecSuccess || myIdentity == nil) { NSLog(@"Failed to extract identity and trust: %ld", status);} //Likely due to corruption
        else { SecIdentityCopyCertificate(myIdentity, &myCertificate); }                //This method is supposed to store the Certificate, but Fiori doesn't see it here
        const void *certs[] = { myCertificate };                                        //Initialize an array for one certificate
        CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL);                    //Make the array the way Apple wants it to be
        NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity certificates:(__bridge NSArray*)certsArray persistence:NSURLCredentialPersistencePermanent];                                       //MobileIron's method of Credential storage
        NSMutableDictionary *secIdentityParams = [[NSMutableDictionary alloc] init];    //Initialize Dictionary to store identity
        [secIdentityParams setObject:(__bridge id)myIdentity forKey:(__bridge id)kSecValueRef]; //Build the secIdentityParams dictionary in the way the next method expects it to be
        OSStatus certInstallStatus = SecItemAdd((__bridge CFDictionaryRef) secIdentityParams, NULL); //Add the identity to the keychain for Fiori consumption
        if (myIdentity) CFRelease(myIdentity);                                          //Free
        if (certsArray) CFRelease(certsArray);                                          //Up
        if (myCertificate) CFRelease(myCertificate);                                    //Memory
        return nil;                                                                     //Success
} 
// Copied from Apple document on Certificates:
// http://developer.Apple.com/library/mac/documentation/security/conceptual/CertKeyTrustProgGuide/CertKeyTrustProgGuide.pdf
OSStatus extractIdentityAndTrust(CFDataRef inP12data, CFStringRef password, SecIdentityRef *identity, SecTrustRef *trust){
        OSStatus securityError = errSecSuccess;
        const void *keys[] = { kSecImportExportPassphrase };
        const void *values[] = { password };
        CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
        CFArrayRef items = nil;
        securityError = SecPKCS12Import(inP12data, options, &items);
        if (securityError == errSecSuccess) {
                CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
                if (identity && CFDictionaryGetValueIfPresent(myIdentityAndTrust, kSecImportItemIdentity, (const void **)identity)) {
                        CFRetain(*identity);
                    }
                if (trust && CFDictionaryGetValueIfPresent(myIdentityAndTrust, kSecImportItemTrust, (const void **)trust)) {
                        CFRetain(*trust);
                    }
            }  
        if (options) {CFRelease(options);}
        if (items) {CFRelease(items);}
        return securityError;
}

アプリを作成したら、MobileIron管理者に、AppConnectを使用できるようにアプリを「ラップ」するように依頼します。それが完了し、ラップされたアプリがMobileIronを介してユーザーをテストするためにデプロイされたら、プロビジョニングされたユーザーに固有のユーザー証明書を取得し、CoreConfigキー「kUserCert」の下でプロビジョニングされたデバイスにプッシュするCoreConfigをセットアップします。

1
Jarek Lupinski