Allow certificate based rejection of DO connection attempts.

This commit is contained in:
Richard Frith-Macdonald 2022-11-21 10:40:33 +00:00
parent a9901204e2
commit d5d8a71c79
8 changed files with 111 additions and 2 deletions

View file

@ -1,3 +1,18 @@
2022-11-21 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Foundation/NSFileHandle.h:
* Headers/GNUstepBase/GSTLS.h:
* Source/GSHTTPURLHandle.m:
* Source/GSSocketStream.m:
* Source/GSTLS.m:
* Source/NSURLProtocol.m:
* Source/externs.m:
Fixup to use strict rfc4514 for distinguished names of issuer and
owner of certificates. Add GSTLSIssuers and GSTLSOwners properties
to reject remote certificates which do not match distinguishd names
accepted. This allows encrypted DO to be configured to automatically
reject connection attempts which do not have trusted certificates.
2022-11-15 Richard Frith-Macdonald <rfm@gnu.org>
* GSSocketStream.m:

View file

@ -324,6 +324,18 @@ GS_EXPORT_CLASS
* <desc>A boolean specifying whether diagnostic debug is to be enabled
* to log information about a connection where the handshake fails.<br />
* </desc>
* <term>GSTLSIssuers</term>
* <desc>An array of distinguished names (in RFC4514 format) listing the
* permitted issuers of the remote certificate. If this is present and the
* issuer of the remote certificate is not in the array, the connection
* handshake is failed.
* </desc>
* <term>GSTLSOwners</term>
* <desc>An array of distinguished names (in RFC4514 format) listing the
* permitted owners/subjects of the remote certificate. If this is present
* and the owner/subject of the remote certificate is not in the array, the
* connection handshake is failed.
* </desc>
* <term>GSTLSPriority</term>
* <desc>A GNUTLS priority string describing the ciphers etc which may be
* used for the connection. In addition the string may be one of
@ -399,6 +411,14 @@ GS_EXPORT NSString * const GSTLSDebug;
*/
GS_EXPORT NSString * const GSTLSPriority;
/** Dictionary key for an array of issuers to use in certificate verification.
*/
GS_EXPORT NSString * const GSTLSIssuers;
/** Dictionary key for an array of owners to use in certificate verification.
*/
GS_EXPORT NSString * const GSTLSOwners;
/** Dictionary key for a list of hosts to use in certificate verification.
*/
GS_EXPORT NSString * const GSTLSRemoteHosts;

View file

@ -33,6 +33,8 @@ GS_EXPORT NSString * const GSTLSCertificateFile;
GS_EXPORT NSString * const GSTLSCertificateKeyFile;
GS_EXPORT NSString * const GSTLSCertificateKeyPassword;
GS_EXPORT NSString * const GSTLSDebug;
GS_EXPORT NSString * const GSTLSIssuers;
GS_EXPORT NSString * const GSTLSOwners;
GS_EXPORT NSString * const GSTLSPriority;
GS_EXPORT NSString * const GSTLSRemoteHosts;
GS_EXPORT NSString * const GSTLSRevokeFile;

View file

@ -1268,6 +1268,8 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
GSTLSCertificateKeyFile,
GSTLSCertificateKeyPassword,
GSTLSDebug,
GSTLSIssuers,
GSTLSOwners,
GSTLSPriority,
GSTLSRemoteHosts,
GSTLSRevokeFile,

View file

@ -482,6 +482,8 @@ static NSArray *keys = nil;
GSTLSCertificateKeyFile,
GSTLSCertificateKeyPassword,
GSTLSDebug,
GSTLSIssuers,
GSTLSOwners,
GSTLSPriority,
GSTLSRemoteHosts,
GSTLSRevokeFile,
@ -825,6 +827,8 @@ static NSArray *keys = nil;
GSTLSCertificateKeyFile,
GSTLSCertificateKeyPassword,
GSTLSDebug,
GSTLSIssuers,
GSTLSOwners,
GSTLSPriority,
GSTLSRemoteHosts,
GSTLSRevokeFile,

View file

