Initial commit with JWK parsing implementation.
This commit is contained in:
3
src/main/jwt.nim
Normal file
3
src/main/jwt.nim
Normal file
@ -0,0 +1,3 @@
|
||||
import jwt/jwk
|
||||
|
||||
export jwk
|
191
src/main/jwt/jwk.nim
Normal file
191
src/main/jwt/jwk.nim
Normal file
@ -0,0 +1,191 @@
|
||||
import std/json, std/options, std/sequtils
|
||||
|
||||
import ../private/jsonutils
|
||||
|
||||
type
|
||||
JwkKeyType* = enum EcPublic, EcPrivate, RsaPublic, RsaPrivate, Octet
|
||||
JwkKty* = enum ktyEC = "EC", ktyRSA = "RSA", ktyOctet = "oct"
|
||||
|
||||
JwkUse* = enum jwkuSignature = "sig", jwkuEncrypt = "enc"
|
||||
|
||||
JwkOps* = enum jwkopSign = "sign", jwkopVerify = "verify",
|
||||
jwkopEncrypt = "encrypt", jwkopDecrypt = "decrypt",
|
||||
jwkopWrapKey = "wrapKey", jwkopUnwrapKey = "unwrapKey",
|
||||
jwkopDeriveKey = "deriveKey", jwkopDeriveBits = "deriveBits"
|
||||
|
||||
JwkAlg* = enum
|
||||
HS256 = "HS256", HS384 = "HS384", HS512 = "HS512",
|
||||
RS256 = "RS256", RS384 = "RS384", RS512 = "RS512",
|
||||
ES256 = "ES256", ES384 = "ES384", ES512 = "ES512",
|
||||
PS256 = "PS256", PS384 = "PS384", PS512 = "PS512",
|
||||
|
||||
algNone = "none", algDir = "dir",
|
||||
|
||||
RSA1_5 = "RSA1_5", RSA_OAEP = "RSA-OAEP", RSA_OAEP_256 = "RSA-OEAP-256",
|
||||
|
||||
A128KW = "A128KW", A192KW = "A192KW", A256KW = "A256KW",
|
||||
|
||||
ECDH_ES = "ECDH_ES", ECDH_ES_A128KW = "ECDH_ES_A128KW",
|
||||
ECDH_ES_A192KW = "ECDH_ES_A192KW", ECDH_ES_A256KW = "ECDH_ES_A256KW",
|
||||
|
||||
A128GCMKW = "A128GCMKW", A192GCMKW = "A192GCMKW", A256GCMKW = "A256GCMKW",
|
||||
|
||||
PBES2_HS256_A128KW = "PBES2_HS256_A128KW",
|
||||
PBES2_HS384_A192KW = "PBES2_HS384_A192KW",
|
||||
PBES2_HS512_A256KW = "PBES2_HS512_A256KW",
|
||||
|
||||
A128CBC_HS256 = "A128CBC_HS256",
|
||||
A192CBC_HS384 = "A192CBC_HS384",
|
||||
A256CBC_HS512 = "A256CBC_HS512",
|
||||
|
||||
A128GCM = "A128GCM", A192GCM = "A192GCM", A256GCM = "A256GCM"
|
||||
|
||||
EcCrv* = enum P256 = "P-256", P384 = "P-384", P521 = "P-521"
|
||||
|
||||
EcPubKey = object of RootObj
|
||||
crv*: string
|
||||
x*: string
|
||||
y*: Option[string]
|
||||
|
||||
EcPrvKey* = object of EcPubKey
|
||||
d*: string
|
||||
|
||||
RsaPubKey* = object of RootObj
|
||||
n*: string
|
||||
e*: string
|
||||
|
||||
RsaOtherPrime* = object
|
||||
r*: string
|
||||
d*: string
|
||||
t*: string
|
||||
|
||||
RsaPrvKey* = object of RsaPubKey
|
||||
d*: string
|
||||
p*: Option[string]
|
||||
q*: Option[string]
|
||||
dp*: Option[string]
|
||||
dq*: Option[string]
|
||||
qi*: Option[string]
|
||||
oth*: Option[seq[RsaOtherPrime]]
|
||||
|
||||
OctetKey* = object
|
||||
k*: string
|
||||
|
||||
JWK* = object
|
||||
json: JsonNode
|
||||
kty*: string
|
||||
use*: Option[string]
|
||||
key_ops*: Option[string]
|
||||
alg*: Option[string]
|
||||
kid*: Option[string]
|
||||
x5u*: Option[string]
|
||||
x5c*: Option[string]
|
||||
x5t*: Option[string]
|
||||
x5tS256*: Option[string]
|
||||
|
||||
case keyKind*: JwkKeyType
|
||||
of EcPublic: ecPub*: EcPubKey
|
||||
of EcPrivate: ecPrv*: EcPrvKey
|
||||
of RsaPublic: rsaPub*: RsaPubKey
|
||||
of RsaPrivate: rsaPrv*: RsaPrvKey
|
||||
of Octet: octKey*: OctetKey
|
||||
|
||||
JwkSet* = seq[JWK]
|
||||
|
||||
func `[]`*(jwk: JWK, key: string): JsonNode = jwk.json[key]
|
||||
func `[]=`*(jwk: JWK, key: string, val: JsonNode): void = jwk.json[key] = val
|
||||
|
||||
func parseEcPubKey*(n: JsonNode): EcPubKey =
|
||||
EcPubKey(
|
||||
crv: n.reqStrVal("crv"),
|
||||
x: n.reqStrVal("x"),
|
||||
y: n.optStrVal("y"))
|
||||
|
||||
func parseEcPrvKey*(n: JsonNode): EcPrvKey =
|
||||
let pk = parseEcPubKey(n)
|
||||
EcPrvKey(crv: pk.crv, x: pk.x, y: pk.y, d: n.reqStrVal("d"))
|
||||
|
||||
func parseRsaPubKey*(n: JsonNode): RsaPubKey =
|
||||
RsaPubKey(
|
||||
n: n.reqStrVal("n"),
|
||||
e: n.reqStrVal("e"))
|
||||
|
||||
func parseRsaOtherPrime(n: JsonNode): RsaOtherPrime =
|
||||
RsaOtherPrime(
|
||||
r: n.reqStrVal("r"),
|
||||
d: n.reqStrVal("d"),
|
||||
t: n.reqStrVal("t"))
|
||||
|
||||
func parseRsaPrvKey*(n: JsonNode): RsaPrvKey =
|
||||
let pk = parseRsaPubKey(n)
|
||||
RsaPrvKey(n: pk.n, e: pk.e,
|
||||
d: n.reqStrVal("d"),
|
||||
p: n.optStrVal("p"),
|
||||
q: n.optStrVal("q"),
|
||||
dp: n.optStrVal("dp"),
|
||||
dq: n.optStrVal("dq"),
|
||||
qi: n.optStrVal("qi"),
|
||||
oth:
|
||||
if n.hasKey("oth"):
|
||||
some(n["oth"].getElems.mapIt(parseRsaOtherPrime(it)))
|
||||
else: none[seq[RsaOtherPrime]]()
|
||||
)
|
||||
|
||||
|
||||
func parseOctetKey*(n: JsonNode): OctetKey =
|
||||
OctetKey(k: n.reqStrVal("k"))
|
||||
|
||||
func parseJwk*(n: JsonNode): JWK =
|
||||
# TODO: documentation, example, handle encrypted keys (JWEs)
|
||||
case n["kty"].getStr(""):
|
||||
|
||||
of $ktyEC:
|
||||
if n.hasKey("d"):
|
||||
result = JWK(
|
||||
kty: $ktyEC,
|
||||
keyKind: EcPrivate,
|
||||
ecPrv: parseEcPrvKey(n))
|
||||
else:
|
||||
result = JWK(
|
||||
kty: $ktyEC,
|
||||
keyKind: EcPublic,
|
||||
ecPub: parseEcPubKey(n))
|
||||
|
||||
of $ktyRSA:
|
||||
if n.hasKey("d"):
|
||||
result = JWK(
|
||||
kty: $ktyRSA,
|
||||
keyKind: RsaPrivate,
|
||||
rsaPrv: parseRsaPrvKey(n))
|
||||
else:
|
||||
result = JWK(
|
||||
kty: $ktyRSA,
|
||||
keyKind: RsaPublic,
|
||||
rsaPub: parseRsaPubKey(n))
|
||||
|
||||
of $ktyOctet:
|
||||
result = JWK(
|
||||
kty: $ktyOctet,
|
||||
keyKind: Octet,
|
||||
octKey: parseOctetKey(n))
|
||||
|
||||
else: raise newException(ValueError,
|
||||
"Unrecognized or missing kty: '" & n["kty"].getStr("") & "'")
|
||||
|
||||
result.json = n
|
||||
result.use = n.optStrVal("use")
|
||||
result.key_ops = n.optStrVal("key_ops")
|
||||
result.alg = n.optStrVal("alg")
|
||||
result.kid = n.optStrVal("kid")
|
||||
result.x5u = n.optStrVal("x5u")
|
||||
result.x5c = n.optStrVal("x5c")
|
||||
result.x5t = n.optStrVal("x5t")
|
||||
result.x5tS256 = n.optStrVal("x5t#S256")
|
||||
|
||||
func parseJwkSet*(n: JsonNode): JwkSet =
|
||||
# TODO: documentation, examples, handled encrypted set (JWE)
|
||||
if not n.hasKey("keys") or n["keys"].kind != JArray:
|
||||
raise newException(ValueError, "JWK Set is missing the 'keys' member, " &
|
||||
"or 'keys' is not an array.")
|
||||
|
||||
return n["keys"].getElems.mapIt(parseJwk(it))
|
12
src/main/private/jsonutils.nim
Normal file
12
src/main/private/jsonutils.nim
Normal file
@ -0,0 +1,12 @@
|
||||
import std/json, std/options, std/strutils
|
||||
|
||||
func reqStrVal*(n: JsonNode, key: string): string =
|
||||
if n.hasKey(key):
|
||||
let val = n[key].getStr("")
|
||||
if not val.isEmptyOrWhitespace: return val
|
||||
|
||||
raise newException(ValueError, "missing value for '" & key & "'")
|
||||
|
||||
func optStrVal*(n: JsonNode, key: string): Option[string] =
|
||||
if n.hasKey(key): some(n[key].getStr)
|
||||
else: none[string]()
|
2
src/test/unit/config.nims
Normal file
2
src/test/unit/config.nims
Normal file
@ -0,0 +1,2 @@
|
||||
switch("path", "../../main")
|
||||
switch("verbosity", "0")
|
3
src/test/unit/runner.nim
Normal file
3
src/test/unit/runner.nim
Normal file
@ -0,0 +1,3 @@
|
||||
import std/unittest
|
||||
|
||||
import ./tjwk
|
217
src/test/unit/tjwk.nim
Normal file
217
src/test/unit/tjwk.nim
Normal file
@ -0,0 +1,217 @@
|
||||
import std/json, std/options, std/unittest
|
||||
|
||||
import jwt/jwk
|
||||
|
||||
suite "jwt/jwk":
|
||||
|
||||
const rfc7517A1ExamplePubKeysStr = """
|
||||
{"keys":
|
||||
[
|
||||
{"kty":"EC",
|
||||
"crv":"P-256",
|
||||
"x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
|
||||
"y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
|
||||
"use":"enc",
|
||||
"kid":"1"},
|
||||
{"kty":"RSA",
|
||||
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
|
||||
"e":"AQAB",
|
||||
"alg":"RS256",
|
||||
"kid":"2011-04-29"}
|
||||
]
|
||||
}"""
|
||||
|
||||
let rfc7517A1ExamplePubKeysJson = parseJson(rfc7517A1ExamplePubKeysStr)
|
||||
|
||||
const rfc7517A2ExamplePrvKeysStr = """
|
||||
{"keys":
|
||||
[
|
||||
{"kty":"EC",
|
||||
"crv":"P-256",
|
||||
"x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
|
||||
"y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
|
||||
"d":"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE",
|
||||
"use":"enc",
|
||||
"kid":"1"},
|
||||
|
||||
{"kty":"RSA",
|
||||
"n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
|
||||
"e":"AQAB",
|
||||
"d":"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q",
|
||||
"p":"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs",
|
||||
"q":"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk",
|
||||
"dp":"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0",
|
||||
"dq":"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk",
|
||||
"qi":"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU",
|
||||
"alg":"RS256",
|
||||
"kid":"2011-04-29"}
|
||||
]
|
||||
}"""
|
||||
|
||||
let rfc7517A2ExamplePrvKeysJson = parseJson(rfc7517A2ExamplePrvKeysStr)
|
||||
|
||||
test "parseEcPubKey parses valid keys":
|
||||
let keyNode = rfc7517A1ExamplePubKeysJson["keys"][0]
|
||||
let jwk = parseJwk(keyNode)
|
||||
|
||||
check:
|
||||
jwk.kty == $ktyEC
|
||||
jwk.keyKind == EcPublic
|
||||
jwk.use.isSome
|
||||
jwk.use.get == $jwkuEncrypt
|
||||
jwk.kid.isSome
|
||||
jwk.kid.get == "1"
|
||||
jwk.key_ops.isNone
|
||||
jwk.ecPub.crv == $P256
|
||||
jwk.ecPub.x == "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4"
|
||||
jwk.ecPub.y.isSome
|
||||
jwk.ecPub.y.get == "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
|
||||
|
||||
test "parseEcPubKey rejects keys missing required values":
|
||||
let keyNode = rfc7517A1ExamplePubKeysJson["keys"][0]
|
||||
|
||||
let withoutCrv = parseJson($keyNode)
|
||||
withoutCrv.delete("crv")
|
||||
expect ValueError: discard parseJwk(withoutCrv)
|
||||
|
||||
let withoutX = parseJson($keyNode)
|
||||
withoutX.delete("x")
|
||||
expect ValueError: discard parseJwk(withoutX)
|
||||
|
||||
let withoutY = parseJson($keyNode)
|
||||
withoutY.delete("y")
|
||||
let jwkWithoutY = parseJwk(withoutY)
|
||||
|
||||
check:
|
||||
jwkWithoutY.kty == $ktyEc
|
||||
jwkWithoutY.keyKind == EcPublic
|
||||
jwkWithoutY.ecPub.y.isNone
|
||||
|
||||
test "parseRsaPubKey parses valid keys":
|
||||
let keyNode = rfc7517A1ExamplePubKeysJson["keys"][1]
|
||||
let jwk = parseJwk(keyNode)
|
||||
|
||||
check:
|
||||
jwk.kty == $ktyRSA
|
||||
jwk.keyKind == RsaPublic
|
||||
jwk.alg.isSome
|
||||
jwk.alg.get == $RS256
|
||||
jwk.use.isNone
|
||||
jwk.kid.isSome
|
||||
jwk.kid.get == "2011-04-29"
|
||||
jwk.key_ops.isNone
|
||||
jwk.rsaPub.e == "AQAB"
|
||||
jwk.rsaPub.n == "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
|
||||
|
||||
test "parseRsaPubKey rejects keys missing required values":
|
||||
let keyNode = rfc7517A1ExamplePubKeysJson["keys"][1]
|
||||
|
||||
let withoutN = parseJson($keyNode)
|
||||
withoutN.delete("n")
|
||||
expect ValueError: discard parseJwk(withoutN)
|
||||
|
||||
let withoutE = parseJson($keyNode)
|
||||
withoutE.delete("e")
|
||||
expect ValueError: discard parseJwk(withoutE)
|
||||
|
||||
test "parseEcPrvKey parses valid keys":
|
||||
let keyNode = rfc7517A2ExamplePrvKeysJson["keys"][0]
|
||||
let jwk = parseJwk(keyNode)
|
||||
|
||||
check:
|
||||
jwk.kty == $ktyEC
|
||||
jwk.keyKind == EcPrivate
|
||||
jwk.use.isSome
|
||||
jwk.use.get == $jwkuEncrypt
|
||||
jwk.kid.isSome
|
||||
jwk.kid.get == "1"
|
||||
jwk.key_ops.isNone
|
||||
jwk.ecPrv.crv == $P256
|
||||
jwk.ecPrv.x == "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4"
|
||||
jwk.ecPrv.y.isSome
|
||||
jwk.ecPrv.y.get == "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
|
||||
jwk.ecPrv.d == "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE"
|
||||
|
||||
test "parseEcPrvKey rejects keys missing required values":
|
||||
let keyNode = rfc7517A2ExamplePrvKeysJson["keys"][0]
|
||||
|
||||
let withoutCrv = parseJson($keyNode)
|
||||
withoutCrv.delete("crv")
|
||||
expect ValueError: discard parseJwk(withoutCrv)
|
||||
|
||||
let withoutX = parseJson($keyNode)
|
||||
withoutX.delete("x")
|
||||
expect ValueError: discard parseJwk(withoutX)
|
||||
|
||||
let withoutY = parseJson($keyNode)
|
||||
withoutY.delete("y")
|
||||
let jwkWithoutY = parseJwk(withoutY)
|
||||
|
||||
check:
|
||||
jwkWithoutY.kty == $ktyEc
|
||||
jwkWithoutY.keyKind == EcPrivate
|
||||
jwkWithoutY.ecPrv.y.isNone
|
||||
|
||||
test "parseRsaPrvKey parses valid keys":
|
||||
let keyNode = rfc7517A2ExamplePrvKeysJson["keys"][1]
|
||||
let jwk = parseJwk(keyNode)
|
||||
|
||||
check:
|
||||
jwk.kty == $ktyRSA
|
||||
jwk.keyKind == RsaPrivate
|
||||
jwk.alg.isSome
|
||||
jwk.alg.get == $RS256
|
||||
jwk.use.isNone
|
||||
jwk.kid.isSome
|
||||
jwk.kid.get == "2011-04-29"
|
||||
jwk.key_ops.isNone
|
||||
jwk.rsaPrv.e == "AQAB"
|
||||
jwk.rsaPrv.n == "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
|
||||
jwk.rsaPrv.d == "X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q"
|
||||
jwk.rsaPrv.p.isSome
|
||||
jwk.rsaPrv.p.get == "83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs"
|
||||
jwk.rsaPrv.q.isSome
|
||||
jwk.rsaPrv.q.get == "3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk"
|
||||
jwk.rsaPrv.dp.isSome
|
||||
jwk.rsaPrv.dp.get == "G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0"
|
||||
jwk.rsaPrv.dq.isSome
|
||||
jwk.rsaPrv.dq.get == "s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk"
|
||||
jwk.rsaPrv.qi.isSome
|
||||
jwk.rsaPrv.qi.get == "GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU"
|
||||
jwk.rsaPrv.oth.isNone
|
||||
|
||||
test "parseRsaPrvKey rejects keys missing required values":
|
||||
let keyNode = rfc7517A2ExamplePrvKeysJson["keys"][1]
|
||||
|
||||
let withoutN = parseJson($keyNode)
|
||||
withoutN.delete("n")
|
||||
expect ValueError: discard parseJwk(withoutN)
|
||||
|
||||
let withoutE = parseJson($keyNode)
|
||||
withoutE.delete("e")
|
||||
expect ValueError: discard parseJwk(withoutE)
|
||||
|
||||
let withoutP = parseJson($keyNode)
|
||||
withoutP.delete("p")
|
||||
let jwkWithoutP = parseJwk(withoutP)
|
||||
check jwkWithoutP.rsaPrv.p.isNone
|
||||
|
||||
test "parseJwkSet (public key examples)":
|
||||
let jwkSet = parseJwkSet(rfc7517A1ExamplePubKeysJson)
|
||||
|
||||
check:
|
||||
jwkSet.len == 2
|
||||
jwkSet[0].kty == $ktyEC
|
||||
jwkSet[0].keyKind == EcPublic
|
||||
jwkSet[1].kty == $ktyRSA
|
||||
jwkSet[1].keyKind == RsaPublic
|
||||
|
||||
test "parseJwkSet (private key examples)":
|
||||
let jwkSet = parseJwkSet(rfc7517A2ExamplePrvKeysJson)
|
||||
|
||||
check:
|
||||
jwkSet.len == 2
|
||||
jwkSet[0].kty == $ktyEC
|
||||
jwkSet[0].keyKind == EcPrivate
|
||||
jwkSet[1].kty == $ktyRSA
|
||||
jwkSet[1].keyKind == RsaPrivate
|
Reference in New Issue
Block a user