12

私は最近、非常にシンプルであるべきでありながら、本質的にどこかで見つけられないように見えるものを構築するために、非常に困難なプロセスを経てきました。ここにすべてを掲載して、私が何か間違ったことをしていないかどうかを尋ね、そうでない場合は、この情報が必要な人を助けたいと思います.

背景: 私がセキュリティを提供しようとしていた製品/サービスは、Windows サーバー上の WCF サービスを中心に構築されており、PC または iPad 上のカスタム クライアント アプリからのみアクセスできます。顧客ごとに 1 つのサーバー、ブラウザ アクセスなし。すべてが、Windows 標準メカニズムと商用 CA の証明書を使用した認証と承認によって、すでに TLS で保護されていました。

アクセスをさらに制限するために、自己署名証明書を使用してクライアント/サーバー証明書が Windows プラットフォームに実装されました (反対の主張にもかかわらず、パブリック/ブラウザー アクセスのない相互認証がある場合、商用 CA は必要ありません)。管理する)。

これらすべてを iPad で機能させることは、驚くべき量の偽情報または部分的に正しい推奨事項を含む、ひどく文書化された悪夢でした. 以下では、最良の情報源へのリンクを試みましたが、誤って帰属を見逃していた場合はお詫び申し上げます. この投稿について何か間違っている/誤解を招くようなことがあればコメントしてください。

ありがとう

4

2 に答える 2

22

主な手順は次のとおりです。

  1. 証明書を生成するためのシステムを作成します (本番システムの場合は簡単ですが、簡単ではありません)。
  2. 証明書を iPad に転送します (App Store バンドルには組み込まれていません!)
  3. 受信したすべての資格情報をアプリのキーチェーンに保存します (Apple が所属すると言っている場所)
  4. NSURLConnections で使用するためにキーチェーンから保存された資格情報を取得します
  5. サーバー証明書を実際に認証し、クライアント資格情報を返す

ステップ 1.証明書を生成する

参照: http://developer-should-know.tumblr.com/post/127063737582/how-to-create-your-own-pki-with-openssl

