От: http://blog.asolutions.com/2011/02/using-tls-with-self-signed-certificates-or-custom-root-certificates-in-ios/
У вас есть два варианта: добавить сертификат сервера в связку ключей или выполнить проверку вручную. Независимо от вашего подхода, вам нужно будет включить в приложение открытый сертификат X.509 в кодировке DER. В приведенном ниже примере он называется «ios-trust-cert.der») и с его помощью создается SecCertificateRef. (Если сертификат вашего сервера является частью цепочки к корневому центру сертификации, вам следует установить корневой центр сертификации, а не сертификат вашего сервера.)
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSData *iosTrustedCertDerData =
[NSData dataWithContentsOfFile:[bundle pathForResource:@"ios-trusted-cert"
ofType:@"der"]];
SecCertificateRef certificate =
SecCertificateCreateWithData(NULL,
(CFDataRef) iosTrustedCertDerData);
Помните, что SecCertificateCreateWithData следует правилу создания владения памятью, поэтому вы должны CFRelease, когда он вам больше не нужен, чтобы избежать утечек памяти.
Затем вы можете добавить сертификат в связку ключей вашего приложения. Это уместно, если вы хотите, чтобы iOS доверяла вашему сертификату для каждого нового созданного вами сокета.
- (void) useKeychain: (SecCertificateRef) certificate {
OSStatus err =
SecItemAdd((CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
(id) kSecClassCertificate, kSecClass,
certificate, kSecValueRef,
nil],
NULL);
if ((err == noErr) || // success!
(err == errSecDuplicateItem)) { // the cert was already added. Success!
// create your socket normally.
// This is oversimplified. Refer to the CFNetwork Guide for more details.
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL,
(CFStringRef)@"localhost",
8443,
&readStream,
&writeStream);
CFReadStreamSetProperty(readStream,
kCFStreamPropertySocketSecurityLevel,
kCFStreamSocketSecurityLevelTLSv1);
CFReadStreamOpen(readStream);
CFWriteStreamOpen(writeStream);
} else {
// handle the error. There is probably something wrong with your cert.
}
}
Если вы хотите проверить сертификат только для создаваемого сокета и ни для каких других сокетов в своем приложении, вы можете проверить свое доверие к сертификату вручную. Сначала создайте сокет (при условии, что ваш сервер прослушивает порт 8443 на том же компьютере, что и ваш клиент) и отключите проверку цепочки сертификатов в настройках ssl:
- (void) verifiesManually: (SecCertificateRef) certificate {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL,
(CFStringRef)@"localhost",
8443,
&readStream,
&writeStream);
// Set this kCFStreamPropertySocketSecurityLevel before
// setting kCFStreamPropertySSLSettings.
// Setting kCFStreamPropertySocketSecurityLevel
// appears to override previous settings in kCFStreamPropertySSLSettings
CFReadStreamSetProperty(readStream,
kCFStreamPropertySocketSecurityLevel,
kCFStreamSocketSecurityLevelTLSv1);
// this disables certificate chain validation in ssl settings.
NSDictionary *sslSettings =
[NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanFalse, (id)kCFStreamSSLValidatesCertificateChain,
nil];
CFReadStreamSetProperty(readStream,
kCFStreamPropertySSLSettings,
sslSettings);
NSInputStream *inputStream = (NSInputStream *)readStream;
NSOutputStream *outputStream = (NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
CFReadStreamOpen(readStream);
CFWriteStreamOpen(writeStream);
}
Затем, когда вы получите обратный вызов о том, что ваш сокет готов к записи данных, вы должны проверить доверие к сертификату, включенному вашим сервером, прежде чем записывать какие-либо данные или читать какие-либо данные с сервера. Сначала (1) создайте клиентскую политику SSL с именем хоста сервера, к которому вы подключились. Имя хоста включается в сертификат сервера, чтобы подтвердить, что сервер, на который вас направил DNS, является сервером, которому вы доверяете. Далее (2) вы берете актуальные сертификаты сервера из сокета. С сервером может быть связано несколько сертификатов, если сертификат сервера является частью цепочки сертификатов. Когда у вас есть актуальные сертификаты сервера, вы можете (3) создать объект доверия. Объект доверия представляет собой локальный контекст для оценок доверия. Он изолирует индивидуальные оценки доверия, тогда как сертификаты связки ключей применяются ко всем доверенным сокетам. После того, как у вас есть объект доверия, вы можете (4) установить сертификаты привязки, которые являются сертификатами, которым вы доверяете. Наконец (5), вы можете оценить объект доверия и выяснить, можно ли доверять серверу.
#pragma mark -
#pragma mark NSStreamDelegate
- (void)stream:(NSStream *)aStream
handleEvent:(NSStreamEvent)eventCode {
switch (eventCode) {
case NSStreamEventNone:
break;
case NSStreamEventOpenCompleted:
break;
case NSStreamEventHasBytesAvailable:
break;
case NSStreamEventHasSpaceAvailable:
// #1
// NO for client, YES for server. In this example, we are a client
// replace "localhost" with the name of the server to which you are connecting
SecPolicyRef policy = SecPolicyCreateSSL(NO, CFSTR("localhost"));
SecTrustRef trust = NULL;
// #2
CFArrayRef streamCertificates =
[aStream propertyForKey:(NSString *) kCFStreamPropertySSLPeerCertificates];
// #3
SecTrustCreateWithCertificates(streamCertificates,
policy,
&trust);
// #4
SecTrustSetAnchorCertificates(trust,
(CFArrayRef) [NSArray arrayWithObject:(id) self.certificate]);
// #5
SecTrustResultType trustResultType = kSecTrustResultInvalid;
OSStatus status = SecTrustEvaluate(trust, &trustResultType);
if (status == errSecSuccess) {
// expect trustResultType == kSecTrustResultUnspecified
// until my cert exists in the keychain see technote for more detail.
if (trustResultType == kSecTrustResultUnspecified) {
NSLog(@"We can trust this certificate! TrustResultType: %d", trustResultType);
} else {
NSLog(@"Cannot trust certificate. TrustResultType: %d", trustResultType);
}
} else {
NSLog(@"Creating trust failed: %d", status);
[aStream close];
}
if (trust) {
CFRelease(trust);
}
if (policy) {
CFRelease(policy);
}
break;
case NSStreamEventErrorOccurred:
NSLog(@"unexpected NSStreamEventErrorOccurred: %@", [aStream streamError]);
break;
case NSStreamEventEndEncountered:
break;
default:
break;
}
}
person
Deam
schedule
26.03.2013