aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/objective-c/GRPCClient/private/GRPCHost.m
diff options
context:
space:
mode:
authorGravatar Paul Querna <pquerna@apache.org>2016-03-03 23:09:06 -0800
committerGravatar Paul Querna <pquerna@apache.org>2016-04-29 08:19:44 -0700
commit40f11aa5dc706892d1a5b848ac9f9d85a0cf12cd (patch)
treecfd4c3586988638025b311041ec3bc13405238d3 /src/objective-c/GRPCClient/private/GRPCHost.m
parent5e6cc81842184386271e3429b9958477ad2899ba (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.m92
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