session-ios/Signal/src/network/tcp/tls/SecureEndPoint.m

116 lines
4.4 KiB
Objective-C

#import "SecureEndPoint.h"
#import "Util.h"
#import "DnsManager.h"
@implementation SecureEndPoint
@synthesize certificate, hostNameEndPoint;
+(SecureEndPoint*) secureEndPointForHost:(HostNameEndPoint*)host
identifiedByCertificate:(Certificate*)certificate {
require(host != nil);
require(certificate != nil);
return [self secureEndPointForHost:host
identifiedByCertificate:certificate
withOptionalMoreSpecificEndPoint:nil];
}
+(SecureEndPoint*) secureEndPointForHost:(HostNameEndPoint*)host
identifiedByCertificate:(Certificate*)certificate
withOptionalMoreSpecificEndPoint:(id<NetworkEndPoint>)optionalMoreSpecificEndPoint {
require(host != nil);
require(certificate != nil);
SecureEndPoint* s = [SecureEndPoint new];
s->hostNameEndPoint = host;
s->certificate = certificate;
s->optionalMoreSpecificEndPoint = optionalMoreSpecificEndPoint;
return s;
}
-(StreamPair *)createStreamPair {
if (optionalMoreSpecificEndPoint != nil) {
return [optionalMoreSpecificEndPoint createStreamPair];
}
return [hostNameEndPoint createStreamPair];
}
-(void) handleStreamsOpened:(StreamPair *)streamPair {
[[streamPair inputStream] setProperty:NSStreamSocketSecurityLevelNegotiatedSSL
forKey:NSStreamSocketSecurityLevelKey];
[[streamPair outputStream] setProperty:NSStreamSocketSecurityLevelNegotiatedSSL
forKey:NSStreamSocketSecurityLevelKey];
NSDictionary *settings = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
hostNameEndPoint.hostname, kCFStreamSSLPeerName,
nil];
CFReadStreamSetProperty((CFReadStreamRef)[streamPair inputStream],
kCFStreamPropertySSLSettings,
(CFTypeRef)settings);
CFWriteStreamSetProperty((CFWriteStreamRef)[streamPair outputStream],
kCFStreamPropertySSLSettings,
(CFTypeRef)settings);
}
-(void) authenticateSslStream:(StreamPair*)streamPair {
SecTrustRef trust = (__bridge SecTrustRef)[[streamPair outputStream] propertyForKey:(__bridge NSString*)kCFStreamPropertySSLPeerTrust];
checkOperation(SecTrustGetCertificateCount(trust) > 0);
[certificate setAsAnchorForTrust:trust];
SecTrustResultType trustResult = kSecTrustResultInvalid;
OSStatus evalResult = SecTrustEvaluate(trust, &trustResult);
checkSecurityOperation(evalResult == 0,
([NSString stringWithFormat:@"NetworkStream: SecTrustEvaluate failed with error code: %d", (int)evalResult]));
checkSecurityOperation(trustResult != kSecTrustResultProceed,
@"Unexpected: User approved certificate somehow? Failing safe.");
checkSecurityOperation(trustResult == kSecTrustResultUnspecified,
([NSString stringWithFormat:@"NetworkStream: SecTrustEvaluate returned bad result: %u.", trustResult]));
}
-(Future *)asyncHandleStreamsConnected:(StreamPair *)streamPair {
require(streamPair != nil);
@try {
[self authenticateSslStream:streamPair];
return [Future finished:@YES];
} @catch (OperationFailed* ex) {
return [Future failed:ex];
}
}
-(Future*) asyncResolveToSpecificEndPointsUnlessCancelled:(id<CancelToken>)unlessCancelledToken {
Future* futureResolvedLocations = [hostNameEndPoint asyncResolveToSpecificEndPointsUnlessCancelled:unlessCancelledToken];
return [futureResolvedLocations then:^(NSArray* specificEndPoints) {
return [specificEndPoints map:^(id<NetworkEndPoint> specificEndPoint) {
return [SecureEndPoint secureEndPointForHost:hostNameEndPoint
identifiedByCertificate:certificate
withOptionalMoreSpecificEndPoint:specificEndPoint];
}];
}];
}
-(NSString*) description {
if (optionalMoreSpecificEndPoint == nil) {
return [NSString stringWithFormat:@"Host: %@, Certificate: %@)",
hostNameEndPoint,
certificate];
}
return [NSString stringWithFormat:@"Host: %@ (resolved to %@), Certificate: %@)",
hostNameEndPoint,
optionalMoreSpecificEndPoint,
certificate];
}
@end