WIP: restructure, debug PEM support.

This commit is contained in:
Jonathan Bernard 2021-12-25 17:50:04 -06:00
parent 73189ebf15
commit 6df1ffa547
21 changed files with 291 additions and 91 deletions

10
comment-on-issue-8.md Normal file
View File

@ -0,0 +1,10 @@
@yglukhov After thinking, I decided to take the time to implement the entire
JWT standard (RFCs 7515-7520). This ended up being a pretty big architectural
change.
The result of my effort currently lives here:
https://git.jdb-software.com/jdb/nim-jwt
I'd love to get feedback on the implementation and thoughts on how this fits
into the Nim ecosystem: does it make sense to have parallel implementations,
naming, etc. For broader discussion I opened a thread on the Nim forums:

View File

@ -5,7 +5,6 @@ author = "Jonathan Bernard"
description = "Full JWT, JWS, JWE, and JWK implementation for Nim, compliant with RFCs 7515-7519." description = "Full JWT, JWS, JWE, and JWK implementation for Nim, compliant with RFCs 7515-7519."
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
srcDir = "src/main" srcDir = "src/main"
skipDirs = @["private"]
# Dependencies # Dependencies

View File

@ -16,9 +16,9 @@
import std/json, std/options, std/times import std/json, std/options, std/times
import ../private/encoding import ./private/encoding
import ../private/jsonutils import ./private/jsonutils
import ../private/timeutils import ./private/timeutils
type type
JwtClaims* = object JwtClaims* = object

View File

@ -17,8 +17,8 @@
import std/json, std/options, std/sequtils, std/strutils import std/json, std/options, std/sequtils, std/strutils
import ./jwa, ./jwk import ./jwa, ./jwk
import ../private/encoding import ./private/encoding
import ../private/jsonutils import ./private/jsonutils
type type
JoseHeader* = object JoseHeader* = object

View File

@ -13,8 +13,8 @@
import std/json, std/options, std/sequtils, std/strutils import std/json, std/options, std/sequtils, std/strutils
import ../private/jsonutils
import ./jwa import ./jwa
import ./private/jsonutils
type type
JwkKeyType* = enum EcPublic, EcPrivate, RsaPublic, RsaPrivate, Octet JwkKeyType* = enum EcPublic, EcPrivate, RsaPublic, RsaPrivate, Octet

View File

