Закрепление сертификатов SocketRocket и iOS

В настоящее время я использую SocketRocket в качестве реализации WebSocket для своих приложений iOS и хотел бы прикрепить CA моего сервера в качестве доверенного сертификата с помощью свойства SR_SSLPinnedCertificates. Я ищу хороший пример загрузки одного или нескольких сертификатов для передачи в SocketRocket. У меня работает следующий код, но я не уверен, что он правильный или есть более прямой подход.

CFArrayRef keyref = NULL;
NSString *path = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"p12"];
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
OSStatus status = SecPKCS12Import((__bridge CFDataRef)data, (__bridge CFDictionaryRef)[NSDictionary dictionaryWithObject:@"eftl_key_pass" forKey:(__bridge id)kSecImportExportPassphrase], &keyref);
if (status == noErr) {
    CFDictionaryRef identityDict = CFArrayGetValueAtIndex(keyref, 0);
    SecIdentityRef identityRef = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
    SecCertificateRef certRef = NULL;
    SecIdentityCopyCertificate(identityRef, &certRef);
}

2 ответа

Закрепление сертификата с помощью SocketRocket выполняется следующим образом:

Во-первых, нам нужно инициализировать SocketRocket из NSURLRequest, а не из NSURL.

NSURL *url = [[NSURL alloc] initWithString:@"wss://path-to-socket:1234"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];

Тогда давайте настроим сертификат. Важно, чтобы ваш сертификат был в двоичном формате DER, а не в кодировке base64 PEM. Файл сертификата должен быть в вашем основном комплекте.

NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"myOwnCertificate" ofType:@"cer"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:cerPath];
CFDataRef certDataRef = (__bridge CFDataRef)certData;
SecCertificateRef certRef = SecCertificateCreateWithData(NULL, certDataRef);
id certificate = (__bridge id)certRef;

Затем мы устанавливаем закрепленные сертификаты запроса в массив, содержащий только тот, который мы настроили ранее.

[request setSR_SSLPinnedCertificates:@[certificate]];

И теперь мы можем доработать сокет.

SRWebSocket *socket = [[SRWebSocket alloc] initWithURLRequest:request];       
[socket open];

Для кода в Swift:

if let pinnedCertificatePath = NSBundle.mainBundle().pathForResource("subdomain.yourwebsite.com", ofType: "der"),
let pinnedCertificateData = NSData(contentsOfFile: pinnedCertificatePath),
let cert = SecCertificateCreateWithData(nil, pinnedCertificateData) {
    request.SR_SSLPinnedCertificates = [cert]

    // make the websocket call!
    let ws = SRWebSocket(URLRequest: request)
    // configure the websocket
    ws.open()
} else {
    NSLog("Failed to open websocket, could not find pinned certificate!")
}
Другие вопросы по тегам