2013-08-14 5 views
2

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

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); 
} 
+0

Отличный вопрос! Надеюсь, на это скоро на него назовут ответ ... – arik

ответ

5

Свидетельство пиннинга с SocketRocket делается таким образом:

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

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

Затем давайте создадим сертификат. Крайне важно, чтобы ваш сертификат находился в двоичном формате DER, а не в PEM, закодированном в base64. Файл сертификата должен находиться в вашем основном пакете.

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]; 
+0

Можно ли также выполнить SSL-квитирование с помощью ракеты-носителя (проверяющей цепочку сертификатов), как с делегатами, предоставленными NSURLConnection? –

+0

SocketRocket делает это по умолчанию, фактически. Вышеуказанный метод полезен, если у вас нет сертификата, цепочка которого ведет к доверенным полномочным органам, но если у вас есть собственный, возможно, сам подписанный сертификат. – arik

+0

это формат «DER» вместо «DEM», – mash

1

Для кода в 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!") 
} 
Смежные вопросы