【前言】
这只是之前闲着写了个demo,能连上github的go版本的带证书 DTLS服务端,并不保证完全正确,并不保证数据收发正常,思路仅供参考,具体请自行修改调试,仅测试到握手通过,其他的部分未测试,现在放上来供大家参考。
.m文件
#import <Foundation/Foundation.h>
#import <Network/Network.h>
#import "YHDTLSManager.h"
NSErrorDomain const ConnectError = @"连接异常";
NSErrorDomain const ReceiveError = @"接收数据异常";
NSErrorDomain const SendError = @"发送数据异常";
@interface YHDTLSManager()
@property (nonatomic, strong) nw_parameters_t params;
@property (nonatomic, strong) nw_connection_t connection;
@property (nonatomic, strong) dispatch_queue_t connectQueue;
@property (nonatomic, copy) DTLSDataHandle receiveData;
@end
@implementation YHDTLSManager
+(instancetype)shareinstance {
static YHDTLSManager * yhdtls;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
yhdtls = [[YHDTLSManager alloc] init];
});
return yhdtls;
}
-(void)setConnectInfoWithCertName:(NSString*)cert
{
self.params = nw_parameters_create_secure_udp(^(nw_protocol_options_t _Nonnull options) {
sec_protocol_options_t option = nw_tls_copy_sec_protocol_options(options);
NSData *pkcs12data = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]];
CFDataRef inPKCS12Data = (CFDataRef)CFBridgingRetain(pkcs12data);
CFStringRef password = CFSTR("12345678");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef refoptions = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = SecPKCS12Import(inPKCS12Data, refoptions, &items);
CFRelease(refoptions);
CFRelease(password);
CFRelease(inPKCS12Data);
NSLog(@"securityError:%d",(int)securityError);
if(securityError == errSecSuccess)
NSLog(@"Success opening p12 certificate.");
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
sec_protocol_options_append_tls_ciphersuite(option, tls_ciphersuite_ECDHE_RSA_WITH_AES_256_CBC_SHA);
sec_protocol_options_set_verify_block(option, ^(sec_protocol_metadata_t _Nonnull metadata, sec_trust_t _Nonnull trust_ref, sec_protocol_verify_complete_t _Nonnull complete){
SecTrustRef trust = sec_trust_copy_ref(trust_ref);
struct __CFError *err;
NSMutableArray *certificates = [NSMutableArray array];
NSData *cerData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"check" ofType:@"cer"]];
SecCertificateRef cerRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)cerData);
if(cerRef != nil){
[certificates addObject:(__bridge_transfer id)cerRef];
}{
NSLog(@"cerRef is nil");
}
SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)certificates);
SecTrustSetAnchorCertificatesOnly(trust, false);
if(!SecTrustEvaluateWithError(trust, &err)){
NSLog(@"ERROR :%@",err);
complete(true);
}else{
complete(true);
};
}, dispatch_get_main_queue());
sec_protocol_options_set_tls_ocsp_enabled(option, FALSE);
SecIdentityRef myIdent = (SecIdentityRef)CFDictionaryGetValue(identityDict,
kSecImportItemIdentity);
sec_protocol_options_set_tls_false_start_enabled(option, TRUE);
sec_protocol_options_set_peer_authentication_required(option, TRUE);
sec_protocol_options_set_challenge_block(option, ^(sec_protocol_metadata_t metadata, sec_protocol_challenge_complete_t complete){
complete(sec_identity_create(myIdent));
}, self.connectQueue);
sec_protocol_options_set_local_identity(option, sec_identity_create(myIdent));
sec_protocol_options_set_min_tls_protocol_version(option, tls_protocol_version_DTLSv12);
sec_protocol_options_set_max_tls_protocol_version(option, tls_protocol_version_DTLSv12);
}, ^(nw_protocol_options_t _Nonnull options) {
NW_PARAMETERS_DEFAULT_CONFIGURATION;
});
}
- (void)linkServerWithHost:(NSString *)host
port:(NSString *)port
queue:(dispatch_queue_t)queue{
if (host == nil || [host isEqualToString:@""]) {
return;
}
if (port == nil || [port isEqualToString:@""]) {
return;
}
nw_endpoint_t endpoint = nw_endpoint_create_host([host UTF8String], [port UTF8String]);
self.connection = nw_connection_create(endpoint, self.params);
nw_connection_set_queue(self.connection, queue);
nw_connection_start(self.connection);
}
- (void)disConnect {
dispatch_async(self.connectQueue, ^{
nw_connection_cancel(self.connection);
});
}
- (void)sendData:(NSData *)data
complete:(DTLSSessionCompletedHandle)complete {
dispatch_data_t data_t = [self dispatchDataFromNsdata:data];
nw_connection_send(self.connection, data_t, NW_CONNECTION_FINAL_MESSAGE_CONTEXT, true, ^(nw_error_t _Nullable error) {
NSError *nserror;
if (error != nil) {
nserror = [[NSError alloc] initWithDomain:SendError code:nw_error_get_error_code(error) userInfo:@{@"nw_connection_send: nw_error_get_error_domain": @(nw_error_get_error_domain(error))}];
}
NSLog(@"DTLS发送数据:%@",data);
if (complete) {
complete(nserror);
}
});
}
- (void)receiveData:(DTLSDataHandle)receiveHandle {
self.receiveData = receiveHandle;
[self receiveMsg];
}
- (void)receiveMsg {
__weak typeof (self)weakSelf = self;
nw_connection_receive_message(self.connection, ^(dispatch_data_t _Nullable content, nw_content_context_t _Nullable context, bool is_complete, nw_error_t _Nullable error) {
NSLog(@"DTLS接收数据:content=%@, context=%@, is_complete=%d, error=%@",content, context, is_complete, error);
NSLog(@"DTLS接收数据:content=%@, context=%@, is_complete=%d, error=%@",content, context, is_complete, error);
__strong typeof (weakSelf)strongSelf = weakSelf;
if (error == nil && content != nil) {
NSData *data = [strongSelf nsdataFromDispatchData:content];
if (data != nil) {
strongSelf.receiveData(data,nil);
[self receiveMsg];
} else {
NSError *nserror = [[NSError alloc] initWithDomain:ReceiveError code:nw_error_get_error_code(error) userInfo:@{@"nw_connection_receive_message: nw_error_get_error_domain": @(nw_error_get_error_domain(error))}];
if (strongSelf.receiveData) {
strongSelf.receiveData(nil, nserror);
}
}
}else{
NSError *nserror = [[NSError alloc] initWithDomain:ReceiveError code:nw_error_get_error_code(error) userInfo:@{@"nw_connection_receive_message: nw_error_get_error_domain": @(nw_error_get_error_domain(error))}];
if (strongSelf.receiveData) {
strongSelf.receiveData(nil, nserror);
}
}
});
}
- (dispatch_data_t)dispatchDataFromNsdata:(NSData *)nsdata {
if (nsdata == nil) {
return nil;
}
Byte byte[nsdata.length];
[nsdata getBytes:byte length:nsdata.length];
dispatch_data_t data = dispatch_data_create(byte, nsdata.length, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
return data;
}
- (NSData *)nsdataFromDispatchData:(dispatch_data_t)dispatchData {
if (dispatchData == nil) {
return nil;
}
const void *buffer = NULL;
size_t size = 0;
dispatch_data_t new_data_file = dispatch_data_create_map(dispatchData, &buffer, &size);
if(new_data_file) {
}
NSData *nsdata = [[NSData alloc] initWithBytes:buffer length:size];
return nsdata;
}
@end
.h文件
#import <Foundation/Foundation.h>
#import <Network/Network.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^DTLSDataHandle)(NSData *_Nullable data, NSError *_Nullable error);
typedef void (^DTLSSessionCompletedHandle)(NSError *_Nullable error);
@interface YHDTLSManager : NSObject
+(instancetype)shareinstance ;
//设置连接信息
-(void)setConnectInfoWithCertName:(NSString*)cert ;
//连接服务器
- (void)linkServerWithHost:(NSString *)host
port:(NSString *)port
queue:(dispatch_queue_t)queue;
//断开链接
- (void)disConnect ;
//发送数据
- (void)sendData:(NSData *)data
complete:(DTLSSessionCompletedHandle)complete ;
//接收数据回调
- (void)receiveData:(DTLSDataHandle)receiveHandle ;
@end
NS_ASSUME_NONNULL_END