diff --git a/SignalServiceKit/src/Contacts/CDSSigningCertificate.m b/SignalServiceKit/src/Contacts/CDSSigningCertificate.m index e0035e22c..03398914f 100644 --- a/SignalServiceKit/src/Contacts/CDSSigningCertificate.m +++ b/SignalServiceKit/src/Contacts/CDSSigningCertificate.m @@ -69,6 +69,17 @@ NS_ASSUME_NONNULL_BEGIN return nil; } + // The leaf is always the first certificate. + NSData *_Nullable leafCertificateData = [certificateDerDatas firstObject]; + if (!leafCertificateData) { + DDLogError(@"%@ Could not extract leaf certificate data.", self.logTag); + return nil; + } + if (![self verifyDistinguishedNameOfCertificate:leafCertificateData]) { + OWSProdLogAndFail(@"%@ Leaf certificate has invalid name.", self.logTag); + return nil; + } + NSMutableArray *certificates = [NSMutableArray new]; for (NSData *certificateDerData in certificateDerDatas) { SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certificateDerData)); @@ -117,10 +128,6 @@ NS_ASSUME_NONNULL_BEGIN OWSProdLogAndFail(@"%@ Could not load DER.", self.logTag); return nil; } - if (![self verifyDistinguishedNameOfCertificate:certificateData]) { - OWSProdLogAndFail(@"%@ Certificate has invalid name.", self.logTag); - return nil; - } [pinnedCertificates addObject:(__bridge_transfer id)certificate]; } @@ -271,11 +278,9 @@ NS_ASSUME_NONNULL_BEGIN } // 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 = @{ @(SN_commonName) : // "CN" - @"Intel SGX Attestation Report Signing CA", + @"Intel SGX Attestation Report Signing", @(SN_organizationName) : // "O" @"Intel Corporation", @(SN_localityName) : // "L" @@ -285,6 +290,7 @@ NS_ASSUME_NONNULL_BEGIN @(SN_countryName) : // "C" @"US", }; + if (![properties isEqualToDictionary:expectedProperties]) { OWSFail(@"%@ Unexpected certificate properties. %@ != %@", self.logTag, expectedProperties, properties); return NO; @@ -307,7 +313,7 @@ NS_ASSUME_NONNULL_BEGIN return nil; } - X509_NAME *_Nullable subjectName = X509_get_issuer_name(certificateX509); + X509_NAME *_Nullable subjectName = X509_get_subject_name(certificateX509); if (!subjectName) { OWSFail(@"%@ could not extract subject name.", self.logTag); return nil; @@ -346,8 +352,6 @@ NS_ASSUME_NONNULL_BEGIN OWSFail(@"%@ could not parse entry name data.", self.logTag); return nil; } - DDLogVerbose(@"%@ certificate[%@]: %@", self.logTag, oid, entryString); - [DDLog flushLog]; certificateProperties[oid] = entryString; } return certificateProperties; diff --git a/SignalServiceKit/src/Contacts/ContactDiscoveryService.m b/SignalServiceKit/src/Contacts/ContactDiscoveryService.m index 2324fc0a8..20338efef 100644 --- a/SignalServiceKit/src/Contacts/ContactDiscoveryService.m +++ b/SignalServiceKit/src/Contacts/ContactDiscoveryService.m @@ -470,29 +470,6 @@ NS_ASSUME_NONNULL_BEGIN DDLogVerbose(@"%@ remote attestation complete.", self.logTag); - //+ RemoteAttestation remoteAttestation = new RemoteAttestation(requestId, keys); - //+ List addressBook = new LinkedList<>(); - //+ - //+ for (String e164number : e164numbers) { - //+ addressBook.add(e164number.substring(1)); - //+ } - //+ - //+ DiscoveryRequest request = cipher.createDiscoveryRequest(addressBook, remoteAttestation); - //+ DiscoveryResponse response = this.pushServiceSocket.getContactDiscoveryRegisteredUsers(authorization, - //request, attestationResponse.second(), mrenclave); - //+ byte[] data = cipher.getDiscoveryResponseData(response, remoteAttestation); - //+ - //+ Iterator addressBookIterator = addressBook.iterator(); - //+ List results = new LinkedList<>(); - //+ - //+ for (byte aData : data) { - //+ String candidate = addressBookIterator.next(); - //+ - //+ if (aData != 0) results.add('+' + candidate); - //+ } - //+ - //+ return results; - return result; } @@ -679,39 +656,6 @@ NS_ASSUME_NONNULL_BEGIN return decryptedData; } -// A successful (HTTP 200) response json object consists of: -// serverEphemeralPublic: (32 bytes, base64) an ephemeral curve25519 public key generated by the server -// serverStaticPublic: (32 bytes, base64) a static curve25519 public key generated by the server -// ciphertext: (variable length, base64) a "request id" to be decrypted by the client (see below for derivation -// of server_key) (ciphertext, tag) = AES-256-GCM(key=server_key, plaintext=requestId, AAD=(), iv) iv: (12 -// bytes, base64) an IV for encrypted ciphertext tag: (16 bytes, base64) a MAC for encrypted ciphertext -// quote: (variable length, base64) a binary structure from an Intel CPU containing runtime information -// about a running enclave signatureBody: (json object) a response from Intel Attestation Services attesting to -// the genuineness of the Quote signature: (base64) a signature over signatureBody, with public key in -// corresponding signing certificate certificates: (url-encoded PEM) signing certificate chain The response also -// contains HTTP session cookies which must be preserved for exactly one corresponding Contact Discovery request. -// -// After this PUT response is received, the client must: -// parse and verify fields in quote (see sample client code for parsing details): -// report_data: (64 bytes) must equal (serverStaticPublic || 0 ...) -// mrenclave: (32 bytes) must equal the request's enclaveId -// flags: (8 bytes) debug flag must be unset, as well as being validated against expected values during -// parsing all other fields must be validated against a range of expected values during parsing (as shown in example -// parsing code), but are otherwise ignored See client/src/main/java/org/whispersystems/contactdiscovery/Quote.java parse -// and verify fields in signatureBody json object: isvEnclaveQuoteBody: (base64) must equal quote -// isvEnclaveQuoteStatus: (ascii) must equal "OK" -//"GROUP_OUT_OF_DATE" may be allowed for testing only -// timestamp: (ascii) UTC timestamp formatted as "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" which must fall within the -// last 24h verify validity of signature over signatureBody using the public key contained in the leaf signing -// certificate in certificates verify signing certificates chain, with fixed trust anchors to be hard-coded in clients -// client/src/main/java/org/whispersystems/contactdiscovery/SigningCertificate.java contains X.509 PKI certificate chain -// validation code to follow -// -// After Curve25519-DH/HKDF key derivation upon the three public keys (client ephemeral private key, server ephemeral -// public key, and server static public key, described below), the client can now decrypt the ciphertext in the Remote -// Attestation Response containing a requestId to be sent along with a Contact Discovery request, and encrypt the body of -// a Contact Discovery request using client_key, bound for the enclave it performed attestation with. - @end NS_ASSUME_NONNULL_END