2016-03-08 6 views
3

Недавно я прошел чрезвычайно сложный процесс по созданию чего-то, что должно быть очень простым, но, по-видимому, практически невозможно найти в любом месте. Я хотел бы попытаться поставить все здесь, чтобы спросить, не делаю ли я что-то неправильно и, если нет, помогать тем, кому нужна эта информация.Как реализовать клиентские сертификаты и аутентификацию сервера для iOS

Справочная информация. Продукт/услуга, для которой я пытался обеспечить безопасность, строится вокруг служб WCF на сервере Windows, которые доступны только для пользовательских клиентских приложений на ПК или iPad. Один сервер на одного клиента, без доступа к браузеру. Все уже было TLS с аутентификацией и авторизацией с использованием стандартных механизмов и сертификатов Windows из коммерческого центра сертификации.

Для дальнейшего ограничения доступа сертификаты клиент/сервер были реализованы для платформы Windows с использованием самозаверяющих сертификатов (коммерческие ЦС не требуются в случаях, когда существует взаимная аутентификация без публичного доступа к браузерам - несмотря на утверждения об обратном - и их сложнее управлять).

Получение всего этого для iPad было ужасным документированным кошмаром с удивительным количеством дезинформации или частично правильными рекомендациями. В дальнейшем я попытался связаться с лучшими источниками, но приношу свои извинения, если я случайно пропустил атрибуцию. Пожалуйста, прокомментируйте, если что-то не так/ошибочно об этом сообщении.

Благодаря

ответ

7

Основными шагами являются:

  1. Создать систему для генерации сертификатов (простой, но нетривиальной, если это производственная система)
  2. Передача сертификатов на IPad (не встраивается в комплекте с магазином приложений!)
  3. Сохраните все полученные учетные данные в цепочке ключей приложения (где Apple говорит, что они принадлежат)
  4. Получить сохраненные учетные данные f ром брелок для использования в NSURLConnections
  5. На самом деле подлинность сертификата сервера и вернуть учетные данные клиента

Шаг 1. Сформировать Сертификаты

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

