|
@@ -199,12 +199,25 @@ module Header = struct
|
|
|> Assrt.equals_string __LOC__ "a";
|
|
|> Assrt.equals_string __LOC__ "a";
|
|
assert true
|
|
assert true
|
|
|
|
|
|
|
|
+ let tc_sig_encode () =
|
|
|
|
+ [ "k1","v1";
|
|
|
|
+ "k2","v2"; ] |> Http.Signature.encode
|
|
|
|
+ |> check string __LOC__ {|k1="v1",k2="v2"|};
|
|
|
|
+ `GET
|
|
|
|
+ |> Cohttp.Code.string_of_method
|
|
|
|
+ |> Astring.String.map Astring.Char.Ascii.lowercase
|
|
|
|
+ |> check string __LOC__ "get"
|
|
|
|
+
|
|
let tc_signature () =
|
|
let tc_signature () =
|
|
Logr.info (fun m -> m "http_test.test_signature");
|
|
Logr.info (fun m -> m "http_test.test_signature");
|
|
let si = {|keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date",signature="qdx+H7PHHDZgy4y/Ahn9Tny9V3GP6YgBPyUXMmoxWtLbHpUnXS2mg2+SbrQDMCJypxBLSPQR2aAjn7ndmw2iicw3HMbe8VfEdKFYRqzic+efkb3nndiv/x1xSHDJWeSWkx3ButlYSuBskLu6kd9Fswtemr3lgdDEmn04swr2Os0="|} in
|
|
let si = {|keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date",signature="qdx+H7PHHDZgy4y/Ahn9Tny9V3GP6YgBPyUXMmoxWtLbHpUnXS2mg2+SbrQDMCJypxBLSPQR2aAjn7ndmw2iicw3HMbe8VfEdKFYRqzic+efkb3nndiv/x1xSHDJWeSWkx3ButlYSuBskLu6kd9Fswtemr3lgdDEmn04swr2Os0="|} in
|
|
- let si = Http.Signature.decode si |> Result.get_ok in
|
|
|
|
- si |> List.length |> Assrt.equals_int __LOC__ 4;
|
|
|
|
- assert true
|
|
|
|
|
|
+ let si' = si
|
|
|
|
+ |> Http.Signature.decode
|
|
|
|
+ |> Result.get_ok in
|
|
|
|
+ si' |> List.length |> Assrt.equals_int __LOC__ 4;
|
|
|
|
+ si'
|
|
|
|
+ |> Tyre.eval Http.Signature.P.list_auth_param
|
|
|
|
+ |> check string __LOC__ si
|
|
|
|
|
|
let priv_key_cavage =
|
|
let priv_key_cavage =
|
|
{|-----BEGIN RSA PRIVATE KEY-----
|
|
{|-----BEGIN RSA PRIVATE KEY-----
|
|
@@ -238,95 +251,38 @@ oYi+1hqp1fIekaxsyQIDAQAB
|
|
|> X509.Public_key.decode_pem |> Result.get_ok
|
|
|> X509.Public_key.decode_pem |> Result.get_ok
|
|
|
|
|
|
let tc_sign2 () =
|
|
let tc_sign2 () =
|
|
- (*
|
|
|
|
- which interface?
|
|
|
|
-
|
|
|
|
- A: - (request-target) method + uri
|
|
|
|
- - signing function: string -> string
|
|
|
|
- - list of headers' names to sign: string list
|
|
|
|
- - all headers list (or cohttp)
|
|
|
|
- return: header list incl. signature header
|
|
|
|
-
|
|
|
|
- B: - (request-target) method + uri
|
|
|
|
- - signing function: string -> string
|
|
|
|
- - to sign headers list (or cohttp)
|
|
|
|
- return: header list incl. signature header
|
|
|
|
-
|
|
|
|
- *)
|
|
|
|
- (** build the string to sign *)
|
|
|
|
- let to_sign_string
|
|
|
|
- (meth : Cohttp.Code.meth)
|
|
|
|
- (targ : Uri.t)
|
|
|
|
- (hdrs : (string * string) list) =
|
|
|
|
- let n,s = [],[] in
|
|
|
|
- let n,s = match hdrs |> List.assoc_opt "Digest" with
|
|
|
|
- | None -> n,s
|
|
|
|
- | Some d -> "digest" :: n,("digest",d) :: s in
|
|
|
|
- let n = "(request-target)" :: "host" :: "date" :: n in
|
|
|
|
- let s = ("(request-target)",Printf.sprintf "%s %s"
|
|
|
|
- (meth |> Cohttp.Code.string_of_method |> Astring.String.map Astring.Char.Ascii.lowercase)
|
|
|
|
- (targ |> Uri.path_and_query))
|
|
|
|
- :: ("host",targ |> Uri.host |> Option.get)
|
|
|
|
- :: ("date",hdrs |> List.assoc "Date")
|
|
|
|
- :: s in
|
|
|
|
- n,s
|
|
|
|
- in
|
|
|
|
- let add_signature
|
|
|
|
- (priv : X509.Private_key.t)
|
|
|
|
- (meth : Cohttp.Code.meth)
|
|
|
|
- (targ : Uri.t)
|
|
|
|
- (hdrs : (string * string) list) =
|
|
|
|
- assert (hdrs |> List.assoc_opt "Date" |> Option.is_some);
|
|
|
|
- assert (hdrs |> List.assoc "Host" |> Astring.String.equal (targ |> Uri.host_with_default ~default:""));
|
|
|
|
- let n,s = to_sign_string meth targ hdrs in
|
|
|
|
- let s = s |> Cohttp.Header.of_list |> Cohttp.Header.to_frames |> Astring.String.concat ~sep:"\n" in
|
|
|
|
- let n = n |> Astring.String.concat ~sep:" " in
|
|
|
|
- (* build the signature header value *)
|
|
|
|
- match `Message (s |> Cstruct.of_string) |> X509.Private_key.sign `SHA256 ~scheme:`RSA_PKCS1 priv with
|
|
|
|
- | Error _ as e -> e
|
|
|
|
- | Ok s ->
|
|
|
|
- let v = [
|
|
|
|
- "signature", s |> Cstruct.to_string |> Base64.encode_string;
|
|
|
|
- "headers" ,n;
|
|
|
|
- "algorithm","rsa-sha256";
|
|
|
|
- ]
|
|
|
|
- |> List.fold_left (fun init (k,v) -> Printf.sprintf {|%s="%s"|} k v :: init) []
|
|
|
|
- |> Astring.String.concat ~sep:"," in
|
|
|
|
- (* add it to the header list *)
|
|
|
|
- Ok ( ("Signature",v) :: hdrs ) in
|
|
|
|
`GET |> Cohttp.Code.string_of_method |> check string __LOC__ "GET";
|
|
`GET |> Cohttp.Code.string_of_method |> check string __LOC__ "GET";
|
|
- let n,s = ["Date","today";
|
|
|
|
- "Digest","SHA256=0815"]
|
|
|
|
- |> to_sign_string
|
|
|
|
|
|
+ let n,s = ["date","today";
|
|
|
|
+ "digest","SHA256=0815"]
|
|
|
|
+ |> Http.Signature.to_sign_string2
|
|
`GET
|
|
`GET
|
|
- ("https://example.com/uhu?foo=bar#baz" |> Uri.of_string)
|
|
|
|
- in
|
|
|
|
|
|
+ ("https://example.com/uhu?foo=bar#baz" |> Uri.of_string) in
|
|
let s = s |> Cohttp.Header.of_list |> Cohttp.Header.to_frames |> Astring.String.concat ~sep:"\n" in
|
|
let s = s |> Cohttp.Header.of_list |> Cohttp.Header.to_frames |> Astring.String.concat ~sep:"\n" in
|
|
let n = n |> Astring.String.concat ~sep:" " in
|
|
let n = n |> Astring.String.concat ~sep:" " in
|
|
n |> check string __LOC__ "(request-target) host date digest";
|
|
n |> check string __LOC__ "(request-target) host date digest";
|
|
s |> check string __LOC__ "(request-target): get /uhu?foo=bar\nhost: example.com\ndate: today\ndigest: SHA256=0815";
|
|
s |> check string __LOC__ "(request-target): get /uhu?foo=bar\nhost: example.com\ndate: today\ndigest: SHA256=0815";
|
|
- ["Host","example.com";
|
|
|
|
- "Date","today";
|
|
|
|
- "Digest","SHA256=0815"]
|
|
|
|
- |> add_signature
|
|
|
|
|
|
+ ["host","example.com";
|
|
|
|
+ "date","today";
|
|
|
|
+ "digest","SHA256=0815"]
|
|
|
|
+ |> Http.Signature.add
|
|
priv_key_cavage
|
|
priv_key_cavage
|
|
`GET
|
|
`GET
|
|
("https://example.com/uhu?foo=bar#baz" |> Uri.of_string)
|
|
("https://example.com/uhu?foo=bar#baz" |> Uri.of_string)
|
|
|> Result.get_ok
|
|
|> Result.get_ok
|
|
|> Cohttp.Header.of_list
|
|
|> Cohttp.Header.of_list
|
|
|> Cohttp.Header.to_frames |> Astring.String.concat ~sep:"\n"
|
|
|> Cohttp.Header.to_frames |> Astring.String.concat ~sep:"\n"
|
|
- |> check string __LOC__ {|Signature: algorithm="rsa-sha256",headers="(request-target) host date digest",signature="AFq6XChsi63zuCVVzeVigx7BV/HzHnsg304i9uqJ44t2QufQ4WvYS1jDh2B539B3VyBQiuXoiNrSssMoShVORmZzA1y4dnnFlYncFdQRsRDRA//E2YB39ECSby0Fl6pBK+Ws/090RWcxFxTBFsD0H9JQuVASbBCDxy2lhHTFugg="
|
|
|
|
-Host: example.com
|
|
|
|
-Date: today
|
|
|
|
-Digest: SHA256=0815|}
|
|
|
|
|
|
+ |> check string __LOC__ {|host: example.com
|
|
|
|
+date: today
|
|
|
|
+digest: SHA256=0815
|
|
|
|
+signature: algorithm="rsa-sha256",headers="(request-target) host date digest",signature="AFq6XChsi63zuCVVzeVigx7BV/HzHnsg304i9uqJ44t2QufQ4WvYS1jDh2B539B3VyBQiuXoiNrSssMoShVORmZzA1y4dnnFlYncFdQRsRDRA//E2YB39ECSby0Fl6pBK+Ws/090RWcxFxTBFsD0H9JQuVASbBCDxy2lhHTFugg="|}
|
|
|
|
|
|
let tc_to_sign_string_basic () =
|
|
let tc_to_sign_string_basic () =
|
|
let open Cohttp in
|
|
let open Cohttp in
|
|
let uri = Uri.of_string "/foo?param=value&pet=dog" in
|
|
let uri = Uri.of_string "/foo?param=value&pet=dog" in
|
|
- let request = Some ("post",uri) in
|
|
|
|
|
|
+ let request = Some (`POST,uri) in
|
|
[
|
|
[
|
|
- ("host", "example.com");
|
|
|
|
- ("date", "Sun, 05 Jan 2014 21:31:40 GMT");
|
|
|
|
|
|
+ "host", "example.com" ;
|
|
|
|
+ "date", "Sun, 05 Jan 2014 21:31:40 GMT" ;
|
|
]
|
|
]
|
|
|> Header.of_list
|
|
|> Header.of_list
|
|
|> Http.Signature.to_sign_string ~request
|
|
|> Http.Signature.to_sign_string ~request
|
|
@@ -339,7 +295,6 @@ date: Sun, 05 Jan 2014 21:31:40 GMT|};
|
|
(*
|
|
(*
|
|
* https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#appendix-C.2
|
|
* https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#appendix-C.2
|
|
*)
|
|
*)
|
|
-
|
|
|
|
let tc_sign_basic () =
|
|
let tc_sign_basic () =
|
|
Logr.info (fun m -> m "http_test.test_sign_basic");
|
|
Logr.info (fun m -> m "http_test.test_sign_basic");
|
|
let pk = priv_key_cavage in
|
|
let pk = priv_key_cavage in
|
|
@@ -350,7 +305,7 @@ date: Sun, 05 Jan 2014 21:31:40 GMT|};
|
|
("host", "example.com");
|
|
("host", "example.com");
|
|
("date", "Sun, 05 Jan 2014 21:31:40 GMT");
|
|
("date", "Sun, 05 Jan 2014 21:31:40 GMT");
|
|
] |> Header.of_list in
|
|
] |> Header.of_list in
|
|
- let request = Some("post",uri) in
|
|
|
|
|
|
+ let request = Some(`POST,uri) in
|
|
let s = h |> Http.Signature.to_sign_string ~request in
|
|
let s = h |> Http.Signature.to_sign_string ~request in
|
|
s |> Assrt.equals_string __LOC__
|
|
s |> Assrt.equals_string __LOC__
|
|
"(request-target): post /foo?param=value&pet=dog\n\
|
|
"(request-target): post /foo?param=value&pet=dog\n\
|
|
@@ -505,7 +460,7 @@ date: Sun, 05 Jan 2014 21:31:40 GMT|};
|
|
let tc_verify_basic () =
|
|
let tc_verify_basic () =
|
|
Logr.info (fun m -> m "http_test.test_verify_basic");
|
|
Logr.info (fun m -> m "http_test.test_verify_basic");
|
|
let pub = pub_key_cavage in
|
|
let pub = pub_key_cavage in
|
|
- let request = Some("post", Uri.of_string "/foo?param=value&pet=dog") in
|
|
|
|
|
|
+ let request = Some(`POST, Uri.of_string "/foo?param=value&pet=dog") in
|
|
let h = [
|
|
let h = [
|
|
("some", "bogus");
|
|
("some", "bogus");
|
|
("date", {|Sun, 05 Jan 2014 21:31:40 GMT|});
|
|
("date", {|Sun, 05 Jan 2014 21:31:40 GMT|});
|
|
@@ -574,7 +529,7 @@ host: dev.seppo.social
|
|
date: Mon, 16 Sep 2024 12:26:45 GMT
|
|
date: Mon, 16 Sep 2024 12:26:45 GMT
|
|
digest: SHA-256=bcLAcfJg/048pSOMeA29j/PqW2iQJw96mT+egmjF+Zk='
|
|
digest: SHA-256=bcLAcfJg/048pSOMeA29j/PqW2iQJw96mT+egmjF+Zk='
|
|
*)
|
|
*)
|
|
- let request = Some ("post","https://dev.seppo.social/2024-03-19/seppo.cgi/activitypub/inbox.jsa" |> Uri.of_string) in
|
|
|
|
|
|
+ let request = Some (`POST,"https://dev.seppo.social/2024-03-19/seppo.cgi/activitypub/inbox.jsa" |> Uri.of_string) in
|
|
let h = [
|
|
let h = [
|
|
("host", {|dev.seppo.social|});
|
|
("host", {|dev.seppo.social|});
|
|
("date", {|Mon, 16 Sep 2024 12:26:45 GMT|});
|
|
("date", {|Mon, 16 Sep 2024 12:26:45 GMT|});
|
|
@@ -628,7 +583,7 @@ digest: SHA-256=bcLAcfJg/048pSOMeA29j/PqW2iQJw96mT+egmjF+Zk='
|
|
("signature", {|keyId="https://gotosocial.dev.seppo.social/users/demo/main-key",algorithm="hs2019",headers="(request-target) host date digest",signature="MG9tIV9rWJHDFKEFGsjakYoBtPjZbyk/ddTn6Xr2xHkmTVZDmkJmGcD4yDfWfQ4m8BYS+jd4lnb8O5fdm/pFwpFDGU70IDLsg6INGxZJQKuWbQB7dFEBJt22h8GcjOIlXvw4cKsgc3KvplIjTrFlnYiQQVvcSy+uQRXJTJTm2Y6vxOQzFvSJa0S8lXz5+x/CqpqXJtj1cSztEHZEFdBla2M30smV1uJvQcfa+lIRPwXdwtL0COsg8J00hAYBoFXPo+4N/jytArkYOFz6MasUrRODURuAE2fR6JI2aAerBy0WFE17TyWuXjWlnYt6t9aO5Wzo/qc/3DgMWHQr8NZGVg=="|});
|
|
("signature", {|keyId="https://gotosocial.dev.seppo.social/users/demo/main-key",algorithm="hs2019",headers="(request-target) host date digest",signature="MG9tIV9rWJHDFKEFGsjakYoBtPjZbyk/ddTn6Xr2xHkmTVZDmkJmGcD4yDfWfQ4m8BYS+jd4lnb8O5fdm/pFwpFDGU70IDLsg6INGxZJQKuWbQB7dFEBJt22h8GcjOIlXvw4cKsgc3KvplIjTrFlnYiQQVvcSy+uQRXJTJTm2Y6vxOQzFvSJa0S8lXz5+x/CqpqXJtj1cSztEHZEFdBla2M30smV1uJvQcfa+lIRPwXdwtL0COsg8J00hAYBoFXPo+4N/jytArkYOFz6MasUrRODURuAE2fR6JI2aAerBy0WFE17TyWuXjWlnYt6t9aO5Wzo/qc/3DgMWHQr8NZGVg=="|});
|
|
("digest", {|SHA-256=bcLAcfJg/048pSOMeA29j/PqW2iQJw96mT+egmjF+Zk=|});
|
|
("digest", {|SHA-256=bcLAcfJg/048pSOMeA29j/PqW2iQJw96mT+egmjF+Zk=|});
|
|
] |> Cohttp.Header.of_list in
|
|
] |> Cohttp.Header.of_list in
|
|
- let request = Some ("post","" |> Uri.of_string) in
|
|
|
|
|
|
+ let request = Some (`POST,"" |> Uri.of_string) in
|
|
h |> Http.Signature.to_sign_string ~request
|
|
h |> Http.Signature.to_sign_string ~request
|
|
|> Assrt.equals_string __LOC__ {|(request-target): post /
|
|
|> Assrt.equals_string __LOC__ {|(request-target): post /
|
|
host: dev.seppo.social
|
|
host: dev.seppo.social
|
|
@@ -787,6 +742,7 @@ let () =
|
|
"tc_to_string", `Quick, Cookie.tc_to_string;
|
|
"tc_to_string", `Quick, Cookie.tc_to_string;
|
|
"tc_of_string", `Quick, Cookie.tc_of_string;
|
|
"tc_of_string", `Quick, Cookie.tc_of_string;
|
|
"tc_headers", `Quick, Header.tc_headers;
|
|
"tc_headers", `Quick, Header.tc_headers;
|
|
|
|
+ "tc_sig_encode", `Quick, Header.tc_sig_encode;
|
|
"tc_signature", `Quick, Header.tc_signature;
|
|
"tc_signature", `Quick, Header.tc_signature;
|
|
"tc_sign2", `Quick, Header.tc_sign2;
|
|
"tc_sign2", `Quick, Header.tc_sign2;
|
|
"tc_to_sign_string_basic", `Quick, Header.tc_to_sign_string_basic;
|
|
"tc_to_sign_string_basic", `Quick, Header.tc_to_sign_string_basic;
|