Я хочу предотвратить MITM-атаку между моим приложением и сервером, поэтому я пытаюсь настроить закрепление SSL, но у меня возникают проблемы с его работой с AFNetworking 2.2 с использованием самозаверяющего сертификата. Я думаю, что это в основном проблема с тем, как я генерирую сертификат.
Сначала я попытался создать самозаверяющий сертификат в соответствии с эти инструкции:
Генерация закрытого ключа:
sudo openssl genrsa -des3 -out server.key 2048
Создание запроса на подпись и использование доменного имени при запросе общего имени:
sudo openssl req -new -key server.key -out server.csr
Генерация сертификата:
sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
Наконец, преобразование его в формат der
(поскольку AFNetworking требует его а>)
sudo openssl x509 -outform der -in server.crt -out server.der
Сервер — Ubuntu 12.04, на котором работает ngninx+passenger для обслуживания приложения Rails 4. Вот часть конфигурации моего сервера nginx для включения SSL:
server {
listen 80;
listen 443;
server_name myapp.com;
passenger_enabled on;
root /var/www/myapp/current/public;
rails_env production;
ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
}
После перезапуска nginx, загрузки файла der
, добавления его в мой проект и переименования в «server.cer» (поскольку AFNetworking требует, чтобы сертификат использовал расширение .cer), я использую этот код, чтобы включить закрепление SSL для моего подкласса AFHTTPSessionManager
:
client.securityPolicy = [AFSecurityPolicy
policyWithPinningMode:AFSSLPinningModeCertificate];
Затем при первом запросе к серверу AFNetworking пытается проверить, что «доверие» действительно в функции AFServerTrustIsValid
:
static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {
SecTrustResultType result = 0;
OSStatus status = SecTrustEvaluate(serverTrust, &result);
NSCAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status);
return (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
}
Если я поставлю точку останова на выходе, я вижу, что результат всегда kSecTrustResultRecoverableTrustFailure
.
Если я пропущу функцию AFServerTrustIsValid
, установив allowInvalidCertificates
в YES
в политике безопасности, запрос будет успешным. Но я действительно не хочу разрешать недействительные сертификаты, если мне это не нужно.
Вернемся к чертежной доске: этот ТАК вопрос привел меня к это руководство по созданию самозаверяющего сертификата с созданием ЦС. Я настраиваю свой файл openssl.cnf следующим образом:
[ req ]
default_md = sha1
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
countryName = United Kingdon
countryName_default = UK
countryName_min = 2
countryName_max = 2
localityName = Locality
localityName_default = London
organizationName = Organization
organizationName_default = Eric Organization
commonName = Common Name
commonName_max = 64
[ certauth ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:true
crlDistributionPoints = @crl
[ server ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
nsCertType = server
subjectAltName = DNS:myapp.com
crlDistributionPoints = @crl
[ crl ]
URI=http://testca.local/ca.crl
А затем использовал эти команды для генерации всего. Сначала материал CA:
sudo openssl req -config ./openssl.cnf -newkey rsa:2048 -nodes -keyform PEM -keyout ca.key -x509 -days 3650 -extensions certauth -outform PEM -out ca.cer
Затем снова закрытый ключ сервера:
sudo openssl genrsa -out server.key 2048
Запрос на подпись:
sudo openssl req -config ./openssl.cnf -new -key server.key -out server.req
Сертификат:
sudo openssl x509 -req -in server.req -CA ca.cer -CAkey ca.key -set_serial 100 -extfile openssl.cnf -extensions server -days 365 -outform PEM -out server.cer
И, наконец, файл der
:
sudo openssl x509 -outform der -in server.cer -out stopcastapp.com.der
Когда я обновляю и перезапускаю nginx, загружаю и добавляю server.der
в свой проект (не забудьте переименовать его в server.cer
и сбросить симулятор), я получаю точно такой же результат.
Страшный kSecTrustResultRecoverableTrustFailure
снова поднимает свою уродливую голову.
Что я делаю неправильно? Мне ОЧЕНЬ не по себе от того, как все это работает, или мне нужно настроить всего одну мелочь, чтобы все заработало? Если бы вы могли как-то помочь, я был бы очень, очень признателен (я занимаюсь этой проблемой уже два дня). Спасибо!