File: SSLPublicKey.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 (89 lines) | stat: -rw-r--r-- 3,372 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
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

#if compiler(>=5.1)
@_implementationOnly import CNIOBoringSSL
#else
import CNIOBoringSSL
#endif

/// An `NIOSSLPublicKey` is an abstract handle to a public key owned by BoringSSL.
///
/// This object is of minimal utility, as it cannot be used for very many operations
/// in `NIOSSL`. Its primary purpose is to allow extracting public keys from
/// `NIOSSLCertificate` objects to be serialized, so that they can be passed to
/// general-purpose cryptography libraries.
public class NIOSSLPublicKey {
    private let _ref: UnsafeMutableRawPointer /*<EVP_PKEY>*/

    private var ref: UnsafeMutablePointer<EVP_PKEY> {
        return self._ref.assumingMemoryBound(to: EVP_PKEY.self)
    }

    fileprivate init(withOwnedReference ref: UnsafeMutablePointer<EVP_PKEY>) {
        self._ref = UnsafeMutableRawPointer(ref) // erasing the type for @_implementationOnly import CNIOBoringSSL
    }

    deinit {
        CNIOBoringSSL_EVP_PKEY_free(self.ref)
    }
}

// MARK:- Helpful initializers
extension NIOSSLPublicKey {
    /// Create an `NIOSSLPublicKey` object from an internal `EVP_PKEY` pointer.
    ///
    /// This method expects `pointer` to be passed at +1, and consumes that reference.
    ///
    /// - parameters:
    ///    - pointer: A pointer to an `EVP_PKEY` structure containing the public key.
    /// - returns: An `NIOSSLPublicKey` wrapping the pointer.
    internal static func fromInternalPointer(takingOwnership pointer: UnsafeMutablePointer<EVP_PKEY>) -> NIOSSLPublicKey {
        return NIOSSLPublicKey(withOwnedReference: pointer)
    }
}

extension NIOSSLPublicKey {
    /// Extracts the bytes of this public key in the SubjectPublicKeyInfo format.
    ///
    /// The SubjectPublicKeyInfo format is defined in RFC 5280. In addition to the raw key bytes, it also
    /// provides an identifier of the algorithm, ensuring that the key can be unambiguously decoded.
    ///
    /// - returns: The DER-encoded SubjectPublicKeyInfo bytes for this public key.
    /// - throws: If an error occurred while serializing the key.
    public func toSPKIBytes() throws -> [UInt8] {
        guard let bio = CNIOBoringSSL_BIO_new(CNIOBoringSSL_BIO_s_mem()) else {
            fatalError("Failed to malloc for a BIO handler")
        }

        defer {
            CNIOBoringSSL_BIO_free(bio)
        }

        let rc = CNIOBoringSSL_i2d_PUBKEY_bio(bio, self.ref)
        guard rc == 1 else {
            let errorStack = BoringSSLError.buildErrorStack()
            throw BoringSSLError.unknownError(errorStack)
        }

        var dataPtr: UnsafeMutablePointer<CChar>? = nil
        let length = CNIOBoringSSL_BIO_get_mem_data(bio, &dataPtr)

        guard let bytes = dataPtr.map({ UnsafeMutableRawBufferPointer(start: $0, count: length) }) else {
            fatalError("Failed to map bytes from a public key")
        }

        return Array(bytes)
    }
}