diff --git a/Sources/JWSETKit/Base/Storage.swift b/Sources/JWSETKit/Base/Storage.swift index 85f900b..d187e70 100644 --- a/Sources/JWSETKit/Base/Storage.swift +++ b/Sources/JWSETKit/Base/Storage.swift @@ -85,7 +85,7 @@ public struct JSONWebValueStorage: Codable, Hashable, ExpressibleByDictionaryLit if urlEncoded { return Data(urlBase64Encoded: value) } else { - return Data(base64Encoded: value) + return Data(base64Encoded: value, options: [.ignoreUnknownCharacters]) } } set { diff --git a/Sources/JWSETKit/Base/StorageField.swift b/Sources/JWSETKit/Base/StorageField.swift index 83d2d8f..1fef066 100644 --- a/Sources/JWSETKit/Base/StorageField.swift +++ b/Sources/JWSETKit/Base/StorageField.swift @@ -57,7 +57,7 @@ extension Data: JSONWebFieldEncodable, JSONWebFieldDecodable { case let value as Data: return value case let value as String: - return Data(urlBase64Encoded: value) ?? Data(base64Encoded: value, options: [.ignoreUnknownCharacters]) + return Data(urlBase64Encoded: value) default: return nil } @@ -84,8 +84,21 @@ extension Date: JSONWebFieldEncodable, JSONWebFieldDecodable { } static func castValue(_ value: Any?) -> Self? { - (value as? NSNumber) - .map { Date(timeIntervalSince1970: $0.doubleValue) } + switch value { + case let value as NSNumber: + return Date(timeIntervalSince1970: value.doubleValue) + case let value as Date: + return value + case let value as String: + if let value = Double(value) { + return Date(timeIntervalSince1970: value) + } else if let value = ISO8601DateFormatter().date(from: value) { + return value + } + return nil + default: + return nil + } } } diff --git a/Sources/JWSETKit/Cryptography/EC/CryptoKitAbstract.swift b/Sources/JWSETKit/Cryptography/EC/CryptoKitAbstract.swift index 8b14985..3cfb973 100644 --- a/Sources/JWSETKit/Cryptography/EC/CryptoKitAbstract.swift +++ b/Sources/JWSETKit/Cryptography/EC/CryptoKitAbstract.swift @@ -31,12 +31,10 @@ extension CryptoECPublicKey { public static func create(storage: JSONWebValueStorage) throws -> Self { let keyData = AnyJSONWebKey(storage: storage) - guard let x = keyData.xCoordinate, !x.isEmpty else { + guard let x = keyData.xCoordinate, !x.isEmpty, let y = keyData.yCoordinate, y.count == x.count else { throw CryptoKitError.incorrectKeySize } - let y = keyData.yCoordinate ?? .init() - let rawKey = x + y - return try .init(rawRepresentation: rawKey) + return try .init(rawRepresentation: x + y) } public func hash(into hasher: inout Hasher) { diff --git a/Sources/JWSETKit/Cryptography/EC/Ed25519.swift b/Sources/JWSETKit/Cryptography/EC/Ed25519.swift index f74c77b..1c702a5 100644 --- a/Sources/JWSETKit/Cryptography/EC/Ed25519.swift +++ b/Sources/JWSETKit/Cryptography/EC/Ed25519.swift @@ -22,6 +22,15 @@ extension Curve25519.Signing.PublicKey: CryptoECPublicKey { result.xCoordinate = rawRepresentation return result.storage } + + + public static func create(storage: JSONWebValueStorage) throws -> Self { + let keyData = AnyJSONWebKey(storage: storage) + guard let x = keyData.xCoordinate, !x.isEmpty else { + throw CryptoKitError.incorrectKeySize + } + return try .init(rawRepresentation: x) + } } extension Curve25519.KeyAgreement.PublicKey: CryptoECPublicKey { @@ -34,6 +43,14 @@ extension Curve25519.KeyAgreement.PublicKey: CryptoECPublicKey { result.xCoordinate = rawRepresentation return result.storage } + + public static func create(storage: JSONWebValueStorage) throws -> Self { + let keyData = AnyJSONWebKey(storage: storage) + guard let x = keyData.xCoordinate, !x.isEmpty else { + throw CryptoKitError.incorrectKeySize + } + return try .init(rawRepresentation: x) + } } extension Curve25519.Signing.PublicKey: JSONWebValidatingKey { diff --git a/Sources/JWSETKit/Cryptography/RSA/RSA.swift b/Sources/JWSETKit/Cryptography/RSA/RSA.swift index 81e942d..c8f9fc5 100644 --- a/Sources/JWSETKit/Cryptography/RSA/RSA.swift +++ b/Sources/JWSETKit/Cryptography/RSA/RSA.swift @@ -107,7 +107,7 @@ extension _RSA.Signing.PrivateKey: JSONWebKeyImportable, JSONWebKeyExportable { // PEM is always a valid Bas64. Data(base64Encoded: pkcs8PEMRepresentation .components(separatedBy: .whitespacesAndNewlines) - .dropFirst().dropLast().joined()).unsafelyUnwrapped + .dropFirst().dropLast().joined(), options: [.ignoreUnknownCharacters]).unsafelyUnwrapped } public init(importing key: Data, format: JSONWebKeyFormat) throws { diff --git a/Sources/JWSETKit/Extensions/Base64.swift b/Sources/JWSETKit/Extensions/Base64.swift index cc70271..dc1142b 100644 --- a/Sources/JWSETKit/Extensions/Base64.swift +++ b/Sources/JWSETKit/Extensions/Base64.swift @@ -13,16 +13,16 @@ extension DataProtocol { /// - returns: The URL-safe Base-64 encoded data. public func urlBase64EncodedData() -> Data { let result = Data(self).base64EncodedData() - .compactMap { - switch $0 { - case UInt8(ascii: "+"): - return UInt8(ascii: "-") - case UInt8(ascii: "/"): - return UInt8(ascii: "_") - case UInt8(ascii: "="): + .compactMap { (byte: UInt8) -> UInt8? in + switch byte { + case "+": + return "-" + case "/": + return "_" + case "=": return nil default: - return $0 + return byte } } return Data(result) @@ -36,26 +36,31 @@ extension DataProtocol { } } +extension UInt8: ExpressibleByUnicodeScalarLiteral { + public init(unicodeScalarLiteral value: UnicodeScalar) { + self = .init(value.value) + } +} + extension Data { /// Initialize a `Data` from a URL-safe Base-64, UTF-8 encoded `Data`. /// /// Returns nil when the input is not recognized as valid Base-64. /// /// - parameter urlBase64Encoded: URL-safe Base-64, UTF-8 encoded input data. - /// - parameter options: Decoding options. Default value is `[]`. public init?(urlBase64Encoded: any DataProtocol) { - var urlBase64Encoded = urlBase64Encoded.compactMap { - switch $0 { - case UInt8(ascii: "-"): - return UInt8(ascii: "+") - case UInt8(ascii: "_"): - return UInt8(ascii: "/") + var urlBase64Encoded = urlBase64Encoded.map { (byte: UInt8) -> UInt8 in + switch byte { + case "-": + return "+" + case "_": + return "/" default: - return $0 + return byte } } if urlBase64Encoded.count % 4 != 0 { - urlBase64Encoded.append(contentsOf: [UInt8](repeating: .init(ascii: "="), count: 4 - urlBase64Encoded.count % 4)) + urlBase64Encoded.append(contentsOf: [UInt8](repeating: "=", count: 4 - urlBase64Encoded.count % 4)) } guard let value = Data(base64Encoded: .init(urlBase64Encoded), options: [.ignoreUnknownCharacters]) else { return nil @@ -68,7 +73,6 @@ extension Data { /// /// Returns nil when the input is not recognized as valid Base-64. /// - parameter urlBase64Encoded: The string to parse. - /// - parameter options: Encoding options. Default value is `[]`. public init?(urlBase64Encoded: String) { guard let value = Data(urlBase64Encoded: Data(urlBase64Encoded.utf8)) else { return nil } self = value diff --git a/Sources/JWSETKit/Extensions/LockValue.swift b/Sources/JWSETKit/Extensions/LockValue.swift index 2de2f36..decde63 100644 --- a/Sources/JWSETKit/Extensions/LockValue.swift +++ b/Sources/JWSETKit/Extensions/LockValue.swift @@ -450,21 +450,16 @@ extension LockedValue: ExpressibleByBooleanLiteral where Value: ExpressibleByBoo } public protocol DictionaryInitialzable: ExpressibleByDictionaryLiteral { - init(elements: [(Key, Value)]) + init(uniqueKeysWithValues keysAndValues: S) where S: Sequence, S.Element == (Key, Value) } -extension Dictionary: DictionaryInitialzable { - @inlinable - public init(elements: [(Key, Value)]) { - self.init(uniqueKeysWithValues: elements) - } -} +extension Dictionary: DictionaryInitialzable {} extension LockedValue: ExpressibleByDictionaryLiteral where Value: ExpressibleByDictionaryLiteral & DictionaryInitialzable, Value.Key: Hashable { @inlinable public convenience init(dictionaryLiteral elements: (Value.Key, Value.Value)...) { let elements = elements.map { ($0, $1) } - self.init(wrappedValue: Value(elements: elements)) + self.init(wrappedValue: Value(uniqueKeysWithValues: elements)) } } diff --git a/Tests/JWSETKitTests/Base/StorageTests.swift b/Tests/JWSETKitTests/Base/StorageTests.swift index 405427b..9e0b5da 100644 --- a/Tests/JWSETKitTests/Base/StorageTests.swift +++ b/Tests/JWSETKitTests/Base/StorageTests.swift @@ -56,7 +56,7 @@ final class StorageTests: XCTestCase { XCTAssertEqual(keys[0].keyType, .ellipticCurve) XCTAssertEqual( try P256.Signing.PublicKey.create(storage: keys[0].storage).rawRepresentation, - Data(base64Encoded: "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==") + "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==".decoded ) XCTAssertEqual(keys[1].keyType, .rsa) XCTAssert(type(of: keys[0]) == JSONWebECPublicKey.self) diff --git a/Tests/JWSETKitTests/Cryptography/CompressionTests.swift b/Tests/JWSETKitTests/Cryptography/CompressionTests.swift index 52b15b8..67a2bd9 100644 --- a/Tests/JWSETKitTests/Cryptography/CompressionTests.swift +++ b/Tests/JWSETKitTests/Cryptography/CompressionTests.swift @@ -9,8 +9,8 @@ import XCTest @testable import JWSETKit final class CompressionTests: XCTestCase { - let decompressed = Data("Data compression test. This text must be compressed.".utf8) - let deflateCompressed = Data(base64Encoded: "c0ksSVRIzs8tKEotLs7Mz1MoSS0u0VMIycgsBjIrShRyS4tLFJJS4WpSU/QA")! + let decompressed = "Data compression test. This text must be compressed.".data + let deflateCompressed = "c0ksSVRIzs8tKEotLs7Mz1MoSS0u0VMIycgsBjIrShRyS4tLFJJS4WpSU/QA".decoded var deflateCompressor: (any JSONWebCompressor.Type)? { guard JSONWebCompressionAlgorithm.registeredAlgorithms.contains(.deflate) else { return nil } diff --git a/Tests/JWSETKitTests/Cryptography/RFC7520EncryptionTests.swift b/Tests/JWSETKitTests/Cryptography/RFC7520EncryptionTests.swift index 54ee508..4762d41 100644 --- a/Tests/JWSETKitTests/Cryptography/RFC7520EncryptionTests.swift +++ b/Tests/JWSETKitTests/Cryptography/RFC7520EncryptionTests.swift @@ -327,7 +327,7 @@ final class RFC7520EncryptionTests: XCTestCase { XCTAssertEqual(jwe.header.protected.encoded, header) XCTAssertEqual(jwe.encryptedKey, "5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi".decoded) XCTAssertEqual(jwe.sealed.nonce, "p9pUq6XHY0jfEZIl".decoded) - #if canImport(Compression) +#if canImport(Compression) // TODO: Replace SWCompression with a library which matches zlib deflate algorithm. XCTAssertEqual(jwe.sealed.ciphertext, """ HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyez\ @@ -336,9 +336,9 @@ final class RFC7520EncryptionTests: XCTestCase { hpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw """.decoded) XCTAssertEqual(jwe.sealed.tag, "VILuUwuIxaLVmh5X-T7kmA".decoded) - #else +#else XCTAssertLessThan(jwe.sealed.ciphertext.count, plainText.data.count) - #endif +#endif XCTAssertEqual(try jwe.decrypt(using: RFC7520ExampleKeys.keyWrapSymmetricKey.key), plainText.data) } diff --git a/Tests/JWSETKitTests/Cryptography/RSATests.swift b/Tests/JWSETKitTests/Cryptography/RSATests.swift index 218e360..a31d01e 100644 --- a/Tests/JWSETKitTests/Cryptography/RSATests.swift +++ b/Tests/JWSETKitTests/Cryptography/RSATests.swift @@ -12,7 +12,7 @@ import CommonCrypto #endif final class RSATests: XCTestCase { - let privateKeyDER = Data(base64Encoded: """ + let privateKeyDER = """ MIIEogIBAAKCAQBc8heBuESxpRARckQCuVNuiLsH5AX73F1lqNxpFsS+GPWl6rrT\ Q0j9Ox/ag2ZwyPby3FtJ11gWT/kDYkjTbqYBCzmzUeGjm3MbuCzErQLPjzGvdUDn\ vCxx8G+uE2uqTdryfEaregUyo69JmucLq3HQ91cHVeLMN/xMvaAu+xEUbZFiDBcV\ @@ -38,9 +38,9 @@ final class RSATests: XCTestCase { 5mECgYEAiZXJe66KpFZlzomsvoghwjTCdMb0CSzH8DvstGRC7X2QR1s9BhS8pvSS\ 1cPwodOyPbUm6t16iYgZN1ibqxWG+TtiftzNzBjrPWGAIWVW+v0uvYBRgdOKbN/c\ nFi6gyV13lGIMMK61gCaEgcgBtJ9hbuIEH6B3a3n8TACIzewfx0= - """)! + """.decoded - let publicKeyDER = Data(base64Encoded: """ + let publicKeyDER = """ MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBc8heBuESxpRARckQCuVNu\ iLsH5AX73F1lqNxpFsS+GPWl6rrTQ0j9Ox/ag2ZwyPby3FtJ11gWT/kDYkjTbqYB\ CzmzUeGjm3MbuCzErQLPjzGvdUDnvCxx8G+uE2uqTdryfEaregUyo69JmucLq3HQ\ @@ -48,7 +48,7 @@ final class RSATests: XCTestCase { rbIRyO49u56Y9SulTm/aOcQn/1Qgpc5NvHfRnHJ4Y7zclERWhtOLiDlVPIR7JjOM\ g3wVUEK18XPgoKdTxHBLJymLF2dQSQhfhLruUcndV0R9vOdt3kMB0cSo7NzF4Fcb\ AgMBAAE= - """)! + """.decoded let plaintext = Data("The quick brown fox jumps over the lazy dog.".utf8) diff --git a/Tests/JWSETKitTests/Entities/JOSEHeaderJWSTests.swift b/Tests/JWSETKitTests/Entities/JOSEHeaderJWSTests.swift index 3b35497..288b698 100644 --- a/Tests/JWSETKitTests/Entities/JOSEHeaderJWSTests.swift +++ b/Tests/JWSETKitTests/Entities/JOSEHeaderJWSTests.swift @@ -38,15 +38,15 @@ final class JOSEHeaderJWSTests: XCTestCase { } """ - let cert1 = try! Certificate(derEncoded: .init(base64Encoded: "MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYwMTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3HKrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQmVZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpRSgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRTcDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEuMB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDSkdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUHAgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IGOgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMUA2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTXRE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuHqDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWVU+4=")!) + let cert1 = try! Certificate(derEncoded: "MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYwMTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3HKrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQmVZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpRSgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRTcDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEuMB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDSkdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUHAgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IGOgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMUA2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTXRE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuHqDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWVU+4=".decoded) - let cert2 = try! Certificate(derEncoded: .init(base64Encoded: "MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoXDTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHUTBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMbVmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlvbiBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEgMB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdvZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUdIAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4OWBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0VmsfSxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==")!) + let cert2 = try! Certificate(derEncoded: "MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoXDTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHUTBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMbVmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlvbiBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEgMB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdvZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUdIAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4OWBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0VmsfSxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==".decoded) - let cert3 = try! Certificate(derEncoded: .init(base64Encoded: "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd")!) + let cert3 = try! Certificate(derEncoded: "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd".decoded) let ecKey: JSONWebECPublicKey = { var result = JSONWebECPublicKey(storage: .init()) - result.storage = try! P256.Signing.PublicKey(rawRepresentation: Data(base64Encoded: "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==")!).storage + result.storage = try! P256.Signing.PublicKey(rawRepresentation: "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==".decoded).storage result.keyId = "1" return result }() @@ -60,7 +60,7 @@ final class JOSEHeaderJWSTests: XCTestCase { XCTAssertEqual(claims.key?.storage, ecKey.storage) XCTAssertEqual(claims.keyId, "2011-04-29") XCTAssertEqual(claims.certificateURL, URL(string: "http://example.com/janedoe")) - XCTAssertEqual(claims.certificateThumbprint, Data(base64Encoded: "We5K4CMGHXgX4urupYm/Zq2gIhm7d6MdNTEyRu+b6Ck=")) + XCTAssertEqual(claims.certificateThumbprint, "We5K4CMGHXgX4urupYm/Zq2gIhm7d6MdNTEyRu+b6Ck=".decoded) XCTAssertEqual(claims.certificateChain, [cert1, cert2, cert3]) XCTAssertEqual(claims.type, .jwt) XCTAssertEqual(claims.contentType, .init(rawValue: "application/json")) @@ -75,7 +75,7 @@ final class JOSEHeaderJWSTests: XCTestCase { claims.key = ecKey claims.keyId = "2011-04-29" claims.certificateURL = URL(string: "http://example.com/janedoe") - claims.certificateThumbprint = Data(base64Encoded: "We5K4CMGHXgX4urupYm/Zq2gIhm7d6MdNTEyRu+b6Ck=") + claims.certificateThumbprint = "We5K4CMGHXgX4urupYm/Zq2gIhm7d6MdNTEyRu+b6Ck=".decoded claims.certificateChain = [cert1, cert2, cert3] claims.type = .jwt claims.contentType = .init(rawValue: "json") diff --git a/Tests/JWSETKitTests/Entities/JWSTests.swift b/Tests/JWSETKitTests/Entities/JWSTests.swift index db14c89..d28bb56 100644 --- a/Tests/JWSETKitTests/Entities/JWSTests.swift +++ b/Tests/JWSETKitTests/Entities/JWSTests.swift @@ -27,7 +27,7 @@ final class JWSTests: XCTestCase { typealias JWSDetached = JSONWebSignature func testSignatureHS256() throws { - let signature = Data(base64Encoded: "dCfJaSBBMSnC8CXslIf5orCzS7AboBan4qE7aXuYSDs=") + let signature = "dCfJaSBBMSnC8CXslIf5orCzS7AboBan4qE7aXuYSDs=".decoded let key = try JSONWebKeyHMAC(ExampleKeys.symmetric) var jws = jws jws.signatures[0].protected.algorithm = .hmacSHA256 @@ -37,7 +37,7 @@ final class JWSTests: XCTestCase { } func testSignatureHS384() throws { - let signature = Data(base64Encoded: "oXDrZsBTd6/RlkXLUTQJ0DSfHx5raR4Pq5jlRHf5v0WTm+zt8xcsCvXagNl0J4eM") + let signature = "oXDrZsBTd6/RlkXLUTQJ0DSfHx5raR4Pq5jlRHf5v0WTm+zt8xcsCvXagNl0J4eM".decoded let key = try JSONWebKeyHMAC(ExampleKeys.symmetric) var jws = jws jws.signatures[0].protected.algorithm = .hmacSHA384 @@ -47,7 +47,7 @@ final class JWSTests: XCTestCase { } func testSignatureHS512() throws { - let signature = Data(base64Encoded: "CyfHecbVPqPzB3zBwYd3rgVBi2Dgg+eAeX7JT8B85QbKLwSXyll8WKGdehse606szf9G3i+jr24QGkEtMAGSpg==") + let signature = "CyfHecbVPqPzB3zBwYd3rgVBi2Dgg+eAeX7JT8B85QbKLwSXyll8WKGdehse606szf9G3i+jr24QGkEtMAGSpg==".decoded let key = try JSONWebKeyHMAC(ExampleKeys.symmetric) var jws = jws jws.signatures[0].protected.algorithm = .hmacSHA512 diff --git a/Tests/JWSETKitTests/ExampleKeys.swift b/Tests/JWSETKitTests/ExampleKeys.swift index f35766b..2c51b4e 100644 --- a/Tests/JWSETKitTests/ExampleKeys.swift +++ b/Tests/JWSETKitTests/ExampleKeys.swift @@ -432,7 +432,7 @@ enum RFC7520ExampleKeys { extension String { var data: Data { Data(utf8) } - var decoded: Data { Data(urlBase64Encoded: data) ?? Data(base64Encoded: data)! } + var decoded: Data { Data(urlBase64Encoded: data).unsafelyUnwrapped } var key: any JSONWebKey { get throws {