iOS。在钥匙链中预先安装SSL证书--以编程方式安装
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS。在钥匙链中预先安装SSL证书--以编程方式安装相关的知识,希望对你有一定的参考价值。
我想在用户访问网站之前,在钥匙链中安装保存一个证书。我有一个HTTPS服务器,我的应用程序在用户访问之前对用户进行身份验证。https:/mysite.
有什么方法可以让我通过POST请求在keychain中安装保存证书,或者我可以将证书(文件)复制到资源捆绑中来标记它的可信度?
一旦你有德格式的服务器证书,你可以尝试以下代码。
+ (void) addCertToKeychain:(NSData*)certInDer
OSStatus err = noErr;
SecCertificateRef cert;
cert = SecCertificateCreateWithData(NULL, (CFDataRef) certInDer);
assert(cert != NULL);
CFTypeRef result;
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kSecClassCertificate, kSecClass,
cert, kSecValueRef,
nil];
err = SecItemAdd((CFDictionaryRef)dict, &result);
assert(err == noErr || err == errSecDuplicateItem);
CFRelease(cert);
它将会把证书添加到你的应用程序的钥匙链沙盒中 也就是没有其他应用程序会信任你的证书。
从: http:/blog.asolutions.com201102使用-tls-自签证书或自定义根证书-ios
您有两个选择:将服务器的证书添加到密钥链中,或者手动执行验证。无论你的方法是什么,你都需要在你的应用程序中包含一个DER编码的X.509公共证书。在下面的例子中,它被命名为 "ios-trusted-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对你创建的每个新socket都信任你的cert时,这是很合适的。
- (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;
以上是关于iOS。在钥匙链中预先安装SSL证书--以编程方式安装的主要内容,如果未能解决你的问题,请参考以下文章
如何以编程方式将证书导入我的iOS应用程序的钥匙串,并在需要时将身份传递给服务器?
在 InstallShield 安装期间导入 SSL 证书后,无法以编程方式将其与 IIS 中的绑定相关联