Skip to content

Commit f4feb2b

Browse files
committed
[Collections] Signing (all, 2): signed collections
This is part 2 of a series of PRs to support package collection signing on **all** platforms. Originally swiftlang#3242. Depends on swiftlang#3260, swiftlang#3264
1 parent c595e6f commit f4feb2b

File tree

4 files changed

+150
-6
lines changed

4 files changed

+150
-6
lines changed

Sources/PackageCollectionsSigning/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ add_library(PackageCollectionsSigning
2424
Key/Key+EC.swift
2525
Key/Key+RSA.swift
2626
PackageCollectionSigning.swift
27+
Signing/BoringSSLSigning.swift
2728
Signing/Signature.swift
2829
Signing/Signing.swift
2930
Signing/Signing+ECKey.swift

Sources/PackageCollectionsSigning/Key/Key+RSA.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,15 @@ struct CoreRSAPublicKey: PublicKey {
106106
#else
107107
final class BoringSSLRSAPrivateKey: PrivateKey, BoringSSLKey {
108108
let underlying: UnsafeMutablePointer<CCryptoBoringSSL.RSA>
109-
static let algorithm: OpaquePointer = CCryptoBoringSSL_EVP_sha256()
110109

111110
deinit {
112111
CCryptoBoringSSL_RSA_free(self.underlying)
113112
}
114113

114+
var sizeInBits: Int {
115+
toBits(bytes: Int(CCryptoBoringSSL_RSA_size(self.underlying)))
116+
}
117+
115118
init<Data>(pem data: Data) throws where Data: DataProtocol {
116119
let key = try Self.load(pem: data) { bio in
117120
CCryptoBoringSSL_PEM_read_bio_PrivateKey(bio, nil, nil, nil)
@@ -128,12 +131,15 @@ final class BoringSSLRSAPrivateKey: PrivateKey, BoringSSLKey {
128131

129132
final class BoringSSLRSAPublicKey: PublicKey, BoringSSLKey {
130133
let underlying: UnsafeMutablePointer<CCryptoBoringSSL.RSA>
131-
static let algorithm: OpaquePointer = CCryptoBoringSSL_EVP_sha256()
132134

133135
deinit {
134136
CCryptoBoringSSL_RSA_free(self.underlying)
135137
}
136138

139+
var sizeInBits: Int {
140+
toBits(bytes: Int(CCryptoBoringSSL_RSA_size(self.underlying)))
141+
}
142+
137143
/// `data` should be in the PKCS #1 format
138144
init(data: Data) throws {
139145
let bytes = data.copyBytes()
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2021 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This source file is part of the Vapor open source project
14+
//
15+
// Copyright (c) 2017-2020 Vapor project authors
16+
// Licensed under MIT
17+
//
18+
// See LICENSE for license information
19+
//
20+
// SPDX-License-Identifier: MIT
21+
//
22+
//===----------------------------------------------------------------------===//
23+
24+
#if !canImport(Security)
25+
import Foundation
26+
27+
@_implementationOnly import CCryptoBoringSSL
28+
29+
protocol BoringSSLSigning {
30+
var algorithm: BoringSSLEVP { get }
31+
}
32+
33+
struct BoringSSLEVP {
34+
let underlying: OpaquePointer
35+
36+
init(type: EVPType) {
37+
switch type {
38+
case .sha256:
39+
self.underlying = CCryptoBoringSSL_EVP_sha256()
40+
}
41+
}
42+
43+
enum EVPType {
44+
case sha256
45+
}
46+
}
47+
48+
extension BoringSSLSigning {
49+
// Source: https://github.com/vapor/jwt-kit/blob/master/Sources/JWTKit/Utilities/OpenSSLSigner.swift
50+
func digest<Message>(_ message: Message) throws -> [UInt8] where Message: DataProtocol {
51+
let context = CCryptoBoringSSL_EVP_MD_CTX_new()
52+
defer { CCryptoBoringSSL_EVP_MD_CTX_free(context) }
53+
54+
guard CCryptoBoringSSL_EVP_DigestInit_ex(context, self.algorithm.underlying, nil) == 1 else {
55+
throw BoringSSLSigningError.digestInitializationFailure
56+
}
57+
58+
let message = message.copyBytes()
59+
60+
guard CCryptoBoringSSL_EVP_DigestUpdate(context, message, numericCast(message.count)) == 1 else {
61+
throw BoringSSLSigningError.digestUpdateFailure
62+
}
63+
64+
var digest: [UInt8] = .init(repeating: 0, count: Int(EVP_MAX_MD_SIZE))
65+
var digestLength: UInt32 = 0
66+
67+
guard CCryptoBoringSSL_EVP_DigestFinal_ex(context, &digest, &digestLength) == 1 else {
68+
throw BoringSSLSigningError.digestFinalizationFailure
69+
}
70+
71+
return .init(digest[0 ..< Int(digestLength)])
72+
}
73+
}
74+
75+
enum BoringSSLSigningError: Error {
76+
case digestInitializationFailure
77+
case digestUpdateFailure
78+
case digestFinalizationFailure
79+
}
80+
#endif

Sources/PackageCollectionsSigning/Signing/Signing+RSAKey.swift

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,25 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This source file is part of the Vapor open source project
14+
//
15+
// Copyright (c) 2017-2020 Vapor project authors
16+
// Licensed under MIT
17+
//
18+
// See LICENSE for license information
19+
//
20+
// SPDX-License-Identifier: MIT
21+
//
22+
//===----------------------------------------------------------------------===//
23+
1124
import struct Foundation.Data
1225

1326
#if os(macOS)
1427
import Security
28+
#else
29+
@_implementationOnly import CCryptoBoringSSL
1530
#endif
1631

1732
// MARK: - MessageSigner and MessageValidator conformance using the Security framework
@@ -45,15 +60,57 @@ extension CoreRSAPublicKey {
4560
// MARK: - MessageSigner and MessageValidator conformance using BoringSSL
4661

4762
#else
48-
extension BoringSSLRSAPrivateKey {
63+
// Reference: https://github.com/vapor/jwt-kit/blob/master/Sources/JWTKit/RSA/RSASigner.swift
64+
extension BoringSSLRSAPrivateKey: BoringSSLSigning {
65+
private static let algorithm = BoringSSLEVP(type: .sha256)
66+
67+
var algorithm: BoringSSLEVP {
68+
Self.algorithm
69+
}
70+
4971
func sign(message: Data) throws -> Data {
50-
fatalError("Not implemented: \(#function)")
72+
let digest = try self.digest(message)
73+
74+
var signatureLength: UInt32 = 0
75+
var signature = [UInt8](
76+
repeating: 0,
77+
count: Int(CCryptoBoringSSL_RSA_size(self.underlying))
78+
)
79+
80+
guard CCryptoBoringSSL_RSA_sign(
81+
CCryptoBoringSSL_EVP_MD_type(self.algorithm.underlying),
82+
digest,
83+
numericCast(digest.count),
84+
&signature,
85+
&signatureLength,
86+
self.underlying
87+
) == 1 else {
88+
throw SigningError.signFailure
89+
}
90+
91+
return Data(signature[0 ..< numericCast(signatureLength)])
5192
}
5293
}
5394

54-
extension BoringSSLRSAPublicKey {
95+
extension BoringSSLRSAPublicKey: BoringSSLSigning {
96+
private static let algorithm = BoringSSLEVP(type: .sha256)
97+
98+
var algorithm: BoringSSLEVP {
99+
Self.algorithm
100+
}
101+
55102
func isValidSignature(_ signature: Data, for message: Data) throws -> Bool {
56-
fatalError("Not implemented: \(#function)")
103+
let digest = try self.digest(message)
104+
let signature = signature.copyBytes()
105+
106+
return CCryptoBoringSSL_RSA_verify(
107+
CCryptoBoringSSL_EVP_MD_type(self.algorithm.underlying),
108+
digest,
109+
numericCast(digest.count),
110+
signature,
111+
numericCast(signature.count),
112+
self.underlying
113+
) == 1
57114
}
58115
}
59116
#endif

0 commit comments

Comments
 (0)