From 8f7aadcfff2a5c790119d34b3c475c696abf7a0d Mon Sep 17 00:00:00 2001 From: Ulrik Strid Date: Mon, 13 Feb 2023 15:30:52 +0100 Subject: [PATCH] Cleanup and add tests --- jose/Jwk.ml | 11 +++- test/JWSTest.ml | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ test/JWTTest.ml | 29 ---------- test/RFC7515.ml | 144 ++++++++++++++++++++++++++++++++++++++++++++++ test/test.ml | 2 + 5 files changed, 303 insertions(+), 32 deletions(-) create mode 100644 test/JWSTest.ml create mode 100644 test/RFC7515.ml diff --git a/jose/Jwk.ml b/jose/Jwk.ml index 827ae01..e77e310 100644 --- a/jose/Jwk.ml +++ b/jose/Jwk.ml @@ -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 { @@ -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 @@ -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 diff --git a/test/JWSTest.ml b/test/JWSTest.ml new file mode 100644 index 0000000..e3761b2 --- /dev/null +++ b/test/JWSTest.ml @@ -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 diff --git a/test/JWTTest.ml b/test/JWTTest.ml index d4d1fca..1297200 100644 --- a/test/JWTTest.ml +++ b/test/JWTTest.ml @@ -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 diff --git a/test/RFC7515.ml b/test/RFC7515.ml new file mode 100644 index 0000000..602a134 --- /dev/null +++ b/test/RFC7515.ml @@ -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 diff --git a/test/test.ml b/test/test.ml index 8a83878..b38829c 100644 --- a/test/test.ml +++ b/test/test.ml @@ -5,8 +5,10 @@ let () = [ JWKsTest.jwks_suite; JWKTest.jwk_suite; + JWSTest.jws_suite; JWTTest.jwt_suite; JWETest.jwe_suite; + RFC7515.suite; RFC7520.suite; RFC7638.suite; ]