From aef881cad3614f542c1fe96bea96f91ce8bc4160 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 25 Jul 2018 17:38:26 -0400 Subject: [PATCH] Verify certificate subject. --- .../src/Contacts/CDSSigningCertificate.m | 94 +++++++++++++++++-- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/SignalServiceKit/src/Contacts/CDSSigningCertificate.m b/SignalServiceKit/src/Contacts/CDSSigningCertificate.m index cfe7a2abf..cc3bce932 100644 --- a/SignalServiceKit/src/Contacts/CDSSigningCertificate.m +++ b/SignalServiceKit/src/Contacts/CDSSigningCertificate.m @@ -7,6 +7,7 @@ #import "NSData+Base64.h" #import "NSData+OWS.h" #import +#import NS_ASSUME_NONNULL_BEGIN @@ -116,7 +117,7 @@ NS_ASSUME_NONNULL_BEGIN OWSProdLogAndFail(@"%@ Could not load DER.", self.logTag); return nil; } - if (![self verifyDistinguishedName:certificate]) { + if (![self verifyDistinguishedName:certificate certificateData:certificateData]) { OWSProdLogAndFail(@"%@ Certificate has invalid name.", self.logTag); return nil; } @@ -257,18 +258,97 @@ NS_ASSUME_NONNULL_BEGIN return YES; } -+ (BOOL)verifyDistinguishedName:(SecCertificateRef)certificate ++ (BOOL)verifyDistinguishedName:(SecCertificateRef)certificate certificateData:(NSData *)certificateData { OWSAssert(certificate); + OWSAssert(certificateData); - NSString *expectedDistinguishedName - = @"CN=Intel SGX Attestation Report Signing,O=Intel Corporation,L=Santa Clara,ST=CA,C=US"; - - // The Security framework doesn't offer access to certificate details like the name. - // TODO: Use OpenSSL to extract the name. + // The Security framework doesn't offer access to certificate properties + // with API available on iOS 9. We use OpenSSL to extract the name. + NSDictionary *_Nullable properties = [self propertiesForCertificate:certificateData]; + if (!properties) { + OWSFail(@"%@ Could not retrieve certificate properties.", self.logTag); + return NO; + } + // NSString *expectedDistinguishedName + // = @"CN=Intel SGX Attestation Report Signing,O=Intel Corporation,L=Santa Clara,ST=CA,C=US"; + // NOTE: "Intel SGX Attestation Report Signing CA" is not the same as: + // "Intel SGX Attestation Report Signing" + NSDictionary *expectedProperties = @{ + @"CN" : @"Intel SGX Attestation Report Signing CA", + @"O" : @"Intel Corporation", + @"L" : @"Santa Clara", + @"ST" : @"CA", + @"C" : @"US", + }; + if (![properties isEqualToDictionary:expectedProperties]) { + OWSFail(@"%@ Unexpected certificate properties. %@ != %@", self.logTag, expectedProperties, properties); + return NO; + } return YES; } ++ (nullable NSDictionary *)propertiesForCertificate:(NSData *)certificateData +{ + OWSAssert(certificateData); + + if (certificateData.length >= UINT32_MAX) { + OWSFail(@"%@ certificate data is too long.", self.logTag); + return nil; + } + const unsigned char *certificateDataBytes = (const unsigned char *)[certificateData bytes]; + X509 *_Nullable certificateX509 = d2i_X509(NULL, &certificateDataBytes, [certificateData length]); + if (!certificateX509) { + OWSFail(@"%@ could not parse certificate.", self.logTag); + return nil; + } + + X509_NAME *_Nullable subjectName = X509_get_issuer_name(certificateX509); + if (!subjectName) { + OWSFail(@"%@ could not extract subject name.", self.logTag); + return nil; + } + + NSMutableDictionary *certificateProperties = [NSMutableDictionary new]; + for (NSString *oid in @[ + @(SN_commonName), // "CN" + @(SN_organizationName), // "O" + @(SN_localityName), // "L" + @(SN_stateOrProvinceName), // "ST" + @(SN_countryName), // "C" + ]) { + int nid = OBJ_txt2nid(oid.UTF8String); + int index = X509_NAME_get_index_by_NID(subjectName, nid, -1); + + X509_NAME_ENTRY *_Nullable entry = X509_NAME_get_entry(subjectName, index); + if (!entry) { + OWSFail(@"%@ could not extract entry.", self.logTag); + return nil; + } + + ASN1_STRING *_Nullable entryData = X509_NAME_ENTRY_get_data(entry); + if (!entryData) { + OWSFail(@"%@ could not extract entry data.", self.logTag); + return nil; + } + + unsigned char *entryName = ASN1_STRING_data(entryData); + if (entryName == NULL) { + OWSFail(@"%@ could not extract entry string.", self.logTag); + return nil; + } + NSString *_Nullable entryString = [NSString stringWithUTF8String:(char *)entryName]; + if (!entryString) { + OWSFail(@"%@ could not parse entry name data.", self.logTag); + return nil; + } + DDLogVerbose(@"%@ certificate[%@]: %@", self.logTag, oid, entryString); + [DDLog flushLog]; + certificateProperties[oid] = entryString; + } + return certificateProperties; +} + @end NS_ASSUME_NONNULL_END