我有一个简单的TCP服务器客户端设置。这种连接实际上很好用。
现在我想为套接字连接实现SSL TLS加密。我使用keychain访问创建了一个PKCS12证书。在我的服务器中,我在accept回调里面有以下代码。
NSString *certificatePath = [[NSBundle mainBundle] pathForResource:@"TCPServerCertificate" ofType:@"p12"];
NSData *certificateData = [NSData dataWithContentsOfFile:certificatePath];
CFArrayRef keyRef;
OSStatus status = SecPKCS12Import((__bridge CFDataRef)certificateData, (__bridge CFDictionaryRef)@{(__bridge NSString *)kSecImportExportPassphrase: @"1234"}, &keyRef);
if (status != noErr) {
NSLog(@"PKCS12 import error %i", status);
return;
}
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(keyRef, 0);
SecIdentityRef identityRef = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
SecCertificateRef certificate;
status = SecIdentityCopyCertificate(identityRef, &certificate);
if (status != noErr) {
NSLog(@"sec identity copy failed: %i", status);
return;
}
NSArray *certificates = [NSArray arrayWithObjects:(__bridge id)identityRef, (__bridge id)certificate, nil];
NSDictionary *settings = @{(NSString *)kCFStreamPropertyShouldCloseNativeSocket: [NSNumber numberWithBool:YES],
(NSString *)kCFStreamSSLValidatesCertificateChain: [NSNumber numberWithBool:YES],
(NSString *)kCFStreamSSLAllowsExpiredCertificates: [NSNumber numberWithBool:NO],
(NSString *)kCFStreamSSLAllowsExpiredRoots: [NSNumber numberWithBool:NO],
(NSString *)kCFStreamSSLAllowsAnyRoot: [NSNumber numberWithBool:YES],
(NSString *)kCFStreamSSLCertificates: certificates,
(NSString *)kCFStreamSSLIsServer: [NSNumber numberWithBool:YES],
(NSString *)kCFStreamSSLLevel: (NSString *)kCFStreamSocketSecurityLevelTLSv1};
CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
然后我创建了 NSStream
流的实例,并在另一个类中处理它们。
当我运行服务器并连接客户端时,我得到了常规的 NSStreamEventOpenCompleted
中的委托。然后,当我试图向流或事件写入时,如果我只是关闭连接,我得到以下错误。
2013-10-25 13:27:08.584 TCPServer[6435:303] CFNetwork SSLHandshake failed (-9800)
2013-10-25 13:27:08.584 TCPServer[6435:303] NSStreamEventOpenCompleted
2013-10-25 13:27:08.585 TCPServer[6435:303] NSStreamEventErrorOccurred
我想知道我在客户端需要实现什么。另外我也不知道为什么我在客户端发送数据或断开连接时,会出现握手失败的情况。每当出现这个错误时,客户端就认为自己还在连接。
有没有什么好的TCP SSLTLS教程或其他资料,同时涵盖了,客户端和服务器端?
这段代码有一些问题:你不能用kCFStreamPropertySSLSettings来设置kCFStreamPropertyShouldCloseNativeSocket,而且你不应该混合服务器和客户端代码。
对于服务器,你应该只设置一个证书
CFReadStreamSetProperty(read, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(write, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
//kCFStreamPropertySocketSecurityLevel
//Note: If you set this key, you must do so before setting any other SSL options, such as kCFStreamPropertySSLSettings.
CFReadStreamSetProperty(read, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
CFWriteStreamSetProperty(write, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
//Creating server dictionnary
//kCFStreamSSLIsServer
//If the value of this key is kCFBooleanTrue, the kCFStreamSSLCertificates key must contain a valid value
//kCFStreamSSLCertificates
//Security property key whose value is a CFArray of SecCertificateRefs except for the first element in the array, which is a SecIdentityRef.
//For more information, see SSLSetCertificate() in Security/SecureTransport.h.
NSDictionary *settings = @{(id)kCFStreamSSLCertificates: certificates,
(id)kCFStreamSSLIsServer: @YES};
//Apply settings
CFReadStreamSetProperty(read, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)(settings));
CFWriteStreamSetProperty(write, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)(settings));
对于客户端,如果你想覆盖验证链(请参阅Apple关于覆盖链验证的文档)你应该做以下工作。
CFReadStreamSetProperty(read, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(write, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
//kCFStreamPropertySocketSecurityLevel
//Note: If you set this key, you must do so before setting any other SSL options, such as kCFStreamPropertySSLSettings.
CFReadStreamSetProperty(read, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
CFWriteStreamSetProperty(write, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
//DO NOT USE kCFStreamPropertySSLContext as it overrides the following configuration
//create dictionnary for kCFStreamPropertySSLSettings
//keys for dictionnary we want to change:kCFStreamSSLAllowsExpiredCertificates;kCFStreamSSLAllowsExpiredRoots;kCFStreamSSLAllowsAnyRoot;
//kCFStreamSSLValidatesCertificateChain => no need to worry about the root
//kCFStreamSSLPeerName kCFNull prevents name verification
settings = @{(id)kCFStreamSSLValidatesCertificateChain: @NO,//The delegate will verify this
(id)kCFStreamSSLPeerName: (id)kCFNull};//prevents name verification if server is not fixed (eg. IP)
//Apply settings
CFReadStreamSetProperty(read, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)(settings));
CFWriteStreamSetProperty(write, kCFStreamPropertySSLSettings, (__bridge CFDictionaryRef)(settings));
我刚刚创建了一个包,使TLSTCP更容易 与新的iOS 13限制。希望它能帮助别人 欢迎贡献自己的力量。