iOS: Network SSL相关问题

这篇博客探讨了在iOS平台上运行HTTPS服务器时遇到的SSL身份证书问题。通过引用StackOverflow上的多个问题和Apple官方文档,文章讨论了如何处理SSL认证、创建服务器套接字进行双向SSL认证,以及评估由自签名PKI根CA签署的服务器证书。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题引自:点击打开链接

http://stackoverflow.com/questions/9874932/ssl-identity-certificate-to-run-an-https-server-on-ios

http://stackoverflow.com/questions/26592389/ios-creating-a-server-socket-for-mutual-ssl-authentication-using-gcdasyncsocket

http://stackoverflow.com/questions/28407397/objective-c-eveluate-server-certificate-signed-by-our-own-pki-root-ca-on-tls

Apple Doc

https://developer.apple.com/library/ios/documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html#//apple_ref/doc/uid/TP40001358-CH208-SW13

I'm trying to build an HTTPS server in an iOS app, in order to act as a proxy between my web-app and my external server.

I have managed to make an HTTP server by listening to a socket, either thanks to CFSocketRef or using the GCDAsyncSocket library. I have also succeed to make a Mac app running an HTTPS server, using the GCDAsyncSocket library and thanks to my method "secureSocket:" below which secures the connection:

- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
    // (...)
    // secure the connection
    [self secureSocket:newSocket];
    // (...)
}

- (void)secureSocket:(GCDAsyncSocket *)sock
{
    // The root self-signed certificate I have created
    NSString *certificatePath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"cer"];
    NSData *certData = [[NSData alloc] initWithContentsOfFile:certificatePath];
    CFDataRef certDataRef = (CFDataRef)certData;
    SecCertificateRef cert = SecCertificateCreateWithData(NULL, certDataRef);
    [certData release];

    // the "identity" certificate
    SecIdentityRef identityRef;
    SecIdentityCreateWithCertificate(NULL, cert, &identityRef);

    // the certificates array, containing the identity then the root certificate
    NSArray *certs = [[NSArray alloc] initWithObjects:(id)identityRef, (id)cert, nil];

    // the SSL configuration
    NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:3];
    [settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];
    [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];
    [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsExpiredRoots];
    [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsExpiredCertificates];
    [settings setObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];
    [settings setObject:(NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(NSString*)kCFStreamSSLLevel];
    [settings setObject:certs forKey:(NSString *)kCFStreamSSLCertificates];
    [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLIsServer];

    [sock startTLS:settings];
    [certs release];
}

The certificate I'm using is a self-signed server SSL certificate I have created with Keychain Access. So I understand that I have to give the system a configuration set with an array containing an identity and a certificate. And it works fine on my Mac app.

The problem is to enable the SSL on the HTTP server of my iOS app. The method "SecIdentityCreateWithCertificate()" which creates the identity doesn't exist on iOS and I don't know how to create an identity another way.

How to create an SecIdentityRef on iOS (to enable SSL server side)? Did I miss somethinglike to store the public/private key in my app, or something else? Thank you so much.

share improve this question
 
 
It has been changed in CocoaAsyncSocket v7.4, some old option keys are now unavailable and will throw exception. Use GCDAsyncSocketManuallyEvaluateTrust and evaluate in -socket:didReceiveTrust: delegate instead. See my example in gist.github.com/hlung/6432966 –   Hlung  Jul 4 '14 at 10:16 

2 Answers

up vote 3 down vote accepted

I will post a separate answer, as comments are not suitable for code sharing.
Here is what I use to import my PKCS12:

CFArrayRef keyref = NULL;
OSStatus sanityChesk = SecPKCS12Import((__bridge CFDataRef)p12Data, 
                                       (__bridge CFDictionaryRef)[NSDictionary 
                                                                  dictionaryWithObject:password 
                                                                  forKey:(__bridge id)kSecImportExportPassphrase], 
                                       &keyref);

if (sanityChesk != noErr) {
    NSLog(@"Error while importing pkcs12 [%d]", sanityChesk);
    return nil;
}

NSArray *keystore = (__bridge_transfer NSArray *)keyref;

The complete p12 content will be in the keystore array.

share improve this answer
 
 
my code here uses the ARC, hence the need of the cryptic __bridge keywords ;) –   pmilosev  May 2 '12 at 15:25
 
I was doing the same. I get the same result with your code: keystore array is empty. If you have a better result with the same code, I guess it means that I don't generate or store my certificates right? What I did is to create a self-signed root certificate from Keychain Access then I store both .cer and .p12 files in my project bundle and I try to use them without success as you can see. Thank you for your time, I appreciate your help.–   Laurent  May 8 '12 at 11:35
 
just to get it work ... why don't you try exporting some of yours working key/certificate pairs (e.g. development certs signed by Apple). –   pmilosev  May 10 '12 at 13:59
 
I have tried with a valid certificate and it worked. I have another issue but thanks for your help! –   Laurent Jun 1 '12 at 15:48

It looks like you need to import the identity using a PKCS #12 file. See listing 2-2 inhttps://developer.apple.com/library/ios/#documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html#//apple_ref/doc/uid/TP40001358-CH208-SW13 .

share improve this answer
 
 
I have already tried that actually, but I can't make it working - it might be the right question here. I have imported my private key (p12 file) and used the extractIdentityAndTrust() function as shown by Apple in your link, but I always get an empty items array that makes this function crashing while trying to access the first element of the array. Any idea about that? –   Laurent  Mar 28 '12 at 10:41 
 
If you have used the 'SecPKCS12Import' method it will return an NSArray containing NSDictionaries. The identity in the dictionary is stored under the key 'kSecImportItemIdentity', while the certificate chain (NSArray again) under the key 'kSecImportItemCertChain'. In meantime I am also looking for a way to create the identity in runtime, since I am not dealing with pre-loaded certs. Will post the result here if I find something ;)–   pmilosev  Apr 4 '12 at 15:56
 
Thanks @pmilosev. My problem is that I use the function extractIdentityAndTrust as shown by Apple in the link above but the array items I get is always empty: NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"myPrivateKeyPassword" forKey:(id)kSecImportExportPassphrase]; CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); securityError = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items); –   Laurent  May 1 '12 at 14:46 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小涵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值