Skip to content

Commit

Permalink
feat: Support importing compact representation of EC (minimum iOS 16,…
Browse files Browse the repository at this point in the history
… macOS 13)

chore: Fix Swift 6.0 warnings and errors
  • Loading branch information
amosavian committed Jun 15, 2024
1 parent 32fbbb0 commit 57f47a6
Show file tree
Hide file tree
Showing 48 changed files with 137 additions and 303 deletions.
4 changes: 0 additions & 4 deletions Sources/JWSETKit/Base/EncryptedData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
//

import Foundation
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif

/// A container for AES ciphers, e.g. AES-GCM, AES-CBC-HMAC, etc.
public struct SealedData: DataProtocol, BidirectionalCollection, Hashable, Sendable {
Expand Down
4 changes: 0 additions & 4 deletions Sources/JWSETKit/Cryptography/Algorithms/Algorithms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
//

import Foundation
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif

/// JSON Web Signature Algorithms.
public protocol JSONWebAlgorithm: StringRepresentable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
//

import Foundation
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif

/// JSON Web Key Encryption Algorithms
public struct JSONWebContentEncryptionAlgorithm: JSONWebAlgorithm {
Expand Down
4 changes: 0 additions & 4 deletions Sources/JWSETKit/Cryptography/Algorithms/KeyEncryption.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
//

import Foundation
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif

/// JSON Web Key Encryption Algorithms
public struct JSONWebKeyEncryptionAlgorithm: JSONWebAlgorithm {
Expand Down
4 changes: 0 additions & 4 deletions Sources/JWSETKit/Cryptography/Algorithms/Signature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
//

import Foundation
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif

/// JSON Web Signature Algorithms
public struct JSONWebSignatureAlgorithm: JSONWebAlgorithm {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@
//

import Foundation
import X509
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif
import X509

/// JSON Web Key (JWK) container for X509 Certificate chain.
///
Expand Down
14 changes: 7 additions & 7 deletions Sources/JWSETKit/Cryptography/Certificate/SecCertificate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import CommonCrypto
import CryptoKit
import X509

extension SecCertificate: JSONWebValidatingKey {
extension Security.SecCertificate: JSONWebValidatingKey {
public var storage: JSONWebValueStorage {
var key = AnyJSONWebKey(storage: (try? publicKey.storage) ?? .init())
if let certificate = try? Certificate(self) {
Expand Down Expand Up @@ -46,13 +46,13 @@ extension SecCertificate: JSONWebValidatingKey {
}
}

extension SecCertificate: Expirable {
extension Security.SecCertificate: Expirable {
public func verifyDate(_ currentDate: Date) throws {
try Certificate(self).verifyDate(currentDate)
}
}

extension SecTrust: JSONWebValidatingKey {
extension Security.SecTrust: JSONWebValidatingKey {
public var storage: JSONWebValueStorage {
var key = AnyJSONWebKey(storage: (try? certificateChain.first?.publicKey.storage) ?? .init())
key.certificateChain = (try? certificateChain.compactMap(Certificate.init)) ?? []
Expand Down Expand Up @@ -97,13 +97,13 @@ extension SecTrust: JSONWebValidatingKey {
}
}

extension SecTrust: Expirable {
extension Security.SecTrust: Expirable {
public func verifyDate(_ currentDate: Date) throws {
try certificateChain.forEach { try $0.verifyDate(currentDate) }
}
}

extension Certificate {
extension X509.Certificate {
/// Casts `X509.Certificate` into `SecCertificate`.
///
/// - Returns: A new `SecCertificate` instance.
Expand All @@ -120,11 +120,11 @@ extension Certificate {
}
}

public func == (lhs: Certificate, rhs: SecCertificate) -> Bool {
public func == (lhs: X509.Certificate, rhs: Security.SecCertificate) -> Bool {
lhs == (try? Certificate(rhs))
}

public func == (lhs: SecCertificate, rhs: Certificate) -> Bool {
public func == (lhs: Security.SecCertificate, rhs: X509.Certificate) -> Bool {
(try? Certificate(lhs)) == rhs
}
#endif
12 changes: 4 additions & 8 deletions Sources/JWSETKit/Cryptography/Certificate/X509Certificate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,13 @@

import Foundation
import SwiftASN1
import X509
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif
import X509
#if canImport(_CryptoExtras)
import _CryptoExtras
#endif

extension Certificate.PublicKey: JSONWebValidatingKey {
extension X509.Certificate.PublicKey: JSONWebValidatingKey {
public var storage: JSONWebValueStorage {
(try? jsonWebKey().storage) ?? .init()
}
Expand Down Expand Up @@ -85,7 +81,7 @@ extension DERImplicitlyTaggable {
}
}

extension Certificate: JSONWebValidatingKey {
extension X509.Certificate: JSONWebValidatingKey {
public var storage: JSONWebValueStorage {
var key = AnyJSONWebKey(storage: publicKey.storage)
key.certificateChain = [self]
Expand All @@ -105,7 +101,7 @@ extension Certificate: JSONWebValidatingKey {
}
}

extension Certificate: Expirable {
extension X509.Certificate: Expirable {
public func verifyDate(_ currentDate: Date) throws {
if currentDate > notValidAfter {
throw JSONWebValidationError.tokenExpired(expiry: notValidAfter)
Expand Down
98 changes: 50 additions & 48 deletions Sources/JWSETKit/Cryptography/EC/CryptoKitAbstract.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
//

import Foundation
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif

protocol CryptoECPublicKey: JSONWebKey {
static var curve: JSONWebKeyCurve { get }
Expand Down Expand Up @@ -46,46 +42,6 @@ extension CryptoECPublicKey {
}
}

protocol CryptoECPublicKeyPortable: JSONWebKeyImportable, JSONWebKeyExportable {
var x963Representation: Data { get }
var derRepresentation: Data { get }

init<Bytes>(x963Representation: Bytes) throws where Bytes: ContiguousBytes
init<Bytes>(derRepresentation: Bytes) throws where Bytes: RandomAccessCollection, Bytes.Element == UInt8
}

extension CryptoECPublicKeyPortable {
public init<D>(importing key: D, format: JSONWebKeyFormat) throws where D: DataProtocol {
switch format {
case .raw:
if key.regions.count == 1, let keyData = key.regions.first {
try self.init(x963Representation: keyData)
} else {
try self.init(x963Representation: Data(key))
}
case .spki:
try self.init(derRepresentation: key)
case .jwk:
self = try JSONDecoder().decode(Self.self, from: Data(key))
default:
throw JSONWebKeyError.invalidKeyFormat
}
}

public func exportKey(format: JSONWebKeyFormat) throws -> Data {
switch format {
case .raw:
return x963Representation
case .spki:
return derRepresentation
case .jwk:
return try jwkRepresentation
default:
throw JSONWebKeyError.invalidKeyFormat
}
}
}

protocol CryptoECPrivateKey: JSONWebKey {
associatedtype PublicKey: CryptoECPublicKey

Expand Down Expand Up @@ -119,15 +75,20 @@ extension CryptoECPrivateKey {
}
}

protocol CryptoECPrivateKeyPortable: JSONWebKeyImportable, JSONWebKeyExportable {
protocol CryptoECKeyPortable: JSONWebKeyImportable, JSONWebKeyExportable {
var x963Representation: Data { get }
var derRepresentation: Data { get }

init<Bytes>(x963Representation: Bytes) throws where Bytes: ContiguousBytes
init<Bytes>(derRepresentation: Bytes) throws where Bytes: RandomAccessCollection, Bytes.Element == UInt8
}

extension CryptoECPrivateKeyPortable {
protocol CryptoECKeyPortableCompactRepresentable: CryptoECKeyPortable {
@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *)
init<Bytes>(compressedRepresentation: Bytes) throws where Bytes : ContiguousBytes
}

extension CryptoECKeyPortable {
public init<D>(importing key: D, format: JSONWebKeyFormat) throws where D: DataProtocol {
switch format {
case .raw:
Expand All @@ -136,7 +97,8 @@ extension CryptoECPrivateKeyPortable {
} else {
try self.init(x963Representation: Data(key))
}
case .pkcs8:
case .spki where Self.self is (any CryptoECPublicKey).Type,
.pkcs8 where Self.self is (any CryptoECPrivateKey).Type:
try self.init(derRepresentation: key)
case .jwk:
self = try JSONDecoder().decode(Self.self, from: Data(key))
Expand All @@ -149,7 +111,8 @@ extension CryptoECPrivateKeyPortable {
switch format {
case .raw:
return x963Representation
case .pkcs8:
case .spki where self is any CryptoECPublicKey,
.pkcs8 where self is any CryptoECPrivateKey:
return derRepresentation
case .jwk:
return try jwkRepresentation
Expand All @@ -158,3 +121,42 @@ extension CryptoECPrivateKeyPortable {
}
}
}

extension CryptoECKeyPortableCompactRepresentable {
private init<D>(importingRaw key: D) throws where D: DataProtocol {
switch key.first {
case 0x04:
if key.regions.count == 1, let keyData = key.regions.first {
try self.init(x963Representation: keyData)
} else {
try self.init(x963Representation: Data(key))
}
case 0x02, 0x03:
if #available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) {
if key.regions.count == 1, let keyData = key.regions.first {
try self.init(compressedRepresentation: keyData)
} else {
try self.init(compressedRepresentation: Data(key))
}
} else {
throw CryptoKitError.incorrectParameterSize
}
default:
throw CryptoKitError.incorrectParameterSize
}
}

public init<D>(importing key: D, format: JSONWebKeyFormat) throws where D: DataProtocol {
switch format {
case .raw:
try self.init(importingRaw: key)
case .spki where Self.self is (any CryptoECPublicKey).Type,
.pkcs8 where Self.self is (any CryptoECPrivateKey).Type:
try self.init(derRepresentation: key)
case .jwk:
self = try JSONDecoder().decode(Self.self, from: Data(key))
default:
throw JSONWebKeyError.invalidKeyFormat
}
}
}
22 changes: 9 additions & 13 deletions Sources/JWSETKit/Cryptography/EC/Ed25519.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,9 @@
//

import Foundation
#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif

extension Curve25519.Signing.PublicKey: CryptoECPublicKey {
extension Crypto.Curve25519.Signing.PublicKey: CryptoECPublicKey {
static var curve: JSONWebKeyCurve { .ed25519 }

public var storage: JSONWebValueStorage {
Expand All @@ -32,7 +28,7 @@ extension Curve25519.Signing.PublicKey: CryptoECPublicKey {
}
}

extension Curve25519.KeyAgreement.PublicKey: CryptoECPublicKey {
extension Crypto.Curve25519.KeyAgreement.PublicKey: CryptoECPublicKey {
static var curve: JSONWebKeyCurve { .x25519 }

public var storage: JSONWebValueStorage {
Expand All @@ -52,19 +48,19 @@ extension Curve25519.KeyAgreement.PublicKey: CryptoECPublicKey {
}
}

extension Curve25519.Signing.PublicKey: JSONWebValidatingKey {
extension Crypto.Curve25519.Signing.PublicKey: JSONWebValidatingKey {
public func verifySignature<S, D>(_ signature: S, for data: D, using _: JSONWebSignatureAlgorithm) throws where S: DataProtocol, D: DataProtocol {
if !isValidSignature(signature, for: data) {
throw CryptoKitError.authenticationFailure
}
}
}

extension Curve25519.Signing.PublicKey: CryptoEdKeyPortable {}
extension Crypto.Curve25519.Signing.PublicKey: CryptoEdKeyPortable {}

extension Curve25519.KeyAgreement.PublicKey: CryptoEdKeyPortable {}
extension Crypto.Curve25519.KeyAgreement.PublicKey: CryptoEdKeyPortable {}

extension Curve25519.Signing.PrivateKey: JSONWebSigningKey, CryptoECPrivateKey {
extension Crypto.Curve25519.Signing.PrivateKey: JSONWebSigningKey, CryptoECPrivateKey {
public init(algorithm _: any JSONWebAlgorithm) throws {
self.init()
}
Expand All @@ -74,15 +70,15 @@ extension Curve25519.Signing.PrivateKey: JSONWebSigningKey, CryptoECPrivateKey {
}
}

extension Curve25519.KeyAgreement.PrivateKey: CryptoECPrivateKey {
extension Crypto.Curve25519.KeyAgreement.PrivateKey: CryptoECPrivateKey {
public init(algorithm _: any JSONWebAlgorithm) throws {
self.init()
}
}

extension Curve25519.Signing.PrivateKey: CryptoEdKeyPortable {}
extension Crypto.Curve25519.Signing.PrivateKey: CryptoEdKeyPortable {}

extension Curve25519.KeyAgreement.PrivateKey: CryptoEdKeyPortable {}
extension Crypto.Curve25519.KeyAgreement.PrivateKey: CryptoEdKeyPortable {}

protocol CryptoEdKeyPortable: JSONWebKeyImportable, JSONWebKeyExportable {
var rawRepresentation: Data { get }
Expand Down
Loading

0 comments on commit 57f47a6

Please sign in to comment.