File: Signature.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (131 lines) | stat: -rw-r--r-- 4,713 bytes parent folder | download
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))
        }
    }
}