diff --git a/JOSESwift/Sources/ECKeyCodable.swift b/JOSESwift/Sources/ECKeyCodable.swift index f2b8e44f..5a828f5a 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,9 +68,17 @@ extension ECPublicKey: Decodable { } // Other common parameters are optional. - var parameters: [String: String] = [:] - for key in commonParameters.allKeys where !JWKParameter.nonStringParameters.contains(key) { - parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) + var parameters: [String: JWKParameterType] = [:] + + 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. @@ -92,8 +106,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,9 +142,17 @@ extension ECPrivateKey: Decodable { } // Other common parameters are optional. - var parameters: [String: String] = [:] - for key in commonParameters.allKeys where !JWKParameter.nonStringParameters.contains(key) { - parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) + var parameters: [String: JWKParameterType] = [:] + + 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. 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 } diff --git a/JOSESwift/Sources/JWK.swift b/JOSESwift/Sources/JWK.swift index 822c1c9c..94bdaf6f 100644 --- a/JOSESwift/Sources/JWK.swift +++ b/JOSESwift/Sources/JWK.swift @@ -55,7 +55,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). @@ -63,7 +63,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) -> JWKParameterType? { get } /// Initializes a JWK from given JSON data. /// diff --git a/JOSESwift/Sources/JWKExtensions.swift b/JOSESwift/Sources/JWKExtensions.swift index e078f10d..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) -> String? { + subscript(parameter: String) -> JWKParameterType? { return parameters[parameter] } } @@ -46,3 +46,59 @@ public extension JWK { return try? JSONEncoder().encode(self) } } + +// 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 + } +} + diff --git a/JOSESwift/Sources/JWKParameters.swift b/JOSESwift/Sources/JWKParameters.swift index ad4a4900..22b4da80 100644 --- a/JOSESwift/Sources/JWKParameters.swift +++ b/JOSESwift/Sources/JWKParameters.swift @@ -24,6 +24,12 @@ import Foundation +// Common protocol for all types that can be used as JWK parameters. +public protocol JWKParameterType: Codable { } + +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 { @@ -37,10 +43,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..9465f532 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,9 +67,17 @@ extension RSAPublicKey: Decodable { } // Other common parameters are optional. - var parameters: [String: String] = [:] - for key in commonParameters.allKeys where !JWKParameter.nonStringParameters.contains(key) { - parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) + var parameters: [String: JWKParameterType] = [:] + + 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. @@ -89,8 +103,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,9 +138,17 @@ extension RSAPrivateKey: Decodable { } // Other common parameters are optional. - var parameters: [String: String] = [:] - for key in commonParameters.allKeys where !JWKParameter.nonStringParameters.contains(key) { - parameters[key.rawValue] = try commonParameters.decode(String.self, forKey: key) + var parameters: [String: JWKParameterType] = [:] + + 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. diff --git a/JOSESwift/Sources/RSAKeys.swift b/JOSESwift/Sources/RSAKeys.swift index d9da63bb..5b614747 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,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: String] = [:]) throws { + public init(publicKey: ExpressibleAsRSAPublicKeyComponents, + additionalParameters parameters: [String: JWKParameterType] = [:]) throws { guard let components = try? publicKey.rsaPublicKeyComponents() else { throw JOSESwiftError.couldNotConstructJWK } @@ -184,7 +185,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 +206,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 +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: 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 } diff --git a/README.md b/README.md index 96025da7..1c81204d 100644 --- a/README.md +++ b/README.md @@ -317,8 +317,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. diff --git a/Tests/JWKECDecodingTests.swift b/Tests/JWKECDecodingTests.swift index b3f1c9d4..0ea70bd8 100644 --- a/Tests/JWKECDecodingTests.swift +++ b/Tests/JWKECDecodingTests.swift @@ -245,20 +245,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 78310547..833fd87e 100644 --- a/Tests/JWKECKeysTests.swift +++ b/Tests/JWKECKeysTests.swift @@ -32,7 +32,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") } } @@ -46,7 +46,7 @@ class JWKECKeysTests: ECCryptoTestCase { additionalParameters: [ "kty": "wrongKty" ] ) - XCTAssertEqual(jwk["kty"] ?? "", "EC") + XCTAssertEqual(jwk["kty"] as? String ?? "", "EC") } } @@ -59,16 +59,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) @@ -86,19 +86,19 @@ 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/JWKRSADecodingTests.swift b/Tests/JWKRSADecodingTests.swift index 5032c3a4..071c47c3 100644 --- a/Tests/JWKRSADecodingTests.swift +++ b/Tests/JWKRSADecodingTests.swift @@ -65,7 +65,7 @@ class JWKRSADecodingTests: RSACryptoTestCase { 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\ @@ -74,8 +74,8 @@ class JWKRSADecodingTests: RSACryptoTestCase { """ ) 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() { @@ -84,7 +84,7 @@ class JWKRSADecodingTests: RSACryptoTestCase { 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\ @@ -93,8 +93,8 @@ class JWKRSADecodingTests: RSACryptoTestCase { """ ) 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() { @@ -194,7 +194,7 @@ class JWKRSADecodingTests: RSACryptoTestCase { 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\ @@ -210,8 +210,8 @@ class JWKRSADecodingTests: RSACryptoTestCase { """ ) 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 testDecodingPrivateKey() { @@ -220,7 +220,7 @@ class JWKRSADecodingTests: RSACryptoTestCase { 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: RSACryptoTestCase { """ ) 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 8a0b9ca6..d9472682 100644 --- a/Tests/JWKRSAKeysTests.swift +++ b/Tests/JWKRSAKeysTests.swift @@ -32,7 +32,7 @@ class JWKRSAKeysTests: RSACryptoTestCase { "kty": "wrongKty" ]) - XCTAssertEqual(jwk["kty"] ?? "", "RSA") + XCTAssertEqual(jwk["kty"] as? String ?? "", "RSA") } func testMergingDuplicateAdditionalParametersInPrivateKey() { @@ -43,20 +43,20 @@ class JWKRSAKeysTests: RSACryptoTestCase { 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) @@ -66,16 +66,16 @@ class JWKRSAKeysTests: RSACryptoTestCase { 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) @@ -85,24 +85,24 @@ class JWKRSAKeysTests: RSACryptoTestCase { 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/JWKRSAParameterTypeTests.swift b/Tests/JWKRSAParameterTypeTests.swift new file mode 100644 index 00000000..bcb3b812 --- /dev/null +++ b/Tests/JWKRSAParameterTypeTests.swift @@ -0,0 +1,91 @@ +// +// JWKRSAParameterTypeTests.swift +// Tests +// +// Created by Daniel on 24.10.18. +// + +import XCTest +@testable import JOSESwift + +class JWKRSAParameterTypeTests: 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", "use":"sig"} + """.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.keyUse, "sig") + + XCTAssertEqual(key.algorithm ?? "", "RS256") + XCTAssertEqual(key.keyIdentifier ?? "", "2011-04-29") + } + + func testDecodingStringArrayParameterKeyOpsSubscript() { + let key = try! RSAPublicKey(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! 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==") + } +} diff --git a/Tests/JWKSetCodingTests.swift b/Tests/JWKSetCodingTests.swift index 873c9c16..45811f49 100644 --- a/Tests/JWKSetCodingTests.swift +++ b/Tests/JWKSetCodingTests.swift @@ -277,9 +277,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() { @@ -292,8 +292,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() { @@ -307,9 +307,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) @@ -317,9 +317,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() { @@ -333,9 +333,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) @@ -344,9 +344,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() { @@ -360,9 +360,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) @@ -371,17 +371,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 @@ -397,9 +397,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) @@ -407,9 +407,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/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==") + } +} diff --git a/Tests/SymmetricKeyTests.swift b/Tests/SymmetricKeyTests.swift index d530a741..c1dc0d07 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\"}",