@ -12,9 +12,9 @@
import std/json, std/logging, std/options, std/sequtils, std/strutils import std/json, std/logging, std/options, std/sequtils, std/strutils
import ../private/crypto import ./private/crypto
import ../private/encoding import ./private/encoding
import ../private/jsonutils import ./private/jsonutils
import ./claims import ./claims
import ./joseheader import ./joseheader
@ -108,7 +108,12 @@ proc initJWS*(n: JsonNode): JWS =
payloadB64: n.reqStrVal("payload"), payloadB64: n.reqStrVal("payload"),
signatures: @[initJwsSignature(n)]) signatures: @[initJwsSignature(n)])
proc sign*(payload: string, header: JoseHeader, key: JWK, payloadIsB64Encoded = false): JWS = proc sign*(
payload: string,
header: JoseHeader,
key: JWK | string,
payloadIsB64Encoded = false
): JWS =
## Create a JWS signing the given payload, which can be any arbitrary data. ## Create a JWS signing the given payload, which can be any arbitrary data.
## The returned JWS can be serialized with the compact serialization. All ## The returned JWS can be serialized with the compact serialization. All
## header data will be protected. ## header data will be protected.
@ -144,7 +149,7 @@ proc sign*(
payload: string, payload: string,
unprotected: JoseHeader, unprotected: JoseHeader,
protected: JoseHeader, protected: JoseHeader,
key: JWK, key: JWK | string,
payloadIsB64Encoded = false): JWS = payloadIsB64Encoded = false): JWS =
## Create a JWS signing the given payload, which can be arbitrary data. The ## Create a JWS signing the given payload, which can be arbitrary data. The
## returned JWS can be serialized with the compact serialization. ## returned JWS can be serialized with the compact serialization.
@ -177,7 +182,7 @@ proc sign*(
jws: JWS, jws: JWS,
unprotected: JoseHeader, unprotected: JoseHeader,
protected: JoseHeader, protected: JoseHeader,
key: JWK): JWS = key: JWK | string): JWS =
## Create a new JWS signing the payload again with the newly supplied header ## Create a new JWS signing the payload again with the newly supplied header
## and key. The resulting JWS token will have multiple signatures and cannot ## and key. The resulting JWS token will have multiple signatures and cannot
## be serialized with the compact serialization. ## be serialized with the compact serialization.
@ -202,7 +207,7 @@ proc sign*(
result.compactSerialization = none[string]() result.compactSerialization = none[string]()
proc validate*(jws: JWS, alg: JwtAlgorithm, key: JWK, sigIdx = 0) = proc validate*(jws: JWS, alg: JwtAlgorithm, key: JWK | string, sigIdx = 0) =
if jws.len == 0: if jws.len == 0:
raise newException(InvalidSignature, "JWS has no signature.") raise newException(InvalidSignature, "JWS has no signature.")
@ -241,7 +246,7 @@ proc validate*(jws: JWS, alg: JwtAlgorithm, key: JWK, sigIdx = 0) =
raise newException(InvalidSignature, "failed to verify signature value.") raise newException(InvalidSignature, "failed to verify signature value.")
proc tryValidate*(jws: JWS, alg: JwtAlgorithm, key: JWK): bool = proc tryValidate*(jws: JWS, alg: JwtAlgorithm, key: JWK | string): bool =
try: try:
jws.validate(alg, key) jws.validate(alg, key)
return true return true

View File

@ -13,7 +13,7 @@ import std/json, std/options
import ./jwa import ./jwa
import ./joseheader import ./joseheader
import ../private/jsonutils import ./private/jsonutils
type type
JwsSignature* = object JwsSignature* = object

View File

@ -74,7 +74,21 @@ proc createSignedJwt*(
claims: claims, claims: claims,
jws: sign(claims, header, key)) jws: sign(claims, header, key))
proc validate*(jwt: JWT, sigAlg: JwtAlgorithm, key: JWK) = proc validateTimeClaims*(jwt: JWT) =
let now = now()
if jwt.claims.exp.isSome and now > jwt.claims.exp.get:
raise newException(InvalidToken, "Token is expired.")
if jwt.claims.nbf.isSome and now < jwt.claims.nbf.get:
raise newException(InvalidToken, "Token cannot be used yet.")
proc validate*(
jwt: JWT,
sigAlg: JwtAlgorithm,
key: JWK,
validateTimeClaims = true
) =
case jwt.kind: case jwt.kind:
of jkJWS: of jkJWS:
jwt.jws.validate(sigAlg, key) jwt.jws.validate(sigAlg, key)
@ -82,12 +96,21 @@ proc validate*(jwt: JWT, sigAlg: JwtAlgorithm, key: JWK) =
of jkJWE: of jkJWE:
raise newException(Exception, "JWE validation is not yet implemented") raise newException(Exception, "JWE validation is not yet implemented")
proc tryValidate*(jwt: JWT, sigAlg: JwtAlgorithm, key: JWK): bool = if validateTimeClaims: jwt.validateTimeClaims
proc tryValidate*(
jwt: JWT,
sigAlg: JwtAlgorithm,
key: JWK,
validateTimeClaims = true
): bool =
try: try:
jwt.validate(sigAlg, key) jwt.validate(sigAlg, key)
return true return true
except: return false except: return false
# proc verify*(jwt: JWT): bool = ## proc verify*(jwt: JWT, secret: string, alg: SignatureAlgorithm): bool =
## tryValidate(jwt, sigAlg, secret)
# proc sign*(jwt: JWT, key: JWK): JWT = # proc sign*(jwt: JWT, key: JWK): JWT =

View File

@ -1,8 +1,8 @@
import std/options import std/options
import bearssl import bearssl
import ../jwt/jwa import ../jwa
import ../jwt/jwk import ../jwk
import ./crypto/ecdsa import ./crypto/ecdsa
import ./crypto/hmac import ./crypto/hmac
@ -20,7 +20,7 @@ proc computeSignature*(
key: JWK | string key: JWK | string
): string = ): string =
validateAlgMatchesKey(alg, key) if typeof(key) is JWK: validateAlgMatchesKey(alg, cast[JWK](key))
case alg: case alg:
of HS256, HS384, HS512: return hmac(payload, alg, key) of HS256, HS384, HS512: return hmac(payload, alg, key)
@ -34,10 +34,10 @@ proc verifySignature*(
payload: string, payload: string,
signature: string, signature: string,
alg: JwtAlgorithm, alg: JwtAlgorithm,
key: JWK key: JWK | string
): bool = ): bool =
validateAlgMatchesKey(alg, key) if typeof(key) is JWK: validateAlgMatchesKey(alg, cast[JWK](key))
case alg: case alg:
of HS256, HS384, HS512: of HS256, HS384, HS512:

View File

