Remove SMK{Sender,Server}Certificate in favor of SignalClient

This commit is contained in:
Jordan Rose 2020-12-02 15:53:48 -08:00
parent 276a3cc873
commit 902ed32a34
9 changed files with 47 additions and 263 deletions

View File

@ -5,16 +5,18 @@
import Foundation
import Curve25519Kit
import SignalCoreKit
import SignalClient
public enum SMKCertificateError: Error {
case invalidCertificate(description: String)
}
@objc public protocol SMKCertificateValidator: class {
@objc(SMKCertificateValidator)
public protocol SMKCertificateValidatorObjC {}
@objc func throwswrapped_validate(senderCertificate: SMKSenderCertificate, validationTime: UInt64) throws
@objc func throwswrapped_validate(serverCertificate: SMKServerCertificate) throws
public protocol SMKCertificateValidator: SMKCertificateValidatorObjC {
func throwswrapped_validate(senderCertificate: SenderCertificate, validationTime: UInt64) throws
func throwswrapped_validate(serverCertificate: ServerCertificate) throws
}
// See: https://github.com/signalapp/libsignal-metadata-java/blob/master/java/src/main/java/org/signal/libsignal/metadata/certificate/CertificateValidator.java
@ -38,10 +40,10 @@ public enum SMKCertificateError: Error {
}
// public void validate(SenderCertificate certificate, long validationTime) throws InvalidCertificateException {
@objc public func throwswrapped_validate(senderCertificate: SMKSenderCertificate, validationTime: UInt64) throws {
public func throwswrapped_validate(senderCertificate: SenderCertificate, validationTime: UInt64) throws {
// try {
// ServerCertificate serverCertificate = certificate.getSigner();
let serverCertificate = senderCertificate.signer
let serverCertificate = try! senderCertificate.serverCertificate()
// validate(serverCertificate);
try throwswrapped_validate(serverCertificate: serverCertificate)
@ -49,8 +51,8 @@ public enum SMKCertificateError: Error {
// if (!Curve.verifySignature(serverCertificate.getKey(), certificate.getCertificate(), certificate.getSignature())) {
// throw new InvalidCertificateException("Signature failed");
// }
guard try serverCertificate.key.verifySignature(message: senderCertificate.certificateData,
signature: senderCertificate.signatureData) else {
guard try serverCertificate.publicKey().verifySignature(message: senderCertificate.certificateBytes(),
signature: senderCertificate.signatureBytes()) else {
Logger.error("Sender certificate signature verification failed.")
let error = SMKCertificateError.invalidCertificate(description: "Sender certificate signature verification failed.")
Logger.error("\(error)")
@ -60,7 +62,7 @@ public enum SMKCertificateError: Error {
// if (validationTime > certificate.getExpiration()) {
// throw new InvalidCertificateException("Certificate is expired");
// }
guard validationTime <= senderCertificate.expirationTimestamp else {
guard validationTime <= (try! senderCertificate.expiration()) else {
let error = SMKCertificateError.invalidCertificate(description: "Certficate is expired.")
Logger.error("\(error)")
throw error
@ -72,13 +74,13 @@ public enum SMKCertificateError: Error {
}
// void validate(ServerCertificate certificate) throws InvalidCertificateException {
@objc public func throwswrapped_validate(serverCertificate: SMKServerCertificate) throws {
public func throwswrapped_validate(serverCertificate: ServerCertificate) throws {
// try {
// if (!Curve.verifySignature(trustRoot, certificate.getCertificate(), certificate.getSignature())) {
// throw new InvalidCertificateException("Signature failed");
// }
guard try trustRoot.key.verifySignature(message: serverCertificate.certificateData,
signature: serverCertificate.signatureData) else {
guard try trustRoot.key.verifySignature(message: serverCertificate.certificateBytes(),
signature: serverCertificate.signatureBytes()) else {
let error = SMKCertificateError.invalidCertificate(description: "Server certificate signature verification failed.")
Logger.error("\(error)")
throw error
@ -87,7 +89,7 @@ public enum SMKCertificateError: Error {
// if (REVOKED.contains(certificate.getKeyId())) {
// throw new InvalidCertificateException("Server certificate has been revoked");
// }
guard !SMKCertificateDefaultValidator.kRevokedCertificateIds.contains(serverCertificate.keyId) else {
guard !SMKCertificateDefaultValidator.kRevokedCertificateIds.contains(try! serverCertificate.keyId()) else {
let error = SMKCertificateError.invalidCertificate(description: "Revoked certificate.")
Logger.error("\(error)")
throw error

View File

@ -199,7 +199,7 @@ fileprivate extension SMKMessageType {
public func throwswrapped_encryptMessage(recipient: SMKAddress,
deviceId: Int32,
paddedPlaintext: Data,
senderCertificate: SMKSenderCertificate,
senderCertificate: SenderCertificate,
protocolContext: SPKProtocolWriteContext?) throws -> Data {
guard deviceId > 0 else {
throw SMKError.assertionError(description: "\(SMKSecretSessionCipher.logTag) invalid deviceId")
@ -210,7 +210,7 @@ fileprivate extension SMKMessageType {
var protocolContextAsPtr = protocolContext
return Data(try sealedSenderEncrypt(message: paddedPlaintext,
for: recipientAddress,
from: SenderCertificate(senderCertificate.serializedData),
from: senderCertificate,
sessionStore: sessionStore,
identityStore: identityStore,
context: &protocolContextAsPtr))
@ -219,7 +219,7 @@ fileprivate extension SMKMessageType {
// public Pair<SignalProtocolAddress, byte[]> decrypt(CertificateValidator validator, byte[] ciphertext, long timestamp)
// throws InvalidMetadataMessageException, InvalidMetadataVersionException, ProtocolInvalidMessageException, ProtocolInvalidKeyException, ProtocolNoSessionException, ProtocolLegacyMessageException, ProtocolInvalidVersionException, ProtocolDuplicateMessageException, ProtocolInvalidKeyIdException, ProtocolUntrustedIdentityException
@objc
public func throwswrapped_decryptMessage(certificateValidator: SMKCertificateValidator,
public func throwswrapped_decryptMessage(certificateValidator: SMKCertificateValidatorObjC,
cipherTextData: Data,
timestamp: UInt64,
localE164: String?,
@ -244,12 +244,11 @@ fileprivate extension SMKMessageType {
throw SMKSecretSessionCipherError.selfSentMessage
}
// validator.validate(content.getSenderCertificate(), timestamp);
do {
let certificateData = Data(try! messageContent.senderCertificate().serialize())
// validator.validate(content.getSenderCertificate(), timestamp);
let certificateValidator = certificateValidator as! SMKCertificateValidator
try certificateValidator.throwswrapped_validate(
senderCertificate: try! SMKSenderCertificate(serializedData: certificateData),
senderCertificate: try messageContent.senderCertificate(),
validationTime: timestamp)
let paddedMessagePlaintext = try throwswrapped_decrypt(messageContent: messageContent,

View File

@ -1,74 +0,0 @@
//
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import Foundation
import SignalClient
// See:
// https://github.com/signalapp/libsignal-metadata-java/blob/cac0dde9de416a192e64a8940503982820870090/java/src/main/java/org/signal/libsignal/metadata/certificate/SenderCertificate.java
@objc
public class SMKSenderCertificate: NSObject {
// private final ServerCertificate signer;
// private final ECPublicKey key;
// private final int senderDeviceId;
// private final String sender;
// private final long expiration;
public let signer: SMKServerCertificate
public let key: PublicKey
public let senderDeviceId: UInt32
public let senderAddress: SMKAddress
public let expirationTimestamp: UInt64
// private final byte[] serialized;
// private final byte[] certificate;
// private final byte[] signature;
public let serializedData: Data
public let certificateData: Data
public let signatureData: Data
public init(serializedData: Data) throws {
// SignalProtos.SenderCertificate wrapper = SignalProtos.SenderCertificate.parseFrom(serialized);
//
// if (!wrapper.hasSignature() || !wrapper.hasCertificate()) {
// throw new InvalidCertificateException("Missing fields");
// }
let wrapperProto = try SMKProtoSenderCertificate.parseData(serializedData)
// SignalProtos.SenderCertificate.Certificate certificate = SignalProtos.SenderCertificate.Certificate.parseFrom(wrapper.getCertificate());
//
// if (!certificate.hasSigner() || !certificate.hasIdentityKey() || !certificate.hasSenderDevice() || !certificate.hasExpires() || !certificate.hasSender()) {
// throw new InvalidCertificateException("Missing fields");
// }
let certificateProto = try SMKProtoSenderCertificateCertificate.parseData(wrapperProto.certificate)
// this.signer = new ServerCertificate(certificate.getSigner().toByteArray());
// this.key = Curve.decodePoint(certificate.getIdentityKey().toByteArray(), 0);
self.signer = try SMKServerCertificate(serializedData: certificateProto.signer.serializedData())
self.key = try PublicKey(certificateProto.identityKey)
// this.sender = certificate.getSender();
let senderE164 = certificateProto.senderE164
let senderUuid: UUID?
if let senderUuidString = certificateProto.senderUuid {
senderUuid = UUID(uuidString: senderUuidString)
assert(senderUuid != nil)
} else {
senderUuid = nil
}
self.senderAddress = try SMKAddress(uuid: senderUuid, e164: senderE164)
// this.senderDeviceId = certificate.getSenderDevice();
// this.expiration = certificate.getExpires();
self.senderDeviceId = certificateProto.senderDevice
self.expirationTimestamp = certificateProto.expires
// this.serialized = serialized;
// this.certificate = wrapper.getCertificate().toByteArray();
// this.signature = wrapper.getSignature().toByteArray();
self.serializedData = serializedData
self.certificateData = wrapperProto.certificate
self.signatureData = wrapperProto.signature
}
}

View File

@ -1,54 +0,0 @@
//
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import Foundation
import SignalClient
// See:
// https://github.com/signalapp/libsignal-metadata-java/blob/cac0dde9de416a192e64a8940503982820870090/java/src/main/java/org/signal/libsignal/metadata/certificate/ServerCertificate.java
@objc
public class SMKServerCertificate: NSObject {
// private final int keyId;
// private final ECPublicKey key;
public let keyId: UInt32
public let key: PublicKey
// private final byte[] serialized;
// private final byte[] certificate;
// private final byte[] signature;
public let serializedData: Data
public let certificateData: Data
public let signatureData: Data
// public ServerCertificate(byte[] serialized) throws InvalidCertificateException {
public init(serializedData: Data) throws {
// SignalProtos.ServerCertificate wrapper = SignalProtos.ServerCertificate.parseFrom(serialized);
// if (!wrapper.hasCertificate() || !wrapper.hasSignature()) {
// throw new InvalidCertificateException("Missing fields");
// }
let wrapperProto = try SMKProtoServerCertificate.parseData(serializedData)
// SignalProtos.ServerCertificate.Certificate certificate = // SignalProtos.ServerCertificate.Certificate.parseFrom(wrapper.getCertificate());
//
// if (!certificate.hasId() || !certificate.hasKey()) {
// throw new InvalidCertificateException("Missing fields");
// }
let certificateProto = try SMKProtoServerCertificateCertificate.parseData(wrapperProto.certificate)
// this.keyId = certificate.getId();
self.keyId = certificateProto.id
// this.key = Curve.decodePoint(certificate.getKey().toByteArray(), 0);
self.key = try PublicKey(certificateProto.key)
// this.serialized = serialized;
self.serializedData = serializedData
// this.certificate = wrapper.getCertificate().toByteArray();
// this.signature = wrapper.getSignature().toByteArray();
self.certificateData = wrapperProto.certificate
self.signatureData = wrapperProto.signature
}
}

View File

@ -37,31 +37,6 @@ class SMKTest: XCTestCase {
XCTAssertEqual(key, parsedKey)
}
func testUDServerCertificate() {
let serializedData = try! buildServerCertificateProto().serializedData()
let serverCertificate = try! SMKServerCertificate(serializedData: serializedData)
let roundTripped = try! SMKServerCertificate(serializedData: serverCertificate.serializedData)
XCTAssertEqual(serverCertificate.keyId, roundTripped.keyId)
XCTAssertEqual(serverCertificate.key, roundTripped.key)
XCTAssertEqual(serverCertificate.signatureData, roundTripped.signatureData)
}
func testUDSenderCertificate() {
let serializedData = try! buildSenderCertificateProto().serializedData()
let senderCertificate = try! SMKSenderCertificate(serializedData: serializedData)
let roundTripped = try! SMKSenderCertificate(serializedData: senderCertificate.serializedData)
XCTAssertEqual(senderCertificate.signer.serializedData, roundTripped.signer.serializedData)
XCTAssertEqual(senderCertificate.key, roundTripped.key)
XCTAssertEqual(senderCertificate.senderDeviceId, roundTripped.senderDeviceId)
XCTAssertEqual(senderCertificate.senderAddress, roundTripped.senderAddress)
XCTAssertEqual(senderCertificate.expirationTimestamp, roundTripped.expirationTimestamp)
XCTAssertEqual(senderCertificate.signatureData, roundTripped.signatureData)
}
func testUDSessionCipher_encrypt() {
// NOTE: We use MockClient to ensure consistency between of our session state.
let aliceMockClient = MockClient(address: .e164("+13213214321"), deviceId: 456, registrationId: 123)
@ -75,7 +50,7 @@ class SMKTest: XCTestCase {
let plaintext = Randomness.generateRandomBytes(200)
let paddedPlaintext = (plaintext as NSData).paddedMessageBody()
let senderCertificate = try! SMKSenderCertificate(serializedData: try! buildSenderCertificateProto(senderClient: aliceMockClient).serializedData())
let senderCertificate = try! SenderCertificate(buildSenderCertificateProto(senderClient: aliceMockClient).serializedData())
let encryptedMessage = try! aliceToBobCipher.throwswrapped_encryptMessage(recipient: bobMockClient.address,
deviceId: bobMockClient.deviceId,
paddedPlaintext: paddedPlaintext,

View File

@ -260,73 +260,18 @@ class SMKSecretSessionCipherTest: XCTestCase {
senderAddress: SMKAddress,
senderDeviceId: UInt32,
identityKey: PublicKey,
expirationTimestamp: UInt64) -> SMKSenderCertificate {
// ECKeyPair serverKey = Curve.generateKeyPair();
expirationTimestamp: UInt64) -> SenderCertificate {
let serverKey = try! IdentityKeyPair.generate()
// byte[] serverCertificateBytes = SignalProtos.ServerCertificate.Certificate.newBuilder()
// .setId(1)
// .setKey(ByteString.copyFrom(serverKey.getPublicKey().serialize()))
// .build()
// .toByteArray();
let serverCertificateBuilder = SMKProtoServerCertificateCertificate.builder(
id: 1,
key: Data(try! serverKey.publicKey.serialize()))
let serverCertificateData = try! serverCertificateBuilder.build().serializedData()
// byte[] serverCertificateSignature = Curve.calculateSignature(trustRoot.getPrivateKey(), serverCertificateBytes);
let serverCertificateSignature = try! trustRoot.privateKey.generateSignature(message: serverCertificateData)
// ServerCertificate serverCertificate = new ServerCertificate(SignalProtos.ServerCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(serverCertificateBytes))
// .setSignature(ByteString.copyFrom(serverCertificateSignature))
// .build()
// .toByteArray());
let serverCertificate: SMKServerCertificate = {
let builder = SMKProtoServerCertificate.builder(certificate: serverCertificateData,
signature: Data(serverCertificateSignature))
return try! SMKServerCertificate(serializedData: try! builder.buildSerializedData())
}()
// byte[] senderCertificateBytes = SignalProtos.SenderCertificate.Certificate.newBuilder()
// .setSender(sender)
// .setSenderDevice(deviceId)
// .setIdentityKey(ByteString.copyFrom(identityKey.serialize()))
// .setExpires(expires)
// .setSigner(SignalProtos.ServerCertificate.parseFrom(serverCertificate.getSerialized()))
// .build()
// .toByteArray();
let senderCertificateData: Data = {
let signer = try! SMKProtoServerCertificate.parseData(serverCertificate.serializedData)
let builder = SMKProtoSenderCertificateCertificate.builder(senderDevice: senderDeviceId,
expires: expirationTimestamp,
identityKey: Data(try! identityKey.serialize()),
signer: signer)
if let e164 = senderAddress.e164 {
builder.setSenderE164(e164)
}
if let uuid = senderAddress.uuid {
builder.setSenderUuid(uuid.uuidString)
}
return try! builder.buildSerializedData()
}()
// byte[] senderCertificateSignature = Curve.calculateSignature(serverKey.getPrivateKey(), senderCertificateBytes);
let senderCertificateSignature = try! serverKey.privateKey.generateSignature(message: senderCertificateData)
// return new SenderCertificate(SignalProtos.SenderCertificate.newBuilder()
// .setCertificate(ByteString.copyFrom(senderCertificateBytes))
// .setSignature(ByteString.copyFrom(senderCertificateSignature))
// .build()
// .toByteArray());
return {
let builder = SMKProtoSenderCertificate.builder(certificate: senderCertificateData,
signature: Data(senderCertificateSignature))
return try! SMKSenderCertificate(serializedData: try! builder.buildSerializedData())
}()
let serverCertificate = try! ServerCertificate(keyId: 1,
publicKey: serverKey.publicKey,
trustRoot: trustRoot.privateKey)
return try! SenderCertificate(sender: SealedSenderAddress(e164: senderAddress.e164,
uuidString: senderAddress.uuid?.uuidString,
deviceId: senderDeviceId),
publicKey: identityKey,
expiration: expirationTimestamp,
signerCertificate: serverCertificate,
signerKey: serverKey.privateKey)
}
// private void initializeSessions(TestInMemorySignalProtocolStore aliceStore, TestInMemorySignalProtocolStore bobStore)

View File

@ -5,6 +5,7 @@
import XCTest
import SignalMetadataKit
import Curve25519Kit
import SignalClient
// See: https://github.com/signalapp/libsignal-metadata-java/blob/master/tests/src/test/java/org/signal/libsignal/metadata/certificate/SenderCertificateTest.java
//
@ -48,7 +49,7 @@ class SMKSenderCertificateTest: XCTestCase {
let senderCertificateData = try! SMKProtoSenderCertificate.builder(certificate: certificateData,
signature: certificateSignature)
.buildSerializedData()
let senderCertificate = try! SMKSenderCertificate(serializedData: senderCertificateData)
let senderCertificate = try! SenderCertificate(senderCertificateData)
// new CertificateValidator(trustRoot.getPublicKey()).validate(senderCertificate, 31336);
let certificateValidator = try! SMKCertificateDefaultValidator(trustRoot: trustRoot.ecPublicKey())
@ -90,7 +91,7 @@ class SMKSenderCertificateTest: XCTestCase {
let senderCertificateData = try! SMKProtoSenderCertificate.builder(certificate: certificateData,
signature: certificateSignature)
.buildSerializedData()
let senderCertificate = try! SMKSenderCertificate(serializedData: senderCertificateData)
let senderCertificate = try! SenderCertificate(senderCertificateData)
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(senderCertificate, 31338);
@ -148,7 +149,7 @@ class SMKSenderCertificateTest: XCTestCase {
// .toByteArray());
let serializedData = try! SMKProtoSenderCertificate.builder(certificate: certificateData,
signature: badSignature).buildSerializedData()
let senderCertificate = try! SMKSenderCertificate(serializedData: serializedData)
let senderCertificate = try! SenderCertificate(serializedData)
// try {
// new CertificateValidator(trustRoot.getPublicKey()).validate(senderCertificate, 31336);
@ -216,7 +217,7 @@ class SMKSenderCertificateTest: XCTestCase {
signature: certificateSignature)
.buildSerializedData()
let senderCertificate = try! SMKSenderCertificate(serializedData: senderCertificateData)
let senderCertificate = try! SenderCertificate(senderCertificateData)
let stableTrustRoot = try! ECPublicKey(serializedKeyData: trustRootPublicKeyData)

View File

@ -73,7 +73,7 @@ class SMKServerCertificateTest: XCTestCase {
.buildSerializedData()
// new CertificateValidator(trustRoot.getPublicKey()).validate(new ServerCertificate(serialized));
let serverCertificate = try! SMKServerCertificate(serializedData: serializedData)
let serverCertificate = try! ServerCertificate(serializedData)
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
try! certificateValidator.throwswrapped_validate(serverCertificate: serverCertificate)
}
@ -126,7 +126,7 @@ class SMKServerCertificateTest: XCTestCase {
// } catch (InvalidCertificateException e) {
// // good
// }
let serverCertificate = try! SMKServerCertificate(serializedData: serializedData)
let serverCertificate = try! ServerCertificate(serializedData)
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
XCTAssertThrowsError(try certificateValidator.throwswrapped_validate(serverCertificate: serverCertificate))
}
@ -159,22 +159,12 @@ class SMKServerCertificateTest: XCTestCase {
// } catch (InvalidCertificateException e) {
// // good
// }
let serverCertificate: SMKServerCertificate
let serverCertificate: ServerCertificate
do {
serverCertificate = try SMKServerCertificate(serializedData: serializedData)
} catch BinaryDecodingError.malformedProtobuf {
// Some bad certificates will fail to parse.
continue
} catch BinaryDecodingError.truncated {
// Some bad certificates will fail to parse.
continue
} catch SMKProtoError.invalidProtobuf {
// Some bad certificates will fail to parse.
continue
} catch SMKError.assertionError {
// Some bad certificates will fail to parse.
continue
} catch SignalError.invalidKey {
serverCertificate = try ServerCertificate(serializedData)
} catch SignalError.protobufError,
SignalError.invalidMessage,
SignalError.invalidKey {
// Some bad certificates will fail to parse.
continue
} catch {

View File

@ -8,11 +8,11 @@ import SignalClient
class MockCertificateValidator: NSObject, SMKCertificateValidator {
@objc public func throwswrapped_validate(senderCertificate: SMKSenderCertificate, validationTime: UInt64) throws {
public func throwswrapped_validate(senderCertificate: SenderCertificate, validationTime: UInt64) throws {
// Do not throw
}
@objc public func throwswrapped_validate(serverCertificate: SMKServerCertificate) throws {
public func throwswrapped_validate(serverCertificate: ServerCertificate) throws {
// Do not throw
}
}