File: Extension.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 (139 lines) | stat: -rw-r--r-- 5,636 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
132
133
134
135
136
137
138
139
//===----------------------------------------------------------------------===//
//
// 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

extension Certificate {
    /// A general-purpose representation of a specific X.509 extension.
    ///
    /// X.509 extensions are a general representation, with three properties: an identifier, a critical flag, and the encoded value.
    /// The specific data contained in the encoded value is determined by the value of the identifier stored in ``oid``.
    ///
    /// This value enables ``Certificate/Extensions-swift.struct`` to store the value of all extensions in a certificate, even ones
    /// it does not understand. A number of extensions have built-in support, and can be decoded directly from an ``Extension``
    /// value. These are:
    ///
    /// - ``AuthorityInformationAccess``
    /// - ``AuthorityKeyIdentifier``
    /// - ``BasicConstraints``
    /// - ``ExtendedKeyUsage``
    /// - ``KeyUsage``
    /// - ``NameConstraints``
    /// - ``SubjectAlternativeNames``
    /// - ``SubjectKeyIdentifier``
    ///
    /// Users can write their own types by using a similar approach to these types, when it is necessary to add support for
    /// different X.509 extension.
    public struct Extension {
        /// The identifier for this extension type.
        ///
        /// Common values are stored in `ASN1ObjectIdentifier.X509ExtensionID`.
        public var oid: ASN1ObjectIdentifier

        /// Whether this extension must be processed in order to trust the certificate.
        ///
        /// If the code processing this ``Certificate`` does not understand this extension, the certificate
        /// must not be trusted.
        public var critical: Bool

        /// The encoded bytes of the value of this extension.
        ///
        /// This value should be decoded based on the value of ``oid``.
        public var value: ArraySlice<UInt8>

        /// Construct a new extension from its constituent parts.
        ///
        /// - Parameters:
        ///   - oid: The identifier for this extension type.
        ///   - critical: Whether this extension must be processed in order to trust the certificate.
        ///   - value: The encoded bytes of the value of this extension.
        @inlinable
        public init(oid: ASN1ObjectIdentifier, critical: Bool, value: ArraySlice<UInt8>) {
            self.oid = oid
            self.critical = critical
            self.value = value
        }
    }
}

extension Certificate.Extension: Hashable {}

extension Certificate.Extension: Sendable {}

extension Certificate.Extension: CustomStringConvertible {
    public var description: String {
        if let knownExtension = try? AuthorityInformationAccess(self) {
            return String(reflecting: knownExtension)
        } else if let knownExtension = try? SubjectKeyIdentifier(self) {
            return String(reflecting: knownExtension)
        } else if let knownExtension = try? AuthorityKeyIdentifier(self) {
            return String(reflecting: knownExtension)
        } else if let knownExtension = try? ExtendedKeyUsage(self) {
            return String(reflecting: knownExtension)
        } else if let knownExtension = try? BasicConstraints(self) {
            return String(reflecting: knownExtension)
        } else if let knownExtension = try? KeyUsage(self) {
            return String(reflecting: knownExtension)
        } else if let knownExtension = try? NameConstraints(self) {
            return String(reflecting: knownExtension)
        } else if let knownExtension = try? SubjectAlternativeNames(self) {
            return String(reflecting: knownExtension)
        } else {
            return """
                Extension(\
                oid: \(String(reflecting: self.oid)), \
                critical: \(String(reflecting: self.critical)), \
                value: \(self.value.count) bytes\
                )
                """
        }
    }
}

extension Certificate.Extension: DERImplicitlyTaggable {
    @inlinable
    public static var defaultIdentifier: ASN1Identifier {
        .sequence
    }

    @inlinable
    public init(derEncoded rootNode: ASN1Node, withIdentifier identifier: ASN1Identifier) throws {
        self = try DER.sequence(rootNode, identifier: identifier) { nodes in
            let extensionID = try ASN1ObjectIdentifier(derEncoded: &nodes)
            let critical = try DER.decodeDefault(&nodes, defaultValue: false)
            let value = try ASN1OctetString(derEncoded: &nodes)

            return Certificate.Extension(oid: extensionID, critical: critical, value: value.bytes)
        }
    }

    @inlinable
    public func serialize(into coder: inout DER.Serializer, withIdentifier identifier: ASN1Identifier) throws {
        try coder.appendConstructedNode(identifier: identifier) { coder in
            try coder.serialize(self.oid)

            if self.critical {
                try coder.serialize(self.critical)
            }

            try coder.serialize(ASN1OctetString(contentBytes: self.value))
        }
    }
}

extension Certificate.Extension: CertificateExtensionConvertible {
    public func makeCertificateExtension() -> Certificate.Extension {
        self
    }
}