Da: http://blog.asolutions.com/2011/02/using-tls-with-self-signed-certificates-or-custom-root-certificates-in-ios/
Sono disponibili due opzioni disponibili: aggiungere il certificato del server al portachiavi o eseguire la convalida manualmente. Indipendentemente dal tuo approccio, dovrai includere un certificato pubblico X.509 con codifica DER nella tua app. Nell'esempio seguente, è denominato "ios-trusted-cert.der") e crea un SecCertificateRef con esso. (Se il certificato del server è parte di una catena di un'autorità di certificazione, è necessario installare l'autorità di certificazione principale piuttosto che il certificato del server.)
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSData *iosTrustedCertDerData =
[NSData dataWithContentsOfFile:[bundle pathForResource:@"ios-trusted-cert"
ofType:@"der"]];
SecCertificateRef certificate =
SecCertificateCreateWithData(NULL,
(CFDataRef) iosTrustedCertDerData);
Ricordate che SecCertificateCreateWithData segue la regola di creare di proprietà di memoria, in modo da CFRilasciarlo quando non ne hai più bisogno per evitare perdite di memoria.
Successivamente, è possibile aggiungere il certificato al portachiavi dell'app. Questo è appropriato quando vuoi che iOS si fidi del tuo certificato per ogni nuovo socket che crei.
- (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.
}
}
Se si desidera solo per verificare il CERT per la presa che si sta creando e per nessun altro prese del tuo app, è possibile verificare la tua fiducia nel cert manualmente. In primo luogo, creare un socket (supponendo che il server è in ascolto sulla porta 8443 sulla stessa macchina come client) e disabilitare sua validazione catena di certificati nelle sue impostazioni 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);
}
Poi, quando si riceve un callback che la presa è pronto per scrivere i dati, è necessario verificare la fiducia nel certificato incluso nel server prima di scrivere qualsiasi dato o leggere qualsiasi dato dal server. Primo (1), creare un criterio SSL client con il nome host del server a cui si è connessi. Il nome host è incluso nel certificato del server per autenticare che il server a cui il DNS ha diretto l'utente è il server di cui ti fidi. Successivo (2), si prendono i certificati del server effettivo dal socket. Potrebbero esserci più certificati associati al server se il certificato del server fa parte di una catena di certificati. Quando hai i certificati server effettivi, puoi (3) creare un oggetto trust. L'oggetto trust rappresenta un contesto locale per le valutazioni di trust. Isola le singole valutazioni di trust mentre i certificati portachiavi si applicano a tutti i socket fidati. Dopo aver avuto un trust object, puoi (4) impostare i certificati di ancoraggio, che sono i certificati di cui ti fidi. Infine (5), è possibile valutare l'oggetto trust e scoprire se il server può essere considerato affidabile.
#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;
}
}
È necessario accettare una risposta o chiarire le proprie preoccupazioni se non hanno risolto i problemi. – MrTJ