1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCertificates open source project
//
// Copyright (c) 2022 Apple Inc. and the SwiftCertificates project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftCertificates project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import SwiftASN1
@preconcurrency import _CryptoExtras
import Foundation
extension Certificate {
/// An abstract representation of the cryptographic signature on a certificate.
///
/// Certificates may have a wide range of signature types. This type provides a runtime
/// abstraction across these types. It ensures that we understand the algorithm used to
/// sign the certificate, and enables us to provide verification logic, without forcing
/// users to wrestle with the wide variety of runtime types that may represent a
/// signature.
///
/// This type is almost entirely opaque. It can be validated by way of
/// ``Certificate/PublicKey-swift.struct/isValidSignature(_:for:)``, and it
/// can be generated by ``Certificate/PrivateKey``s automatically when
/// used by ``Certificate/init(version:serialNumber:publicKey:notValidBefore:notValidAfter:issuer:subject:signatureAlgorithm:extensions:issuerPrivateKey:)``.
/// Otherwise, this type has essentially no behaviours.
public struct Signature {
@usableFromInline
var backing: BackingSignature
@inlinable
internal init(backing: BackingSignature) {
self.backing = backing
}
@inlinable
internal init(signatureAlgorithm: SignatureAlgorithm, signatureBytes: ASN1BitString) throws {
switch signatureAlgorithm {
case .ecdsaWithSHA256, .ecdsaWithSHA384, .ecdsaWithSHA512:
let signature = try ECDSASignature(derEncoded: signatureBytes.bytes)
self.backing = .ecdsa(signature)
case .sha1WithRSAEncryption, .sha256WithRSAEncryption, .sha384WithRSAEncryption, .sha512WithRSAEncryption:
let signature = _RSA.Signing.RSASignature(rawRepresentation: signatureBytes.bytes)
self.backing = .rsa(signature)
default:
throw CertificateError.unsupportedSignatureAlgorithm(reason: "\(signatureAlgorithm)")
}
}
}
}
extension Certificate.Signature: Hashable {}
extension Certificate.Signature: Sendable {}
extension Certificate.Signature: CustomStringConvertible {
public var description: String {
switch backing {
case .ecdsa:
return "ECDSA"
case .rsa:
return "RSA"
}
}
}
extension Certificate.Signature {
@usableFromInline
enum BackingSignature: Hashable, Sendable {
case ecdsa(ECDSASignature)
case rsa(_CryptoExtras._RSA.Signing.RSASignature)
@inlinable
static func == (lhs: BackingSignature, rhs: BackingSignature) -> Bool {
switch (lhs, rhs) {
case (.ecdsa(let l), .ecdsa(let r)):
return l == r
case (.rsa(let l), .rsa(let r)):
return l.rawRepresentation == r.rawRepresentation
default:
return false
}
}
@inlinable
func hash(into hasher: inout Hasher) {
switch self {
case .ecdsa(let sig):
hasher.combine(0)
hasher.combine(sig)
case .rsa(let digest):
hasher.combine(1)
hasher.combine(digest.rawRepresentation)
}
}
}
}
extension ASN1BitString {
@inlinable
init(_ signature: Certificate.Signature) {
switch signature.backing {
case .ecdsa(let sig):
var serializer = DER.Serializer()
try! serializer.serialize(sig)
self = ASN1BitString(bytes: serializer.serializedBytes[...])
case .rsa(let sig):
self = ASN1BitString(bytes: ArraySlice(sig.rawRepresentation))
}
}
}
extension ASN1OctetString {
@inlinable
init(_ signature: Certificate.Signature) {
switch signature.backing {
case .ecdsa(let sig):
var serializer = DER.Serializer()
try! serializer.serialize(sig)
self = ASN1OctetString(contentBytes: serializer.serializedBytes[...])
case .rsa(let sig):
self = ASN1OctetString(contentBytes: ArraySlice(sig.rawRepresentation))
}
}
}
|