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
}
}
|