Skip to content

Commit

Permalink
Cleanup and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ulrikstrid committed Feb 14, 2023
1 parent 354be89 commit a0be1e0
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 52 deletions.
11 changes: 8 additions & 3 deletions jose/Jwk.ml
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,10 @@ let priv_rsa_of_json json : (priv t, 'error) result =
let oct_of_json json =
let module Json = Yojson.Safe.Util in
try
let alg = Some (json |> Json.member "alg" |> Jwa.alg_of_json) in
let alg =
json |> Json.member "alg" |> Json.to_string_option
|> U_Opt.map Jwa.alg_of_string
in
Ok
(Oct
{
Expand Down Expand Up @@ -831,7 +834,8 @@ let of_pub_json (json : Yojson.Safe.t) : (public t, 'error) result =
| _ -> Error `Unsupported_kty

let of_pub_json_string str : (public t, 'error) result =
Yojson.Safe.from_string str |> of_pub_json
try Yojson.Safe.from_string str |> of_pub_json
with Yojson.Json_error s -> Error (`Json_parse_failed s)

let of_priv_json json : (priv t, 'error) result =
let module Json = Yojson.Safe.Util in
Expand All @@ -843,7 +847,8 @@ let of_priv_json json : (priv t, 'error) result =
| _ -> Error `Unsupported_kty

let of_priv_json_string str : (priv t, 'error) result =
Yojson.Safe.from_string str |> of_priv_json
try Yojson.Safe.from_string str |> of_priv_json
with Yojson.Json_error s -> Error (`Json_parse_failed s)

let pub_of_priv (jwk : priv t) : public t =
match jwk with
Expand Down
22 changes: 2 additions & 20 deletions jose/Jwt.ml
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,6 @@ let to_string t =
let payload = U_Base64.url_encode_string t.raw_payload in
Printf.sprintf "%s.%s.%s" t.raw_header payload t.signature

let unsafe_of_string token =
String.split_on_char '.' token |> function
| [ header_str; payload_str; signature ] ->
let header = Header.of_string header_str in
let payload = payload_of_string payload_str in
U_Result.both header payload
|> U_Result.flat_map (fun (header, payload) ->
Ok
{
header;
raw_header = header_str;
payload;
raw_payload =
U_Base64.url_decode payload_str |> U_Result.get_exn;
(* The string is already decoded so this is fine but
redundant *)
signature;
})
| _ -> Error (`Msg "token didn't include header, payload or signature")

let to_jws (t : t) =
Jws.
{
Expand All @@ -87,6 +67,8 @@ let of_jws (jws : Jws.t) =
raw_payload = jws.payload;
}

let unsafe_of_string token = Jws.of_string token |> U_Result.map of_jws

let check_expiration t =
let module Json = Yojson.Safe.Util in
match Json.member "exp" t.payload |> Json.to_int_option with
Expand Down
149 changes: 149 additions & 0 deletions test/JWSTest.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
let () = Mirage_crypto_rng_unix.initialize ()

open Helpers

(* These values are borrowed from the `ocaml-letsencrypt` test suite
https://github.com/mmaker/ocaml-letsencrypt *)
let testkey_pem =
"\n\
-----BEGIN PRIVATE KEY-----\n\
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDjGBnd5E+TChG/\n\
Lup5FRuYwN7RX7Ef15Yt27SKF54uWuYPaapZd8/0h5IoCluffiDxO4BL2DnOGrwQ\n\
tDeSaOv4pXzoYAyAjpUBwaWrdCvOlMJ//fQBvv7NrCt9FoU41rUfATM9jUoecZWT\n\
ElzzmA2TBgj1JjZEde2+WffOznAhM2t2iyoRd5oiRVgESFuE27nimneTGjpO5YuL\n\
17qld5Z60TCaUHC1ZmU+iJvaPdPEsGSwpl+jIXJ6TfzSYeAkC6ZD8jZ+OP3z/3ua\n\
TeKE5jgCBV0IOPXP8YKhmQblGrudsIbKizIpbINfTRmz6c2pWGgt4i9cLiedZ0kx\n\
nquiDHJBAgMBAAECggEABaFh98xKtEe0QbAXOGYPc3m5tIl5teNFmhC30NIt1fKj\n\
QFfTdUkpDuQjGarLE4DgLnb2EvtTEJL9XXEobRD8o8Mvnf/Oo4vVcjATzFTSprot\n\
udhpKbdrcBxADkeGCU8aecCw/WpQv4E7rwQuKYx4LrBgPbrDLu6ZFMZ8hEQ+R7Zn\n\
j0jWswOZEwM5xNHZ8RlwP4xsyFChvBR43lymHwDwQegd7ukbY0OcwXZ+2sxcKltr\n\
LBZKKFPzMugKnMbZtwm3TRIUTDGjB+IZGU7dPXgF8cK4KR4yDRZ5HKIZWbqxCPCP\n\
6TphI+Jz83OxpXU9R8rfPgUhnBgqwTdDpc5pGfmyiQKBgQD+I1TKDW5tF0fXWnza\n\
Xwoe0ULUM8TRXWBJmxfb1OkzmNLiq/jor6zxibXOas5EzzH5zKd8/HVVBlDfgRh4\n\
IwhfbXavIn7MMBOXg0TQjia4y9KIf2/HpdzsWaE2dpjM+wEvlOb2ea1C4/T1gSfy\n\
miI4kWIOz/iiWcPmiADk7hMcaQKBgQDkwgupZgFS6psRYtG0yu5S2kBJyWsGo02w\n\
kSwwZt6oEmagzF0d5JlyRss6uqbsaUzI1Ek17/m5ZEZLNoxi4abCw+kRHOoS9gWd\n\
KumNbli1dn4m3EVc1V+b1nWAsuC8ak5QIhRFumgNyQN7W+BS6TfLn4ONmKGz6uog\n\
njlfNdPMGQKBgFa5/ex6Cu4lnLmsQqFO/6gmp5S9GfSM1hgoWksF7JNUGtuJ7oaR\n\
tQY0hZusrTmkL5zcr2eiy/O5FQ5BAvW0lt3iADeiIP1ThswU2v4FFMfJns5AFwhd\n\
3Pe3WqG4dUq2eeAgA3Wnbm4+VtEVQ2myGe2OB5WgeWwGEClyzkNRz6nJAoGAPN4c\n\
+D/6DjP6es/OeMqeS1FjVb7QSX3eSCL4nRBiIlpzEEoQZMnUwoFvxfqwO6txEObb\n\
bAykZ930jkK/a/gaxSwXscP9zHnF2KH4bvdzhyU2P+TQV/k2bWLM9SejgL7Qg6Xt\n\
uvf0g+Z+lK5HrAf+HqIdAOoh7JuPHIq9PUY3StECgYEAoYP7hkj8TUygnkJcHxwM\n\
MwdqBsTdyr8O2ZjMTa/UMWlBi7kjg8KblzsRB4g/p1m2/wgyC0Yhv3VBf2le8/Rr\n\
OfNArBggDydmCgQ0I9+IxM+IQNP17/SU5s71daxeltJOxE+PSy/WsH5TMEnQ+CMr\n\
irbM4XSw2jtvX7qeUzcFY/E=\n\
-----END PRIVATE KEY-----\n"

let testkey_jwk = Jose.Jwk.of_priv_pem testkey_pem |> Result.get_ok

let expected_protected =
"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZuaWN4emg2V0VUUWxydmRj"
^ "aGt6LVUzZTNET1FaNGhlSktVNjNyZnFNcVEiLCJqd2siOnsiZSI6"
^ "IkFRQUIiLCJuIjoiNHhnWjNlUlBrd29Sdnk3cWVSVWJtTURlMFYt"
^ "eEg5ZVdMZHUwaWhlZUxscm1EMm1xV1hmUDlJZVNLQXBibjM0ZzhU"
^ "dUFTOWc1emhxOEVMUTNrbWpyLUtWODZHQU1nSTZWQWNHbHEzUXJ6"
^ "cFRDZl8zMEFiNy16YXdyZlJhRk9OYTFId0V6UFkxS0huR1ZreEpj"
^ "ODVnTmt3WUk5U1kyUkhYdHZsbjN6czV3SVROcmRvc3FFWGVhSWtW"
^ "WUJFaGJoTnU1NHBwM2t4bzZUdVdMaTllNnBYZVdldEV3bWxCd3RX"
^ "WmxQb2liMmozVHhMQmtzS1pmb3lGeWVrMzgwbUhnSkF1bVFfSTJm"
^ "amo5OF85N21rM2loT1k0QWdWZENEajF6X0dDb1prRzVScTduYkNH"
^ "eW9zeUtXeURYMDBacy1uTnFWaG9MZUl2WEM0bm5XZEpNWjZyb2d4"
^ "eVFRIiwia3R5IjoiUlNBIiwia2lkIjoiNm5pY3h6aDZXRVRRbHJ2"
^ "ZGNoa3otVTNlM0RPUVo0aGVKS1U2M3JmcU1xUSIsIng1dCI6Ijk4"
^ "WEZNbUZxRWtrb0RudTdHSjhjRFdGaTJJWSJ9LCJub25jZSI6Im5v" ^ "bmNlIn0"

let expected_payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
let expected_decoded_payload = {|{"Msg":"Hello JWS"}|}

let expected_signature =
"qv79C1SFoz_7EWt7WVIhg5kVBPbCK__Xa1kFtodtS7hD78KvRQrU"
^ "Cx4Usa5T6PrFKmutXumyArjW3RxwRa1ATKo7g8k-F0TeUELXsZic"
^ "fLs_5jHu8vj3g47_mlhjMg9oJ6YNDVdhg3Gm19ZXgm6W_WlnM8wC"
^ "2dUVVSVYLxP7Hk2b6urM_tXJ3HtWRHbmQtD8hxQaMCNzz99usPvA"
^ "I1SW5b-I1rK0dxIOZ205Kce4VtLgEVs9hz45b4t93-g0bP1clHCU"
^ "iNKf-vzOs_45H1EKkxEpGDO5fQkeNfoQxTsE03AnB9SZXiF-ApDW"
^ "QMz_4f3YJ9YhRVB1iXx9vgAMkqhTaQ"

let jws_suite, _ =
Junit_alcotest.run_and_report ~package:"jose" "JWS"
[
( "JWS",
[
Alcotest.test_case "fail to parse {}" `Quick (fun () ->
let jws_string = "{}" in
let jws_result = Jose.Jws.of_string jws_string in
check_result_string "failing to parse"
(Result.map (fun (jws : Jose.Jws.t) -> jws.payload) jws_result)
(Error
(`Msg "token didn't include header, payload or signature")));
Alcotest.test_case "parses a flattened json representation correctly"
`Quick (fun () ->
let jws_string =
Printf.sprintf
{|{"protected": "%s", "payload": "%s", "signature": "%s"}|}
expected_protected expected_payload expected_signature
in
let validated =
Jose.Jws.of_string jws_string
|> CCResult.flat_map (Jose.Jws.validate ~jwk:testkey_jwk)
in
check_result_string "Correct signature"
(Result.map (fun (jws : Jose.Jws.t) -> jws.signature) validated)
(Ok expected_signature);
check_result_string "Correct payload"
(Result.map (fun (jws : Jose.Jws.t) -> jws.payload) validated)
(Ok expected_decoded_payload));
Alcotest.test_case "Produces the same output" `Quick (fun () ->
let header =
Jose.Header.make_header
~extra:[ ("nonce", `String "nonce") ]
~jwk_header:true testkey_jwk
in
let jws =
Jose.Jws.sign ~header ~payload:expected_decoded_payload
testkey_jwk
in
let jws_string =
Result.map (Jose.Jws.to_string ~serialization:`Flattened) jws
in
let expected_jws_string =
Printf.sprintf
{|{"payload":"%s","protected":"%s","signature":"%s"}|}
expected_payload expected_protected expected_signature
in
check_result_string "matches original jws"
(Ok expected_jws_string) jws_string);
Alcotest.test_case "Roundtrip with ES384" `Quick (fun () ->
let priv_string =
{|{
"alg":"ES384",
"crv":"P-384",
"x":"rxz9m2FeRvvTE7_lSSSLve2c_ZkXxAasRId4jLqzIlsud19DtF52LOn91mQTRP9Y",
"y":"3_G1QTpidcws41ep1nLoc--6fHQjPXgu-oVuZhXB7VSihC3nLrF4irfhlB8cmTsa",
"d":"9eZFD1YrsUj5yQKj5u3Rju-Wx4JPL1TGXDWS1zE8AvYAmz_1Hp62R_oTtk1H7ARH",
"kty":"EC",
"kid":"W1X4opFJerkT7BFhQaf1-A5fRZTBJBmuJwerrUEcU4c"
}|}
in
let jwk =
Jose.Jwk.of_priv_json_string priv_string |> Result.get_ok
in
let jws = Jose.Jws.sign ~payload:"hello" jwk in
let jws_string = Result.map Jose.Jws.to_string jws in
let validated =
jws_string
|> CCResult.flat_map Jose.Jws.of_string
|> CCResult.flat_map (Jose.Jws.validate ~jwk)
in
let pub_jwk = Jose.Jwk.pub_of_priv jwk in
let _validated =
CCResult.flat_map (Jose.Jws.validate ~jwk:pub_jwk) jws
in

check_result_string "Correct payload" (Ok "hello")
(Result.map (fun (jws : Jose.Jws.t) -> jws.payload) validated));
] );
]

let jws_suite = jws_suite
29 changes: 0 additions & 29 deletions test/JWTTest.ml
Original file line number Diff line number Diff line change
Expand Up @@ -205,35 +205,6 @@ let jwt_suite, _ =
in
check_string "JWT was parsed correctly without kid" "RS256"
(jwt.header.alg |> Jose.Jwa.alg_to_string));
Alcotest.test_case "rfc7515 A.3" `Quick (fun () ->
let jwk_str =
{|{"kty":"EC",
"crv":"P-256",
"x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
"d":"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI"
}|}
in
let payload_str =
{|{"iss":"joe",
"exp":1300819380,
"http://example.com/is_root":true
}|}
in
let expected_str =
{|eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q|}
in
let jwk =
Jose.Jwk.of_priv_json_string jwk_str |> CCResult.get_exn
in
Jose.Jwt.unsafe_of_string expected_str
|> CCResult.flat_map (Jose.Jwt.validate_signature ~jwk)
|> CCResult.map (fun (jwt : Jose.Jwt.t) ->
Yojson.Safe.to_string jwt.payload)
|> check_result_string "Validated payload is correct"
(Ok
(payload_str |> Yojson.Safe.from_string
|> Yojson.Safe.to_string)));
Alcotest.test_case "Checks for expiration when calling `of_string`"
`Quick (fun () ->
let open Jose in
Expand Down
144 changes: 144 additions & 0 deletions test/RFC7515.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
(* These tests are based on rfc7515, https://tools.ietf.org/html/rfc7515 *)

let oct_priv_json =
{|{"kty":"oct",
"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
}|}

let rsa_priv_json =
{|{"kty":"RSA",
"n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ",
"e":"AQAB",
"d":"Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97IjlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYTCBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLhBOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ",
"p":"4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPGBY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc",
"q":"uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc",
"dp":"BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3QCLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0",
"dq":"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU",
"qi":"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U"
}|}

let ec_priv_json_es256 =
{|{"kty":"EC",
"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d",
"crv":"P-256",
"x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
"d":"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI"
}|}

let ec_priv_json_es512 =
{|{"kty":"EC",
"crv":"P-521",
"x":"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk",
"y":"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDly79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2",
"d":"AY5pb7A0UFiB3RELSD64fTLOSV_jazdF7fLYyuTw8lOfRhWg6Y6rUrPAxerEzgdRhajnu0ferB0d53vM9mE15j2C"
}|}

(* The real value has \r\n and I can't make that happen *)
let payload_to_same payload =
Yojson.Safe.from_string payload |> Yojson.Safe.to_string

let payload_str =
{|{"iss":"joe",
"exp":1300819380,
"http://example.com/is_root":true}|}
|> payload_to_same

open Helpers

let jws_tests =
( "RFC7515",
[
Alcotest.test_case "A.1" `Quick (fun () ->
let expected_str =
{|eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk|}
in
let jwk =
Jose.Jwk.of_priv_json_string oct_priv_json |> CCResult.get_exn
in
Jose.Jws.of_string expected_str
|> CCResult.flat_map (Jose.Jws.validate ~jwk)
|> CCResult.map (fun (jws : Jose.Jws.t) ->
payload_to_same jws.payload)
|> check_result_string "Validated payload is correct" (Ok payload_str));
Alcotest.test_case "A.2" `Quick (fun () ->
let expected_str =
{|eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw|}
in
let jwk =
Jose.Jwk.of_priv_json_string rsa_priv_json |> CCResult.get_exn
in
Jose.Jws.of_string expected_str
|> CCResult.flat_map (Jose.Jws.validate ~jwk)
|> CCResult.map (fun (jws : Jose.Jws.t) ->
payload_to_same jws.payload)
|> check_result_string "Validated payload is correct" (Ok payload_str));
Alcotest.test_case "A.3" `Quick (fun () ->
let expected_str =
{|eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q|}
in
let jwk =
Jose.Jwk.of_priv_json_string ec_priv_json_es256 |> CCResult.get_exn
in
Jose.Jws.of_string expected_str
|> CCResult.flat_map (Jose.Jws.validate ~jwk)
|> CCResult.map (fun (jws : Jose.Jws.t) ->
payload_to_same jws.payload)
|> check_result_string "Validated payload is correct" (Ok payload_str));
Alcotest.test_case "A.4" `Quick (fun () ->
let expected_str =
{|eyJhbGciOiJFUzUxMiJ9.UGF5bG9hZA.AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn|}
in
let jwk =
Jose.Jwk.of_priv_json_string ec_priv_json_es512 |> CCResult.get_exn
in
Jose.Jws.of_string expected_str
|> CCResult.flat_map (Jose.Jws.validate ~jwk)
|> CCResult.map (fun (jws : Jose.Jws.t) -> jws.payload)
|> check_result_string "Validated payload is correct" (Ok "Payload"));
(* We currently do not support `none` *)
Alcotest.test_case "A.5" `Quick (fun () ->
let expected_str =
{|eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.|}
in
let jwk =
Jose.Jwk.of_priv_json_string ec_priv_json_es256 |> CCResult.get_exn
in
Jose.Jws.of_string expected_str
|> CCResult.flat_map (Jose.Jws.validate ~jwk)
|> CCResult.map (fun (jws : Jose.Jws.t) ->
payload_to_same jws.payload)
|> check_result_string "Validated payload is correct"
(Error (`Msg "alg not supported for signing")));
(* A.6 uses multiple signatures which we don't support yet *)
Alcotest.test_case "A.7" `Quick (fun () ->
let header =
Jose.Header.
{
alg = `ES256;
jwk = None;
kid = None;
x5t = None;
x5t256 = None;
typ = None;
cty = None;
enc = None;
extra = None;
}
in
let jwk =
Jose.Jwk.of_priv_json_string ec_priv_json_es256 |> CCResult.get_exn
in
Jose.Jws.sign ~header ~payload:payload_str jwk
|> CCResult.map (Jose.Jws.to_string ~serialization:`Flattened)
|> check_result_string "Validated payload is correct"
(* We currently don't have a notion of Unprotected Headers Values so this is not exactly correct*)
(Ok
{|{"payload":"eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ","protected":"eyJhbGciOiJFUzI1NiJ9","signature":"4XSeJsUDLhZisF7Vhx7iYI_q9x7a3Mk8-wsj-jpf39DRe-bDEt-w7UlN1xwfpiouuoGssgJKAT9GwEeORjzuIg"}|}));
] )

(* Begin tests *)
let rfc_suite, _ =
Junit_alcotest.run_and_report ~package:"jose" "RFC7515" [ jws_tests ]

let suite = rfc_suite
Loading

0 comments on commit a0be1e0

Please sign in to comment.