Вы можете использовать другие методы, но OpenSSL для Windows [http://slproweb.com/products.html] является довольно удивительным, за исключением того, что стандартным интерфейсом является cmdline, и документация трудно выполнить.

Что я хочу, чтобы кто-то мне объяснил, это очевидно, но нет: [a] Приложение устанавливается в корневой каталог уровня и включает файлы конфигурации, которые используются по умолчанию для параметров, которые не указаны в команде строка [b] местоположения промежуточных и выходных файлов должны быть указаны в файлах конфигурации [c] определенные файлы должны быть созданы вручную перед запуском команд [d] вы должны создать структуру файлов/папок, которая подходит что вы пытаетесь сделать, а затем соответствующим образом настроить файлы cfg.

В моем случае это означало, что для моей компании был один 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 

В сертификаты \ папка шаблона

IntermediateCA.cfg 

Установить рабочий каталог и запустить OpenSSL кд \ 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 

Check ключ и сертификат (необязательно)

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

Создайте файл сертификата цепи путем конкатенации промежуточные и корневые сертификаты (это только простой Append из командной строки - новая цепь будет добавлена ​​в окончательный пакет 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 

Rename PKCS для импорта в прошивку из электронной почты/ITunes

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 файлы: Root

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  = [email protected] 
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 

Intermediate

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   = [email protected] 
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

Ref: how to register the app to open the pdf file in my app in ipad

компании Apple рекомендует регистрирующую новый тип файл обрабатывается вашим приложением и передача файлов p12 переименованных с новым расширением пользовательского к устройству (вручную или электронной почты) для установки клиентских сертификатов. Файл p12 должен включать в себя общедоступную цепочку сертификатов, а также информацию о сертификате клиента, как определено в шаге 1 выше. Когда вы пытаетесь открыть такой файл, устройство отправляет запуск/пробуждение в ваш делегат приложения, который вам нужно обрабатывать (не в didload, потому что это может быть след).

Это немного изменилось с помощью v8 или 9, но мне нужно поддерживать 7, поэтому это относится к устаревшему обработчику. Это же решение, хотя и начинается с добавления в файл plist приложения, как показано на скриншотах ниже.

Обратите внимание, что вам потребуется две новые иконки и расширение файла, который, вероятно, будет востребовано другим приложением

enter image description here

enter image description here

Далее вам нужно делегат/обработчик, который должен быть само не -explanatory. Поскольку эта часть не имеет никакого отношения к нормальному потоку управления, я обрабатываю обработку всех делегатов в AppDelegate.m. (Это так неправильно?) Установить методы/переменные по мере необходимости и игнорируйте параноидальную дополнительную проверку на наличие файла ...

Ref: 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. Сохранить полученный учетные данные в app keychain

Теперь, когда у вас есть необработанные данные p12, должно быть просто выяснить, что делать дальше ... НЕ. Вся документация, по-видимому, относится к хранилищу имен/pwd, а страшное количество плакатов предполагает сохранение сертификата сервера в файловой системе, что нормально, но совершенно не имеет смысла, когда у вас есть брелок, и Apple говорит, что для этого и есть. И последнее, но не менее важное: как вы различаете хранимые сертификаты и как их обновлять?

Короче говоря, я решил сделать полное удаление/переустановку после того, как попробовал всевозможные вещи, которые не работают, чтобы проверить, должно ли оно быть обновление или начальная загрузка. Кроме того, это то, что я хотел сделать в первом потому что это моя сеть приложений. Все это материал CF, и я не использую ARC, потому что я отказываюсь переносить все, что мне не нужно. Насколько я могу судить, до тех пор, пока вы назначаете CF, бросаете NS и CFRelease после использования, никаких предупреждений нет.

Это ключевые ссылки:

Enumerate all Keychain items in my iOS application

[важно, чтобы помочь себе, что ваш брелок выглядит]

How to delete all keychain items accessible to an app?

What makes a keychain item unique (in 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. 

резюме в том, что (Дух), проще всего сделать, это присвоить метку к серт, так что вы можете посмотреть его однозначно и понимать, что если вы сохраните идентичность, он будет автоматически разделен на ключ и сертификат, что может быть - не обязательно - привело к некоторым трудностям с заменой.

Код (объяснение следует):

- (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 слишком много/сложны, чтобы объяснить здесь подробно. Достаточно сказать, что все очищено, затем сохраняется извлеченная идентификация клиента, а затем извлечение корневого ЦС, который затем сохраняется отдельно. Почему цикл? потому что я не знал, является ли технически правильным предположить, что корень находится в конце цепи, но будет, если я сгенерирую 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. Authenticate и вернуть клиенту верительные грамоты

Hoo boy. Это редактирование, объясняющее, как на самом деле использовать извлеченные сертификаты (это должно было быть легко очевидной частью ...)

Во-первых, уже сомнительная документация Apple уже омрачена новой инфраструктурой безопасности приложений (см., Например, : http://useyourloaf.com/blog/app-transport-security/). Я не собираюсь заниматься этим, но идея состоит в том, чтобы заставить всех всегда использовать https и доверенные сертификаты по умолчанию. Для моего сценария, с сертификатом пиннингом и взаимной аутентификацией между выделенными клиентами и частным сервером вы можете безопасно отключить эту функцию, добавив словарь на PLIST следующим образом:

enter image description here

Затем на шаге- уже имел учетные данные клиента для немедленного реагирования на эту проблему, но серверный сертификат плавает вокруг как NSData в формате DER, созданный SecCertificateCopyData, и неясно, что должно произойти, когда это вызовет.

Оказывается, что вы должны выполнить алгоритм в разделе 6 «Стандарт X.509» (https://tools.ietf.org/html/rfc5280). К счастью, это реализовано за кулисами с помощью функции iOS SecTrustEvaluate, но есть строительные леса для создания и странные вещи для понимания.

[Незначительная проблема - закончился из космоса !! Добавлен новый вопрос, в том числе и в конце этого шага.]

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

[Продолжение с другого поста]

Так вот это. Извините за не совсем качество производства, но я хотел похлопать его вместе, пока он был еще свеж в моем сознании. Я буду обновлять сообщение, если найду ошибки.

Надеется, что это помогает, и вот последнее звено в очень хорошую книгу, что, помимо всего прочего, даст вам мурашку о доверчивых коммерческих центрах ...

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

+0

Эй люди удивительного пост, Ваше наблюдение однако сообщение было удалено. Как вы могли бы предоставить отдых в чате? – murphguy

+0

К сожалению, кто-то отказался от этого: «Я голосую, чтобы закрыть этот вопрос как не относящийся к теме, потому что это сообщение в блоге, а не вопрос - Paulw11 13 мар в 16:14». Может быть, у кого-то есть возможность его реактивировать, он все еще там? – saminpa

+0

Спасибо, кстати. Я был бы рад отправить остальных, но на этом форуме нет возможности добраться до PM – saminpa