他の方法を使用することもできますが、Windows 用の OpenSSL [http://slproweb.com/products.html] は非常に優れています。ただし、標準インターフェイスが cmdline であり、ドキュメントがわかりにくい点が異なります。

誰かが前もって説明してくれたらよかったのに、そうではありません: [a] アプリはルート レベル ディレクトリにインストールされ、コマンド ラインで指定されていない設定にデフォルトで使用される構成ファイルが含まれます [b]中間ファイルと出力ファイルの場所は、構成ファイルで指定する必要があります [c] コマンドを実行する前に、特定のファイルを手動で作成する必要があります [d] 実行しようとしていることに適したファイル/フォルダー構造を構築してから、それに応じて cfg ファイルをカスタマイズします。

私の場合、これは会社用の 1 つの RootCA、顧客ごとの中間証明書 (クライアント証明書のみを作成するために適切に設定)、顧客ごとのサーバー証明書、および必要に応じてクライアント証明書を意味しました。(これは最小構成です。CA/クライアントのペアは使用せず、ルートをロックボックスに保管してください) これが私のファイル構造です。

c:\sslcert
    root
    certs
        YourCompany (duplicate this structure as required)
             intermediate
             server
             client
             crl (optional)

最上位の sslcert フォルダー内

.rnd        (empty file)
certindex.txt   (empty file)
serial.txt  (Text file seeded with the text “01”, hold the quotes)

ルートフォルダー内

RootCA.cfg

certs\template フォルダー内

IntermediateCA.cfg

作業ディレクトリを設定し、OpenSSL cd \sslcert c:\OpenSSL-Win32\bin\openssl.exe を起動します

ルートキーと証明書をワンステップで作成

req -config ./root/RootCA.cfg -new -x509 -days 7300 -extensions v3_ca -keyout root/YourCompanyRootCAkey.pem -out root/YourCompanyRootCAcert.cer

初心者向けの注意: -extensions を使用すると、同じ cfg ファイル内のいくつかのサブセクションのいずれかを適用することを選択できます。

キーと証明書を確認する (オプション)

x509 -noout -text -in root/YourCompanyRootCAcert.cer

新しい中間証明書をリクエストする

req -config certs/YourCompany/IntermediateCA.cfg -new -keyout certs/YourCompany/intermediate/intermediateCAkey.pem -out certs/YourCompany/intermediate/intermediateCAreq.pem  

ルート構成にあるルート証明書を使用して中間証明書に署名する

ca -config root/RootCA.cfg -extensions v3_intermediate_ca -days 3650 -notext -in certs/YourCompany/intermediate/intermediateCAreq.pem -out certs/YourCompany/intermediate/YourCompanyIntermediateCAcert.cer

キーと証明書を確認する (オプション)

x509 -noout -text -in certs/YourCompany/intermediate/YourCompanyIntermediateCAcert.cer

中間証明書とルート証明書を連結して、証明書チェーン ファイルを作成します (これは、コマンド ラインから単純に追加するだけです。新しいチェーンは、最終的な p12 パッケージに追加されます)。

c:\sslcert> type c:\sslcert\certs\YourCompany\intermediate\YourCompanyIntermediateCAcert.cer c:\sslcert\root\YourCompanyRootCAcert.cer > c:\sslcert\certs\YourCompany\intermediate\YourCompanyCAchain.cer

新しいクライアント キーと証明書を要求する

genrsa -aes256 -out certs/YourCompany/client/YourCompanyClientkey.pem 2048
req -config certs/YourCompany/IntermediateCA.cfg -key 
certs/YourCompany/client/YourCompanyClientkey.pem -new -sha256 -out         certs/YourCompany/client/YourCompanyClientreq.pem

中間機関でクライアント証明書に署名してテストする

ca -config certs/YourCompany/IntermediateCA.cfg -extensions usr_cert -days 1095 -notext -md sha256 -in certs/YourCompany/client/YourCompanyClientreq.pem -out certs/YourCompany/client/YourCompanyClientcert.cer
x509 -noout -text -in certs/YourCompany/client/YourCompanyClientcert.cer
verify -CAfile certs/YourCompany/intermediate/YourCompanyCAchain.cer certs/YourCompany/client/YourCompanyClientcert.cer

パッケージ クライアント証明書

pkcs12 -export -in certs/YourCompany/client/YourCompanyClientcert.cer -name “YourCompany Smips Client” -inkey certs/YourCompany/client/YourCompanyClientkey.pem -certfile certs/YourCompany/intermediate/YourCompanyCAchain.cer -out certs/YourCompany/client/YourCompanyClientWithName.p12

メール/iTunes から iOS にインポートするために pkcs の名前を変更します

c:\sslcert> copy c:\sslcert\certs\YourCompany\client\YourCompanyClient.p12 c:\sslcert\certs\YourCompany\client\YourCompanyClient.yourext12

新しいサーバー キーと証明書を要求する

genrsa -aes256 -out certs/YourCompany/server/YourCompanyServerkey.pem 2048
req -config certs/YourCompany/IntermediateCA.cfg -key certs/YourCompany/server/YourCompanyServerkey.pem -new -sha256 -out certs/YourCompany/server/YourCompanyServerreq.pem

中間機関によるサーバー証明書の署名とテスト

ca -config certs/YourCompany/IntermediateCA.cfg -extensions server_cert -days 1095 -notext -md sha256 -in certs/YourCompany/server/YourCompanyServerreq.pem -out certs/YourCompany/server/YourCompanyServercert.cer
x509 -noout -text -in certs/YourCompany/server/YourCompanyServercert.cer
verify -CAfile certs/YourCompany/intermediate/YourCompanyCAchain.cer certs/YourCompany/server/YourCompanyServercert.cer

パッケージ サーバー証明書

pkcs12 -export -in certs/YourCompany/server/YourCompanyServercert.cer -name “YourCompany Smips Server” -inkey certs/YourCompany/server/YourCompanyServerkey.pem -certfile certs/YourCompany/intermediate/YourCompanyCAchain.cer -out certs/YourCompany/server/YourCompanyServer.p12

cfg ファイルは次のとおりです。

dir                 = .

[ ca ]
default_ca              = CA_default
 
[ CA_default ]
serial              = $dir/serial.txt
database                = $dir/certindex.txt
new_certs_dir           = $dir/certs
certs                   = $dir/certs
private_key             = $dir/root/yourcompanyRootCAkey.pem
certificate             = $dir/root/yourcompanyRootCAcert.cer
default_days            = 7300
default_md              = sha256
preserve                = no
email_in_dn             = no
nameopt             = default_ca 
certopt             = default_ca 
policy              = policy_strict

[ policy_strict ]
countryName                 = match
stateOrProvinceName         = match
organizationName            = match
organizationalUnitName      = optional
commonName                  = supplied
emailAddress                = optional

[ req ]
default_bits            = 4096      # Size of keys
default_keyfile         = key.pem       # name of generated keys
default_md              = sha256        # message digest algorithm
string_mask             = nombstr       # permitted characters
distinguished_name      = req_distinguished_name
x509_extensions         = v3_ca

[ req_distinguished_name ]
0.organizationName           = Organization Name
organizationalUnitName       = Organizational Unit Name
emailAddress                 = Email Address
emailAddress_max            = 40
localityName            = Locality Name (city, district)
stateOrProvinceName     = State or Province Name (full name)
countryName             = Country Name (2 letter code)
countryName_min         = 2
countryName_max         = 2
commonName              = Common Name (hostname, IP, or your name)
commonName_max          = 64

0.organizationName_default  = yourcompany
organizationalUnitName_default  = yourcompanyRoot Certification
emailAddress_default        = info@yourcompany.com
localityName_default        = Okeefenokee
stateOrProvinceName_default = Wisconsin
countryName_default     = US

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ crl_ext ]
authorityKeyIdentifier=keyid:always

