From 1ed666cf0ba8e1416ba56ff85a5bec36e0c513b5 Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Fri, 18 Jun 2021 10:32:45 +0100 Subject: [PATCH] Security code enhancement --- ChangeLog | 9 +++++++ EcCommand.m | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ EcProcess.m | 61 +++++++++++++++++++++++++++---------------- 3 files changed, 122 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index ef94969..ea4acfe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2021-06-18 Richard Frith-Macdonald + + * EcCommand.m: + * EcProcess.m: + Pass TLS information from Command server to clients via pipe, so the + clients can use a key/certificate shared with the Command server to + encrypt communications. This avoids each client process having to + do expensive generation of a key. + 2021-06-17 Richard Frith-Macdonald * EcCommand.m: diff --git a/EcCommand.m b/EcCommand.m index 7bf4648..3dd99e3 100644 --- a/EcCommand.m +++ b/EcCommand.m @@ -29,6 +29,12 @@ #import +#import + +#if GS_USE_GNUTLS +#import +#endif + #import "EcProcess.h" #import "EcAlarm.h" #import "EcClientI.h" @@ -1425,6 +1431,75 @@ valgrindLog(NSString *name) [defs setObject: @"0" forKey: @"CoreSize"]; } +#if GS_USE_GNUTLS + /* If TLS is supported, all Distributed Object communications + * between our processes must be encrypted. Generally we can + * use shared certificate/key passed to our subprocesses on + * launch, so the subprocesses don't need to waste a lot of + * CPU (and real) time generating their own keys. + */ + if ([defs objectForKey: @"NSSocketPortOptionsForTLS"] == nil) + { + NSUserDefaults *defs = [command cmdDefaults]; + NSMutableDictionary *opts; + id opt; + + opts = [NSMutableDictionary dictionary]; + + /* If no certificate key was provided in the Command server + * configuration, we use our self-signed certificate key, + * generating it if necessary. + */ + opt = [defs objectForKey: GSTLSCertificateKeyFile]; + if (nil == opt) + { + opt = [GSTLSObject dataForTLSFile: @"self-signed-key"]; + if (nil == opt) + { + (void)[GSTLSCredentials selfSigned: YES]; + opt = [GSTLSObject + dataForTLSFile: @"self-signed-key"]; + } + } + if (opt) + { + [opts setObject: opt forKey: GSTLSCertificateKeyFile]; + } + + /* If no certificate was provided in the Command server + * configuration, we use our self-signed certificate, + * generating it if necessary. + */ + opt = [defs objectForKey: GSTLSCertificateFile]; + if (nil == opt) + { + opt = [GSTLSObject dataForTLSFile: @"self-signed-crt"]; + } + if (opt) + { + [opts setObject: opt forKey: GSTLSCertificateFile]; + } + + /* Pass on the TLS debug settings from the Command server + * configuration to the client. + */ + if ((opt = [defs objectForKey: GSTLSDebug]) != nil) + { + [opts setObject: opt forKey: GSTLSDebug]; + } + + /* Pass on the TLS priority settings from the Command server + * configuration to the client. + */ + if ((opt = [defs objectForKey: GSTLSPriority]) != nil) + { + [opts setObject: opt forKey: GSTLSPriority]; + } + + [defs setObject: opts forKey: @"NSSocketPortOptionsForTLS"]; + } +#endif + /* Now we need to make the key/value pairs into a serialised * form to be passed to the subprocess using a pipe. */ diff --git a/EcProcess.m b/EcProcess.m index ec92fe0..0d76409 100644 --- a/EcProcess.m +++ b/EcProcess.m @@ -26,30 +26,13 @@ */ -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import +#import #import #import +#if GS_USE_GNUTLS +#import +#endif #import "EcProcess.h" #import "EcLogger.h" @@ -1642,6 +1625,37 @@ findMode(NSDictionary* d, NSString* s) [cmdDefs removeVolatileDomainForName: NSArgumentDomain]; [cmdDefs setVolatileDomain: m forName: NSArgumentDomain]; } +#if GS_USE_GNUTLS + if ([NSSocketPort respondsToSelector: @selector(setOptionsForTLS:)]) + { + defs = [cmdDefs dictionaryForKey: @"NSSocketPortOptionsForTLS"]; + if (defs != nil) + { + NSMutableDictionary *opts = AUTORELEASE([defs mutableCopy]); + id o; + + /* If we were passed data rather than filenames + * we must set it up as cached data corresponding + * to well known names. + */ + o = [opts objectForKey: GSTLSCertificateKeyFile]; + if ([o isKindOfClass: [NSData class]]) + { + [GSTLSObject setData: o forTLSFile: @"self-signed-key"]; + [opts setObject: @"self-signed-key" + forKey: GSTLSCertificateKeyFile]; + } + o = [opts objectForKey: GSTLSCertificateFile]; + if ([o isKindOfClass: [NSData class]]) + { + [GSTLSObject setData: o forTLSFile: @"self-signed-crt"]; + [opts setObject: @"self-signed-crt" + forKey: GSTLSCertificateFile]; + } + [NSSocketPort setOptionsForTLS: opts]; + } + } +#endif } cmdUser = EC_EFFECTIVE_USER; @@ -3118,13 +3132,14 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval); { if (nil == ecLock) { - /* Enable encrypted DO if supported bu the base library. +#if GS_USE_GNUTLS + /* Enable encrypted DO if supported by the base library. */ if ([NSSocketPort respondsToSelector: @selector(setOptionsForTLS:)]) { [NSSocketPort setOptionsForTLS: [NSDictionary dictionary]]; } - +#endif ecLock = [NSRecursiveLock new]; dateClass = [NSDate class]; cDateClass = [NSCalendarDate class];