@ -1,8 +1,8 @@
import std/tables import std/tables
import bearssl, bearssl_pkey_decoder import bearssl, bearssl_pkey_decoder
import ../../jwt/jwa import ../../jwa
import ../../jwt/jwk import ../../jwk
import ../encoding import ../encoding
@ -63,7 +63,7 @@ proc toEcPublicKey(jwk: JWK): EcPublicKeyObj =
proc toEcPublicKey(pem: string): EcPublicKeyObj = proc toEcPublicKey(pem: string): EcPublicKeyObj =
var pkCtx: PkeyDecoderContext var pkCtx: PkeyDecoderContext
pkeyDecoderInit(addr pkCtx) pkeyDecoderInit(addr pkCtx)
decodePem(pem, "EC PUBLIC KEY", addr pkCtx, decodePem(pem, "PUBLIC KEY", addr pkCtx,
cast[BearPemDecoderCallback](pkeyDecoderPush)) cast[BearPemDecoderCallback](pkeyDecoderPush))
let k = pkCtx.key.ec let k = pkCtx.key.ec
@ -158,6 +158,12 @@ proc ecSign*(message: string, alg: JwtAlgorithm, key: JWK): string =
return bearEcSign(message, alg, toEcPrivateKey(key)) return bearEcSign(message, alg, toEcPrivateKey(key))
proc ecSign*(message: string, alg: JwtAlgorithm, pemKey: string): string =
## Sign a message using the ECDSA algorithm.
##
## *pemKey* is expected to be a PEM
return bearEcSign(message, alg, toEcPrivateKey(pemKey))
proc ecVerify*(message, signature: string, alg: JwtAlgorithm, key: JWK): bool = proc ecVerify*(message, signature: string, alg: JwtAlgorithm, key: JWK): bool =
## Verify the signature for a message using ECDSA. ## Verify the signature for a message using ECDSA.
## ##
@ -170,3 +176,9 @@ proc ecVerify*(message, signature: string, alg: JwtAlgorithm, key: JWK): bool =
"\"typ\"=\"" & $(key.keyKind) & "\" key.") "\"typ\"=\"" & $(key.keyKind) & "\" key.")
return bearEcVerify(message, signature, alg, toEcPublicKey(key)) return bearEcVerify(message, signature, alg, toEcPublicKey(key))
proc ecVerify*(message, signature: string, alg: JwtAlgorithm, pemKey: string): bool =
## Verify the signature for a message using ECDSA.
##
## *pemKey* is expected to be a PEM.
return bearEcVerify(message, signature, alg, toEcPublicKey(pemKey))

View File

@ -2,8 +2,8 @@ import std/logging
import bearssl import bearssl
import ../../jwt/jwa import ../../jwa
import ../../jwt/jwk import ../../jwk
import ../encoding import ../encoding

View File