中級

dir = .

# [For non-command-line folks, everything is keyed to the working directory here (.) so if your working prompt says c:\sslcerts> then the cfg will look for serial.txt at c:\sslcerts\serial.txt and bomb if it doesn’t find things laid out accordingly. Thats why you set up a directory structure to match these entries]

[ ca ]
default_ca              = CA_default

[ CA_default ]
serial                  = $dir/serial.txt
database                = $dir/certindex.txt
crl_dir                 = $dir/certs/yourcompany/crl
new_certs_dir               = $dir/certs
certs                   = $dir/certs
private_key             = $dir/certs/yourcompany/intermediate/IntermediateCAkey.pem
certificate             = $dir/certs/yourcompany/intermediate/yourcompanyIntermediateCAcert.cer
default_days                = 3650
default_md              = sha256
preserve                = no
email_in_dn             = no
nameopt                 = default_ca
certopt                 = default_ca 
crlnumber               = $dir/certs/yourcompany/crl/crlnumber
crl                 = $dir/certs/yourcompany/crl/crl.pem
crl_extensions              = crl_ext
default_crl_days            = 365
policy                  = policy_loose

[ policy_loose ]
countryName                     = optional
stateOrProvinceName             = optional
localityName                    = optional
organizationName                = optional
organizationalUnitName          = optional
commonName                      = supplied
emailAddress                    = optional

[ req ]
default_bits                = 4096              # Size of keys
default_keyfile             = $dir/certs/yourcompany/intermediate/IntermediateCAkey.pem
default_md              = sha256            # message digest 

# the old default was md1 - change this]

algorithm
string_mask             = nombstr           # permitted characters
distinguished_name          = req_distinguished_name
x509_extensions             = v3_intermediate_ca

[ req_distinguished_name ]
0.organizationName                  = Organization Name
organizationalUnitName              = Organizational Unit Name
emailAddress                        = Email Address
emailAddress_max            = 40
localityName                = Locality Name (city, district)
stateOrProvinceName         = State or Province Name (full name)
countryName             = Country Name (2 letter code)
countryName_min             = 2
countryName_max             = 2
commonName              = Common Name (hostname, IP, or your name)
commonName_max              = 64

0.organizationName_default      = yourcompany
organizationalUnitName_default      = yourcompany Intermediate Certification
emailAddress_default            = info@yourcompany.com
localityName_default            = Okeefenokee
stateOrProvinceName_default     = Wisconsin [should be spelled out]
countryName_default         = US

[ v3_intermediate_ca ]
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid:always,issuer
basicConstraints            = critical, CA:true, pathlen:0
keyUsage                = critical, digitalSignature, cRLSign, keyCertSign

# Important - the pathlen parameter prevents this cert from being used to create new intermediate certs. The subsequent subsections for server and client certs allows you to specify their type and intended usage, as distinct from the intermediate cert, in the same cfg file 

[ usr_cert ]
basicConstraints            = CA:FALSE
nsCertType              = client, email
nsComment               = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer
keyUsage                = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage            = clientAuth, emailProtection

[ server_cert ]
basicConstraints            = CA:FALSE
nsCertType              = server
nsComment               = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always
keyUsage                = critical, digitalSignature, keyEncipherment
extendedKeyUsage            = serverAuth

[ crl_ext ]
authorityKeyIdentifier          = keyid:always

2. 証明書を iPad に転送する

参考:ipadのアプリでpdfファイルを開くアプリの登録方法

