Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[117] Allow JWK parameters of type [String] #120

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
722937b
Implement decoding of String and [String] parameters
dlggr Oct 24, 2018
0478b7c
Adapt tests
dlggr Oct 24, 2018
9d98e85
Add new test case
dlggr Oct 24, 2018
32c1e11
Remove key type computed property
dlggr Oct 24, 2018
0bcdd26
Update tests
dlggr Oct 24, 2018
daedd4b
Fix long lines
dlggr Oct 24, 2018
c27f7fa
Update readme
dlggr Oct 24, 2018
82ca0c2
Move parameter getter extension
dlggr Oct 24, 2018
9a6eaa7
Add doc comments to param getters
dlggr Oct 24, 2018
2cf0c6a
Remove old array parameter test
dlggr Oct 24, 2018
3e7ea46
Merge branch 'master' into feature/string-array-jwk-parameters
Nov 7, 2018
2d75cc2
Merge branch 'master' into feature/string-array-jwk-parameters
Dec 13, 2018
bf2539b
Use Codable for JWKPArameterType
daniel-moh Jan 22, 2019
763c67f
Use JWKPArameterType instsead of Any for subscript
daniel-moh Jan 22, 2019
5ad7f1a
Merge branch 'master' into feature/string-array-jwk-parameters
daniel-moh Jan 22, 2019
f006882
Adapt EC keys for String arary parameters
daniel-moh Jan 22, 2019
fcee76c
Adapt tests
daniel-moh Jan 22, 2019
da05a0c
Add symmetric key parsing tests
daniel-moh Jan 22, 2019
df830e1
Merge branch 'master' into feature/string-array-jwk-parameters
Jan 31, 2019
99b7b0a
Add rsa tests to test target
daniel-moh Feb 20, 2019
3044537
Switch on parameter type in a single loop
daniel-moh Feb 20, 2019
575d31a
Add single loop decoding for ec private key as well
daniel-moh Feb 20, 2019
fe2dfe3
Add single loop decoding for rsa private key as well
daniel-moh Feb 20, 2019
3ae5424
Merge branch 'master' into feature/string-array-jwk-parameters
Feb 20, 2019
b75f698
Resolve conflicts
daniel-moh May 27, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 38 additions & 10 deletions JOSESwift/Sources/ECKeyCodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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.
Expand Down
21 changes: 15 additions & 6 deletions JOSESwift/Sources/ECKeys.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions JOSESwift/Sources/JWK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ 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).
/// 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.
///
/// - Parameter parameter: The desired parameter.
subscript(parameter: String) -> String? { get }
subscript(parameter: String) -> JWKParameterType? { get }

/// Initializes a JWK from given JSON data.
///
Expand Down
58 changes: 57 additions & 1 deletion JOSESwift/Sources/JWKExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Foundation
// MARK: Subscript

public extension JWK {
subscript(parameter: String) -> String? {
subscript(parameter: String) -> JWKParameterType? {
return parameters[parameter]
}
}
Expand All @@ -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
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Files should have a single trailing newline.
trailing_newline JWKExtensions.swift:104

19 changes: 15 additions & 4 deletions JOSESwift/Sources/JWKParameters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@

import Foundation

// Common protocol for all types that can be used as JWK parameters.
public protocol JWKParameterType: Codable { }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!


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 {
Expand All @@ -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.
Expand Down
48 changes: 38 additions & 10 deletions JOSESwift/Sources/RSAKeyCodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand All @@ -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.
Expand All @@ -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)
}
}

Expand Down Expand Up @@ -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.
Expand Down
14 changes: 8 additions & 6 deletions JOSESwift/Sources/RSAKeys.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
}
Expand Down
Loading