diff options
author | Paul Querna <pquerna@apache.org> | 2016-03-03 23:09:06 -0800 |
---|---|---|
committer | Paul Querna <pquerna@apache.org> | 2016-04-29 08:19:44 -0700 |
commit | 40f11aa5dc706892d1a5b848ac9f9d85a0cf12cd (patch) | |
tree | cfd4c3586988638025b311041ec3bc13405238d3 /src/objective-c/GRPCClient/private/GRPCHost.m | |
parent | 5e6cc81842184386271e3429b9958477ad2899ba (diff) |
Objective-C: Add ChannelCredentials to gRPC Call.
GRPCHost now has a property channelCreds which is used when creating a GRPCChannel.
Diffstat (limited to 'src/objective-c/GRPCClient/private/GRPCHost.m')
-rw-r--r-- | src/objective-c/GRPCClient/private/GRPCHost.m | 92 |
1 files changed, 86 insertions, 6 deletions
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m index 739d808c53..43166cbb52 100644 --- a/src/objective-c/GRPCClient/private/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -34,6 +34,7 @@ #import "GRPCHost.h" #include <grpc/grpc.h> +#include <grpc/grpc_security.h> #import <GRPCClient/GRPCCall.h> #import <GRPCClient/GRPCCall+ChannelArg.h> @@ -56,6 +57,12 @@ NS_ASSUME_NONNULL_BEGIN return [[self alloc] initWithAddress:address]; } +- (void)dealloc { + if (_channelCreds != nil) { + grpc_channel_credentials_release(_channelCreds); + } +} + // Default initializer. - (nullable instancetype)initWithAddress:(NSString *)address { if (!address) { @@ -105,6 +112,75 @@ NS_ASSUME_NONNULL_BEGIN return [channel unmanagedCallWithPath:path completionQueue:queue]; } +- (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts + withPrivateKey:(nullable NSString *)pemPrivateKey + withCertChain:(nullable NSString *)pemCertChain + error:(NSError **)errorPtr { + static NSData *kDefaultRootsASCII; + static NSError *kDefaultRootsError; + static dispatch_once_t loading; + dispatch_once(&loading, ^{ + NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem + // Do not use NSBundle.mainBundle, as it's nil for tests of library projects. + NSBundle *bundle = [NSBundle bundleForClass:self.class]; + NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"]; + NSError *error; + // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the + // issuer). Load them as UTF8 and produce an ASCII equivalent. + NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path + encoding:NSUTF8StringEncoding + error:&error]; + if (contentInUTF8 == nil) { + kDefaultRootsError = error; + return; + } + kDefaultRootsASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding + allowLossyConversion:YES]; + }); + + NSData *rootsASCII; + if (pemRootCerts != nil) { + rootsASCII = [pemRootCerts dataUsingEncoding:NSASCIIStringEncoding + allowLossyConversion:YES]; + } else { + if (kDefaultRootsASCII == nil) { + if (errorPtr) { + *errorPtr = kDefaultRootsError; + } + NSAssert(kDefaultRootsASCII, @"Could not read gRPCCertificates.bundle/roots.pem. This file, " + "with the root certificates, is needed to establish secure (TLS) connections. " + "Because the file is distributed with the gRPC library, this error is usually a sign " + "that the library wasn't configured correctly for your project. Error: %@", + kDefaultRootsError); + return NO; + } + rootsASCII = kDefaultRootsASCII; + } + + grpc_channel_credentials *creds; + if (pemPrivateKey == nil && pemCertChain == nil) { + creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL); + } else { + grpc_ssl_pem_key_cert_pair key_cert_pair; + NSData *privateKeyASCII = [pemPrivateKey dataUsingEncoding:NSASCIIStringEncoding + allowLossyConversion:YES]; + NSData *certChainASCII = [pemCertChain dataUsingEncoding:NSASCIIStringEncoding + allowLossyConversion:YES]; + key_cert_pair.private_key = privateKeyASCII.bytes; + key_cert_pair.cert_chain = certChainASCII.bytes; + creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL); + } + + @synchronized(self) { + if (_channelCreds != nil) { + grpc_channel_credentials_release(_channelCreds); + } + _channelCreds = creds; + } + + return YES; +} + - (NSDictionary *)channelArgs { NSMutableDictionary *args = [NSMutableDictionary dictionary]; @@ -125,9 +201,16 @@ NS_ASSUME_NONNULL_BEGIN - (GRPCChannel *)newChannel { NSDictionary *args = [self channelArgs]; if (_secure) { - return [GRPCChannel secureChannelWithHost:_address - pathToCertificates:_pathToCertificates - channelArgs:args]; + GRPCChannel *channel; + @synchronized(self) { + if (_channelCreds == nil) { + [self setTLSPEMRootCerts:nil withPrivateKey:nil withCertChain:nil error:nil]; + } + channel = [GRPCChannel secureChannelWithHost:_address + credentials:_channelCreds + channelArgs:args]; + } + return channel; } else { return [GRPCChannel insecureChannelWithHost:_address channelArgs:args]; } @@ -145,9 +228,6 @@ NS_ASSUME_NONNULL_BEGIN } } -// TODO(jcanizales): Don't let set |secure| to |NO| if |pathToCertificates| or |hostNameOverride| -// have been set. Don't let set either of the latter if |secure| has been set to |NO|. - @end NS_ASSUME_NONNULL_END |