File: SubjectKeyIdentifier.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 (108 lines) | stat: -rw-r--r-- 4,324 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
//===----------------------------------------------------------------------===//
//
// 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
import Crypto
import struct Foundation.Data

/// Provides a means of identifying a certificate that contains a particular public key.
///
/// This extension contains a value derived from the public key of the certificate in which it appears.
/// That value can be used to build the ``AuthorityKeyIdentifier/keyIdentifier`` field in
/// any certificate issued by this certificate. This makes it possible to identify a certificate
/// possessing the key that issued another certificate.
public struct SubjectKeyIdentifier {
    public var keyIdentifier: ArraySlice<UInt8>

    /// Construct a Subject Key Identifier extension with a specific key identifier.
    ///
    /// - Parameter keyIdentifier: The identifier to associate with this certificate.
    @inlinable
    public init(keyIdentifier: ArraySlice<UInt8>) {
        self.keyIdentifier = keyIdentifier
    }

    /// Create a new ``SubjectKeyIdentifier`` object
    /// by unwrapping a ``Certificate/Extension``.
    ///
    /// - Parameter ext: The ``Certificate/Extension`` to unwrap
    /// - Throws: if the ``Certificate/Extension/oid`` is not equal to
    ///     `ASN1ObjectIdentifier.X509ExtensionID.subjectKeyIdentifier`.
    @inlinable
    public init(_ ext: Certificate.Extension) throws {
        guard ext.oid == .X509ExtensionID.subjectKeyIdentifier else {
            throw CertificateError.incorrectOIDForExtension(
                reason: "Expected \(ASN1ObjectIdentifier.X509ExtensionID.subjectKeyIdentifier), got \(ext.oid)"
            )
        }

        let asn1KeyIdentifier = try ASN1OctetString(derEncoded: ext.value)
        self.keyIdentifier = asn1KeyIdentifier.bytes
    }
}

extension SubjectKeyIdentifier: Hashable {}

extension SubjectKeyIdentifier: Sendable {}

extension SubjectKeyIdentifier: CustomStringConvertible {
    public var description: String {
        return self.keyIdentifier.lazy.map { String($0, radix: 16) }.joined(separator: ":")
    }
}

extension SubjectKeyIdentifier: CustomDebugStringConvertible {
    public var debugDescription: String {
        "SubjectKeyIdentifier(\(String(describing: self)))"
    }
}

extension Certificate.Extension {
    /// Construct an opaque ``Certificate/Extension`` from this Subject Key Identifier extension.
    ///
    /// - Parameters:
    ///   - ski: The extension to wrap
    ///   - critical: Whether this extension should have the critical bit set.
    @inlinable
    public init(_ ski: SubjectKeyIdentifier, critical: Bool) throws {
        let asn1Representation = ASN1OctetString(contentBytes: ski.keyIdentifier)
        var serializer = DER.Serializer()
        try serializer.serialize(asn1Representation)
        self.init(
            oid: .X509ExtensionID.subjectKeyIdentifier,
            critical: critical,
            value: serializer.serializedBytes[...]
        )
    }
}

extension SubjectKeyIdentifier: CertificateExtensionConvertible {
    public func makeCertificateExtension() throws -> Certificate.Extension {
        return try .init(self, critical: false)
    }
}

extension SubjectKeyIdentifier {
    /// Construct a ``SubjectKeyIdentifier`` by hashing the given `publicKey` with SHA-1 according to RFC 5280 Section 4.2.1.2.
    /// - Parameter publicKey: the public key which will be hashed
    @inlinable
    public init(hash publicKey: Certificate.PublicKey) {
        // RFC 5280 Section 4.2.1.2. Subject Key Identifier (https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.2)
        // The keyIdentifier is composed of the 160-bit SHA-1 hash of the
        // value of the BIT STRING subjectPublicKey (excluding the tag,
        // length, and number of unused bits).
        let hash = Insecure.SHA1.hash(data: publicKey.subjectPublicKeyInfoBytes)
        self.init(keyIdentifier: .init(hash))
    }
}