Skip to content
31 changes: 31 additions & 0 deletions Sources/X509/CertificatePublicKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,37 @@ extension Certificate.PublicKey {
return ed25519.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}
}

/// Confirms that `signature` is a valid signature for `bytes`, created by the
/// private key associated with this public key.
///
/// This function accepts raw signature bytes (such as those from a TLS handshake)
/// and validates them directly against the data.
///
/// - Parameters:
/// - signature: The raw signature bytes to validate.
/// - bytes: The data that was signed.
/// - signatureAlgorithm: The algorithm used to create the signature.
/// - Returns: Whether the signature was produced by signing `bytes` with the private key corresponding to this public key.
@inlinable
public func isValidSignature<SignatureBytes: DataProtocol, Bytes: DataProtocol>(
_ signature: SignatureBytes,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
switch self.backing {
case .p256(let p256):
return p256.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm)
case .p384(let p384):
return p384.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm)
case .p521(let p521):
return p521.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm)
case .rsa(let rsa):
return rsa.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm)
case .ed25519(let ed25519):
return ed25519.isValidSignature(signature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}
}
}

@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, macCatalyst 13, visionOS 1.0, *)
Expand Down
130 changes: 116 additions & 14 deletions Sources/X509/Signature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,37 @@ extension P256.Signing.PublicKey {
return false
}

return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}

@inlinable
internal func isValidSignature<SignatureBytes: DataProtocol, Bytes: DataProtocol>(
_ signature: SignatureBytes,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)),
let innerSignature = P256.Signing.ECDSASignature(ecdsaSignature)
else {
return false
}

return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}

@inlinable
internal func isValidSignature<Bytes: DataProtocol>(
_ signature: P256.Signing.ECDSASignature,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
switch signatureAlgorithm {
case .ecdsaWithSHA256:
return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes))
return self.isValidSignature(signature, for: SHA256.hash(data: bytes))
case .ecdsaWithSHA384:
return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes))
return self.isValidSignature(signature, for: SHA384.hash(data: bytes))
case .ecdsaWithSHA512:
return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes))
return self.isValidSignature(signature, for: SHA512.hash(data: bytes))
default:
return false
}
Expand All @@ -216,13 +240,37 @@ extension P384.Signing.PublicKey {
return false
}

return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}

@inlinable
internal func isValidSignature<SignatureBytes: DataProtocol, Bytes: DataProtocol>(
_ signature: SignatureBytes,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)),
let innerSignature = P384.Signing.ECDSASignature(ecdsaSignature)
else {
return false
}

return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}

@inlinable
internal func isValidSignature<Bytes: DataProtocol>(
_ signature: P384.Signing.ECDSASignature,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
switch signatureAlgorithm {
case .ecdsaWithSHA256:
return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes))
return self.isValidSignature(signature, for: SHA256.hash(data: bytes))
case .ecdsaWithSHA384:
return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes))
return self.isValidSignature(signature, for: SHA384.hash(data: bytes))
case .ecdsaWithSHA512:
return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes))
return self.isValidSignature(signature, for: SHA512.hash(data: bytes))
default:
return false
}
Expand All @@ -244,13 +292,37 @@ extension P521.Signing.PublicKey {
return false
}

return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}

@inlinable
internal func isValidSignature<SignatureBytes: DataProtocol, Bytes: DataProtocol>(
_ signature: SignatureBytes,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
guard let ecdsaSignature = try? ECDSASignature(derEncoded: Array(signature)),
let innerSignature = P521.Signing.ECDSASignature(ecdsaSignature)
else {
return false
}

return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}

@inlinable
internal func isValidSignature<Bytes: DataProtocol>(
_ signature: P521.Signing.ECDSASignature,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
switch signatureAlgorithm {
case .ecdsaWithSHA256:
return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes))
return self.isValidSignature(signature, for: SHA256.hash(data: bytes))
case .ecdsaWithSHA384:
return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes))
return self.isValidSignature(signature, for: SHA384.hash(data: bytes))
case .ecdsaWithSHA512:
return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes))
return self.isValidSignature(signature, for: SHA512.hash(data: bytes))
default:
return false
}
Expand All @@ -269,18 +341,39 @@ extension _RSA.Signing.PublicKey {
// Signature mismatch
return false
}

return self.isValidSignature(innerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}

@inlinable
internal func isValidSignature<SignatureBytes: DataProtocol, Bytes: DataProtocol>(
_ signature: SignatureBytes,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
let rsaSignature = _RSA.Signing.RSASignature(rawRepresentation: signature)

return self.isValidSignature(rsaSignature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}

@inlinable
internal func isValidSignature<Bytes: DataProtocol>(
_ signature: _RSA.Signing.RSASignature,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
// For now we don't support RSA PSS, as it's not deployed in the WebPKI.
let padding = _RSA.Signing.Padding.insecurePKCS1v1_5

switch signatureAlgorithm {
case .sha1WithRSAEncryption:
return self.isValidSignature(innerSignature, for: Insecure.SHA1.hash(data: bytes), padding: padding)
return self.isValidSignature(signature, for: Insecure.SHA1.hash(data: bytes), padding: padding)
case .sha256WithRSAEncryption:
return self.isValidSignature(innerSignature, for: SHA256.hash(data: bytes), padding: padding)
return self.isValidSignature(signature, for: SHA256.hash(data: bytes), padding: padding)
case .sha384WithRSAEncryption:
return self.isValidSignature(innerSignature, for: SHA384.hash(data: bytes), padding: padding)
return self.isValidSignature(signature, for: SHA384.hash(data: bytes), padding: padding)
case .sha512WithRSAEncryption:
return self.isValidSignature(innerSignature, for: SHA512.hash(data: bytes), padding: padding)
return self.isValidSignature(signature, for: SHA512.hash(data: bytes), padding: padding)
default:
return false
}
Expand All @@ -300,9 +393,18 @@ extension Curve25519.Signing.PublicKey {
return false
}

return self.isValidSignature(rawInnerSignature, for: bytes, signatureAlgorithm: signatureAlgorithm)
}

@inlinable
internal func isValidSignature<SignatureBytes: DataProtocol, Bytes: DataProtocol>(
_ signature: SignatureBytes,
for bytes: Bytes,
signatureAlgorithm: Certificate.SignatureAlgorithm
) -> Bool {
switch signatureAlgorithm {
case .ed25519:
return self.isValidSignature(rawInnerSignature, for: bytes)
return self.isValidSignature(signature, for: bytes)
default:
return false
}
Expand Down
Loading