Apple では、アプリで処理される新しいファイル タイプを登録し、新しいカスタム拡張子で名前が変更された p12 ファイルをデバイスに (手動または電子メールで) 転送して、クライアント証明書をインストールすることをお勧めします。p12 ファイルには、上記の手順 1 で定義したように、パブリック証明書チェーンとクライアント証明書情報が含まれている必要があります。このようなファイルを開こうとすると、デバイスは、処理する必要があるアプリ デリゲートに開始/ウェイクアップを送信します (ウェイクである可能性があるため、didload ではありません)。

これは v8 または 9 で少し変更されましたが、7 をサポートする必要があるため、これは非推奨のハンドラー用です。ただし、同じ解決策であり、以下のスクリーンショットに示すように、アプリの plist ファイルに追加することから始まります。

別のアプリによって要求される可能性が低い 2 つの新しいアイコンとファイル拡張子が必要になることに注意してください。

ここに画像の説明を入力

ここに画像の説明を入力

次に、自明のデリゲート/ハンドラーが必要です。この部分は通常の制御フローとは関係がないため、すべてのデリゲート処理を AppDelegate.m で処理しています。(これはとても間違っていますか?) 必要に応じてメソッド/変数を設定し、ファイルの存在に関するパラノイアな余分なチェックを無視してください...

参照: https://www.raywenderlich.com/6475/basic-security-in-ios-5-tutorial-part-1

- (BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication
           annotation:(id)annotation {

    if (url) {

        self.p12Data = [NSData dataWithContentsOfFile:[url path]];
        
        if (!p12Data) {
            [self messageBox:@"Warning" : @"Failed to read data file, cancelling certificate import"];
        }
        else {
            [self presentAlertViewForPassPhrase];
        }
        
        NSFileManager * fileManager = [NSFileManager defaultManager];
        if ( [fileManager fileExistsAtPath:[url path]] ) {
            [fileManager removeItemAtPath:[url path] error:NULL];
        }
    }

    return YES;
}

- (void)presentAlertViewForPassPhrase {
    
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Certificate Credentials"
                                                    message:@"Please enter the passphrase for your certificate"
                                                   delegate:self
                                          cancelButtonTitle:@"Cancel"
                                          otherButtonTitles:@"Done", nil];
    [alert setAlertViewStyle:UIAlertViewStyleSecureTextInput];
    [alert show];
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
    
    if (buttonIndex == 1) {                                             // User selected "Done"
        UITextField *ppField = [alertView textFieldAtIndex:0];
        if ([ppField.text length] > 0) {
            [self loadCertificates:ppField.text];
        }
        //Handle Else
    }
    else
    {                                                                   // User selected "Cancel"
        [self messageBox:@"Information" : @"Certificate import cancelled"];
    }
}

3. 受け取った認証情報をアプリのキーチェーンに保存します

生の p12 データが得られたので、次に何をすべきかを簡単に理解できるはずです...そうではありません。すべてのドキュメントは name/pwd ストレージ用のようで、恐ろしい数のポスターがサーバー証明書をファイル システムに保存することを提案しています。最後になりましたが、保存された証明書をどのように区別し、どのように更新しますか?

簡単に言えば、それが更新なのか初期ロードなのかを確認するために機能しないあらゆる種類のことを試した後、完全な削除/再保存を行うことにしました-それは私が最初にやりたかったことです。アプリチェーン。これはすべて CF のものであり、移植する必要のないものを移植することを拒否するため、ARC を使用していません。私が知る限り、CF を割り当て、NS にキャストし、使用後に CFRelease を使用する限り、警告はありません。

これらは重要な参照です:

iOS アプリケーションですべてのキーチェーン項目を列挙する

[キーチェーンがどのように見えるかを視覚化するのに不可欠]

アプリにアクセス可能なすべてのキーチェーン アイテムを削除するには?

(iOS で) キーチェーン アイテムを一意にするものは何ですか?

http://help.sap.com/saphelp_smp307sdk/helpdata/en/7c/03830b70061014a937d8267bb3f358/content.htm