@ -15,14 +15,16 @@ proc decodePem*(
var pemCtx: PemDecoderContext var pemCtx: PemDecoderContext
pemDecoderInit(addr pemCtx) pemDecoderInit(addr pemCtx)
var bytesRead = 0 var offset = 0
var bytesRemaining = len(pem)
var readingObj = false var readingObj = false
while bytesRead < len(pem): while bytesRemaining > 0:
bytesRead += pemDecoderPush(addr pemCtx, unsafeAddr pem[bytesRead], len(pem)) let bytesRead = pemDecoderPush(addr pemCtx, unsafeAddr pem[offset], bytesRemaining)
offset += bytesRead
bytesRemaining -= bytesRead
case pemDecoderEvent(addr pemCtx): case pemDecoderEvent(addr pemCtx):
of PEM_BEGIN_OBJ: of PEM_BEGIN_OBJ:
if readingObj: if readingObj:
raise newException(ValueError, raise newException(ValueError,

View File

@ -1,8 +1,8 @@
import std/options, std/tables import std/options, std/tables
import bearssl, bearssl_pkey_decoder import bearssl, bearssl_pkey_decoder
import ../../jwt/jwa import ../../jwa
import ../../jwt/jwk import ../../jwk
import ../encoding import ../encoding
@ -57,7 +57,7 @@ proc toRsaPublicKey(jwk: JWK): RsaPublicKeyObj =
proc toRsaPublicKey(pem: string): RsaPublicKeyObj = proc toRsaPublicKey(pem: string): RsaPublicKeyObj =
var pkCtx: PkeyDecoderContext var pkCtx: PkeyDecoderContext
pkeyDecoderInit(addr pkCtx) pkeyDecoderInit(addr pkCtx)
decodePem(pem, "RSA PUBLIC KEY", addr pkCtx, decodePem(pem, "PUBLIC KEY", addr pkCtx,
cast[BearPemDecoderCallback](pkeyDecoderPush)) cast[BearPemDecoderCallback](pkeyDecoderPush))
let k = pkCtx.key.rsa let k = pkCtx.key.rsa

View File

@ -1,29 +1,32 @@
## Example JWT from RFC 7519 (JWT) section 3.1 ## Example JWT from RFC 7519 (JWT) section 3.1
const rfc7519_S31_HeaderB64* = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9" const
const rfc7519_S31_HeaderBytes* = [123, 34, 116, 121, 112, 34, 58, 34, 74, 87, 84, 34, 44, 13, 10, 32, 34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53, 54, 34, 125] rfc7519_S31_HeaderB64* = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9"
const rfc7519_S31_ClaimsB64* = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ" rfc7519_S31_HeaderBytes* = [123, 34, 116, 121, 112, 34, 58, 34, 74, 87, 84, 34, 44, 13, 10, 32, 34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53, 54, 34, 125]
const rfc7519_S31_ClaimsBytes* = [123, 34, 105, 115, 115, 34, 58, 34, 106, 111, 101, 34, 44, 13, 10, 32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48, 56, 49, 57, 51, 56, 48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58, 47, 47, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, 47, 105, 115, 95, 114, 111, 111, 116, 34, 58, 116, 114, 117, 101, 125] rfc7519_S31_ClaimsB64* = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
rfc7519_S31_ClaimsBytes* = [123, 34, 105, 115, 115, 34, 58, 34, 106, 111, 101, 34, 44, 13, 10, 32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48, 56, 49, 57, 51, 56, 48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58, 47, 47, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, 47, 105, 115, 95, 114, 111, 111, 116, 34, 58, 116, 114, 117, 101, 125]
## Examples from RFC 7515 (JWS ## Examples from RFC 7515 (JWS
const rfc7515_A1_HeaderB64* = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9" const
const rfc7515_A1_HeaderBytes* = [123, 34, 116, 121, 112, 34, 58, 34, 74, 87, 84, 34, 44, 13, 10, 32, 34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53, 54, 34, 125] rfc7515_A1_HeaderB64* = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9"
const rfc7515_A1_ClaimsB64* = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ" rfc7515_A1_HeaderBytes* = [123, 34, 116, 121, 112, 34, 58, 34, 74, 87, 84, 34, 44, 13, 10, 32, 34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53, 54, 34, 125]
const rfc7515_A1_ClaimsBytes* = [123, 34, 105, 115, 115, 34, 58, 34, 106, 111, 101, 34, 44, 13, 10, 32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48, 56, 49, 57, 51, 56, 48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58, 47, 47, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, 47, 105, 115, 95, 114, 111, 111, 116, 34, 58, 116, 114, 117, 101, 125] rfc7515_A1_ClaimsB64* = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
const rfc7515_A1_SigB64* = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" rfc7515_A1_ClaimsBytes* = [123, 34, 105, 115, 115, 34, 58, 34, 106, 111, 101, 34, 44, 13, 10, 32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48, 56, 49, 57, 51, 56, 48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58, 47, 47, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, 47, 105, 115, 95, 114, 111, 111, 116, 34, 58, 116, 114, 117, 101, 125]
const rfc7515_A1_SigBytes* = [116, 24, 223, 180, 151, 153, 224, 37, 79, 250, 96, 125, 216, 173, 187, 186, 22, 212, 37, 77, 105, 214, 191, 240, 91, 88, 5, 88, 83, 132, 141, 121] rfc7515_A1_SigB64* = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
const rfc7515_A1_Jwt* = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" rfc7515_A1_SigBytes* = [116, 24, 223, 180, 151, 153, 224, 37, 79, 250, 96, 125, 216, 173, 187, 186, 22, 212, 37, 77, 105, 214, 191, 240, 91, 88, 5, 88, 83, 132, 141, 121]
const rfc7515_A1_JwkStr* = """{ rfc7515_A1_Jwt* = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
rfc7515_A1_JwkStr* = """{
"kty":"oct", "kty":"oct",
"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
}""" }"""
const rfc7515_A2_HeaderB64* = "eyJhbGciOiJSUzI1NiJ9" const
const rfc7515_A2_HeaderBytes* = [123, 34, 97, 108, 103, 34, 58, 34, 82, 83, 50, 53, 54, 34, 125] rfc7515_A2_HeaderB64* = "eyJhbGciOiJSUzI1NiJ9"
const rfc7515_A2_HeaderStr* = """{"alg":"RS256"}""" rfc7515_A2_HeaderBytes* = [123, 34, 97, 108, 103, 34, 58, 34, 82, 83, 50, 53, 54, 34, 125]
const rfc7515_A2_ClaimsB64* = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ" rfc7515_A2_HeaderStr* = """{"alg":"RS256"}"""
const rfc7515_A2_SigB64* = "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw" rfc7515_A2_ClaimsB64* = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
const rfc7515_A2_Jwt* = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw" rfc7515_A2_SigB64* = "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"
const rfc7515_A2_JwkPrvStr* = """{ rfc7515_A2_Jwt* = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"
rfc7515_A2_JwkPrvStr* = """{
"kty":"RSA", "kty":"RSA",
"n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ", "n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ",
"e":"AQAB", "e":"AQAB",
@ -34,20 +37,20 @@ const rfc7515_A2_JwkPrvStr* = """{
"dq":"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU", "dq":"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU",
"qi":"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U" "qi":"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U"
}""" }"""
const rfc7515_A2_JwkPubStr* = """{ rfc7515_A2_JwkPubStr* = """{
"kty":"RSA", "kty":"RSA",
"n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ", "n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ",
"e":"AQAB" "e":"AQAB"
}""" }"""
const
const rfc7515_A3_HeaderB64* = "eyJhbGciOiJFUzI1NiJ9" rfc7515_A3_HeaderB64* = "eyJhbGciOiJFUzI1NiJ9"
const rfc7515_A3_HeaderBytes* = [123, 34, 97, 108, 103, 34, 58, 34, 69, 83, 50, 53, 54, 34, 125] rfc7515_A3_HeaderBytes* = [123, 34, 97, 108, 103, 34, 58, 34, 69, 83, 50, 53, 54, 34, 125]
const rfc7515_A3_HeaderStr* = """{"alg":"ES256"}""" rfc7515_A3_HeaderStr* = """{"alg":"ES256"}"""
const rfc7515_A3_ClaimsB64* = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ" rfc7515_A3_ClaimsB64* = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
const rfc7515_A3_SignB64* = "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q" rfc7515_A3_SignB64* = "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
const rfc7515_A3_Jwt* = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q" rfc7515_A3_Jwt* = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
const rfc7515_A3_JwkStr* = """{ rfc7515_A3_JwkStr* = """{
"kty":"EC", "kty":"EC",
"crv":"P-256", "crv":"P-256",
"x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU", "x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
@ -55,15 +58,15 @@ const rfc7515_A3_JwkStr* = """{
"d":"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI" "d":"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI"
}""" }"""
const
const rfc7515_A4_HeaderB64* = "eyJhbGciOiJFUzUxMiJ9" rfc7515_A4_HeaderB64* = "eyJhbGciOiJFUzUxMiJ9"
const rfc7515_A4_HeaderBytes* = [123, 34, 97, 108, 103, 34, 58, 34, 69, 83, 53, 49, 50, 34, 125] rfc7515_A4_HeaderBytes* = [123, 34, 97, 108, 103, 34, 58, 34, 69, 83, 53, 49, 50, 34, 125]
const rfc7515_A4_HeaderStr* = """{"alg":"ES512"}""" rfc7515_A4_HeaderStr* = """{"alg":"ES512"}"""
const rfc7515_A4_PayloadB64* = "UGF5bG9hZA" rfc7515_A4_PayloadB64* = "UGF5bG9hZA"
const rfc7515_A4_PayloadBytes* = [80, 97, 121, 108, 111, 97, 100] rfc7515_A4_PayloadBytes* = [80, 97, 121, 108, 111, 97, 100]
const rfc7515_A4_SignB64* = "AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn" rfc7515_A4_SignB64* = "AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn"
const rfc7515_A4_Jwt* = "eyJhbGciOiJFUzUxMiJ9.UGF5bG9hZA.AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn" rfc7515_A4_Jwt* = "eyJhbGciOiJFUzUxMiJ9.UGF5bG9hZA.AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn"
const rfc7515_A4_JwkStr* = """{ rfc7515_A4_JwkStr* = """{
"kty":"EC", "kty":"EC",
"crv":"P-521", "crv":"P-521",
"x":"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk", "x":"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk",
@ -75,13 +78,133 @@ const rfc7515_A4_JwkStr* = """{
# match the data from the RFC. For cases where we want exact matches (to # match the data from the RFC. For cases where we want exact matches (to
# validate B64 conversion, signature, etc.) use either the Base64 version or # validate B64 conversion, signature, etc.) use either the Base64 version or
# the byte arrays above. # the byte arrays above.
const rfc7519_S31_HeaderStr* = """{"typ":"JWT", "alg":"HS256"}""" const
const rfc7519_S31_ClaimsStr* = """{"iss":"joe", "exp":1300819380, "http://example.com/is_root":true}""" rfc7519_S31_HeaderStr* = """{"typ":"JWT", "alg":"HS256"}"""
const rfc7515_A1_HeaderStr* = """{"typ":"JWT", "alg":"HS256"}""" rfc7519_S31_ClaimsStr* = """{"iss":"joe", "exp":1300819380, "http://example.com/is_root":true}"""
const rfc7515_A1_ClaimsStr* = """{"iss":"joe", "exp":1300819380, "http://example.com/is_root":true}""" rfc7515_A1_HeaderStr* = """{"typ":"JWT", "alg":"HS256"}"""
const rfc7515_A2_ClaimsStr* = """{"iss":"joe", "exp":1300819380, "http://example.com/is_root":true}""" rfc7515_A1_ClaimsStr* = """{"iss":"joe", "exp":1300819380, "http://example.com/is_root":true}"""
rfc7515_A2_ClaimsStr* = """{"iss":"joe", "exp":1300819380, "http://example.com/is_root":true}"""
const sampleJwt* = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhYmMiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.fKGoqlw-Nporec-dVTrNbC0ZC7kAhUsEs50s12Iwy14" const
const sampleJwtHeaderDecoded* = """{"alg":"HS256","typ":"JWT"}""" sampleJwt* = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhYmMiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.fKGoqlw-Nporec-dVTrNbC0ZC7kAhUsEs50s12Iwy14"
const sampleJwtClaimsDecoded* = """{"sub":"abc","name":"John Doe","iat":1516239022}""" sampleJwtHeaderDecoded* = """{"alg":"HS256","typ":"JWT"}"""
const sampleJwtKey* = """{ "kty": "oct", "k": "eW91ci0yNTYtYml0LXNlY3JldAo" }""" sampleJwtClaimsDecoded* = """{"sub":"abc","name":"John Doe","iat":1516239022}"""
sampleJwtKey* = """{ "kty": "oct", "k": "eW91ci0yNTYtYml0LXNlY3JldAo" }"""
const
sampleJwtRsa* = ""
sampleJwtRsaHeaderDecoded* = """{"alg":"RS256","type":"JWT"}"""
sampleJwtRsaClaimsDecoded* = """{"sub":"abc","name":"John Doe","iat":1516239022}"""
const
sampleRsaPrvPem* = """-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA6quR5amHVIaRWhPfZCe4sF2tBo+1NhhHjcFpzxD6YJ/HQBHP
Mr3aLuQCRKL3y4E5loQ/McGfLF9h/llwY0+6I8eHNPw9fIcVd7n0CYooyxBTIn+l
hsucV2+2tXCnriIQfPZ7VUs2k0ycu1SB/DVHw7Q8K+H98Ta6oQEByZDthWhnPmnF
JInlcg4o6ckE9BKxk2uiKmprhU4MsSgsdBMUVUMStP7nxI/iiTaIlEe78P8VteBB
B6gSy16+d9+VCONQ+MlRSrh3aBWdas0ppYKDUpPrcm8uXWpNxfPqbNpSlNzPUJqg
7FPeTyvRVKm/tbGSSGVYCxNvh8DXazySvVa1XwIDAQABAoIBAQChbD2i5lex/BMW
DF95TJ2NrBJuVgJH4LGvwCDhkAM63g24c8e8Vr4zzSIGRrf/Y7fSYsv5lP/CDSai
SLG3jssy+3h1KSG+fEl3HxHQUho3fNZC/91D+OFlf/IFoyWk8ce3vfEevesfre6O
KdZ0P85Kv7s4UG9XMtd0EvZAyhGo1tQQJqknvAaRpVHKpHUglbTpYroeWxKy03Ud
qCmOP3UTb1oLn4AAGwgFOHVmaSRlOCCs/MPliHBodGrYcw2FkBtNjF8hCH0+2XWL
angHt015o/BgZnKMk2uLWRYzGm4GzALFz7Xk8RaWs1/2RUL0izQ/pVbeE7gMZU+G
rRfkt5gRAoGBAPoiYvTha1udyIkOtZUuZTpC3taO7RlvhSR6mbQGuYj8VTp8v7lB
MA3pgINDcl1DqL0pCNeL3ahy4cFSYVU7ZEheVbTiYbsZ4N3F/Vk4uZDuEEXfC8WA
pf2yvBG6nEhdIE65Sjk1rxU6uSsVZIL0GKcPGMSlZ9cMsOBiXM1AoSt3AoGBAPAs
WUKmqN0DHa2e/oSIfDfFFAqSbN/6gOtAI/onartYFhHOph2H0JuxnPaElIDmfuuq
r59N5M9o1RpgFJ7ZSBT3vhsFw9aVnfGVLDKnSlWNyNGLMeuaKXRxTHlVVIEFE6TW
yZhhsODFwMovC5SeIKJuCgwZvM0ggh+o8Nxpum9ZAoGAMaHZGNYRw2APhoKQrUVD
eMgEB3bcvQtP0+kvznT3I6NOFgji0hOJQXlvspwTeUYPmVknE/4AwYfqG74I6iya
vXFaeEXjNojwAZFjr+x9hbB3MiYL4+ifBzQL9Uid8g3odzZ0790jHIdGbrIT+5gL
vDpWo85eSGGQRzW9TEzirgkCgYEAwIdMppljFIjC6cNi1Gt06GAbyL3IeWQepHcu
YAHpFXVve6bkkxekqqqe4R82zH35kIGrd1DB82JeMl6DKTOVDPnsc00TyJj3nAmw
/IoOlLasHQ4wXmWehbGtVDaLH0IqlSF5SaZGXGkqOumrpt972bnMZBbdurIsnaSY
MJiw00ECgYEAgkkhhWiYUNBpMXWYPeKXIthZ08X9M2l/6XTZsPy4P38Og7kmV2h8
mlElb2jLRGRobR/I5Z4adupXAe3pgCvq8/LrVz6zEvEkTVQ4Ln4E14CmiqpqL1jD
aG3Ed4xKRgUd/5CpdiU3fB15BEeUDn6XdeEbKiZVZF7AA6mykSWFIgg=
-----END RSA PRIVATE KEY-----"""
sampleRsaPubPem* = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6quR5amHVIaRWhPfZCe4
sF2tBo+1NhhHjcFpzxD6YJ/HQBHPMr3aLuQCRKL3y4E5loQ/McGfLF9h/llwY0+6
I8eHNPw9fIcVd7n0CYooyxBTIn+lhsucV2+2tXCnriIQfPZ7VUs2k0ycu1SB/DVH
w7Q8K+H98Ta6oQEByZDthWhnPmnFJInlcg4o6ckE9BKxk2uiKmprhU4MsSgsdBMU
VUMStP7nxI/iiTaIlEe78P8VteBBB6gSy16+d9+VCONQ+MlRSrh3aBWdas0ppYKD
UpPrcm8uXWpNxfPqbNpSlNzPUJqg7FPeTyvRVKm/tbGSSGVYCxNvh8DXazySvVa1
XwIDAQAB
-----END PUBLIC KEY-----"""
# ---------------------------------------------------------------
const
rsPrivateKey* = """-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWw
kWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mr
m/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEi
NQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV
3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2
QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQABAoIBACiARq2wkltjtcjs
kFvZ7w1JAORHbEufEO1Eu27zOIlqbgyAcAl7q+/1bip4Z/x1IVES84/yTaM8p0go
amMhvgry/mS8vNi1BN2SAZEnb/7xSxbflb70bX9RHLJqKnp5GZe2jexw+wyXlwaM
+bclUCrh9e1ltH7IvUrRrQnFJfh+is1fRon9Co9Li0GwoN0x0byrrngU8Ak3Y6D9
D8GjQA4Elm94ST3izJv8iCOLSDBmzsPsXfcCUZfmTfZ5DbUDMbMxRnSo3nQeoKGC
0Lj9FkWcfmLcpGlSXTO+Ww1L7EGq+PT3NtRae1FZPwjddQ1/4V905kyQFLamAA5Y
lSpE2wkCgYEAy1OPLQcZt4NQnQzPz2SBJqQN2P5u3vXl+zNVKP8w4eBv0vWuJJF+
hkGNnSxXQrTkvDOIUddSKOzHHgSg4nY6K02ecyT0PPm/UZvtRpWrnBjcEVtHEJNp
bU9pLD5iZ0J9sbzPU/LxPmuAP2Bs8JmTn6aFRspFrP7W0s1Nmk2jsm0CgYEAyH0X
+jpoqxj4efZfkUrg5GbSEhf+dZglf0tTOA5bVg8IYwtmNk/pniLG/zI7c+GlTc9B
BwfMr59EzBq/eFMI7+LgXaVUsM/sS4Ry+yeK6SJx/otIMWtDfqxsLD8CPMCRvecC
2Pip4uSgrl0MOebl9XKp57GoaUWRWRHqwV4Y6h8CgYAZhI4mh4qZtnhKjY4TKDjx
QYufXSdLAi9v3FxmvchDwOgn4L+PRVdMwDNms2bsL0m5uPn104EzM6w1vzz1zwKz
5pTpPI0OjgWN13Tq8+PKvm/4Ga2MjgOgPWQkslulO/oMcXbPwWC3hcRdr9tcQtn9
Imf9n2spL/6EDFId+Hp/7QKBgAqlWdiXsWckdE1Fn91/NGHsc8syKvjjk1onDcw0
NvVi5vcba9oGdElJX3e9mxqUKMrw7msJJv1MX8LWyMQC5L6YNYHDfbPF1q5L4i8j
8mRex97UVokJQRRA452V2vCO6S5ETgpnad36de3MUxHgCOX3qL382Qx9/THVmbma
3YfRAoGAUxL/Eu5yvMK8SAt/dJK6FedngcM3JEFNplmtLYVLWhkIlNRGDwkg3I5K
y18Ae9n7dHVueyslrb6weq7dTkYDi3iOYRW8HRkIQh06wEdbxt0shTzAJvvCQfrB
jg/3747WSsf/zBTcHihTRBdAv6OmdhV4/dD5YBfLAkLrd+mX7iE=
-----END RSA PRIVATE KEY-----"""
rsPublicKey* = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv
vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc
aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy
tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0
e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb
V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9
MwIDAQAB
-----END PUBLIC KEY-----"""
ec256PrivKey = """-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2
OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r
1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G
-----END PRIVATE KEY-----"""
ec256PubKey = """-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9
q9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==
-----END PUBLIC KEY-----"""
ec384PrivKey = """-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDCAHpFQ62QnGCEvYh/pE9QmR1C9aLcDItRbslbmhen/h1tt8AyMhske
enT+rAyyPhGgBwYFK4EEACKhZANiAAQLW5ZJePZzMIPAxMtZXkEWbDF0zo9f2n4+
T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw8lE5IPUWpgu553SteKigiKLU
PeNpbqmYZUkWGh3MLfVzLmx85ii2vMU=
-----END EC PRIVATE KEY-----"""
ec384PubKey = """-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEC1uWSXj2czCDwMTLWV5BFmwxdM6PX9p+
Pk9Yf9rIf374m5XP1U8q79dBhLSIuaojsvOT39UUcPJROSD1FqYLued0rXiooIii
1D3jaW6pmGVJFhodzC31cy5sfOYotrzF
-----END PUBLIC KEY-----"""
ec512PrivKey = """-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIBiyAa7aRHFDCh2qga9sTUGINE5jHAFnmM8xWeT/uni5I4tNqhV5Xx
0pDrmCV9mbroFtfEa0XVfKuMAxxfZ6LM/yKgBwYFK4EEACOhgYkDgYYABAGBzgdn
P798FsLuWYTDDQA7c0r3BVk8NnRUSexpQUsRilPNv3SchO0lRw9Ru86x1khnVDx+
duq4BiDFcvlSAcyjLACJvjvoyTLJiA+TQFdmrearjMiZNE25pT2yWP1NUndJxPcv
VtfBW48kPOmvkY4WlqP5bAwCXwbsKrCgk6xbsp12ew==
-----END EC PRIVATE KEY-----"""
ec512PubKey = """-----BEGIN PUBLIC KEY-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ
PDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47
6MkyyYgPk0BXZq3mq4zImTRNuaU9slj9TVJ3ScT3L1bXwVuPJDzpr5GOFpaj+WwM
Al8G7CqwoJOsW7Kddns=
-----END PUBLIC KEY-----"""

View File

@ -1,6 +1,6 @@
import std/json, std/options, std/strutils, std/unittest import std/json, std/options, std/strutils, std/unittest
import private/encoding import jwt/private/encoding
import ../testdata import ../testdata
suite "private/encoding": suite "private/encoding":

View File

@ -2,7 +2,7 @@ import std/json, std/unittest
import jwt/claims, jwt/joseheader, jwt/jwa, jwt/jwk, jwt/jws import jwt/claims, jwt/joseheader, jwt/jwa, jwt/jwk, jwt/jws
import private/encoding import jwt/private/encoding
import ../testdata import ../testdata
@ -50,21 +50,21 @@ suite "jwt/jws":
jws.validate(HS256, sampleKey) jws.validate(HS256, sampleKey)
test "RS256 - sign": test "RS256 - sign using JWK":
check rfc7515_A2_Jwt == $sign( check rfc7515_A2_Jwt == $sign(
header = initJoseHeader(rfc7515_A2_HeaderB64), header = initJoseHeader(rfc7515_A2_HeaderB64),
payload = b64UrlDecode(rfc7515_A2_ClaimsB64), payload = b64UrlDecode(rfc7515_A2_ClaimsB64),
key = rfc7515_A2_JwkPrvKey) key = rfc7515_A2_JwkPrvKey)
test "RS256 - verify": test "RS256 - verify using JWK":
validate( validate(
jws = initJWS(rfc7515_A2_Jwt), jws = initJWS(rfc7515_A2_Jwt),
alg = RS256, alg = RS256,
key = rfc7515_A2_JwkPubKey) key = rfc7515_A2_JwkPubKey)
test "RS256 - round trip": test "RS256 - round trip using JWK":
let jws = sign( let jws = sign(
header = initJoseHeader(%*{"alg":"RS256"}), header = initJoseHeader(%*{"alg":"RS256"}),
@ -73,6 +73,31 @@ suite "jwt/jws":
jws.validate(RS256, rfc7515_A2_JwkPubKey) jws.validate(RS256, rfc7515_A2_JwkPubKey)
#[ TODO
test "RS256 - sign using PEM":
#check rfc7515_A2_Jwt == $sign(
echo $sign(
header = initJoseHeader(parseJson(sampleJwtRsaHeaderDecoded)),
payload = $initJwtClaims(parseJson(sampleJwtRsaClaimsDecoded)),
key = rsPrivateKey)
test "RS256 - verify using PEM":
validate(
jws = initJWS(rfc7515_A2_Jwt),
alg = RS256,
key = rsPublicKey)
test "RS256 - round trip using PEM":
let jws = sign(
header = initJoseHeader(%*{"alg":"RS256"}),
payload = "This is a message I want to protect from tampering.",
key = rsPrivateKey)
jws.validate(RS256, rsPublicKey)
test "ES256 - sign": test "ES256 - sign":
check rfc7515_A3_Jwt == $sign( check rfc7515_A3_Jwt == $sign(
@ -118,3 +143,4 @@ suite "jwt/jws":
key = rfc7515_A4_Jwk) key = rfc7515_A4_Jwk)
jws.validate(ES512, rfc7515_A4_Jwk) jws.validate(ES512, rfc7515_A4_Jwk)
]#

View File

@ -1,7 +1,7 @@
import std/json, std/unittest import std/json, std/unittest
import jwt/claims, jwt/joseheader, jwt/jwa, jwt/jwk, jwt/jwt import jwt/claims, jwt/joseheader, jwt/jwa, jwt/jwk, jwt/jwt
import private/encoding import jwt/private/encoding
import ../testdata import ../testdata
@ -33,9 +33,9 @@ suite "jwt/jwt":
test "validate - HS256": test "validate - HS256":
initJwt(rfc7515_A1_Jwt).validate(HS256, rfc7515_A1_Jwk) initJwt(rfc7515_A1_Jwt).validate(HS256, rfc7515_A1_Jwk, validateTimeClaims = false)
initJwt(sampleJwt).validate(HS256, sampleKey) initJwt(sampleJwt).validate(HS256, sampleKey, validateTimeClaims = false)
test "validate - RS256": test "validate - RS256":
initJwt(rfc7515_A2_Jwt).validate(RS256, rfc7515_A2_JwkPubKey) initJwt(rfc7515_A2_Jwt).validate(RS256, rfc7515_A2_JwkPubKey, validateTimeClaims = false)