···1919let b64_decode str =
2020 match Base64.decode ~pad:false ~alphabet:Base64.uri_safe_alphabet str with
2121 | Ok s ->
2222- Ok s
2222+ s
2323 | Error (`Msg e) ->
2424- Error e
2424+ failwith e
25252626let extract_signature_components signature =
2727 if Bytes.length signature <> 64 then failwith "expected 64 byte jwt signature"
···3030 let s = Bytes.sub signature 32 32 in
3131 (r, s)
32323333-let sign_jwt payload signing_key =
3333+let sign_jwt payload ?(typ = "JWT") signing_key =
3434 let _, (module Curve : Kleidos.CURVE) = signing_key in
3535 let alg =
3636 match Curve.name with
···5151 failwith "invalid curve"
5252 in
5353 let header_json =
5454- `Assoc [("alg", `String alg); ("crv", `String crv); ("typ", `String "JWT")]
5454+ `Assoc [("alg", `String alg); ("crv", `String crv); ("typ", `String typ)]
5555 in
5656 let encoded_header = header_json |> Yojson.Safe.to_string |> b64_encode in
5757 let encoded_payload = payload |> Yojson.Safe.to_string |> b64_encode in
···6565let decode_jwt jwt =
6666 match String.split_on_char '.' jwt with
6767 | [header_b64; payload_b64; _] -> (
6868- match (b64_decode header_b64, b64_decode payload_b64) with
6969- | Ok header_str, Ok payload_str -> (
7070- try
7171- let header = Yojson.Safe.from_string header_str in
7272- let payload = Yojson.Safe.from_string payload_str in
7373- Ok (header, payload)
7474- with _ -> Error "invalid json in jwt" )
7575- | Error e, _ | _, Error e ->
7676- Error e )
6868+ try
6969+ let header = Yojson.Safe.from_string (b64_decode header_b64) in
7070+ let payload = Yojson.Safe.from_string (b64_decode payload_b64) in
7171+ Ok (header, payload)
7272+ with _ -> Error "invalid jwt" )
7773 | _ ->
7874 Error "invalid jwt format"
79758076let verify_jwt jwt pubkey =
8177 match String.split_on_char '.' jwt with
8282- | [header_b64; payload_b64; signature_b64] -> (
8383- match b64_decode signature_b64 with
8484- | Error e ->
8585- Error e
8686- | Ok signature_str ->
8787- let signature = Bytes.of_string signature_str in
8888- let signing_input = header_b64 ^ "." ^ payload_b64 in
8989- let verified =
9090- Kleidos.verify ~pubkey ~msg:(Bytes.of_string signing_input) ~signature
9191- in
9292- if verified then decode_jwt jwt
9393- else Error "jwt signature verification failed" )
7878+ | [header_b64; payload_b64; signature_b64] ->
7979+ let signature = Bytes.of_string (b64_decode signature_b64) in
8080+ let signing_input = header_b64 ^ "." ^ payload_b64 in
8181+ let verified =
8282+ Kleidos.verify ~pubkey ~msg:(Bytes.of_string signing_input) ~signature
8383+ in
8484+ if verified then decode_jwt jwt
8585+ else Error "jwt signature verification failed"
9486 | _ ->
9587 Error "invalid jwt format"
9688···126118 let exp = now_s + Defaults.service_token_exp in
127119 let payload = service_jwt_to_yojson {iss= did; aud; lxm; exp} in
128120 sign_jwt payload signing_key
121121+122122+let extract_claim claims key =
123123+ try
124124+ let open Yojson.Safe.Util in
125125+ let rec find_nested json keys =
126126+ match keys with
127127+ | [] ->
128128+ Some json
129129+ | k :: rest ->
130130+ find_nested (json |> member k) rest
131131+ in
132132+ let keys = String.split_on_char '.' key in
133133+ find_nested claims keys
134134+ with _ -> None
+9-17
pegasus/lib/oauth/dpop.ml
···2929 Bytes.set_int64_be data 0 counter ;
3030 Digestif.SHA256.(
3131 hmac_bytes ~key:(Bytes.to_string secret) data
3232- |> to_raw_string
3333- |> Base64.encode_exn ~pad:false )
3232+ |> to_raw_string |> Jwt.b64_encode )
34333534let create_nonce_state secret =
3635 let counter =
···7978 ?port:(Uri.port uri) ~path:(Uri.path uri) ()
8079 |> Uri.to_string
81808282-let b64url_decode s =
8383- Base64.decode_exn ~alphabet:Base64.uri_safe_alphabet ~pad:false s
8484-8581let compute_jwk_thumbprint jwk =
8682 let open Yojson.Safe.Util in
8783 let crv = jwk |> member "crv" |> to_string in
···9288 (* keys must be in lexicographic order *)
9389 Printf.sprintf {|{"crv":"%s","kty":"%s","x":"%s","y":"%s"}|} crv kty x y
9490 in
9595- Digestif.SHA256.(
9696- digest_string tp |> to_raw_string |> Base64.encode_exn ~pad:false )
9191+ Digestif.SHA256.(digest_string tp |> to_raw_string |> Jwt.b64_encode)
97929893let verify_signature jwt jwk =
9994 let open Yojson.Safe.Util in
···10196 match parts with
10297 | [header_b64; payload_b64; sig_b64] ->
10398 let signing_input = header_b64 ^ "." ^ payload_b64 in
104104- let msg =
105105- Digestif.SHA256.(digest_string signing_input |> to_raw_string)
106106- |> Bytes.of_string
107107- in
9999+ let msg = Bytes.of_string signing_input in
108100 let x =
109109- jwk |> member "x" |> to_string |> b64url_decode |> Bytes.of_string
101101+ jwk |> member "x" |> to_string |> Jwt.b64_decode |> Bytes.of_string
110102 in
111103 let y =
112112- jwk |> member "y" |> to_string |> b64url_decode |> Bytes.of_string
104104+ jwk |> member "y" |> to_string |> Jwt.b64_decode |> Bytes.of_string
113105 in
114106 let crv = jwk |> member "crv" |> to_string in
115107 let pubkey = Bytes.cat (Bytes.of_string "\x04") (Bytes.cat x y) in
···123115 | _ ->
124116 failwith "unsupported algorithm" )
125117 in
126126- let sig_bytes = b64url_decode sig_b64 |> Bytes.of_string in
118118+ let sig_bytes = Jwt.b64_decode sig_b64 |> Bytes.of_string in
127119 let r = Bytes.sub sig_bytes 0 32 in
128120 let s = Bytes.sub sig_bytes 32 32 in
129121 let signature = Bytes.cat r s in
···139131 let open Yojson.Safe.Util in
140132 match String.split_on_char '.' jwt with
141133 | [header_b64; payload_b64; _] -> (
142142- let header = Yojson.Safe.from_string (b64url_decode header_b64) in
143143- let payload = Yojson.Safe.from_string (b64url_decode payload_b64) in
134134+ let header = Yojson.Safe.from_string (Jwt.b64_decode header_b64) in
135135+ let payload = Yojson.Safe.from_string (Jwt.b64_decode payload_b64) in
144136 let typ = header |> member "typ" |> to_string in
145137 if typ <> "dpop+jwt" then Lwt.return_error "invalid typ in dpop proof"
146138 else
···202194 let expected_ath =
203195 Digestif.SHA256.(
204196 digest_string token |> to_raw_string
205205- |> Base64.encode_exn ~pad:false )
197197+ |> Jwt.b64_encode )
206198 in
207199 if Some expected_ath <> ath_claim then
208200 Lwt.return_error "ath mismatch"