【问题标题】:Ocj-C Secure Sockets Server with real cert - SSL Protocol Error (GCDAsyncSockets based)具有真实证书的 Ocj-C 安全套接字服务器 - SSL 协议错误(基于 GCDAsyncSockets)
【发布时间】:2015-09-01 14:36:16
【问题描述】:

我一直在为一个奇怪的问题而苦恼 - 一些似乎没有说出来(或称为完全不同)的问题。 令人惊讶的是,我找不到 HTTPS 示例 - 我找到的所有东西都有这个“待办事项”!

简而言之:

我正在尝试使用有效证书创建一个使用 TLS 的“服务器”。

问题:

一旦我成功导入证书,为 GCDAsyncSockets 设置设置,然后调用 startTLS,连接将立即断开 “SecureTransport 错误 -9800” - Chrome 将此称为“ERR_SSL_PROTOCOL_ERROR”

测试:

  1. 运行服务器。
  2. 通过 Chrome 或 Safari(https://localhosthttps://localhost:somefreeport)连接。
  3. 尝试从收到的数据中观察页面请求。
  4. 在握手阶段观察失败。

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


    【解决方案1】:

    哇 - 我花了很长时间解决这个问题,然后在这里寻求提示。

    10 分钟后想通了!

    我的改变:

    //THIS! Tried prior, but GCDAsyncSocket docs stated not-needed, plus was getting different handshake errors.
    settings[(NSString *)kCFStreamSSLIsServer] = [NSNumber numberWithBool:YES];
    

    其他 SO 用户可能会觉得有用的其他更改:

    //Apparently prefereable
    settings[(NSString*)kCFStreamPropertyShouldCloseNativeSocket] = [NSNumber numberWithBool:YES];
    //Above example was both matching for test. 4-8 was always preferable.
    settings[GCDAsyncSocketSSLProtocolVersionMin] = [NSNumber numberWithInteger:4];
    settings[GCDAsyncSocketSSLProtocolVersionMax] = [NSNumber numberWithInteger:8];
    

    非常感谢 - 即使你喜欢橡胶鸭!

    【讨论】:

      猜你喜欢
      • 2011-09-26
      • 2013-11-13
      • 2014-04-10
      • 1970-01-01
      • 1970-01-01
      • 2011-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多