Ios 为什么我的SSL握手在发送任何SSL消息之前失败?
我正在尝试使用TLS1.2和苹果的安全传输API将iOS客户端连接到OSX服务器。我的BSD套接字通信工作正常,我在用TLS包装它时遇到了很多麻烦。就我从Wireshark的输出中可以看出,SSL握手甚至还没有真正开始,因此可能是我在一侧或另一侧设置了错误的SSL,但我不确定我可能做错了什么 服务器端:Ios 为什么我的SSL握手在发送任何SSL消息之前失败?,ios,macos,ssl,secure-transport,Ios,Macos,Ssl,Secure Transport,我正在尝试使用TLS1.2和苹果的安全传输API将iOS客户端连接到OSX服务器。我的BSD套接字通信工作正常,我在用TLS包装它时遇到了很多麻烦。就我从Wireshark的输出中可以看出,SSL握手甚至还没有真正开始,因此可能是我在一侧或另一侧设置了错误的SSL,但我不确定我可能做错了什么 服务器端: void establish_connection(int sockfd) { SSLContexRef sslContext = SSLCreateContext(kCFAllocator
void establish_connection(int sockfd) {
SSLContexRef sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
SSLSetIOFuncs(sslContext, readFromSocket, writeToSocket);
SSLSetConnection(sslContext, (SSLConnectionRef)(long)sockfd);
SSLSetProtocolVersionMin(sslContext, kTLSProtocol12);
// Get self-signed certificate from p12 data
CFDataRef cert_data = CFDataCreate(kCFAllocatorDefault, cert_p12, cert_p12_len);
CFArrayRef items = NULL;
const void *options_keys[] = { kSecImportExportPassphrase };
const void *options_values[] = { CFSTR("password") };
CFDictionaryRef options = CFDictionaryCreate(kCFAllocatorDefault, options_keys, options_values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
SecPKCS12Import(cert_data, options, &items);
CFRelease(options);
CFDictionaryRef item = CFArrayGetValueAtIndex(items, 0);
SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(item, kSecImportItemIdentity);
CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, (const void **)&identity, 1, NULL);
SSLSetCertificate(sslContext, certs);
// Fails with errSSLProtocol
SSLHandshake(sslContext);
...
}
客户端:
void establish_connection(int server_sockfd) {
SSLContextRef sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
SSLSetIOFuncs(sslContext, readFromSocket, writeToSocket);
SSLSetConnection(sslContext, (SSLConnectionRef)server_sockfd);
SSLSetProtocolVersionMin(sslContext, kTLSProtocol12);
// Fails with errSSLProtocol
SSLHandshake(sslContext);
...
}
Wireshark对尝试握手的转储:
Source Destination Protocol Length Info
client server TCP 78 50743 > 49754 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 WS=16 TSval=365690143 TSecr=0 SACK_PERM=1
server client TCP 78 49754 > 50743 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=1460 WS=16 TSval=666304222 TSecr=365690143 SACK_PERM=1
client server TCP 66 50743 > 49754 [ACK] Seq=1 Ack=1 Win=131760 Len=0 TSval=365690468 TSecr=666304222
server client TCP 66 [TCP Window Update] 49754 > 50743 [ACK] Seq=1 Ack=1 Win=131760 Len=0 TSval=666304252 TSecr=365690468
server client TCP 66 49754 > 50743 [FIN, ACK] Seq=1 Ack=1 Win=131760 Len=0 TSval=666304281 TSecr=365690468
client server TCP 66 50743 > 49754 [ACK] Seq=1 Ack=2 Win=131760 Len=0 TSval=365690498 TSecr=666304281
server client TCP 66 [TCP Dup ACK 9099#1] 49754 > 50743 [ACK] Seq=2 Ack=1 Win=131760 Len=0 TSval=666304283 TSecr=365690498
使用Wireshark尝试诊断问题,我甚至看不到任何SSL握手消息。我看到TCP连接已建立,然后立即关闭,没有长度大于0的数据包。我会做错什么呢?看起来问题在于我的IO功能实现不正确。我正在粘贴套接字IO函数,这些函数似乎可以工作,但是IO函数的要求没有很好的文档记录,所以我可能遗漏了一些东西
OSStatus readFromSocket(SSLConnectionRef connection, void *data, size_t *dataLength) {
int sockfd = (int)connection;
size_t bytesRequested = *dataLength;
ssize_t status = read(sockfd, data, bytesRequested);
if (status > 0) {
*dataLength = status;
if (bytesRequested > *dataLength)
return errSSLWouldBlock;
else
return noErr;
} else if (0 == status) {
*dataLength = 0;
return errSSLClosedGraceful;
} else {
*dataLength = 0;
switch (errno) {
case ENOENT:
return errSSLClosedGraceful;
case EAGAIN:
return errSSLWouldBlock;
case ECONNRESET:
return errSSLClosedAbort;
default:
return errSecIO;
}
return noErr;
}
}
OSStatus writeToSocket(SSLConnectionRef connection, const void *data, size_t *dataLength) {
int sockfd = (int)connection;
size_t bytesToWrite = *dataLength;
ssize_t status = write(sockfd, data, bytesToWrite);
if (status > 0) {
*dataLength = status;
if (bytesToWrite > *dataLength)
return errSSLWouldBlock;
else
return noErr;
} else if (0 == status) {
*dataLength = 0;
return errSSLClosedGraceful;
} else {
*dataLength = 0;
if (EAGAIN == errno) {
return errSSLWouldBlock;
} else {
return errSecIO;
}
}
}
能否显示完整的堆栈跟踪和/或交换的数据包的更多细节?我已编辑了该问题,以添加尝试握手的Wireshark转储。Wireshark转储看起来好像显示了服务器的半关闭,而不是完全关闭。不过,如果服务器希望协商SSL连接,则不应关闭。我不熟悉iOS电话,但我想知道你是需要从双方开始握手,还是应该只从一方开始握手。嗨,格雷格,我也在做同样的工作。你能建议我握手后下一步做什么吗。我将非常感谢您……:)如果握手成功,您应该能够使用
SSLRead
和SSLWrite
通过连接进行通信,就像使用标准套接字使用read
和write
一样。是的,我在深夜实现了它。。但无论如何,我感谢你的建议和帮助。。太多了。。快乐编码…:)从我的实验中,似乎关键是在没有读取所请求的字节数时,从读取回调返回errSSLWouldBlock。如果其他人需要实现自定义回调并看到类似问题,请将此保留在此处。另一个警告:SSL层可能会要求回调获取数据,即使它的缓冲区中仍有数据。当底层阻塞时,这尤其令人恼火,因此应用程序可能只在底层超时后才获取缓冲数据。该问题的解决方案是使用ioctl(或与较低层相关的任何东西)检查较低层是否有可用数据。如果没有可用数据,则从回调返回errSSLWouldBlock,即使这意味着您不向SSL层返回任何数据。