Я пытаюсь подключить приложение iOS к серверу Windows C#, используя TLS через TCP/IP.iOS SecTrustRef Always NULL
соединение TLS использует ненадежных сертификаты, созданные из ненадежных CA корневого сертификата с использованием MakeCert полезности.
Чтобы проверить эти сертификаты, я создал простой клиент C# и используя эти сертификаты, он смог подключиться и связаться с сервером.
Я не квалифицирован в развитии IOS, но мне удалось найти какой-то код, который соединяет меня с сервером, следующим образом:
-(bool)CreateAndConnect:(NSString *) remoteHost withPort:(NSInteger) serverPort
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)(remoteHost),
serverPort, &readStream, &writeStream);
CFReadStreamSetProperty(readStream, kCFStreamPropertySocketSecurityLevel,
kCFStreamSocketSecurityLevelNegotiatedSSL);
NSInputStream *inputStream = (__bridge_transfer NSInputStream *)readStream;
NSOutputStream *outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL forKey:NSStreamSocketSecurityLevelKey];
// load certificate from servers exported p12 file
NSArray *certificates = [[NSArray alloc] init];
[self loadClientCertificates:certificates];
NSDictionary *sslSettings = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanFalse, (id)kCFStreamSSLValidatesCertificateChain,
certificates,(id)kCFStreamSSLCertificates,
nil];
[inputStream setProperty:sslSettings forKey:(__bridge NSString *)kCFStreamPropertySSLSettings];
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
CFReadStreamOpen(readStream);
CFWriteStreamOpen(writeStream);
return true;
}
код также, кажется, сделать некоторые формы TLS переговоров, поскольку сервер C# отклоняет соединение, если сертификаты p12 не предоставляются как часть настроек NSStream.
Итак, похоже, что первый этап переговоров TLS работает.
Для проверки сертификата сервера у меня есть эта функция, которая вызывается, делегат NSStream на NSStreamEventHasSpaceAvailable события:
// return YES if certificate verification is successful, otherwise NO
-(BOOL) VerifyCertificate:(NSStream *)stream
{
NSData *trustedCertData = nil;
BOOL result = NO;
SecTrustRef trustRef = NULL;
NSString *root_certificate_name = @"reference_cert";
NSString *root_certificate_extension = @"der";
/* Load reference cetificate */
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
trustedCertData = [NSData dataWithContentsOfFile:[bundle pathForResource: root_certificate_name ofType: root_certificate_extension]];
/* get trust object */
/* !!!!! error is here as trustRef is NULL !!!! */
trustRef = (__bridge SecTrustRef)[stream propertyForKey:(__bridge id)kCFStreamPropertySSLPeerTrust];
/* loacate the reference certificate */
NSInteger numCerts = SecTrustGetCertificateCount(trustRef);
for (NSInteger i = 0; i < numCerts; i++) {
SecCertificateRef secCertRef = SecTrustGetCertificateAtIndex(trustRef, i);
NSData *certData = CFBridgingRelease(SecCertificateCopyData(secCertRef));
if ([trustedCertData isEqualToData: certData]) {
result = YES;
break;
}
}
return result;
}
Теперь проблема не в том, независимо от того, что я стараюсь, то trustRef объекта является всегда null.
От этого Apple, разработчик ссылки: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html
Существует эта цитата, предполагает, что это не должно быть так:
К тому времени обработчика события вашего потока делегата получает призванный показывает, что существует доступное в сокете, работающая система уже построила канал TLS, получила сертификат с другого конца соединения и создала объект доверия для его оценки.
Любые подсказки о том, как исправить это?
Как я могу получить доступ к этому объекту trustRef для NSStream?
Edit:
Спасибо за ответ 100phole.
В попытке получить эту работу, я думал, что это могло бы иметь что-то делать с проблемой, и в одном из моих многочисленных попыток я двинул все эти связанные с гнездовыми элементами в класс:
Что-то вроде этого:
@interface Socket
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
NSInputStream *inputStream;
NSOutputStream *outputStream;
@end
Но это придумали те же результаты :(
я только вернулся обратно к версии, показанной выше, потому что, исходя из моего поиска Google, который, кажется, довольно код, общий шаблон.
Например, даже этот код с сайта разработчика Apple, использует очень похожий стиль:
Как я уже говорил ранее, я не эксперт в Objective-C (далеко от него), так Возможно, я ошибаюсь, но из того, что я видел, перемещение этих предметов в класс и их сохранение не похоже ни на что.
Ваши потоки являются локальными переменными в методе, что означает, что они будут уничтожены при возврате метода. – l00phole
Посмотрел ваш код достаточно долго, чтобы спросить ...почему бы не использовать встроенные классы NSURL и классы соединений? Настройка соединения и авторизационные рукопожатия обрабатываются для вас (при необходимости перехватывать крючки). –
Вы видите примечание на веб-странице, на которое вы ссылаетесь: '/ * Храните ссылку на входные и выходные потоки, чтобы они не исчезали .... * /' – Wain