【发布时间】:2015-09-01 14:36:16
【问题描述】:
我一直在为一个奇怪的问题而苦恼 - 一些似乎没有说出来(或称为完全不同)的问题。 令人惊讶的是,我找不到 HTTPS 示例 - 我找到的所有东西都有这个“待办事项”!
简而言之:
我正在尝试使用有效证书创建一个使用 TLS 的“服务器”。
问题:
一旦我成功导入证书,为 GCDAsyncSockets 设置设置,然后调用 startTLS,连接将立即断开 “SecureTransport 错误 -9800” - Chrome 将此称为“ERR_SSL_PROTOCOL_ERROR”
测试:
- 运行服务器。
- 通过 Chrome 或 Safari(https://localhost 或 https://localhost:somefreeport)连接。
- 尝试从收到的数据中观察页面请求。
- 在握手阶段观察失败。
Chrome 是我选择的测试平台,因为此练习稍后将处理 WebSocket 流量 - 因此我使用有效证书,而不是自签名。
长描述:
使用 GCDAsyncSocket 侦听端口,然后在收到连接后,使用该套接字和“startTLS”来处理它。 (我并不排斥使用 GCDAsyncSocket,只是我熟悉它在客户端套接字使用明文和 TLS 和服务器明文 - 只有服务器 TLS 让我难过)。
证书是具有已知公共 CA(Comodo 或 GoDaddy)的签名证书 - 我已经在 .Net 中成功使用它 下面的源将成功打开证书并报告 peername。 然而,.Net 简化了很多,所以比较起来并不容易。 (将带有 pass 的证书加载到 x509 对象中,然后应用于新的套接字。而在这里,我也必须定义密码和 SSL 版本)。
简化代码示例:
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
//Get certificate
NSString* p12Path = [[NSBundle bundleForClass:[self class]] pathForResource:@"mySignedCert"
ofType:@"pfx"];
CFDataRef inPKCS12Data = (CFDataRef)CFBridgingRetain([[NSData alloc] initWithContentsOfFile:p12Path]);
CFStringRef password = CFSTR("myCertPassword"); //Cert Password
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
CFRelease(options);
CFRelease(password);
if(securityError == errSecSuccess)
NSLog(@"Success opening p12 certificate."); //All good!
else
return nil;
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
SecIdentityRef myIdent = (SecIdentityRef)CFDictionaryGetValue(identityDict,
kSecImportItemIdentity);
SecIdentityRef certArray[1] = { myIdent };
CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
//Build TLS settings dictionary
[self willSecureWithSettings:settings]; //This just uses SSLGetNumberSupportedCiphers & SSLGetSupportedCiphers to create a cipher array and appends to settings
settings[(NSString *)kCFStreamSSLCertificates] = (__bridge id)(myCerts);
settings[(NSString *)kCFStreamSSLPeerName] = @"my.peer.address";
/* Valid values for protocol types
kSSLProtocolUnknown = 0, no protocol negotiated/specified; use default
kSSLProtocol3 = 2, SSL 3.0
kTLSProtocol1 = 4, TLS 1.0
kTLSProtocol11 = 7, TLS 1.1
kTLSProtocol12 = 8, TLS 1.2
kDTLSProtocol1 = 9, DTLS 1.0
*/
//Tried 0,2,4,7,8 - 9 throws another error, possibly unsupported.
settings[GCDAsyncSocketSSLProtocolVersionMin] = [NSNumber numberWithInteger:8];
settings[GCDAsyncSocketSSLProtocolVersionMax] = [NSNumber numberWithInteger:8];
[newSocket startTLS:settings];
[newSocket readDataWithTimeout:-1 tag:0];
}
我发现了许多旧示例,但没有一个不再适用(不使用较旧的 GCDAsyncSocket 或较旧的 Xcode)。 我发现最接近的提到后来的“GCDAsyncSocketSSLProtocolVersionMin/Max”设置为 2,例如 Chrome 不支持。
有没有人成功并愿意分享一些指点?
亲切的问候,KF。
【问题讨论】:
标签: macos sockets ssl gcdasyncsocket