GCDAsyncSocket startTLS не работает

Я могу подключиться к нужному сокету с IP и портом.

- (void)socket:(GCDAsyncSocket *)sender didConnectToHost:(NSString *)host port:(UInt16)port {

    [sender startTLS:nil];

    if(self.createTCPSocketHelperDelegate && @selector(returnConnectedTCPSocket:forNASWithMacAddress:))
    {
        [self.createTCPSocketHelperDelegate returnConnectedTCPSocket:sender forNASWithMacAddress:_macAddress];
    }
}

Я отправляю словарь настроек TLS с нулевым значением, так как он использует настройки по умолчанию. Это дает мне ошибку следующим образом

Error Domain=kCFStreamErrorDomainSSL Code=-9806 "The operation couldn’t be completed. (kCFStreamErrorDomainSSL error -9806.)" UserInfo=0x17d92420 {NSLocalizedRecoverySuggestion=Error code definition can be found in Apple's SecureTransport.h}

Я не мог понять, что там происходит. Пожалуйста, помогите мне предоставить пример кода, который подключается к серверу SSL и использует протокол TCP/TLS.

Помощь приветствуется. Заранее спасибо. :)


person Ashish    schedule 17.03.2016    source источник


Ответы (1)


Я понял проблему. По сути, я не мог завершить рукопожатие SSL, я нашел способ следующим образом:

Инициализируйте сокет GCDAsyncSocket и подключитесь к IP и порту следующим образом:

NSError *error;

_gcdAsyncTCPSocket  = [[GCDAsyncSocket alloc] initWithDelegate:self
                                                 delegateQueue:dispatch_get_main_queue()];

_gcdAsyncTCPSocket.delegate = self;

_ipAddress = ipAddress;

_tcpPortNumber = portNumber;

if(![_gcdAsyncTCPSocket connectToHost:ipAddress onPort:portNumber withTimeout:30 error:&error])
{
    if(self.createTCPSocketHelperDelegate && @selector(failedToCreateTCPSocket))
    {
        [self.createTCPSocketHelperDelegate failedToCreateTCPSocket];
    }
}else {

    NSMutableDictionary *settings = [[NSMutableDictionary alloc] init];

    [settings setObject:[NSNumber numberWithBool:YES]
                 forKey:GCDAsyncSocketManuallyEvaluateTrust];

    [_gcdAsyncTCPSocket startTLS:settings];
}

Когда вы устанавливаете GCDAsyncSocketManuallyEvaluateTrust, он вызывает метод делегирования

- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler

В котором я оцениваю самозаверяющий сертификат сервера с локальным сертификатом. Если он равен, то завершениеHandler(YES), иначе завершениеHandler(NO) следующим образом:

- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler {
NSLog(@"didReceiveTrust");

//server certificate
SecCertificateRef serverCertificate = SecTrustGetCertificateAtIndex(trust, 0);
CFDataRef serverCertificateData = SecCertificateCopyData(serverCertificate);

const UInt8* const serverData = CFDataGetBytePtr(serverCertificateData);
const CFIndex serverDataSize = CFDataGetLength(serverCertificateData);
NSData* cert1 = [NSData dataWithBytes:serverData length:(NSUInteger)serverDataSize];


//local certificate
NSString *localCertFilePath = [[NSBundle mainBundle] pathForResource:@"LocalCertificate" ofType:@"cer"];
NSData *localCertData = [NSData dataWithContentsOfFile:localCertFilePath];
CFDataRef myCertData = (__bridge CFDataRef)localCertData;


const UInt8* const localData = CFDataGetBytePtr(myCertData);
const CFIndex localDataSize = CFDataGetLength(myCertData);
NSData* cert2 = [NSData dataWithBytes:localData length:(NSUInteger)localDataSize];


if (cert1 == nil || cert2 == nil) {
    NSLog(@"Certificate NULL");
    completionHandler(NO);
    return;
}


const BOOL equal = [cert1 isEqualToData:cert2];

if (equal) {

    NSLog(@"Certificate match");
    completionHandler(YES);

}else{

    NSLog(@"Certificate not match");
    completionHandler(NO);
}
}

Если сертификаты совпадают с завершениемHandler(YES), он вызовет делегата

- (void)socketDidSecure:(GCDAsyncSocket *)sock {

NSLog(@"socketDidSecure");

_uploadSocket = sock;

//Do your stuff after this
}

Надеюсь, это поможет кому-то разобраться с SSL и GCDAsyncSocket. Удачного кодирования!!

person Ashish    schedule 23.03.2016
comment
Спасибо за этот подробный ответ. Обязательно ли иметь местный сертификат? Есть ли другой маршрут, где сравнение с сохраненным локальным сертификатом не требуется? - person Eden; 17.05.2017
comment
Наличие локального сертификата для сравнения необходимо только в том случае, если на сервере есть самозаверяющий сертификат. Вопрос не касается самозаверяющих сертификатов, поэтому я не думаю, что этот ответ уместен. - person Nicolás; 28.02.2018