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

feat: Ignore newlines in key generation and allow DER formatting #68

Merged
merged 4 commits into from
Jul 16, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
36 changes: 30 additions & 6 deletions Sources/SwiftJWT/BlueRSA.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,22 @@ class BlueRSA: SignerAlgorithm, VerifierAlgorithm {
Log.error("macOS 10.12.0 (Sierra) or higher or iOS 10.0 or higher is required by CryptorRSA")
throw JWTError.osVersionToLow
}
guard let keyString = String(data: key, encoding: .utf8) else {
throw JWTError.invalidPrivateKey
// Convert PEM format to DER
let keyDer: Data
if let keyString = String(data: key, encoding: .utf8) {
let strippedKey = String(keyString.filter { !" \n\t\r".contains($0) })
var pemComponents = strippedKey.components(separatedBy: "-----")
guard pemComponents.count >= 5 else {
throw JWTError.missingPEMHeaders
}
guard let der = Data(base64Encoded: pemComponents[2]) else {
throw JWTError.invalidPrivateKey
}
keyDer = der
} else {
keyDer = key
}
let privateKey = try CryptorRSA.createPrivateKey(withPEM: keyString)
let privateKey = try CryptorRSA.createPrivateKey(with: keyDer)
let myPlaintext = CryptorRSA.createPlaintext(with: data)
guard let signedData = try myPlaintext.signed(with: privateKey, algorithm: algorithm, usePSS: usePSS) else {
throw JWTError.invalidPrivateKey
Expand Down Expand Up @@ -85,10 +97,22 @@ class BlueRSA: SignerAlgorithm, VerifierAlgorithm {
case .privateKey:
return false
case .publicKey:
guard let keyString = String(data: key, encoding: .utf8) else {
return false
// Convert PEM format to DER
let keyDer: Data
if let keyString = String(data: key, encoding: .utf8) {
let strippedKey = String(keyString.filter { !" \n\t\r".contains($0) })
var pemComponents = strippedKey.components(separatedBy: "-----")
guard pemComponents.count >= 5 else {
return false
}
guard let der = Data(base64Encoded: pemComponents[2]) else {
return false
}
keyDer = der
} else {
keyDer = key
}
publicKey = try CryptorRSA.createPublicKey(withPEM: keyString)
publicKey = try CryptorRSA.createPublicKey(with: keyDer)
case .certificate:
publicKey = try CryptorRSA.createPublicKey(extractingFrom: key)
}
Expand Down
5 changes: 4 additions & 1 deletion Sources/SwiftJWT/JWTError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public struct JWTError: Error, Equatable {
private let internalError: InternalError

private enum InternalError {
case invalidJWTString, failedVerification, osVersionToLow, invalidPrivateKey, invalidData, invalidKeyID
case invalidJWTString, failedVerification, osVersionToLow, invalidPrivateKey, invalidData, invalidKeyID, missingPEMHeaders
}

/// Error when an invalid JWT String is provided
Expand All @@ -48,6 +48,9 @@ public struct JWTError: Error, Equatable {
/// Error when the KeyID field `kid` in the JWT header fails to generate a JWTSigner or JWTVerifier
public static let invalidKeyID = JWTError(localizedDescription: "The JWT KeyID `kid` header failed to generate a JWTSigner/JWTVerifier", internalError: .invalidKeyID)

/// Error when a PEM string is provided without the expected PEM headers/footers. (e.g. -----BEGIN PRIVATE KEY-----)
public static let missingPEMHeaders = JWTError(localizedDescription: "The provided key did not have the expected PEM headers/footers", internalError: .missingPEMHeaders)

/// Function to check if JWTErrors are equal. Required for equatable protocol.
public static func == (lhs: JWTError, rhs: JWTError) -> Bool {
return lhs.internalError == rhs.internalError
Expand Down
10 changes: 10 additions & 0 deletions Tests/SwiftJWTTests/TestJWT.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import Foundation

let rsaPrivateKey = read(fileName: "rsa_private_key")
let rsaPublicKey = read(fileName: "rsa_public_key")
let rsaDERPrivateKey = read(fileName: "privateRSA.der")
let rsaDERPublicKey = read(fileName: "publicRSA.der")
let ecdsaPrivateKey = read(fileName: "ecdsa_private_key")
let ecdsaPublicKey = read(fileName: "ecdsa_public_key")
let ec384PrivateKey = read(fileName: "ec384_private_key")
Expand Down Expand Up @@ -158,6 +160,14 @@ class TestJWT: XCTestCase {
}
}

func testSignAndVerifyRSADERKey() {
do {
try signAndVerify(signer: .rs256(privateKey: rsaDERPrivateKey), verifier: .rs256(publicKey: rsaDERPublicKey))
} catch {
XCTFail("testSignAndVerify failed: \(error)")
}
}

func testSignAndVerifyRSAPSS() {
if #available(OSX 10.13, *) {
do {
Expand Down
Binary file added Tests/SwiftJWTTests/privateRSA.der
Binary file not shown.
Binary file added Tests/SwiftJWTTests/publicRSA.der
Binary file not shown.