[https://developer.apple.com/library/ios/samplecode/AdvancedURLConnections/Listings/Credentials_m.html、つまり:

// IMPORTANT: SecCertificateRef's are not uniqued (that is, you can get two
// different SecCertificateRef values that described the same fundamental
// certificate in the keychain), nor can they be compared with CFEqual. So
// we match up certificates based on their data values.

要約すると、最も簡単な方法は、証明書にラベルを割り当てることです。これにより、証明書を一意に検索し、ID を保存すると、キーと証明書に自動的に分割されることに気付くことができます。確かに - 交換が困難になっています。

コード(説明が続きます):

- (void) loadCertificates:(NSString *)passPhrase {
    
    BOOL lastError = false;
    NSMutableDictionary * p12Options = [[NSMutableDictionary alloc] init];
    [p12Options setObject:passPhrase forKey:(id)kSecImportExportPassphrase];
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    OSStatus err = SecPKCS12Import((CFDataRef)p12Data, (CFDictionaryRef)p12Options, &items);
    if (err != noErr) {
        [self messageBox:@"Error" : @"Unable to extract security information with the supplied credentials. Please retry"];
        lastError = true;
    }
    if (!lastError && err == noErr && CFArrayGetCount(items) > 0) {
        CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
        //Clean-up

        NSArray *secItemClasses = [NSArray arrayWithObjects:
                                   (id)kSecClassCertificate,
                                   (id)kSecClassKey,
                                   (id)kSecClassIdentity,
                                   nil];
        
        for (id secItemClass in secItemClasses) {
            NSDictionary *spec = @{(id)kSecClass: secItemClass};
            err = SecItemDelete((CFDictionaryRef)spec);
        }

        //Client Identity & Certificate
        
        SecIdentityRef clientIdentity = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
        
        NSDictionary *addIdentityQuery = [NSDictionary dictionaryWithObjectsAndKeys:
                                          kClientIdentityLabel, kSecAttrLabel,
                                          (id)clientIdentity, kSecValueRef,
                                          nil];
        err = SecItemAdd((CFDictionaryRef)addIdentityQuery, NULL);
        if (err == errSecDuplicateItem) {
            NSLog(@"Duplicate identity");
        }
        if (err != noErr) {
            [self messageBox:@"Warning" : @"Failed to save the new identity"];
            lastError = true;
        }
        //Server Certificate
        CFArrayRef chain = CFDictionaryGetValue(identityDict, kSecImportItemCertChain);
        CFIndex N = CFArrayGetCount(chain);
        BOOL brk = false;
        for (CFIndex i=0; (i < N) && (brk == false); i++) {
            SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(chain, i);
            CFStringRef summary = SecCertificateCopySubjectSummary(cert);
            NSString* strSummary = [[NSString alloc] initWithString:(NSString *)summary];
            if ([strSummary containsString:@"Root"] || (i == N)) {
                
                NSDictionary *addCertQuery = [NSDictionary dictionaryWithObjectsAndKeys:
                                              kServerCertificateLabel, kSecAttrLabel,
                                              (id)cert, kSecValueRef,
                                              nil];
                err = SecItemAdd((CFDictionaryRef)addCertQuery, NULL);
                if (err == errSecDuplicateItem) {
                    NSLog(@"Duplicate root certificate");
            }
            if (err != noErr) {
                [self messageBox:@"Warning" : @"Failed to save the new server certificate"];
                lastError = true;
            }
            brk = true;
        }
        [strSummary release];
        CFRelease(summary);
    }
}
else {
    [self messageBox:@"Error" : @"Unable to extract security information with the supplied credentials. Please retry"];
    lastError = true;
}
    [p12Options release];
    CFRelease(items);
    if (!lastError) [self messageBox:@"Information" : @"Certificate import succeeded"];
}

ここで、kClientIdentityLabel と kServerCertificateLabel は任意のラベルです。

kSec 関数は多すぎて複雑すぎて、ここで詳しく説明することはできません。すべてがクリアされ、抽出されたクライアント ID が保存され、続いてルート CA が抽出され、個別に保存されると言えば十分です。なぜループ?ルートがチェーンの最後にあると仮定することが技術的に正しいかどうかわからなかったので、p12 を生成するとそうなるので、コードは今のところそこにあります。

kSec からのエラーはエンコードされているため、このサイトが不可欠であることに注意してください: https://www.osstatus.com

4.キーチェーンから保存された資格情報を取得します

資格情報がキーチェーンに入ったら、次のように抽出できます (失敗モードでは、何かが必要になります)。

- (void) reloadCredentials {
    
    self.clientCredential = nil;
    self.serverCertificateData = nil;
    
    if (self.useClientCertificateIfPresent) {
        
        NSDictionary* idQuery = [NSDictionary dictionaryWithObjectsAndKeys:
                                 kClientIdentityLabel,            kSecAttrLabel,
                                 (id)kSecClassIdentity,           kSecClass,
                                 kCFBooleanTrue,                  kSecReturnRef,
                                 kSecMatchLimitAll,               kSecMatchLimit,
                                 nil];
        CFArrayRef result = nil;
        OSStatus err = SecItemCopyMatching((CFDictionaryRef)idQuery, (CFTypeRef*)&result);
        if (err == errSecItemNotFound) {
            [self messageBox:@"Warning" : @"Client credentials not found. Server connection may fail"];
        }
        else if (err == noErr && result != nil ) {
            
            SecIdentityRef clientIdentity = (SecIdentityRef)CFArrayGetValueAtIndex(result, 0);
            
            SecCertificateRef clientCertificate;
            SecIdentityCopyCertificate(clientIdentity, &clientCertificate);
            const void *certs[] = { clientCertificate };
            CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL);
            self.clientCredential = [NSURLCredential credentialWithIdentity:clientIdentity certificates:(NSArray*)certsArray
                                                                      persistence:NSURLCredentialPersistenceNone];
            CFRelease(certsArray);
            CFRelease(clientCertificate);
            CFRelease(result);
        }
        else {
            [self messageBox:@"Warning" : @"Client or Server credentials not found. Server connection may fail"];
        }
        
        NSDictionary* serverCertQuery = [NSDictionary dictionaryWithObjectsAndKeys:
                                         kServerCertificateLabel,         kSecAttrLabel,
                                         (id)kSecClassCertificate,        kSecClass,
                                         kCFBooleanTrue,                  kSecReturnRef,
                                         kSecMatchLimitAll,               kSecMatchLimit,
                                         nil];
        CFArrayRef result1 = nil;
        err = SecItemCopyMatching((CFDictionaryRef)serverCertQuery, (CFTypeRef*)&result1);
        if (err == errSecItemNotFound) {
            [self messageBox:@"Warning" : @"Server certificate not found. Server connection may fail"];
        }
        else if (err == noErr && result1 != nil ) {
            
            SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(result1, 0);
            CFDataRef certRefData = SecCertificateCopyData(certRef);
            self.serverCertificateData = (NSData *)certRefData;
            CFRelease(certRefData);
            CFRelease(result1);
        }
        else {
            [self messageBox:@"Warning" : @"Client or Server credentials not found. Server connection may fail"];
        }
    }
}