@ -576,8 +576,12 @@ static NSMutableDictionary *certificateListCache = nil;
+ (void) certInfo: (gnutls_x509_crt_t)cert to: (NSMutableString*)str
{
#if GNUTLS_VERSION_NUMBER >= 0x030507
gnutls_datum_t dn;
#else
char dn[1024];
size_t dn_size = sizeof(dn);
#endif
char serial[40];
size_t serial_size = sizeof(serial);
time_t expiret;
@ -589,6 +593,20 @@ static NSMutableDictionary *certificateListCache = nil;
[str appendFormat: _(@"- Certificate version: #%d\n"),
gnutls_x509_crt_get_version(cert)];
#if GNUTLS_VERSION_NUMBER >= 0x030507
if (GNUTLS_E_SUCCESS == gnutls_x509_crt_get_dn3(cert, &dn, 0))
{
[str appendFormat: @"- Certificate DN: %@\n",
[NSString stringWithUTF8String: (const char*)dn.data]];
gnutls_free(dn.data);
}
if (GNUTLS_E_SUCCESS == gnutls_x509_crt_get_issuer_dn3(cert, &dn, 0))
{
[str appendFormat: _(@"- Certificate Issuer's DN: %@\n"),
[NSString stringWithUTF8String: (const char*)dn.data]];
gnutls_free(dn.data);
}
#else
dn_size = sizeof(dn) - 1;
gnutls_x509_crt_get_dn(cert, dn, &dn_size);
dn[dn_size] = '\0';
@ -600,6 +618,7 @@ static NSMutableDictionary *certificateListCache = nil;
dn[dn_size] = '\0';
[str appendFormat: _(@"- Certificate Issuer's DN: %@\n"),
[NSString stringWithUTF8String: dn]];
#endif
activet = gnutls_x509_crt_get_activation_time(cert);
[str appendFormat: _(@"- Certificate is valid since: %s"),
@ -2447,8 +2466,22 @@ retrieve_callback(gnutls_session_t session,
}
else
{
char dn[1024];
size_t dn_size;
#if GNUTLS_VERSION_NUMBER >= 0x030507
gnutls_datum_t dn;
if (GNUTLS_E_SUCCESS == gnutls_x509_crt_get_dn3(cert, &dn, 0))
{
ASSIGN(owner, [NSString stringWithUTF8String: (const char*)dn.data]);
gnutls_free(dn.data);
}
if (GNUTLS_E_SUCCESS == gnutls_x509_crt_get_issuer_dn3(cert, &dn, 0))
{
ASSIGN(issuer, [NSString stringWithUTF8String: (const char*)dn.data]);
gnutls_free(dn.data);
}
#else
char dn[1024];
size_t dn_size;
/* Get certificate owner and issuer
*/
@ -2461,6 +2494,7 @@ retrieve_callback(gnutls_session_t session,
gnutls_x509_crt_get_issuer_dn(cert, dn, &dn_size);
dn[dn_size] = '\0';
ASSIGN(issuer, [NSString stringWithUTF8String: dn]);
#endif
}
str = [opts objectForKey: GSTLSRemoteHosts];
@ -2503,6 +2537,34 @@ retrieve_callback(gnutls_session_t session,
gnutls_x509_crt_deinit(cert);
names = [opts objectForKey: GSTLSIssuers];
if ([names isKindOfClass: [NSArray class]])
{
if (nil == issuer || NO == [names containsObject: issuer])
{
str = [NSString stringWithFormat:
@"TLS verification: certificate's issuer does not match '%@'",
names];
ASSIGN(problem, str);
if (YES == debug) NSLog(@"%p %@", handle, problem);
return GNUTLS_E_CERTIFICATE_ERROR;
}
}
names = [opts objectForKey: GSTLSOwners];
if ([names isKindOfClass: [NSArray class]])
{
if (nil == owner || NO == [names containsObject: owner])
{
str = [NSString stringWithFormat:
@"TLS verification: certificate's owner does not match '%@'",
names];
ASSIGN(problem, str);
if (YES == debug) NSLog(@"%p %@", handle, problem);
return GNUTLS_E_CERTIFICATE_ERROR;
}
}
return 0; // Verified
}

View file

@ -957,6 +957,8 @@ typedef struct {
GSTLSCertificateKeyFile,
GSTLSCertificateKeyPassword,
GSTLSDebug,
GSTLSIssuers,
GSTLSOwners,
GSTLSPriority,
GSTLSRemoteHosts,
GSTLSRevokeFile,

View file

@ -363,6 +363,8 @@ GS_DECLARE NSString* const GSTLSCertificateFile = @"GSTLSCertificateFile";
GS_DECLARE NSString* const GSTLSCertificateKeyFile = @"GSTLSCertificateKeyFile";
GS_DECLARE NSString* const GSTLSCertificateKeyPassword = @"GSTLSCertificateKeyPassword";
GS_DECLARE NSString* const GSTLSDebug = @"GSTLSDebug";
GS_DECLARE NSString* const GSTLSIssuers = @"GSTLSIssuers";
GS_DECLARE NSString* const GSTLSOwners = @"GSTLSOwners";
GS_DECLARE NSString* const GSTLSPriority = @"GSTLSPriority";
GS_DECLARE NSString* const GSTLSRemoteHosts = @"GSTLSRemoteHosts";
GS_DECLARE NSString* const GSTLSRevokeFile = @"GSTLSRevokeFile";