Это вопрос, который пытается найти решения для моего конкретного случая использования и документировать то, что я пытался сделать для всех, кто следит за этим процессом.
У нас есть сервер RESTful и приложение iOS. У нас есть собственный центр сертификации, и у сервера есть корневой центр сертификации и самоподписанный сертификат. Мы выполнили этот процесс для создания следующих файлов:
http://datacenteroverlords.com/2012/03/01/creating-your-own-ssl-certificate-authority/
rootCA.pem rootCA.key server.crt server.key
Только серверные сертификаты хранятся на нашем сервере, и как часть процесса SSL открытые ключи отправляются с вызовами API для проверки.
Я следил за этим процессом, чтобы использовать AFNetworking для использования фиксации сертификата, а также для фиксации открытого ключа для проверки наших самоподписанных сертификатов:
http://initwithfunk.com/blog/2014/03/12/afnetworking-ssl-pinning-with-self-signed-certificates/
Мы преобразуем файл .crt в файл .cer(в формате DER) в соответствии с этим руководством:
и включите файл .cer(server.cer) в комплекте приложений iOS. Это позволяет нашему приложению делать запросы GET/POST на наш сервер. Однако, поскольку наш серверный сертификат может истекать или переиздаваться, мы хотим вместо этого использовать корневой ЦС, как это сделали люди из этого потока в AFNetworking:
https://github.com/AFNetworking/AFNetworking/issues/1944
В настоящее время мы обновили AFNetworking 2.6.0, поэтому наши сетевые библиотеки должны обязательно включать все обновления, включая те, которые были в этом обсуждении:
https://github.com/AFNetworking/AFNetworking/issues/2744
Код, используемый для создания нашей политики безопасности:
var manager: AFHTTPRequestOperationManager = AFHTTPRequestOperationManager()
manager.requestSerializer = AFJSONRequestSerializer() // force serializer to use JSON encoding
let policy: AFSecurityPolicy = AFSecurityPolicy(pinningMode: AFSSLPinningMode.PublicKey)
var data: [NSData] = [NSData]()
for name: String in ["rootCA", "server"] {
let path: String? = NSBundle.mainBundle().pathForResource(name, ofType: "cer")
let keyData: NSData = NSData(contentsOfFile: path!)!
data.append(keyData)
}
policy.pinnedCertificates = data
policy.allowInvalidCertificates = true
policy.validatesDomainName = false
manager.securityPolicy = policy
С включенным server.cer мы можем доверять нашему серверу, привязывая открытый ключ (также пытаемся использовать AFSecurityPolicyPinningMode.Certificate); это сработало, потому что точный сертификат включен. Однако, поскольку мы можем изменить файл server.crt, который имеет сервер, поэтому мы хотим иметь возможность сделать это с помощью только rootCA.cer.
Однако, только с rootCA, включенным в комплект приложения, это, похоже, не работает. Разве что у rootCA недостаточно информации о публичном ключе для проверки сертификата сервера, который был подписан с корневым центром сертификации? Файл server.crt также может иметь изменение CommonName.
Кроме того, поскольку моя беглость в терминологии SSL довольно грубая, если кто-нибудь может уточнить, задаю ли я правильные вопросы, это было бы здорово. Конкретные вопросы:
- Правильно ли я создаю сертификаты, чтобы сервер мог подтвердить свою личность с помощью самоподписанного файла server.crt?
- Можно ли включить в комплект только файл rootCA.cer и проверить ли серверный сертификат server.crt? Будет ли он проверять другой файл server2.crt, подписанный тем же корневым центром? Или мы должны включать промежуточный сертификат между rootCA и листом?
- Является ли публичный ключ закреплением или сертификатом для правильного решения? Каждый форум и запись в блоге, которые я читал, говорят "да", но даже с самой обновленной библиотекой AFNetworking нам не повезло.
- Нужно ли серверу каким-либо образом отправлять как серверные, так и сигнатуры roomCA.pem?