5. サーバー証明書を認証し、クライアント資格情報を返す

ほー少年。これは、取得した証明書を実際に使用する方法を説明するための編集です (簡単な部分であるはずでした...)

まず、Apple のすでに疑わしいドキュメントは、新しい Application Transport Security フレームワークによって廃止されました (例: http://useyourloaf.com/blog/app-transport-security/を参照)。ここでは詳しく説明しませんが、すべてのユーザーにデフォルトで常に https と信頼できる証明書を使用するように強制するという考えです。私のシナリオでは、証明書のピン留めと専用クライアントとプライベート サーバー間の相互認証を使用すると、次のように plist に辞書を追加することで、この機能を安全にオフにすることができます。

ここに画像の説明を入力

次に、ステップ 4 で、チャレンジがヒットしたときにすぐに応答するためのクライアント資格情報を既に持っていましたが、サーバー証明書は SecCertificateCopyData によって作成された DER 形式の NSData として浮かんでいて、そのチャレンジが到着したときに何が起こるかは明確ではありません。

あなたがすべきことは、「X.509 標準」( https://www.rfc-editor.org/rfc/rfc5280 ) のセクション 6 のアルゴリズムを実装することであることが判明しました。幸いなことに、これは iOS SecTrustEvaluate 関数によって舞台裏で実装されていますが、構築するための足場と理解しなければならない奇妙なものがあります。

【ちょっとした問題・空き容量がなくなった!! このステップの最後を含め、新しい質問を追加しました。]

https://stackoverflow.com/questions/35964632/correctly-use-a-pinned-self-signed-certificate-in-ios-9-2

【別記事の続き】

それだけです。生産品質が不十分で申し訳ありませんが、まだ頭に残っているうちにこれを一緒に平手打ちしたかったのです。エラーが見つかった場合は、投稿を更新します。

これがお役に立てば幸いです。これは非常に優れた本への最後のリンクです。とりわけ、商用 CA を信頼することについてゾッとさせてくれます...

https://www.cs.auckland.ac.nz/~pgut001/pubs/book.pdf

于 2016-03-08T14:52:11.787 に答える