From 722937b9eac0ae5fbe8e15a5401e82489ec4e00d Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 19:47:49 +0200 Subject: [PATCH 01/19] Implement decoding of String and [String] parameters --- JOSESwift/Sources/JWK.swift | 4 +-- JOSESwift/Sources/JWKExtensions.swift | 2 +- JOSESwift/Sources/JWKParameters.swift | 19 ++++++++--- JOSESwift/Sources/RSAKeyCodable.swift | 38 ++++++++++++++++----- JOSESwift/Sources/RSAKeys.swift | 12 +++---- JOSESwift/Sources/SymmetricKeyCodable.swift | 21 +++++++++--- JOSESwift/Sources/SymmetricKeys.swift | 6 ++-- 7 files changed, 73 insertions(+), 29 deletions(-) diff --git a/JOSESwift/Sources/JWK.swift b/JOSESwift/Sources/JWK.swift index 7c18dcd4..8b755df8 100644 --- a/JOSESwift/Sources/JWK.swift +++ b/JOSESwift/Sources/JWK.swift @@ -53,7 +53,7 @@ public protocol JWK: Codable { /// The parameters of the JWK representing the properties of the key(s), including the value(s). /// Check [RFC 7517, Section 4](https://tools.ietf.org/html/rfc7517#section-4) and /// [RFC 7518, Section 6](https://tools.ietf.org/html/rfc7518#section-6) for possible parameters. - var parameters: [String: String] { get } + var parameters: [String: JWKParameterType] { get } /// Accesses the specified parameter. /// The parameters of the JWK representing the properties of the key(s), including the value(s). @@ -61,7 +61,7 @@ public protocol JWK: Codable { /// [RFC 7518, Section 6](https://tools.ietf.org/html/rfc7518#section-6) for possible parameters. /// /// - Parameter parameter: The desired parameter. - subscript(parameter: String) -> String? { get } + subscript(parameter: String) -> Any? { get } /// Initializes a JWK from given JSON data. /// diff --git a/JOSESwift/Sources/JWKExtensions.swift b/JOSESwift/Sources/JWKExtensions.swift index e078f10d..666dacab 100644 --- a/JOSESwift/Sources/JWKExtensions.swift +++ b/JOSESwift/Sources/JWKExtensions.swift @@ -26,7 +26,7 @@ import Foundation // MARK: Subscript public extension JWK { - subscript(parameter: String) -> String? { + subscript(parameter: String) -> Any? { return parameters[parameter] } } diff --git a/JOSESwift/Sources/JWKParameters.swift b/JOSESwift/Sources/JWKParameters.swift index 8be7031c..d1ea846f 100644 --- a/JOSESwift/Sources/JWKParameters.swift +++ b/JOSESwift/Sources/JWKParameters.swift @@ -23,6 +23,12 @@ import Foundation +// Common protocol for all types that can be used as JWK parameters. +public protocol JWKParameterType: Encodable, Decodable { } + +extension String: JWKParameterType { } +extension Array: JWKParameterType where Element == String { } + /// Possible common JWK parameters. /// See [RFC-7517, Section 4](https://tools.ietf.org/html/rfc7517#section-4) for details. public enum JWKParameter: String, CodingKey { @@ -36,10 +42,15 @@ public enum JWKParameter: String, CodingKey { case X509CertificateSHA1Thumbprint = "x5t" case X509CertificateSHA256Thumbprint = "x5t#S256" - static let nonStringParameters: [JWKParameter] = [ - .keyOperations, - .X509CertificateChain - ] + var type: Codable.Type { + switch self { + case .keyType, .keyUse, .algorithm, .keyIdentifier, + .X509URL, .X509CertificateSHA1Thumbprint, .X509CertificateSHA256Thumbprint: + return String.self + case .keyOperations, .X509CertificateChain: + return [String].self + } + } } /// RSA specific JWK parameters. diff --git a/JOSESwift/Sources/RSAKeyCodable.swift b/JOSESwift/Sources/RSAKeyCodable.swift index 659c2ff4..826c8e2e 100644 --- a/JOSESwift/Sources/RSAKeyCodable.swift +++ b/JOSESwift/Sources/RSAKeyCodable.swift @@ -33,8 +33,14 @@ extension RSAPublicKey: Encodable { // Other common parameters are optional. for parameter in parameters { // Only encode known parameters. - if let key = JWKParameter(rawValue: parameter.key) { - try commonParameters.encode(parameter.value, forKey: key) + guard let key = JWKParameter(rawValue: parameter.key) else { + continue + } + + if let value = parameter.value as? String { + try commonParameters.encode(value, forKey: key) + } else if let value = parameter.value as? [String] { + try commonParameters.encode(value, forKey: key) } } @@ -61,11 +67,16 @@ extension RSAPublicKey: Decodable { } // Other common parameters are optional. - var parameters: [String: String] = [:] - for key in commonParameters.allKeys where !JWKParameter.nonStringParameters.contains(key) { + var parameters: [String: JWKParameterType] = [:] + + for key in commonParameters.allKeys where key.type == String.self { parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) } + for key in commonParameters.allKeys where key.type == [String].self { + parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + } + // RSA public key specific parameters. let rsaParameters = try decoder.container(keyedBy: RSAParameter.self) let modulus = try rsaParameters.decode(String.self, forKey: .modulus) @@ -89,8 +100,14 @@ extension RSAPrivateKey: Encodable { // Other common parameters are optional. for parameter in parameters { // Only encode known parameters. - if let key = JWKParameter(rawValue: parameter.key) { - try commonParameters.encode(parameter.value, forKey: key) + guard let key = JWKParameter(rawValue: parameter.key) else { + continue + } + + if let value = parameter.value as? String { + try commonParameters.encode(value, forKey: key) + } else if let value = parameter.value as? [String] { + try commonParameters.encode(value, forKey: key) } } @@ -118,11 +135,16 @@ extension RSAPrivateKey: Decodable { } // Other common parameters are optional. - var parameters: [String: String] = [:] - for key in commonParameters.allKeys where !JWKParameter.nonStringParameters.contains(key) { + var parameters: [String: JWKParameterType] = [:] + + for key in commonParameters.allKeys where key.type == String.self { parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) } + for key in commonParameters.allKeys where key.type == [String].self { + parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + } + // RSA private key specific parameters. let rsaParameters = try decoder.container(keyedBy: RSAParameter.self) let modulus = try rsaParameters.decode(String.self, forKey: .modulus) diff --git a/JOSESwift/Sources/RSAKeys.swift b/JOSESwift/Sources/RSAKeys.swift index d9da63bb..e13f831c 100644 --- a/JOSESwift/Sources/RSAKeys.swift +++ b/JOSESwift/Sources/RSAKeys.swift @@ -94,7 +94,7 @@ public struct RSAPublicKey: JWK { public let keyType: JWKKeyType /// The JWK parameters. - public let parameters: [String: String] + public let parameters: [String: JWKParameterType] /// The modulus value for the RSA public key. public let modulus: String @@ -113,7 +113,7 @@ public struct RSAPublicKey: JWK { /// - exponent: The public exponent value for the RSA public key in `base64urlUInt` encoding /// as specified in [RFC-7518, Section 2](https://tools.ietf.org/html/rfc7518#section-2). /// - parameters: Additional JWK parameters. - public init(modulus: String, exponent: String, additionalParameters parameters: [String: String] = [:]) { + public init(modulus: String, exponent: String, additionalParameters parameters: [String: JWKParameterType] = [:]) { self.keyType = .RSA self.modulus = modulus self.exponent = exponent @@ -134,7 +134,7 @@ public struct RSAPublicKey: JWK { /// - publicKey: The public key that the resulting JWK should represent. /// - parameters: Any additional parameters to be contained in the JWK. /// - Throws: A `JOSESwiftError` indicating any errors. - public init(publicKey: ExpressibleAsRSAPublicKeyComponents, additionalParameters parameters: [String: String] = [:]) throws { + public init(publicKey: ExpressibleAsRSAPublicKeyComponents, additionalParameters parameters: [String: JWKParameterType] = [:]) throws { guard let components = try? publicKey.rsaPublicKeyComponents() else { throw JOSESwiftError.couldNotConstructJWK } @@ -184,7 +184,7 @@ public struct RSAPrivateKey: JWK { public let keyType: JWKKeyType /// The JWK parameters. - public let parameters: [String: String] + public let parameters: [String: JWKParameterType] /// The modulus value for the RSA private key. public let modulus: String @@ -205,7 +205,7 @@ public struct RSAPrivateKey: JWK { // - privateExponent: The private exponent value for the RSA private key in `base64urlUInt` encoding /// as specified in [RFC-7518, Section 2](https://tools.ietf.org/html/rfc7518#section-2). /// - parameters: Additional JWK parameters. - public init(modulus: String, exponent: String, privateExponent: String, additionalParameters parameters: [String: String] = [:]) { + public init(modulus: String, exponent: String, privateExponent: String, additionalParameters parameters: [String: JWKParameterType] = [:]) { self.keyType = .RSA self.modulus = modulus self.exponent = exponent @@ -228,7 +228,7 @@ public struct RSAPrivateKey: JWK { /// - privateKey: The private key that the resulting JWK should represent. /// - parameters: Any additional parameters to be contained in the JWK. /// - Throws: A `JOSESwiftError` indicating any errors. - public init(privateKey: ExpressibleAsRSAPrivateKeyComponents, additionalParameters parameters: [String: String] = [:]) throws { + public init(privateKey: ExpressibleAsRSAPrivateKeyComponents, additionalParameters parameters: [String: JWKParameterType] = [:]) throws { guard let (modulus, exponent, privateExponent) = try? privateKey.rsaPrivateKeyComponents() else { throw JOSESwiftError.couldNotConstructJWK } diff --git a/JOSESwift/Sources/SymmetricKeyCodable.swift b/JOSESwift/Sources/SymmetricKeyCodable.swift index bc8b9889..618a06c1 100644 --- a/JOSESwift/Sources/SymmetricKeyCodable.swift +++ b/JOSESwift/Sources/SymmetricKeyCodable.swift @@ -33,8 +33,14 @@ extension SymmetricKey: Encodable { // Other common parameters are optional. for parameter in parameters { // Only encode known parameters. - if let key = JWKParameter(rawValue: parameter.key) { - try commonParameters.encode(parameter.value, forKey: key) + guard let key = JWKParameter(rawValue: parameter.key) else { + continue + } + + if let value = parameter.value as? String { + try commonParameters.encode(value, forKey: key) + } else if let value = parameter.value as? [String] { + try commonParameters.encode(value, forKey: key) } } @@ -60,12 +66,17 @@ extension SymmetricKey: Decodable { } // Other common parameters are optional. - var parameters: [String: String] = [:] - for key in commonParameters.allKeys { + var parameters: [String: JWKParameterType] = [:] + + for key in commonParameters.allKeys where key.type == String.self { parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) } - // RSA public key specific parameters. + for key in commonParameters.allKeys where key.type == [String].self { + parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + } + + // Symmetric public key specific parameters. let symmetricKeyParameters = try decoder.container(keyedBy: SymmetricKeyParameter.self) let key = try symmetricKeyParameters.decode(String.self, forKey: .key) diff --git a/JOSESwift/Sources/SymmetricKeys.swift b/JOSESwift/Sources/SymmetricKeys.swift index 02c238a2..837c5cf4 100644 --- a/JOSESwift/Sources/SymmetricKeys.swift +++ b/JOSESwift/Sources/SymmetricKeys.swift @@ -57,7 +57,7 @@ public struct SymmetricKey: JWK { public let keyType: JWKKeyType /// The JWK parameters. - public let parameters: [String: String] + public let parameters: [String: JWKParameterType] /// The symmetric key represented as /// base64url encoding of the octet sequence containing the key data. @@ -68,7 +68,7 @@ public struct SymmetricKey: JWK { /// - Parameters: /// - key: The octet sequence containing the key data. /// - parameters: Additional JWK parameters. - public init(key: Data, additionalParameters parameters: [String: String] = [:]) { + public init(key: Data, additionalParameters parameters: [String: JWKParameterType] = [:]) { self.keyType = .OCT self.key = key.base64URLEncodedString() @@ -87,7 +87,7 @@ public struct SymmetricKey: JWK { /// - key: The symmetirc key that the resulting JWK should represent. /// - parameters: Any additional parameters to be contained in the JWK. /// - Throws: A `JOSESwiftError` indicating any errors. - public init(key: ExpressibleAsSymmetricKeyComponents, additionalParameters parameters: [String: String] = [:]) throws { + public init(key: ExpressibleAsSymmetricKeyComponents, additionalParameters parameters: [String: JWKParameterType] = [:]) throws { guard let components = try? key.symmetricKeyComponents() else { throw JOSESwiftError.couldNotConstructJWK } From 0478b7c019323dfa694cf4dd0af08b020dbad30c Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 19:48:21 +0200 Subject: [PATCH 02/19] Adapt tests --- Tests/JWKRSADecodingTests.swift | 24 ++++++------- Tests/JWKRSAKeysTests.swift | 30 ++++++++-------- Tests/JWKSetCodingTests.swift | 62 ++++++++++++++++----------------- Tests/SymmetricKeyTests.swift | 6 ++-- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/Tests/JWKRSADecodingTests.swift b/Tests/JWKRSADecodingTests.swift index 1c88412c..2d7b538a 100644 --- a/Tests/JWKRSADecodingTests.swift +++ b/Tests/JWKRSADecodingTests.swift @@ -64,7 +64,7 @@ class JWKRSADecodingTests: CryptoTestCase { XCTAssertNotNil(jwk) XCTAssertEqual(jwk!.keyType, .RSA) - XCTAssertEqual(jwk!["kty"] ?? "", "RSA") + XCTAssertEqual(jwk!["kty"] as? String ?? "", "RSA") XCTAssertEqual(jwk!.modulus, """ 0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n\ 3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zg\ @@ -73,8 +73,8 @@ class JWKRSADecodingTests: CryptoTestCase { """ ) XCTAssertEqual(jwk!.exponent, "AQAB") - XCTAssertEqual(jwk!["alg"] ?? "", "RS256") - XCTAssertEqual(jwk!["kid"] ?? "", "2011-04-29") + XCTAssertEqual(jwk!["alg"] as? String ?? "", "RS256") + XCTAssertEqual(jwk!["kid"] as? String ?? "", "2011-04-29") } func testDecodingPublicKey() { @@ -83,7 +83,7 @@ class JWKRSADecodingTests: CryptoTestCase { XCTAssertNotNil(jwk) XCTAssertEqual(jwk!.keyType, .RSA) - XCTAssertEqual(jwk!["kty"] ?? "", "RSA") + XCTAssertEqual(jwk!["kty"] as? String ?? "", "RSA") XCTAssertEqual(jwk!.modulus, """ 0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n\ 3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zg\ @@ -92,8 +92,8 @@ class JWKRSADecodingTests: CryptoTestCase { """ ) XCTAssertEqual(jwk!.exponent, "AQAB") - XCTAssertEqual(jwk!["alg"] ?? "", "RS256") - XCTAssertEqual(jwk!["kid"] ?? "", "2011-04-29") + XCTAssertEqual(jwk!["alg"] as? String ?? "", "RS256") + XCTAssertEqual(jwk!["kid"] as? String ?? "", "2011-04-29") } func testDecodingPublicKeyMissingKeyType() { @@ -193,7 +193,7 @@ class JWKRSADecodingTests: CryptoTestCase { XCTAssertNotNil(jwk) XCTAssertEqual(jwk!.keyType, .RSA) - XCTAssertEqual(jwk!["kty"] ?? "", "RSA") + XCTAssertEqual(jwk!["kty"] as? String ?? "", "RSA") XCTAssertEqual(jwk!.modulus, """ 0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n\ 3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zg\ @@ -209,8 +209,8 @@ class JWKRSADecodingTests: CryptoTestCase { """ ) XCTAssertEqual(jwk!.exponent, "AQAB") - XCTAssertEqual(jwk!["alg"] ?? "", "RS256") - XCTAssertEqual(jwk!["kid"] ?? "", "2011-04-29") + XCTAssertEqual(jwk!["alg"] as? String ?? "", "RS256") + XCTAssertEqual(jwk!["kid"] as? String ?? "", "2011-04-29") } @@ -220,7 +220,7 @@ class JWKRSADecodingTests: CryptoTestCase { XCTAssertNotNil(jwk) XCTAssertEqual(jwk!.keyType, .RSA) - XCTAssertEqual(jwk!["kty"] ?? "", "RSA") + XCTAssertEqual(jwk!["kty"] as? String ?? "", "RSA") XCTAssertEqual(jwk!.modulus, """ 0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n\ 3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zg\ @@ -236,8 +236,8 @@ class JWKRSADecodingTests: CryptoTestCase { """ ) XCTAssertEqual(jwk!.exponent, "AQAB") - XCTAssertEqual(jwk!["alg"] ?? "", "RS256") - XCTAssertEqual(jwk!["kid"] ?? "", "2011-04-29") + XCTAssertEqual(jwk!["alg"] as? String ?? "", "RS256") + XCTAssertEqual(jwk!["kid"] as? String ?? "", "2011-04-29") } func testDecodingPrivateKeyMissingKeyType() { diff --git a/Tests/JWKRSAKeysTests.swift b/Tests/JWKRSAKeysTests.swift index 377cdc51..b138355e 100644 --- a/Tests/JWKRSAKeysTests.swift +++ b/Tests/JWKRSAKeysTests.swift @@ -31,7 +31,7 @@ class JWKRSAKeysTests: CryptoTestCase { "kty": "wrongKty" ]) - XCTAssertEqual(jwk["kty"] ?? "", "RSA") + XCTAssertEqual(jwk["kty"] as? String ?? "", "RSA") } func testMergingDuplicateAdditionalParametersInPrivateKey() { @@ -42,20 +42,20 @@ class JWKRSAKeysTests: CryptoTestCase { additionalParameters: [ "kty": "wrongKty" ] ) - XCTAssertEqual(jwk["kty"] ?? "", "RSA") + XCTAssertEqual(jwk["kty"] as? String ?? "", "RSA") } func testInitPublicKeyDirectlyWithoutAdditionalParameters() { let key = RSAPublicKey(modulus: "n", exponent: "e") XCTAssertEqual(key.keyType, .RSA) - XCTAssertEqual(key["kty"] ?? "", "RSA") + XCTAssertEqual(key["kty"] as? String ?? "", "RSA") XCTAssertEqual(key.modulus, "n") - XCTAssertEqual(key["n"] ?? "", "n") + XCTAssertEqual(key["n"] as? String ?? "", "n") XCTAssertEqual(key.exponent, "e") - XCTAssertEqual(key["e"] ?? "", "e") + XCTAssertEqual(key["e"] as? String ?? "", "e") // kty, n, e XCTAssertEqual(key.parameters.count, 3) @@ -65,16 +65,16 @@ class JWKRSAKeysTests: CryptoTestCase { let key = RSAPrivateKey(modulus: "n", exponent: "e", privateExponent: "d") XCTAssertEqual(key.keyType, .RSA) - XCTAssertEqual(key["kty"] ?? "", "RSA") + XCTAssertEqual(key["kty"] as? String ?? "", "RSA") XCTAssertEqual(key.modulus, "n") - XCTAssertEqual(key["n"] ?? "", "n") + XCTAssertEqual(key["n"] as? String ?? "", "n") XCTAssertEqual(key.exponent, "e") - XCTAssertEqual(key["e"] ?? "", "e") + XCTAssertEqual(key["e"] as? String ?? "", "e") XCTAssertEqual(key.privateExponent, "d") - XCTAssertEqual(key["d"] ?? "", "d") + XCTAssertEqual(key["d"] as? String ?? "", "d") // kty, n, e, d XCTAssertEqual(key.parameters.count, 4) @@ -84,24 +84,24 @@ class JWKRSAKeysTests: CryptoTestCase { let jwk = try! RSAPublicKey(publicKey: publicKeyAlice2048!) XCTAssertEqual(jwk.keyType, .RSA) - XCTAssertEqual(jwk[JWKParameter.keyType.rawValue] ?? "", JWKKeyType.RSA.rawValue) - XCTAssertEqual(jwk.parameters[JWKParameter.keyType.rawValue] ?? "", JWKKeyType.RSA.rawValue) + XCTAssertEqual(jwk[JWKParameter.keyType.rawValue] as? String ?? "", JWKKeyType.RSA.rawValue) + XCTAssertEqual(jwk.parameters[JWKParameter.keyType.rawValue] as? String ?? "", JWKKeyType.RSA.rawValue) } func testPrivateKeyKeyTypeIsPresent() { let jwk = RSAPrivateKey(modulus: "A", exponent: "B", privateExponent: "C") XCTAssertEqual(jwk.keyType, .RSA) - XCTAssertEqual(jwk[JWKParameter.keyType.rawValue] ?? "", JWKKeyType.RSA.rawValue) - XCTAssertEqual(jwk.parameters[JWKParameter.keyType.rawValue] ?? "", JWKKeyType.RSA.rawValue) + XCTAssertEqual(jwk[JWKParameter.keyType.rawValue] as? String ?? "", JWKKeyType.RSA.rawValue) + XCTAssertEqual(jwk.parameters[JWKParameter.keyType.rawValue] as? String ?? "", JWKKeyType.RSA.rawValue) } func testSettingAndGettingAdditionalParameter() { let jwk = try! RSAPublicKey(publicKey: publicKeyAlice2048!, additionalParameters: [ "kid": "new on the block" - ]) + ]) - XCTAssertEqual(jwk["kid"] ?? "", "new on the block") + XCTAssertEqual(jwk["kid"] as? String ?? "", "new on the block") } func testPublicKeyAllParametersArePresentInDict() { diff --git a/Tests/JWKSetCodingTests.swift b/Tests/JWKSetCodingTests.swift index 718c3512..d6ee350c 100644 --- a/Tests/JWKSetCodingTests.swift +++ b/Tests/JWKSetCodingTests.swift @@ -276,9 +276,9 @@ class JWKSetCodingTests: XCTestCase { XCTAssertEqual(rsaKey.modulus, modulus) XCTAssertEqual(rsaKey.exponent, exponent) - XCTAssertEqual(rsaKey["kty"], additionalParametersRSA["kty"]) - XCTAssertEqual(rsaKey["kid"], additionalParametersRSA["kid"]) - XCTAssertEqual(rsaKey["alg"], additionalParametersRSA["alg"]) + XCTAssertEqual(rsaKey["kty"] as? String, additionalParametersRSA["kty"]) + XCTAssertEqual(rsaKey["kid"] as? String, additionalParametersRSA["kid"]) + XCTAssertEqual(rsaKey["alg"] as? String, additionalParametersRSA["alg"]) } func testDecodingOneSymmetricKey() { @@ -291,8 +291,8 @@ class JWKSetCodingTests: XCTestCase { let key = jwkSet[0] as! SymmetricKey XCTAssertEqual(key.key, firstSymmetricKey.base64URLEncodedString()) - XCTAssertEqual(key["kty"], firstAdditionalParametersOct["kty"]) - XCTAssertEqual(key["alg"], firstAdditionalParametersOct["alg"]) + XCTAssertEqual(key["kty"] as? String, firstAdditionalParametersOct["kty"]) + XCTAssertEqual(key["alg"] as? String, firstAdditionalParametersOct["alg"]) } func testDecodingTwoRSAPublicKeys() { @@ -306,9 +306,9 @@ class JWKSetCodingTests: XCTestCase { XCTAssertEqual(rsaKey.modulus, modulus) XCTAssertEqual(rsaKey.exponent, exponent) - XCTAssertEqual(rsaKey["kty"], additionalParametersRSA["kty"]) - XCTAssertEqual(rsaKey["kid"], additionalParametersRSA["kid"]) - XCTAssertEqual(rsaKey["alg"], additionalParametersRSA["alg"]) + XCTAssertEqual(rsaKey["kty"] as? String, additionalParametersRSA["kty"]) + XCTAssertEqual(rsaKey["kid"] as? String, additionalParametersRSA["kid"]) + XCTAssertEqual(rsaKey["alg"] as? String, additionalParametersRSA["alg"]) XCTAssert(jwkSet[1] is RSAPublicKey) @@ -316,9 +316,9 @@ class JWKSetCodingTests: XCTestCase { XCTAssertEqual(rsaKey.modulus, modulus) XCTAssertEqual(rsaKey.exponent, exponent) - XCTAssertEqual(rsaKey["kty"], additionalParametersRSA["kty"]) - XCTAssertEqual(rsaKey["kid"], additionalParametersRSA["kid"]) - XCTAssertEqual(rsaKey["alg"], additionalParametersRSA["alg"]) + XCTAssertEqual(rsaKey["kty"] as? String, additionalParametersRSA["kty"]) + XCTAssertEqual(rsaKey["kid"] as? String, additionalParametersRSA["kid"]) + XCTAssertEqual(rsaKey["alg"] as? String, additionalParametersRSA["alg"]) } func testDecodingRSAPublicAndPrivateKey() { @@ -332,9 +332,9 @@ class JWKSetCodingTests: XCTestCase { XCTAssertEqual(rsaPublicKey.modulus, modulus) XCTAssertEqual(rsaPublicKey.exponent, exponent) - XCTAssertEqual(rsaPublicKey["kty"], additionalParametersRSA["kty"]) - XCTAssertEqual(rsaPublicKey["kid"], additionalParametersRSA["kid"]) - XCTAssertEqual(rsaPublicKey["alg"], additionalParametersRSA["alg"]) + XCTAssertEqual(rsaPublicKey["kty"] as? String, additionalParametersRSA["kty"]) + XCTAssertEqual(rsaPublicKey["kid"] as? String, additionalParametersRSA["kid"]) + XCTAssertEqual(rsaPublicKey["alg"] as? String, additionalParametersRSA["alg"]) XCTAssert(jwkSet[1] is RSAPrivateKey) @@ -343,9 +343,9 @@ class JWKSetCodingTests: XCTestCase { XCTAssertEqual(rsaPrivateKey.modulus, modulus) XCTAssertEqual(rsaPrivateKey.exponent, exponent) XCTAssertEqual(rsaPrivateKey.privateExponent, privateExponent) - XCTAssertEqual(rsaPrivateKey["kty"], additionalParametersRSA["kty"]) - XCTAssertEqual(rsaPrivateKey["kid"], additionalParametersRSA["kid"]) - XCTAssertEqual(rsaPrivateKey["alg"], additionalParametersRSA["alg"]) + XCTAssertEqual(rsaPrivateKey["kty"] as? String, additionalParametersRSA["kty"]) + XCTAssertEqual(rsaPrivateKey["kid"] as? String, additionalParametersRSA["kid"]) + XCTAssertEqual(rsaPrivateKey["alg"] as? String, additionalParametersRSA["alg"]) } func testDecodingRSAPublicAndPrivateAndSymmetricKey() { @@ -359,9 +359,9 @@ class JWKSetCodingTests: XCTestCase { XCTAssertEqual(rsaPublicKey.modulus, modulus) XCTAssertEqual(rsaPublicKey.exponent, exponent) - XCTAssertEqual(rsaPublicKey["kty"], additionalParametersRSA["kty"]) - XCTAssertEqual(rsaPublicKey["kid"], additionalParametersRSA["kid"]) - XCTAssertEqual(rsaPublicKey["alg"], additionalParametersRSA["alg"]) + XCTAssertEqual(rsaPublicKey["kty"] as? String, additionalParametersRSA["kty"]) + XCTAssertEqual(rsaPublicKey["kid"] as? String, additionalParametersRSA["kid"]) + XCTAssertEqual(rsaPublicKey["alg"] as? String, additionalParametersRSA["alg"]) XCTAssert(jwkSet[1] is RSAPrivateKey) @@ -370,17 +370,17 @@ class JWKSetCodingTests: XCTestCase { XCTAssertEqual(rsaPrivateKey.modulus, modulus) XCTAssertEqual(rsaPrivateKey.exponent, exponent) XCTAssertEqual(rsaPrivateKey.privateExponent, privateExponent) - XCTAssertEqual(rsaPrivateKey["kty"], additionalParametersRSA["kty"]) - XCTAssertEqual(rsaPrivateKey["kid"], additionalParametersRSA["kid"]) - XCTAssertEqual(rsaPrivateKey["alg"], additionalParametersRSA["alg"]) + XCTAssertEqual(rsaPrivateKey["kty"] as? String, additionalParametersRSA["kty"]) + XCTAssertEqual(rsaPrivateKey["kid"] as? String, additionalParametersRSA["kid"]) + XCTAssertEqual(rsaPrivateKey["alg"] as? String, additionalParametersRSA["alg"]) XCTAssert(jwkSet[2] is SymmetricKey) let key = jwkSet[2] as! SymmetricKey XCTAssertEqual(key.key, firstSymmetricKey.base64URLEncodedString()) - XCTAssertEqual(key["kty"], firstAdditionalParametersOct["kty"]) - XCTAssertEqual(key["alg"], firstAdditionalParametersOct["alg"]) + XCTAssertEqual(key["kty"] as? String, firstAdditionalParametersOct["kty"]) + XCTAssertEqual(key["alg"] as? String, firstAdditionalParametersOct["alg"]) } // - MARK: Convenience Helpers Test @@ -396,9 +396,9 @@ class JWKSetCodingTests: XCTestCase { XCTAssertEqual(rsaKey.modulus, modulus) XCTAssertEqual(rsaKey.exponent, exponent) - XCTAssertEqual(rsaKey["kty"], additionalParametersRSA["kty"]) - XCTAssertEqual(rsaKey["kid"], additionalParametersRSA["kid"]) - XCTAssertEqual(rsaKey["alg"], additionalParametersRSA["alg"]) + XCTAssertEqual(rsaKey["kty"] as? String, additionalParametersRSA["kty"]) + XCTAssertEqual(rsaKey["kid"] as? String, additionalParametersRSA["kid"]) + XCTAssertEqual(rsaKey["alg"] as? String, additionalParametersRSA["alg"]) XCTAssert(jwkSet[1] is RSAPublicKey) @@ -406,9 +406,9 @@ class JWKSetCodingTests: XCTestCase { XCTAssertEqual(rsaKey.modulus, modulus) XCTAssertEqual(rsaKey.exponent, exponent) - XCTAssertEqual(rsaKey["kty"], additionalParametersRSA["kty"]) - XCTAssertEqual(rsaKey["kid"], additionalParametersRSA["kid"]) - XCTAssertEqual(rsaKey["alg"], additionalParametersRSA["alg"]) + XCTAssertEqual(rsaKey["kty"] as? String, additionalParametersRSA["kty"]) + XCTAssertEqual(rsaKey["kid"] as? String, additionalParametersRSA["kid"]) + XCTAssertEqual(rsaKey["alg"] as? String, additionalParametersRSA["alg"]) } func testToJsonData() { diff --git a/Tests/SymmetricKeyTests.swift b/Tests/SymmetricKeyTests.swift index f2a28e25..ce2f7dcc 100644 --- a/Tests/SymmetricKeyTests.swift +++ b/Tests/SymmetricKeyTests.swift @@ -41,7 +41,7 @@ class SymmetricKeyTests: XCTestCase { XCTAssertEqual(jwk.key, "GawgguFyGrWKav7AX4VKUg") XCTAssertEqual(jwk.keyType, .OCT) - XCTAssertEqual(jwk["alg"], "A256CBC-HS512") + XCTAssertEqual(jwk["alg"] as! String, "A256CBC-HS512") XCTAssertEqual( "{\"kty\":\"oct\",\"alg\":\"A256CBC-HS512\",\"k\":\"GawgguFyGrWKav7AX4VKUg\"}", @@ -63,7 +63,7 @@ class SymmetricKeyTests: XCTestCase { XCTAssertEqual(jwk.key, "GawgguFyGrWKav7AX4VKUg") XCTAssertEqual(jwk.keyType, .OCT) - XCTAssertEqual(jwk["alg"], "A256CBC-HS512") + XCTAssertEqual(jwk["alg"] as! String, "A256CBC-HS512") XCTAssertEqual( "{\"kty\":\"oct\",\"alg\":\"A256CBC-HS512\",\"k\":\"GawgguFyGrWKav7AX4VKUg\"}", @@ -85,7 +85,7 @@ class SymmetricKeyTests: XCTestCase { XCTAssertEqual(jwk.key, "GawgguFyGrWKav7AX4VKUg") XCTAssertEqual(jwk.keyType, .OCT) - XCTAssertEqual(jwk["alg"], "A256CBC-HS512") + XCTAssertEqual(jwk["alg"] as! String, "A256CBC-HS512") XCTAssertEqual( "{\"kty\":\"oct\",\"alg\":\"A256CBC-HS512\",\"k\":\"GawgguFyGrWKav7AX4VKUg\"}", From 9d98e856115856c6cf9f6aa552da745281c5d640 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 19:48:42 +0200 Subject: [PATCH 03/19] Add new test case --- JOSESwift.xcodeproj/project.pbxproj | 4 +++ Tests/JWKParameterTypeTests.swift | 55 +++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 Tests/JWKParameterTypeTests.swift diff --git a/JOSESwift.xcodeproj/project.pbxproj b/JOSESwift.xcodeproj/project.pbxproj index ffb433cd..ec55225e 100644 --- a/JOSESwift.xcodeproj/project.pbxproj +++ b/JOSESwift.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 6505236E1FB4940100E0B1B1 /* AESEncrypter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6505236D1FB4940100E0B1B1 /* AESEncrypter.swift */; }; 650523701FB494BE00E0B1B1 /* AESDecrypter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6505236F1FB494BE00E0B1B1 /* AESDecrypter.swift */; }; 6506D9E920F4CA2000F34DD8 /* SymmetricKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6506D9E820F4CA2000F34DD8 /* SymmetricKeyTests.swift */; }; + 6508625B2180D9A00052F9CA /* JWKParameterTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6508625A2180D9A00052F9CA /* JWKParameterTypeTests.swift */; }; 65125A321FBF85FA007CF3AE /* JWSDeserializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65125A311FBF85FA007CF3AE /* JWSDeserializationTests.swift */; }; 6514ADC92031DD15008A4DD3 /* ASN1DEREncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6514ADC82031DD15008A4DD3 /* ASN1DEREncoding.swift */; }; 6514ADCB2031DD27008A4DD3 /* ASN1DEREncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6514ADCA2031DD27008A4DD3 /* ASN1DEREncodingTests.swift */; }; @@ -108,6 +109,7 @@ 6505236D1FB4940100E0B1B1 /* AESEncrypter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AESEncrypter.swift; sourceTree = ""; }; 6505236F1FB494BE00E0B1B1 /* AESDecrypter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AESDecrypter.swift; sourceTree = ""; }; 6506D9E820F4CA2000F34DD8 /* SymmetricKeyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymmetricKeyTests.swift; sourceTree = ""; }; + 6508625A2180D9A00052F9CA /* JWKParameterTypeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWKParameterTypeTests.swift; sourceTree = ""; }; 65125A311FBF85FA007CF3AE /* JWSDeserializationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWSDeserializationTests.swift; sourceTree = ""; }; 6514ADC82031DD15008A4DD3 /* ASN1DEREncoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1DEREncoding.swift; sourceTree = ""; }; 6514ADCA2031DD27008A4DD3 /* ASN1DEREncodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1DEREncodingTests.swift; sourceTree = ""; }; @@ -333,6 +335,7 @@ 65A103A0202B03BB00D22BF5 /* ASN1DERParsingTests.swift */, 65A103A2202B0CDF00D22BF5 /* DataRSAPublicKeyTests.swift */, 6546D605203580C6007217FB /* JWKRSADecodingTests.swift */, + 6508625A2180D9A00052F9CA /* JWKParameterTypeTests.swift */, 65826AB320286B3A00AFFC46 /* JWKRSAEncodingTests.swift */, 65E733D41FEC031B0009EAC6 /* JWKRSAKeysTests.swift */, 6536560A2035DC3900A3AC3B /* JWKSetCodingTests.swift */, @@ -631,6 +634,7 @@ C8F096501FC56B25000BEE4D /* RSAEncrypterTests.swift in Sources */, 65125A321FBF85FA007CF3AE /* JWSDeserializationTests.swift in Sources */, 65A103A3202B0CDF00D22BF5 /* DataRSAPublicKeyTests.swift in Sources */, + 6508625B2180D9A00052F9CA /* JWKParameterTypeTests.swift in Sources */, C81DD9261FD6F07F00026024 /* (null) in Sources */, C84BDE171FAB1CB60002B5D0 /* RSASignerTests.swift in Sources */, C8EE14541FAC797500A616E4 /* RSAVerifierTests.swift in Sources */, diff --git a/Tests/JWKParameterTypeTests.swift b/Tests/JWKParameterTypeTests.swift new file mode 100644 index 00000000..522133f9 --- /dev/null +++ b/Tests/JWKParameterTypeTests.swift @@ -0,0 +1,55 @@ +// +// JWKParameterTypeTests.swift +// Tests +// +// Created by Daniel on 24.10.18. +// + +import XCTest +@testable import JOSESwift + +class JWKParameterTypeTests: XCTestCase { + + let jwk = """ + { "kty": "RSA", "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJ\ + ECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8\ + KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls\ + 1jF44-csFCur-kEgU8awapJzKnqDKgw", "e": "AQAB", "alg": "RS256", "key_ops": ["sign", "verify"], "x5c": ["MIIDQjCC\ + AiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQ\ + KExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCz\ + AJBgNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5Cc\ + mlhbiBDYW1wYmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnHYMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6a\ + mFtPDy2yvz3YlRij66s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jI\ + QRMMGQwsU1quGmFgHIXPLfnpnfajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPqPvEjZ2dbZkaBhPbiZAS3YeYBRDW\ + m1p1OZtWamT3cEvqqPpnjL1XyW+oyVVkaZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAh8zGlfSlc\ + I0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1zFo+Owb1zxtp3\ + PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo4tpzd5\ + rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTqgawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA\ + =="], "kid": "2011-04-29"} + """.data(using: .utf8)! + + func testDecodingStringAndStringArrayParametersDoesNotThrow() { + XCTAssertNoThrow(try RSAPublicKey(data: jwk)) + } + + func testDecodingStringParameters() { + let key = try! RSAPublicKey(data: jwk) + + XCTAssertEqual(key.keyType.rawValue, "RSA") + XCTAssertEqual(key.modulus.prefix(5), "0vx7a") + XCTAssertEqual(key.modulus.suffix(5), "qDKgw") + XCTAssertEqual(key.exponent, "AQAB") + + XCTAssertEqual(key["alg"] as! String, "RS256") + XCTAssertEqual(key["kid"] as! String, "2011-04-29") + } + + func testDecodingStringArrayParameterKeyOps() { + let key = try! RSAPublicKey(data: jwk) + + let keyOperations = key["key_ops"] + + XCTAssertNotNil(keyOperations) + } + +} From 32c1e11e3e0301e0f6af7fa8ac0a650f7af7e036 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 21:27:26 +0200 Subject: [PATCH 04/19] Remove key type computed property --- JOSESwift/Sources/JWK.swift | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/JOSESwift/Sources/JWK.swift b/JOSESwift/Sources/JWK.swift index 8b755df8..415955ad 100644 --- a/JOSESwift/Sources/JWK.swift +++ b/JOSESwift/Sources/JWK.swift @@ -82,3 +82,37 @@ public protocol JWK: Codable { /// `nil` if the encoding failed. func jsonData() -> Data? } + +extension JWK { + var keyUse: String? { + return parameters[JWKParameter.keyUse.rawValue] as? String + } + + var keyOperations: [String]? { + return parameters[JWKParameter.keyOperations.rawValue] as? [String] + } + + var algorithm: String? { + return parameters[JWKParameter.algorithm.rawValue] as? String + } + + var keyIdentifier: String? { + return parameters[JWKParameter.keyIdentifier.rawValue] as? String + } + + var X509URL: String? { + return parameters[JWKParameter.X509URL.rawValue] as? String + } + + var X509CertificateChain: [String]? { + return parameters[JWKParameter.X509CertificateChain.rawValue] as? [String] + } + + var X509CertificateSHA1Thumbprint: String? { + return parameters[JWKParameter.X509CertificateSHA1Thumbprint.rawValue] as? String + } + + var X509CertificateSHA256Thumbprint: String? { + return parameters[JWKParameter.X509CertificateSHA256Thumbprint.rawValue] as? String + } +} From 0bcdd26b4a8c681bbd02a393a57a90914e6e7315 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 21:27:34 +0200 Subject: [PATCH 05/19] Update tests --- Tests/JWKParameterTypeTests.swift | 46 +++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/Tests/JWKParameterTypeTests.swift b/Tests/JWKParameterTypeTests.swift index 522133f9..13e8665e 100644 --- a/Tests/JWKParameterTypeTests.swift +++ b/Tests/JWKParameterTypeTests.swift @@ -25,7 +25,7 @@ class JWKParameterTypeTests: XCTestCase { I0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1zFo+Owb1zxtp3\ PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo4tpzd5\ rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTqgawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA\ - =="], "kid": "2011-04-29"} + =="], "kid": "2011-04-29", "use":"sig"} """.data(using: .utf8)! func testDecodingStringAndStringArrayParametersDoesNotThrow() { @@ -39,17 +39,53 @@ class JWKParameterTypeTests: XCTestCase { XCTAssertEqual(key.modulus.prefix(5), "0vx7a") XCTAssertEqual(key.modulus.suffix(5), "qDKgw") XCTAssertEqual(key.exponent, "AQAB") + XCTAssertEqual(key.keyUse, "sig") - XCTAssertEqual(key["alg"] as! String, "RS256") - XCTAssertEqual(key["kid"] as! String, "2011-04-29") + XCTAssertEqual(key.algorithm ?? "", "RS256") + XCTAssertEqual(key.keyIdentifier ?? "", "2011-04-29") } - func testDecodingStringArrayParameterKeyOps() { + func testDecodingStringArrayParameterKeyOpsSubscript() { let key = try! RSAPublicKey(data: jwk) - let keyOperations = key["key_ops"] + let keyOperations = key["key_ops"] as? [String] XCTAssertNotNil(keyOperations) + XCTAssertEqual(keyOperations!.count, 2) + XCTAssertEqual(keyOperations![0], "sign") + XCTAssertEqual(keyOperations![1], "verify") } + func testDecodingStringArrayParameterKeyOpsComputed() { + let key = try! RSAPublicKey(data: jwk) + + let keyOperations = key.keyOperations + + XCTAssertNotNil(keyOperations) + XCTAssertEqual(keyOperations!.count, 2) + XCTAssertEqual(keyOperations![0], "sign") + XCTAssertEqual(keyOperations![1], "verify") + } + + func testDecodingStringArrayParameterCertificateChainSubscript() { + let key = try! RSAPublicKey(data: jwk) + + let certificateChain = key["x5c"] as? [String] + + XCTAssertNotNil(certificateChain) + XCTAssertEqual(certificateChain!.count, 1) + XCTAssertEqual(certificateChain![0].prefix(5), "MIIDQ") + XCTAssertEqual(certificateChain![0].suffix(5), "OWA==") + } + + func testDecodingStringArrayParameterCertificateChainComputed() { + let key = try! RSAPublicKey(data: jwk) + + let certificateChain = key.X509CertificateChain + + XCTAssertNotNil(certificateChain) + XCTAssertEqual(certificateChain!.count, 1) + XCTAssertEqual(certificateChain![0].prefix(5), "MIIDQ") + XCTAssertEqual(certificateChain![0].suffix(5), "OWA==") + } } From daedd4b27f76de0164183bb20bad79208044198b Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 21:31:30 +0200 Subject: [PATCH 06/19] Fix long lines --- JOSESwift/Sources/RSAKeys.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/JOSESwift/Sources/RSAKeys.swift b/JOSESwift/Sources/RSAKeys.swift index e13f831c..5b614747 100644 --- a/JOSESwift/Sources/RSAKeys.swift +++ b/JOSESwift/Sources/RSAKeys.swift @@ -134,7 +134,8 @@ public struct RSAPublicKey: JWK { /// - publicKey: The public key that the resulting JWK should represent. /// - parameters: Any additional parameters to be contained in the JWK. /// - Throws: A `JOSESwiftError` indicating any errors. - public init(publicKey: ExpressibleAsRSAPublicKeyComponents, additionalParameters parameters: [String: JWKParameterType] = [:]) throws { + public init(publicKey: ExpressibleAsRSAPublicKeyComponents, + additionalParameters parameters: [String: JWKParameterType] = [:]) throws { guard let components = try? publicKey.rsaPublicKeyComponents() else { throw JOSESwiftError.couldNotConstructJWK } @@ -228,7 +229,8 @@ public struct RSAPrivateKey: JWK { /// - privateKey: The private key that the resulting JWK should represent. /// - parameters: Any additional parameters to be contained in the JWK. /// - Throws: A `JOSESwiftError` indicating any errors. - public init(privateKey: ExpressibleAsRSAPrivateKeyComponents, additionalParameters parameters: [String: JWKParameterType] = [:]) throws { + public init(privateKey: ExpressibleAsRSAPrivateKeyComponents, + additionalParameters parameters: [String: JWKParameterType] = [:]) throws { guard let (modulus, exponent, privateExponent) = try? privateKey.rsaPrivateKeyComponents() else { throw JOSESwiftError.couldNotConstructJWK } From c27f7fae450b57aa5578ed003a6cb99fc8f7e9b7 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 21:32:02 +0200 Subject: [PATCH 07/19] Update readme --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 35c9ceee..47d111e8 100644 --- a/README.md +++ b/README.md @@ -307,8 +307,6 @@ let publicKey: SecKey = try! jwk.converted(to: SecKey.self) More details about decoding RSA public keys can be found [in the wiki](../../wiki/jwk). -:warning: We currently ignore the key parameters [`"key_ops"`](https://tools.ietf.org/html/rfc7517#section-4.3) and [`"x5c"`](https://tools.ietf.org/html/rfc7517#section-4.7) when decoding. This is due to a bug in our decoding implementation. See [#117](https://github.com/airsidemobile/JOSESwift/issues/117) for details. - ## Security JOSESwift uses the [iOS Security framework](https://developer.apple.com/documentation/security) and [Appleā€™s CommonCrypto](https://opensource.apple.com//source/CommonCrypto/) for cryptography. From 82ca0c2e5488919d2b58b3b40cab9a11a3606f9c Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 21:48:45 +0200 Subject: [PATCH 08/19] Move parameter getter extension --- JOSESwift/Sources/JWK.swift | 34 ------------------------ JOSESwift/Sources/JWKExtensions.swift | 37 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/JOSESwift/Sources/JWK.swift b/JOSESwift/Sources/JWK.swift index 415955ad..8b755df8 100644 --- a/JOSESwift/Sources/JWK.swift +++ b/JOSESwift/Sources/JWK.swift @@ -82,37 +82,3 @@ public protocol JWK: Codable { /// `nil` if the encoding failed. func jsonData() -> Data? } - -extension JWK { - var keyUse: String? { - return parameters[JWKParameter.keyUse.rawValue] as? String - } - - var keyOperations: [String]? { - return parameters[JWKParameter.keyOperations.rawValue] as? [String] - } - - var algorithm: String? { - return parameters[JWKParameter.algorithm.rawValue] as? String - } - - var keyIdentifier: String? { - return parameters[JWKParameter.keyIdentifier.rawValue] as? String - } - - var X509URL: String? { - return parameters[JWKParameter.X509URL.rawValue] as? String - } - - var X509CertificateChain: [String]? { - return parameters[JWKParameter.X509CertificateChain.rawValue] as? [String] - } - - var X509CertificateSHA1Thumbprint: String? { - return parameters[JWKParameter.X509CertificateSHA1Thumbprint.rawValue] as? String - } - - var X509CertificateSHA256Thumbprint: String? { - return parameters[JWKParameter.X509CertificateSHA256Thumbprint.rawValue] as? String - } -} diff --git a/JOSESwift/Sources/JWKExtensions.swift b/JOSESwift/Sources/JWKExtensions.swift index 666dacab..0f182d88 100644 --- a/JOSESwift/Sources/JWKExtensions.swift +++ b/JOSESwift/Sources/JWKExtensions.swift @@ -46,3 +46,40 @@ public extension JWK { return try? JSONEncoder().encode(self) } } + +// MARK: Parameter getters + +extension JWK { + var keyUse: String? { + return parameters[JWKParameter.keyUse.rawValue] as? String + } + + var keyOperations: [String]? { + return parameters[JWKParameter.keyOperations.rawValue] as? [String] + } + + var algorithm: String? { + return parameters[JWKParameter.algorithm.rawValue] as? String + } + + var keyIdentifier: String? { + return parameters[JWKParameter.keyIdentifier.rawValue] as? String + } + + var X509URL: String? { + return parameters[JWKParameter.X509URL.rawValue] as? String + } + + var X509CertificateChain: [String]? { + return parameters[JWKParameter.X509CertificateChain.rawValue] as? [String] + } + + var X509CertificateSHA1Thumbprint: String? { + return parameters[JWKParameter.X509CertificateSHA1Thumbprint.rawValue] as? String + } + + var X509CertificateSHA256Thumbprint: String? { + return parameters[JWKParameter.X509CertificateSHA256Thumbprint.rawValue] as? String + } +} + From 9a6eaa76de940cb6f83edb3681535a1402f7ffd6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 21:53:32 +0200 Subject: [PATCH 09/19] Add doc comments to param getters --- JOSESwift/Sources/JWKExtensions.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/JOSESwift/Sources/JWKExtensions.swift b/JOSESwift/Sources/JWKExtensions.swift index 0f182d88..27a277ff 100644 --- a/JOSESwift/Sources/JWKExtensions.swift +++ b/JOSESwift/Sources/JWKExtensions.swift @@ -50,34 +50,53 @@ public extension JWK { // MARK: Parameter getters extension JWK { + /// The public key use parameter identifies the intended use of a public key. + /// See [RFC-7517](https://tools.ietf.org/html/rfc7517#section-4.2). var keyUse: String? { return parameters[JWKParameter.keyUse.rawValue] as? String } + /// The key operations parameter identifies the operation(s) for which the key is intended to be used. + /// See [RFC-7517](https://tools.ietf.org/html/rfc7517#section-4.3). var keyOperations: [String]? { return parameters[JWKParameter.keyOperations.rawValue] as? [String] } + /// The algorithm parameter identifies the algorithm intended for use with the key. + /// See [RFC-7517](https://tools.ietf.org/html/rfc7517#section-4.4). var algorithm: String? { return parameters[JWKParameter.algorithm.rawValue] as? String } + /// The key identifier parameter is used to match a specific key. + /// See [RFC-7517](https://tools.ietf.org/html/rfc7517#section-4.5). var keyIdentifier: String? { return parameters[JWKParameter.keyIdentifier.rawValue] as? String } + /// The X.509 URL parameter is a URI that refers to a resource for an X.509 public key certificate + /// or certificate chain. + /// See [RFC-7517](https://tools.ietf.org/html/rfc7517#section-4.6). var X509URL: String? { return parameters[JWKParameter.X509URL.rawValue] as? String } + /// The X.509 certificate chain parameter contains a chain of one or more PKIX certificates. + /// See [RFC-7517](https://tools.ietf.org/html/rfc7517#section-4.7). var X509CertificateChain: [String]? { return parameters[JWKParameter.X509CertificateChain.rawValue] as? [String] } + /// The X.509 certificate SHA-1 thumbprint parameter is a base64url-encoded SHA-1 thumbprint (a.k.a. digest) + /// of the DER encoding of an X.509 certificate. + /// See [RFC-7517](https://tools.ietf.org/html/rfc7517#section-4.8). var X509CertificateSHA1Thumbprint: String? { return parameters[JWKParameter.X509CertificateSHA1Thumbprint.rawValue] as? String } + /// The X.509 certificate SHA-256 thumbprint parameter is a base64url-encoded SHA-256 thumbprint (a.k.a. digest) + /// of the DER encoding of an X.509 certificate. + /// See [RFC-7517](https://tools.ietf.org/html/rfc7517#section-4.9). var X509CertificateSHA256Thumbprint: String? { return parameters[JWKParameter.X509CertificateSHA256Thumbprint.rawValue] as? String } From 2cf0c6a48d26ea912ed8a937e36f87ca1586fdfe Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Oct 2018 21:54:50 +0200 Subject: [PATCH 10/19] Remove old array parameter test --- Tests/JWKRSADecodingTests.swift | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/Tests/JWKRSADecodingTests.swift b/Tests/JWKRSADecodingTests.swift index 2d7b538a..69038eb7 100644 --- a/Tests/JWKRSADecodingTests.swift +++ b/Tests/JWKRSADecodingTests.swift @@ -351,33 +351,4 @@ class JWKRSADecodingTests: CryptoTestCase { XCTFail() } - - - func testBuildingJWKSetShouldNotFailIfCertificatesArePresent() { - // Given - let json = """ - { - "keys": [{ - "kty": "RSA", - "e": "AQAB", - "use": "enc", - "x5t": "eGydA5CgawshHa8ULkMyn5gl9eI", - "kid": "kid-12345", - "x5c": ["Y2VydGlmaWNhdGUxMjM0NWRhdGEx"], - "n": "4r7_nnmRn9hppkfxt8p" - }, { - "kty": "RSA", - "e": "AQAB", - "use": "sig", - "x5t": "gpYbURn6jaHwNX9xhE2MGCIXPd0", - "kid": "kid-12346", - "x5c": ["Y2VydGlmaWNhdGUxMjM0NWRhdGEy"], - "n": "rTZj4tESZaNMpwsj" - }] - } - """.data(using: .utf8)! - - // Then - XCTAssertNoThrow(try JWKSet(data: json)) - } } From bf2539b47cc3a9ee1136cec96abbd009346a43fd Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Jan 2019 13:16:05 +0100 Subject: [PATCH 11/19] Use Codable for JWKPArameterType --- JOSESwift/Sources/JWKParameters.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JOSESwift/Sources/JWKParameters.swift b/JOSESwift/Sources/JWKParameters.swift index d1ea846f..c0742699 100644 --- a/JOSESwift/Sources/JWKParameters.swift +++ b/JOSESwift/Sources/JWKParameters.swift @@ -24,7 +24,7 @@ import Foundation // Common protocol for all types that can be used as JWK parameters. -public protocol JWKParameterType: Encodable, Decodable { } +public protocol JWKParameterType: Codable { } extension String: JWKParameterType { } extension Array: JWKParameterType where Element == String { } From 763c67fde6ec74e82b2c0eb6e7466d81c80b5b68 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Jan 2019 13:17:55 +0100 Subject: [PATCH 12/19] Use JWKPArameterType instsead of Any for subscript --- JOSESwift/Sources/JWK.swift | 2 +- JOSESwift/Sources/JWKExtensions.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/JOSESwift/Sources/JWK.swift b/JOSESwift/Sources/JWK.swift index 8b755df8..85ce8dac 100644 --- a/JOSESwift/Sources/JWK.swift +++ b/JOSESwift/Sources/JWK.swift @@ -61,7 +61,7 @@ public protocol JWK: Codable { /// [RFC 7518, Section 6](https://tools.ietf.org/html/rfc7518#section-6) for possible parameters. /// /// - Parameter parameter: The desired parameter. - subscript(parameter: String) -> Any? { get } + subscript(parameter: String) -> JWKParameterType? { get } /// Initializes a JWK from given JSON data. /// diff --git a/JOSESwift/Sources/JWKExtensions.swift b/JOSESwift/Sources/JWKExtensions.swift index 27a277ff..8962f361 100644 --- a/JOSESwift/Sources/JWKExtensions.swift +++ b/JOSESwift/Sources/JWKExtensions.swift @@ -26,7 +26,7 @@ import Foundation // MARK: Subscript public extension JWK { - subscript(parameter: String) -> Any? { + subscript(parameter: String) -> JWKParameterType? { return parameters[parameter] } } From f006882352eaa47eaea4f84a0b391fb6b5928f29 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Jan 2019 13:41:11 +0100 Subject: [PATCH 13/19] Adapt EC keys for String arary parameters --- JOSESwift/Sources/ECKeyCodable.swift | 38 ++++++++++++++++++++++------ JOSESwift/Sources/ECKeys.swift | 21 ++++++++++----- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/JOSESwift/Sources/ECKeyCodable.swift b/JOSESwift/Sources/ECKeyCodable.swift index d3a709e4..3b6279b0 100644 --- a/JOSESwift/Sources/ECKeyCodable.swift +++ b/JOSESwift/Sources/ECKeyCodable.swift @@ -33,8 +33,14 @@ extension ECPublicKey: Encodable { // Other common parameters are optional. for parameter in parameters { // Only encode known parameters. - if let key = JWKParameter(rawValue: parameter.key) { - try commonParameters.encode(parameter.value, forKey: key) + guard let key = JWKParameter(rawValue: parameter.key) else { + continue + } + + if let value = parameter.value as? String { + try commonParameters.encode(value, forKey: key) + } else if let value = parameter.value as? [String] { + try commonParameters.encode(value, forKey: key) } } @@ -62,11 +68,16 @@ extension ECPublicKey: Decodable { } // Other common parameters are optional. - var parameters: [String: String] = [:] - for key in commonParameters.allKeys { + var parameters: [String: JWKParameterType] = [:] + + for key in commonParameters.allKeys where key.type == String.self{ parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) } + for key in commonParameters.allKeys where key.type == [String].self{ + parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + } + // EC public key specific parameters. let ecParameters = try decoder.container(keyedBy: ECParameter.self) let crv = try ecParameters.decode(ECCurveType.self, forKey: .curve) @@ -92,8 +103,14 @@ extension ECPrivateKey: Encodable { // Other common parameters are optional. for parameter in parameters { // Only encode known parameters. - if let key = JWKParameter(rawValue: parameter.key) { - try commonParameters.encode(parameter.value, forKey: key) + guard let key = JWKParameter(rawValue: parameter.key) else { + continue + } + + if let value = parameter.value as? String { + try commonParameters.encode(value, forKey: key) + } else if let value = parameter.value as? [String] { + try commonParameters.encode(value, forKey: key) } } @@ -122,11 +139,16 @@ extension ECPrivateKey: Decodable { } // Other common parameters are optional. - var parameters: [String: String] = [:] - for key in commonParameters.allKeys { + var parameters: [String: JWKParameterType] = [:] + + for key in commonParameters.allKeys where key.type == String.self{ parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) } + for key in commonParameters.allKeys where key.type == [String].self{ + parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + } + // EC private key specific parameters. let ecParameters = try decoder.container(keyedBy: ECParameter.self) let crv = try ecParameters.decode(ECCurveType.self, forKey: .curve) diff --git a/JOSESwift/Sources/ECKeys.swift b/JOSESwift/Sources/ECKeys.swift index 0409d2ba..1925d971 100644 --- a/JOSESwift/Sources/ECKeys.swift +++ b/JOSESwift/Sources/ECKeys.swift @@ -96,7 +96,7 @@ public struct ECPublicKey: JWK { public let keyType: JWKKeyType /// The JWK parameters. - public let parameters: [String: String] + public let parameters: [String: JWKParameterType] /// The curve value for the EC public key. public let crv: ECCurveType @@ -120,7 +120,10 @@ public struct ECPublicKey: JWK { /// - y: The y coordinate for the EC public key in `base64urlUInt` encoding /// as specified in [RFC-7518, Section 2](https://tools.ietf.org/html/rfc7518#section-2). /// - parameters: Additional JWK parameters. - public init(crv: ECCurveType, x: String, y: String, additionalParameters parameters: [String: String] = [:]) { + public init(crv: ECCurveType, + x: String, + y: String, + additionalParameters parameters: [String: JWKParameterType] = [:]) { self.keyType = .EC self.crv = crv self.x = x @@ -143,7 +146,8 @@ public struct ECPublicKey: JWK { /// - publicKey: The public key that the resulting JWK should represent. /// - parameters: Any additional parameters to be contained in the JWK. /// - Throws: A `JOSESwiftError` indicating any errors. - public init(publicKey: ExpressibleAsECPublicKeyComponents, additionalParameters parameters: [String: String] = [:]) throws { + public init(publicKey: ExpressibleAsECPublicKeyComponents, + additionalParameters parameters: [String: JWKParameterType] = [:]) throws { guard let components = try? publicKey.ecPublicKeyComponents() else { throw JOSESwiftError.couldNotConstructJWK } @@ -197,7 +201,7 @@ public struct ECPrivateKey: JWK { public let keyType: JWKKeyType /// The JWK parameters. - public let parameters: [String: String] + public let parameters: [String: JWKParameterType] /// The curve value for the EC public key. public let crv: ECCurveType @@ -226,7 +230,11 @@ public struct ECPrivateKey: JWK { /// - privateKey: The private key component for the EC public key in `base64urlUInt` encoding /// as specified in [RFC-7518, Section 2](https://tools.ietf.org/html/rfc7518#section-2). /// - parameters: Additional JWK parameters. - public init(crv: String, x: String, y: String, privateKey: String, additionalParameters parameters: [String: String] = [:]) throws { + public init(crv: String, + x: String, + y: String, + privateKey: String, + additionalParameters parameters: [String: JWKParameterType] = [:]) throws { self.keyType = .EC guard let curve = ECCurveType(rawValue: crv) else { @@ -256,7 +264,8 @@ public struct ECPrivateKey: JWK { /// - privateKey: The private key that the resulting JWK should represent. /// - parameters: Any additional parameters to be contained in the JWK. /// - Throws: A `JOSESwiftError` indicating any errors. - public init(privateKey: ExpressibleAsECPrivateKeyComponents, additionalParameters parameters: [String: String] = [:]) throws { + public init(privateKey: ExpressibleAsECPrivateKeyComponents, + additionalParameters parameters: [String: JWKParameterType] = [:]) throws { guard let (crv, x, y, privateKey) = try? privateKey.ecPrivateKeyComponents() else { throw JOSESwiftError.couldNotConstructJWK } From fcee76c3f86c1dc013e05c527ffc7adff99f656b Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Jan 2019 13:47:25 +0100 Subject: [PATCH 14/19] Adapt tests --- JOSESwift.xcodeproj/project.pbxproj | 9 +- Tests/JWKECDecodingTests.swift | 8 +- Tests/JWKECKeysTests.swift | 32 +++---- Tests/JWKECParameterTypeTests.swift | 89 +++++++++++++++++++ ...s.swift => JWKRSAParameterTypeTests.swift} | 4 +- 5 files changed, 117 insertions(+), 25 deletions(-) create mode 100644 Tests/JWKECParameterTypeTests.swift rename Tests/{JWKParameterTypeTests.swift => JWKRSAParameterTypeTests.swift} (98%) diff --git a/JOSESwift.xcodeproj/project.pbxproj b/JOSESwift.xcodeproj/project.pbxproj index 870909d8..8bbabb9d 100644 --- a/JOSESwift.xcodeproj/project.pbxproj +++ b/JOSESwift.xcodeproj/project.pbxproj @@ -35,7 +35,6 @@ 6505236E1FB4940100E0B1B1 /* AESEncrypter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6505236D1FB4940100E0B1B1 /* AESEncrypter.swift */; }; 650523701FB494BE00E0B1B1 /* AESDecrypter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6505236F1FB494BE00E0B1B1 /* AESDecrypter.swift */; }; 6506D9E920F4CA2000F34DD8 /* SymmetricKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6506D9E820F4CA2000F34DD8 /* SymmetricKeyTests.swift */; }; - 6508625B2180D9A00052F9CA /* JWKParameterTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6508625A2180D9A00052F9CA /* JWKParameterTypeTests.swift */; }; 65125A321FBF85FA007CF3AE /* JWSDeserializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65125A311FBF85FA007CF3AE /* JWSDeserializationTests.swift */; }; 6514ADC92031DD15008A4DD3 /* ASN1DEREncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6514ADC82031DD15008A4DD3 /* ASN1DEREncoding.swift */; }; 6514ADCB2031DD27008A4DD3 /* ASN1DEREncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6514ADCA2031DD27008A4DD3 /* ASN1DEREncodingTests.swift */; }; @@ -52,6 +51,7 @@ 6536560D2035DF8300A3AC3B /* JWKSetCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6536560C2035DF8300A3AC3B /* JWKSetCodable.swift */; }; 6546D606203580C6007217FB /* JWKRSADecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6546D605203580C6007217FB /* JWKRSADecodingTests.swift */; }; 6546FB0F2029DD10002E421F /* SecKeyRSAPublicKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6546FB0E2029DD10002E421F /* SecKeyRSAPublicKey.swift */; }; + 6560748721F744970011C888 /* JWKECParameterTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6560748621F744970011C888 /* JWKECParameterTypeTests.swift */; }; 65617FCB1F90F8C700D8C743 /* Encrypter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65617FCA1F90F8C700D8C743 /* Encrypter.swift */; }; 65617FCD1F90FB7600D8C743 /* RSAEncrypter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65617FCC1F90FB7600D8C743 /* RSAEncrypter.swift */; }; 65676D8B1FC220C70031B26D /* JWEDeserializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65676D8A1FC220C70031B26D /* JWEDeserializationTests.swift */; }; @@ -149,7 +149,7 @@ 6505236D1FB4940100E0B1B1 /* AESEncrypter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AESEncrypter.swift; sourceTree = ""; }; 6505236F1FB494BE00E0B1B1 /* AESDecrypter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AESDecrypter.swift; sourceTree = ""; }; 6506D9E820F4CA2000F34DD8 /* SymmetricKeyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymmetricKeyTests.swift; sourceTree = ""; }; - 6508625A2180D9A00052F9CA /* JWKParameterTypeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWKParameterTypeTests.swift; sourceTree = ""; }; + 6508625A2180D9A00052F9CA /* JWKRSAParameterTypeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWKRSAParameterTypeTests.swift; sourceTree = ""; }; 65125A311FBF85FA007CF3AE /* JWSDeserializationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWSDeserializationTests.swift; sourceTree = ""; }; 6514ADC82031DD15008A4DD3 /* ASN1DEREncoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1DEREncoding.swift; sourceTree = ""; }; 6514ADCA2031DD27008A4DD3 /* ASN1DEREncodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1DEREncodingTests.swift; sourceTree = ""; }; @@ -166,6 +166,7 @@ 6536560C2035DF8300A3AC3B /* JWKSetCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWKSetCodable.swift; sourceTree = ""; }; 6546D605203580C6007217FB /* JWKRSADecodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWKRSADecodingTests.swift; sourceTree = ""; }; 6546FB0E2029DD10002E421F /* SecKeyRSAPublicKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecKeyRSAPublicKey.swift; sourceTree = ""; }; + 6560748621F744970011C888 /* JWKECParameterTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWKECParameterTypeTests.swift; sourceTree = ""; }; 65617FCA1F90F8C700D8C743 /* Encrypter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encrypter.swift; sourceTree = ""; }; 65617FCC1F90FB7600D8C743 /* RSAEncrypter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSAEncrypter.swift; sourceTree = ""; }; 65676D8A1FC220C70031B26D /* JWEDeserializationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWEDeserializationTests.swift; sourceTree = ""; }; @@ -367,7 +368,8 @@ 65A103A0202B03BB00D22BF5 /* ASN1DERParsingTests.swift */, 65A103A2202B0CDF00D22BF5 /* DataRSAPublicKeyTests.swift */, 6546D605203580C6007217FB /* JWKRSADecodingTests.swift */, - 6508625A2180D9A00052F9CA /* JWKParameterTypeTests.swift */, + 6508625A2180D9A00052F9CA /* JWKRSAParameterTypeTests.swift */, + 6560748621F744970011C888 /* JWKECParameterTypeTests.swift */, 65826AB320286B3A00AFFC46 /* JWKRSAEncodingTests.swift */, 65E733D41FEC031B0009EAC6 /* JWKRSAKeysTests.swift */, 6536560A2035DC3900A3AC3B /* JWKSetCodingTests.swift */, @@ -651,6 +653,7 @@ 5FB76E7A42B44E4F4416CB7F /* JWKECKeysTests.swift in Sources */, 5FB76093CE81BF1F8E7C254A /* JWKECDecodingTests.swift in Sources */, 5FB765B20A256B93440E79E2 /* JWKECEncodingTests.swift in Sources */, + 6560748721F744970011C888 /* JWKECParameterTypeTests.swift in Sources */, 5FB7656EDD94AE3620A8C13C /* SecKeyECPrivateKeyTests.swift in Sources */, 5FB7656FF300A4A3EF0F3597 /* DataECPrivateKeyTests.swift in Sources */, 5FB762ED79A6159B5A9EDECC /* ECPrivateKeyToSecKeyTests.swift in Sources */, diff --git a/Tests/JWKECDecodingTests.swift b/Tests/JWKECDecodingTests.swift index 6aca253a..212c2c9a 100644 --- a/Tests/JWKECDecodingTests.swift +++ b/Tests/JWKECDecodingTests.swift @@ -224,20 +224,20 @@ class JWKECDecodingTests: ECCryptoTestCase { private func checkSharedKeyComponents(jwk: ECPublicKey) { XCTAssertEqual(jwk.keyType, .EC) - XCTAssertEqual(jwk["kty"] ?? "", "EC") + XCTAssertEqual(jwk["kty"] as? String ?? "", "EC") XCTAssertEqual(jwk.x, Consts.keyX) XCTAssertEqual(jwk.y, Consts.keyY) XCTAssertEqual(jwk.crv, ECCurveType.P256) - XCTAssertEqual(jwk["kid"] ?? "", Consts.kid) + XCTAssertEqual(jwk["kid"] as? String ?? "", Consts.kid) } private func checkSharedKeyComponents(jwk: ECPrivateKey) { XCTAssertEqual(jwk.keyType, .EC) - XCTAssertEqual(jwk["kty"] ?? "", "EC") + XCTAssertEqual(jwk["kty"] as? String ?? "", "EC") XCTAssertEqual(jwk.x, Consts.keyX) XCTAssertEqual(jwk.y, Consts.keyY) XCTAssertEqual(jwk.crv, ECCurveType.P256) - XCTAssertEqual(jwk["kid"] ?? "", Consts.kid) + XCTAssertEqual(jwk["kid"] as? String ?? "", Consts.kid) } private func checkMissingKey(json: Data, key: String) { diff --git a/Tests/JWKECKeysTests.swift b/Tests/JWKECKeysTests.swift index e1b83798..9bc94799 100644 --- a/Tests/JWKECKeysTests.swift +++ b/Tests/JWKECKeysTests.swift @@ -31,7 +31,7 @@ class JWKECKeysTests: ECCryptoTestCase { let params = [ "kty": "wrongKty" ] let jwk = try! ECPublicKey(publicKey: keyData.publicKey, additionalParameters: params) - XCTAssertEqual(jwk["kty"] ?? "", "EC") + XCTAssertEqual(jwk["kty"] as? String ?? "", "EC") } } @@ -45,7 +45,7 @@ class JWKECKeysTests: ECCryptoTestCase { additionalParameters: [ "kty": "wrongKty" ] ) - XCTAssertEqual(jwk["kty"] ?? "", "EC") + XCTAssertEqual(jwk["kty"] as? String ?? "", "EC") } } @@ -58,16 +58,16 @@ class JWKECKeysTests: ECCryptoTestCase { ) XCTAssertEqual(key.keyType, .EC) - XCTAssertEqual(key["kty"] ?? "", "EC") + XCTAssertEqual(key["kty"] as? String ?? "", "EC") XCTAssertEqual(key.crv, ECCurveType(rawValue: keyData.expectedCurveType)) - XCTAssertEqual(key["crv"] ?? "", keyData.expectedCurveType) + XCTAssertEqual(key["crv"] as? String ?? "", keyData.expectedCurveType) XCTAssertEqual(key.x, keyData.expectedXCoordinateBase64Url) - XCTAssertEqual(key["x"] ?? "", keyData.expectedXCoordinateBase64Url) + XCTAssertEqual(key["x"] as? String ?? "", keyData.expectedXCoordinateBase64Url) XCTAssertEqual(key.y, keyData.expectedYCoordinateBase64Url) - XCTAssertEqual(key["y"] ?? "", keyData.expectedYCoordinateBase64Url) + XCTAssertEqual(key["y"] as? String ?? "", keyData.expectedYCoordinateBase64Url) // kty, crv, x, y XCTAssertEqual(key.parameters.count, 4) @@ -85,20 +85,20 @@ class JWKECKeysTests: ECCryptoTestCase { ) XCTAssertEqual(key.keyType, .EC) - XCTAssertEqual(key["kty"] ?? "", "EC") + XCTAssertEqual(key["kty"] as? String ?? "", "EC") XCTAssertEqual(key.crv, ECCurveType(rawValue: keyData.expectedCurveType)) - XCTAssertEqual(key["crv"] ?? "", keyData.expectedCurveType) + XCTAssertEqual(key["crv"] as? String ?? "", keyData.expectedCurveType) XCTAssertEqual(key.x, keyData.expectedXCoordinateBase64Url) - XCTAssertEqual(key["x"] ?? "", keyData.expectedXCoordinateBase64Url) + XCTAssertEqual(key["x"] as? String ?? "", keyData.expectedXCoordinateBase64Url) XCTAssertEqual(key.y, keyData.expectedYCoordinateBase64Url) - XCTAssertEqual(key["y"] ?? "", keyData.expectedYCoordinateBase64Url) + XCTAssertEqual(key["y"] as? String ?? "", keyData.expectedYCoordinateBase64Url) XCTAssertEqual(key.privateKey, keyData.expectedPrivateBase64Url) - XCTAssertEqual(key["d"] ?? "", keyData.expectedPrivateBase64Url) + XCTAssertEqual(key["d"] as? String ?? "", keyData.expectedPrivateBase64Url) // kty, crv, x, y, d XCTAssertEqual(key.parameters.count, 5) @@ -110,8 +110,8 @@ class JWKECKeysTests: ECCryptoTestCase { let jwk = try! ECPublicKey(publicKey: keyData.publicKey) XCTAssertEqual(jwk.keyType, .EC) - XCTAssertEqual(jwk[JWKParameter.keyType.rawValue] ?? "", JWKKeyType.EC.rawValue) - XCTAssertEqual(jwk.parameters[JWKParameter.keyType.rawValue] ?? "", JWKKeyType.EC.rawValue) + XCTAssertEqual(jwk[JWKParameter.keyType.rawValue] as? String ?? "", JWKKeyType.EC.rawValue) + XCTAssertEqual(jwk.parameters[JWKParameter.keyType.rawValue] as? String ?? "", JWKKeyType.EC.rawValue) } } @@ -125,8 +125,8 @@ class JWKECKeysTests: ECCryptoTestCase { ) XCTAssertEqual(jwk.keyType, .EC) - XCTAssertEqual(jwk[JWKParameter.keyType.rawValue] ?? "", JWKKeyType.EC.rawValue) - XCTAssertEqual(jwk.parameters[JWKParameter.keyType.rawValue] ?? "", JWKKeyType.EC.rawValue) + XCTAssertEqual(jwk[JWKParameter.keyType.rawValue] as? String ?? "", JWKKeyType.EC.rawValue) + XCTAssertEqual(jwk.parameters[JWKParameter.keyType.rawValue] as? String ?? "", JWKKeyType.EC.rawValue) } } @@ -135,7 +135,7 @@ class JWKECKeysTests: ECCryptoTestCase { let params = ["kid": "new on the block"] let jwk = try! ECPublicKey(publicKey: keyData.publicKey, additionalParameters: params) - XCTAssertEqual(jwk["kid"] ?? "", "new on the block") + XCTAssertEqual(jwk["kid"] as? String ?? "", "new on the block") } } diff --git a/Tests/JWKECParameterTypeTests.swift b/Tests/JWKECParameterTypeTests.swift new file mode 100644 index 00000000..037005c1 --- /dev/null +++ b/Tests/JWKECParameterTypeTests.swift @@ -0,0 +1,89 @@ +// +// JWKECParameterTypeTests.swift +// Tests +// +// Created by Daniel on 24.10.18. +// + +import XCTest +@testable import JOSESwift + +class JWKECParameterTypeTests: XCTestCase { + + let jwk = """ + {"kty": "EC", "crv": "P-256", "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", "y": "4Etl6SRW2YiLUrN5vfvVHuh\ + p7x8PxltmWWlbbM4IFyM","use": "enc", "kid" :"1", "key_ops": ["sign", "verify"], "x5c": ["MIIDQjCCAiqgAwIBAgIGATz\ + /FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQKExNQaW5nIElkZW\ + 50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBgNVBAYTAlVTM\ + QswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1wYmVs\ + bDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnHYMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRi\ + j66s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmF\ + gHIXPLfnpnfajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPqPvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEv\ + qqPpnjL1XyW+oyVVkaZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXN\ + swb4ECNIKG0CETTUxmXl9KUL+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1zFo+Owb1zxtp3PehFdfQJ610CDLE\ + aS9V9Rqp17hCyybEpOGVwe8fnk+fbEL2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo4tpzd5rFXhjRbg4zW9C+2\ + qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTqgawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA=="]} + """.data(using: .utf8)! + + func testDecodingStringAndStringArrayParametersDoesNotThrow() { + XCTAssertNoThrow(try ECPublicKey(data: jwk)) + } + + func testDecodingStringParameters() { + let key = try! ECPublicKey(data: jwk) + + XCTAssertEqual(key.keyType.rawValue, "EC") + XCTAssertEqual(key.x.prefix(5), "MKBCT") + XCTAssertEqual(key.x.suffix(5), "qv7D4") + XCTAssertEqual(key.y.prefix(5), "4Etl6") + XCTAssertEqual(key.y.suffix(5), "4IFyM") + XCTAssertEqual(key.keyUse, "enc") + + XCTAssertEqual(key.crv, ECCurveType.P256) + XCTAssertEqual(key.keyIdentifier ?? "", "1") + } + + func testDecodingStringArrayParameterKeyOpsSubscript() { + let key = try! ECPublicKey(data: jwk) + + let keyOperations = key["key_ops"] as? [String] + + XCTAssertNotNil(keyOperations) + XCTAssertEqual(keyOperations!.count, 2) + XCTAssertEqual(keyOperations![0], "sign") + XCTAssertEqual(keyOperations![1], "verify") + } + + func testDecodingStringArrayParameterKeyOpsComputed() { + let key = try! ECPublicKey(data: jwk) + + let keyOperations = key.keyOperations + + XCTAssertNotNil(keyOperations) + XCTAssertEqual(keyOperations!.count, 2) + XCTAssertEqual(keyOperations![0], "sign") + XCTAssertEqual(keyOperations![1], "verify") + } + + func testDecodingStringArrayParameterCertificateChainSubscript() { + let key = try! ECPublicKey(data: jwk) + + let certificateChain = key["x5c"] as? [String] + + XCTAssertNotNil(certificateChain) + XCTAssertEqual(certificateChain!.count, 1) + XCTAssertEqual(certificateChain![0].prefix(5), "MIIDQ") + XCTAssertEqual(certificateChain![0].suffix(5), "OWA==") + } + + func testDecodingStringArrayParameterCertificateChainComputed() { + let key = try! ECPublicKey(data: jwk) + + let certificateChain = key.X509CertificateChain + + XCTAssertNotNil(certificateChain) + XCTAssertEqual(certificateChain!.count, 1) + XCTAssertEqual(certificateChain![0].prefix(5), "MIIDQ") + XCTAssertEqual(certificateChain![0].suffix(5), "OWA==") + } +} diff --git a/Tests/JWKParameterTypeTests.swift b/Tests/JWKRSAParameterTypeTests.swift similarity index 98% rename from Tests/JWKParameterTypeTests.swift rename to Tests/JWKRSAParameterTypeTests.swift index 13e8665e..bcb3b812 100644 --- a/Tests/JWKParameterTypeTests.swift +++ b/Tests/JWKRSAParameterTypeTests.swift @@ -1,5 +1,5 @@ // -// JWKParameterTypeTests.swift +// JWKRSAParameterTypeTests.swift // Tests // // Created by Daniel on 24.10.18. @@ -8,7 +8,7 @@ import XCTest @testable import JOSESwift -class JWKParameterTypeTests: XCTestCase { +class JWKRSAParameterTypeTests: XCTestCase { let jwk = """ { "kty": "RSA", "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJ\ From da05a0c640b720934131eee71f15801d5281b7c6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Jan 2019 13:58:40 +0100 Subject: [PATCH 15/19] Add symmetric key parsing tests --- JOSESwift.xcodeproj/project.pbxproj | 4 + Tests/JWKSymmetricParameterTypeTests.swift | 95 ++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 Tests/JWKSymmetricParameterTypeTests.swift diff --git a/JOSESwift.xcodeproj/project.pbxproj b/JOSESwift.xcodeproj/project.pbxproj index 8bbabb9d..f73f8028 100644 --- a/JOSESwift.xcodeproj/project.pbxproj +++ b/JOSESwift.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ 6546D606203580C6007217FB /* JWKRSADecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6546D605203580C6007217FB /* JWKRSADecodingTests.swift */; }; 6546FB0F2029DD10002E421F /* SecKeyRSAPublicKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6546FB0E2029DD10002E421F /* SecKeyRSAPublicKey.swift */; }; 6560748721F744970011C888 /* JWKECParameterTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6560748621F744970011C888 /* JWKECParameterTypeTests.swift */; }; + 6560748921F748690011C888 /* JWKSymmetricParameterTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6560748821F748690011C888 /* JWKSymmetricParameterTypeTests.swift */; }; 65617FCB1F90F8C700D8C743 /* Encrypter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65617FCA1F90F8C700D8C743 /* Encrypter.swift */; }; 65617FCD1F90FB7600D8C743 /* RSAEncrypter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65617FCC1F90FB7600D8C743 /* RSAEncrypter.swift */; }; 65676D8B1FC220C70031B26D /* JWEDeserializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65676D8A1FC220C70031B26D /* JWEDeserializationTests.swift */; }; @@ -167,6 +168,7 @@ 6546D605203580C6007217FB /* JWKRSADecodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWKRSADecodingTests.swift; sourceTree = ""; }; 6546FB0E2029DD10002E421F /* SecKeyRSAPublicKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecKeyRSAPublicKey.swift; sourceTree = ""; }; 6560748621F744970011C888 /* JWKECParameterTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWKECParameterTypeTests.swift; sourceTree = ""; }; + 6560748821F748690011C888 /* JWKSymmetricParameterTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWKSymmetricParameterTypeTests.swift; sourceTree = ""; }; 65617FCA1F90F8C700D8C743 /* Encrypter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encrypter.swift; sourceTree = ""; }; 65617FCC1F90FB7600D8C743 /* RSAEncrypter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSAEncrypter.swift; sourceTree = ""; }; 65676D8A1FC220C70031B26D /* JWEDeserializationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWEDeserializationTests.swift; sourceTree = ""; }; @@ -370,6 +372,7 @@ 6546D605203580C6007217FB /* JWKRSADecodingTests.swift */, 6508625A2180D9A00052F9CA /* JWKRSAParameterTypeTests.swift */, 6560748621F744970011C888 /* JWKECParameterTypeTests.swift */, + 6560748821F748690011C888 /* JWKSymmetricParameterTypeTests.swift */, 65826AB320286B3A00AFFC46 /* JWKRSAEncodingTests.swift */, 65E733D41FEC031B0009EAC6 /* JWKRSAKeysTests.swift */, 6536560A2035DC3900A3AC3B /* JWKSetCodingTests.swift */, @@ -609,6 +612,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 6560748921F748690011C888 /* JWKSymmetricParameterTypeTests.swift in Sources */, 65826AB420286B3A00AFFC46 /* JWKRSAEncodingTests.swift in Sources */, C83070051FD1B7390068C5CB /* AESDecrypterTests.swift in Sources */, C803EFE91FA7893A00B71335 /* JWSHeaderTests.swift in Sources */, diff --git a/Tests/JWKSymmetricParameterTypeTests.swift b/Tests/JWKSymmetricParameterTypeTests.swift new file mode 100644 index 00000000..3111f36b --- /dev/null +++ b/Tests/JWKSymmetricParameterTypeTests.swift @@ -0,0 +1,95 @@ +// +// JWKSymmetricParameterTypeTests.swift +// Tests +// +// Created by Daniel on 24.10.18. +// + +import XCTest +@testable import JOSESwift + +class JWKSymmetricParameterTypeTests: XCTestCase { + + let jwk = """ + {"kty": "oct", "alg": "A256CBC-HS512", "k": "GawgguFyGrWKav7AX4VKUg", "use": "enc", "kid": "12", "key_ops": ["s\ + ign", "encrypt", "decrypt", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"], "x5c": ["MIIDQjCCAiqgAwIBAgIGATz\ + /FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQKExNQaW5nIElkZW\ + 50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBgNVBAYTAlVTM\ + QswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1wYmVs\ + bDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnHYMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRi\ + j66s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmF\ + gHIXPLfnpnfajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPqPvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEv\ + qqPpnjL1XyW+oyVVkaZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXN\ + swb4ECNIKG0CETTUxmXl9KUL+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1zFo+Owb1zxtp3PehFdfQJ610CDLE\ + aS9V9Rqp17hCyybEpOGVwe8fnk+fbEL2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo4tpzd5rFXhjRbg4zW9C+2\ + qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTqgawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA=="]} + """.data(using: .utf8)! + + func testDecodingStringAndStringArrayParametersDoesNotThrow() { + XCTAssertNoThrow(try SymmetricKey(data: jwk)) + } + + func testDecodingStringParameters() { + let key = try! SymmetricKey(data: jwk) + + XCTAssertEqual(key.keyType.rawValue, "oct") + XCTAssertEqual(key.key, "GawgguFyGrWKav7AX4VKUg") + XCTAssertEqual(key.keyUse, "enc") + + XCTAssertEqual(key.keyIdentifier ?? "", "12") + } + + func testDecodingStringArrayParameterKeyOpsSubscript() { + let key = try! SymmetricKey(data: jwk) + + let keyOperations = key["key_ops"] as? [String] + + XCTAssertNotNil(keyOperations) + XCTAssertEqual(keyOperations!.count, 7) + XCTAssertEqual(keyOperations![0], "sign") + XCTAssertEqual(keyOperations![1], "encrypt") + XCTAssertEqual(keyOperations![2], "decrypt") + XCTAssertEqual(keyOperations![3], "wrapKey") + XCTAssertEqual(keyOperations![4], "unwrapKey") + XCTAssertEqual(keyOperations![5], "deriveKey") + XCTAssertEqual(keyOperations![6], "deriveBits") + } + + func testDecodingStringArrayParameterKeyOpsComputed() { + let key = try! SymmetricKey(data: jwk) + + let keyOperations = key.keyOperations + + XCTAssertNotNil(keyOperations) + XCTAssertEqual(keyOperations!.count, 7) + XCTAssertEqual(keyOperations![0], "sign") + XCTAssertEqual(keyOperations![1], "encrypt") + XCTAssertEqual(keyOperations![2], "decrypt") + XCTAssertEqual(keyOperations![3], "wrapKey") + XCTAssertEqual(keyOperations![4], "unwrapKey") + XCTAssertEqual(keyOperations![5], "deriveKey") + XCTAssertEqual(keyOperations![6], "deriveBits") + } + + func testDecodingStringArrayParameterCertificateChainSubscript() { + let key = try! SymmetricKey(data: jwk) + + let certificateChain = key["x5c"] as? [String] + + XCTAssertNotNil(certificateChain) + XCTAssertEqual(certificateChain!.count, 1) + XCTAssertEqual(certificateChain![0].prefix(5), "MIIDQ") + XCTAssertEqual(certificateChain![0].suffix(5), "OWA==") + } + + func testDecodingStringArrayParameterCertificateChainComputed() { + let key = try! SymmetricKey(data: jwk) + + let certificateChain = key.X509CertificateChain + + XCTAssertNotNil(certificateChain) + XCTAssertEqual(certificateChain!.count, 1) + XCTAssertEqual(certificateChain![0].prefix(5), "MIIDQ") + XCTAssertEqual(certificateChain![0].suffix(5), "OWA==") + } +} From 99b7b0adee70127886caeaf66e930a5fdbc3b8b4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 20 Feb 2019 18:17:47 +0100 Subject: [PATCH 16/19] Add rsa tests to test target --- JOSESwift.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/JOSESwift.xcodeproj/project.pbxproj b/JOSESwift.xcodeproj/project.pbxproj index f73f8028..20b8b866 100644 --- a/JOSESwift.xcodeproj/project.pbxproj +++ b/JOSESwift.xcodeproj/project.pbxproj @@ -86,6 +86,7 @@ 65F44EB11FE2D941000C5EA0 /* JWK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F44EB01FE2D941000C5EA0 /* JWK.swift */; }; 65F44EB31FE2E1C6000C5EA0 /* RSAKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F44EB21FE2E1C6000C5EA0 /* RSAKeys.swift */; }; 65FBFDE71F45CC7C005C7D68 /* JOSESwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 65FBFDE51F45CC7C005C7D68 /* JOSESwift.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 65FC10A4221DC2C000F3F2C0 /* JWKRSAParameterTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6508625A2180D9A00052F9CA /* JWKRSAParameterTypeTests.swift */; }; C803EFE51FA77E3000B71335 /* JWSRSATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C803EFE41FA77E3000B71335 /* JWSRSATests.swift */; }; C803EFE91FA7893A00B71335 /* JWSHeaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C803EFE81FA7893A00B71335 /* JWSHeaderTests.swift */; }; C803EFED1FA8849C00B71335 /* JWERSATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C803EFEC1FA8849C00B71335 /* JWERSATests.swift */; }; @@ -632,6 +633,7 @@ C803EFEF1FA884C100B71335 /* JWEHeaderTests.swift in Sources */, C81DD92A1FD7096B00026024 /* HMACTests.swift in Sources */, 65684A4F2031971A00E56C68 /* RSAPublicKeyToSecKeyTests.swift in Sources */, + 65FC10A4221DC2C000F3F2C0 /* JWKRSAParameterTypeTests.swift in Sources */, 65E733D51FEC031B0009EAC6 /* JWKRSAKeysTests.swift in Sources */, 65E733D31FEBFDB30009EAC6 /* JWKtoJSONTests.swift in Sources */, C803EFE51FA77E3000B71335 /* JWSRSATests.swift in Sources */, From 304453717147bd34dabe64f452539511e0144484 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 20 Feb 2019 18:17:59 +0100 Subject: [PATCH 17/19] Switch on parameter type in a single loop --- JOSESwift/Sources/ECKeyCodable.swift | 15 +++++++++------ JOSESwift/Sources/RSAKeyCodable.swift | 15 +++++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/JOSESwift/Sources/ECKeyCodable.swift b/JOSESwift/Sources/ECKeyCodable.swift index 53722dfc..08e0437e 100644 --- a/JOSESwift/Sources/ECKeyCodable.swift +++ b/JOSESwift/Sources/ECKeyCodable.swift @@ -70,12 +70,15 @@ extension ECPublicKey: Decodable { // Other common parameters are optional. var parameters: [String: JWKParameterType] = [:] - for key in commonParameters.allKeys where key.type == String.self{ - parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) - } - - for key in commonParameters.allKeys where key.type == [String].self{ - parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + for key in commonParameters.allKeys { + switch key.type { + case is String.Type: + parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) + case is [String].Type: + parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + default: + break + } } // EC public key specific parameters. diff --git a/JOSESwift/Sources/RSAKeyCodable.swift b/JOSESwift/Sources/RSAKeyCodable.swift index 826c8e2e..4c11624c 100644 --- a/JOSESwift/Sources/RSAKeyCodable.swift +++ b/JOSESwift/Sources/RSAKeyCodable.swift @@ -69,12 +69,15 @@ extension RSAPublicKey: Decodable { // Other common parameters are optional. var parameters: [String: JWKParameterType] = [:] - for key in commonParameters.allKeys where key.type == String.self { - parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) - } - - for key in commonParameters.allKeys where key.type == [String].self { - parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + for key in commonParameters.allKeys { + switch key.type { + case is String.Type: + parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) + case is [String].Type: + parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + default: + break + } } // RSA public key specific parameters. From 575d31ac8bef729ae54a0eccaecf75498c7a0475 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 20 Feb 2019 18:20:06 +0100 Subject: [PATCH 18/19] Add single loop decoding for ec private key as well --- JOSESwift/Sources/ECKeyCodable.swift | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/JOSESwift/Sources/ECKeyCodable.swift b/JOSESwift/Sources/ECKeyCodable.swift index 08e0437e..5a828f5a 100644 --- a/JOSESwift/Sources/ECKeyCodable.swift +++ b/JOSESwift/Sources/ECKeyCodable.swift @@ -144,12 +144,15 @@ extension ECPrivateKey: Decodable { // Other common parameters are optional. var parameters: [String: JWKParameterType] = [:] - for key in commonParameters.allKeys where key.type == String.self{ - parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) - } - - for key in commonParameters.allKeys where key.type == [String].self{ - parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + for key in commonParameters.allKeys { + switch key.type { + case is String.Type: + parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) + case is [String].Type: + parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + default: + break + } } // EC private key specific parameters. From fe2dfe33287251e40509e988a559f68a285cc201 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 20 Feb 2019 18:24:17 +0100 Subject: [PATCH 19/19] Add single loop decoding for rsa private key as well --- JOSESwift/Sources/RSAKeyCodable.swift | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/JOSESwift/Sources/RSAKeyCodable.swift b/JOSESwift/Sources/RSAKeyCodable.swift index 4c11624c..9465f532 100644 --- a/JOSESwift/Sources/RSAKeyCodable.swift +++ b/JOSESwift/Sources/RSAKeyCodable.swift @@ -140,12 +140,15 @@ extension RSAPrivateKey: Decodable { // Other common parameters are optional. var parameters: [String: JWKParameterType] = [:] - for key in commonParameters.allKeys where key.type == String.self { - parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) - } - - for key in commonParameters.allKeys where key.type == [String].self { - parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + for key in commonParameters.allKeys { + switch key.type { + case is String.Type: + parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) + case is [String].Type: + parameters[key.rawValue] = try commonParameters.decode([String].self, forKey: key) + default: + break + } } // RSA private key specific parameters.