Software / code / prosody
Annotate
util/paseto.lua @ 12745:2cbf0e9314ff
mod_smacks: Change boolean attribute from '1' to 'true' for compatibility
Conversations 2.10.10 and earlier expect this to be literally 'true' and don't
recognise '1'. This leads to it not attempting resumption with Prosody at all
since this change was introduced in 36ba170c4fd0.
Thanks to Zash for noticing, debugging and diagnosing this issue.
This issue is fixed in Conversations commit 052c58f3 (unreleased at the time
of writing).
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Fri, 07 Oct 2022 11:35:56 +0100 |
| parent | 12716:0b68b021ce46 |
| child | 12838:2e71b76ac299 |
| rev | line source |
|---|---|
|
12694
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
1 local crypto = require "util.crypto"; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
2 local json = require "util.json"; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
3 local base64_encode = require "util.encodings".base64.encode; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
4 local base64_decode = require "util.encodings".base64.decode; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
5 local secure_equals = require "util.hashes".equals; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
6 local bit = require "util.bitcompat"; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
7 local s_pack = require "util.struct".pack; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
8 |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
9 local s_gsub = string.gsub; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
10 |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
11 local v4_public = {}; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
12 |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
13 local b64url_rep = { ["+"] = "-", ["/"] = "_", ["="] = "", ["-"] = "+", ["_"] = "/" }; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
14 local function b64url(data) |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
15 return (s_gsub(base64_encode(data), "[+/=]", b64url_rep)); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
16 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
17 local function unb64url(data) |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
18 return base64_decode(s_gsub(data, "[-_]", b64url_rep).."=="); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
19 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
20 |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
21 local function le64(n) |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
22 return s_pack("<I8", bit.band(n, 0x7F)); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
23 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
24 |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
25 local function pae(parts) |
|
12716
0b68b021ce46
util.paseto: Do strict type check in pae() function
Kim Alvefur <zash@zash.se>
parents:
12713
diff
changeset
|
26 if type(parts) ~= "table" then |
|
0b68b021ce46
util.paseto: Do strict type check in pae() function
Kim Alvefur <zash@zash.se>
parents:
12713
diff
changeset
|
27 error("bad argument #1 to 'pae' (table expected, got "..type(parts)..")"); |
|
0b68b021ce46
util.paseto: Do strict type check in pae() function
Kim Alvefur <zash@zash.se>
parents:
12713
diff
changeset
|
28 end |
|
12694
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
29 local o = { le64(#parts) }; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
30 for _, part in ipairs(parts) do |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
31 table.insert(o, le64(#part)..part); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
32 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
33 return table.concat(o); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
34 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
35 |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
36 function v4_public.sign(m, sk, f, i) |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
37 if type(m) ~= "table" then |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
38 return nil, "PASETO payloads must be a table"; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
39 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
40 m = json.encode(m); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
41 local h = "v4.public."; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
42 local m2 = pae({ h, m, f or "", i or "" }); |
|
12713
52eead170bb8
util.paseto: Drop custom wrappers around key objects
Matthew Wild <mwild1@gmail.com>
parents:
12711
diff
changeset
|
43 local sig = crypto.ed25519_sign(sk, m2); |
|
12694
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
44 if not f or f == "" then |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
45 return h..b64url(m..sig); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
46 else |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
47 return h..b64url(m..sig).."."..b64url(f); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
48 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
49 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
50 |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
51 function v4_public.verify(tok, pk, expected_f, i) |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
52 local h, sm, f = tok:match("^(v4%.public%.)([^%.]+)%.?(.*)$"); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
53 if not h then |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
54 return nil, "invalid-token-format"; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
55 end |
|
12709
b3f7c77c1f08
util.paseto: Fix to decode footer before comparison
Matthew Wild <mwild1@gmail.com>
parents:
12694
diff
changeset
|
56 f = f and unb64url(f) or nil; |
|
12694
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
57 if expected_f then |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
58 if not f or not secure_equals(expected_f, f) then |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
59 return nil, "invalid-footer"; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
60 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
61 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
62 local raw_sm = unb64url(sm); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
63 if not raw_sm or #raw_sm <= 64 then |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
64 return nil, "invalid-token-format"; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
65 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
66 local s, m = raw_sm:sub(-64), raw_sm:sub(1, -65); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
67 local m2 = pae({ h, m, f or "", i or "" }); |
|
12713
52eead170bb8
util.paseto: Drop custom wrappers around key objects
Matthew Wild <mwild1@gmail.com>
parents:
12711
diff
changeset
|
68 local ok = crypto.ed25519_verify(pk, m2, s); |
|
12694
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
69 if not ok then |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
70 return nil, "invalid-token"; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
71 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
72 local payload, err = json.decode(m); |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
73 if err ~= nil or type(payload) ~= "table" then |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
74 return nil, "json-decode-error"; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
75 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
76 return payload; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
77 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
78 |
|
12713
52eead170bb8
util.paseto: Drop custom wrappers around key objects
Matthew Wild <mwild1@gmail.com>
parents:
12711
diff
changeset
|
79 v4_public.import_private_key = crypto.import_private_pem; |
|
52eead170bb8
util.paseto: Drop custom wrappers around key objects
Matthew Wild <mwild1@gmail.com>
parents:
12711
diff
changeset
|
80 v4_public.import_public_key = crypto.import_public_pem; |
|
12694
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
81 function v4_public.new_keypair() |
|
12713
52eead170bb8
util.paseto: Drop custom wrappers around key objects
Matthew Wild <mwild1@gmail.com>
parents:
12711
diff
changeset
|
82 return crypto.generate_ed25519_keypair(); |
|
12694
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
83 end |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
84 |
|
12711
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
85 function v4_public.init(private_key_pem, public_key_pem, options) |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
86 local sign, verify = v4_public.sign, v4_public.verify; |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
87 local public_key = public_key_pem and v4_public.import_public_key(public_key_pem); |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
88 local private_key = private_key_pem and v4_public.import_private_key(private_key_pem); |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
89 local default_footer = options and options.default_footer; |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
90 local default_assertion = options and options.default_implicit_assertion; |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
91 return private_key and function (token, token_footer, token_assertion) |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
92 return sign(token, private_key, token_footer or default_footer, token_assertion or default_assertion); |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
93 end, public_key and function (token, expected_footer, token_assertion) |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
94 return verify(token, public_key, expected_footer or default_footer, token_assertion or default_assertion); |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
95 end; |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
96 end |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
97 |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
98 function v4_public.new_signer(private_key_pem, options) |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
99 return (v4_public.init(private_key_pem, nil, options)); |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
100 end |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
101 |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
102 function v4_public.new_verifier(public_key_pem, options) |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
103 return (select(2, v4_public.init(public_key_pem, options))); |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
104 end |
|
9e9f158d6699
util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
105 |
|
12694
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
106 return { |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
107 pae = pae; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
108 v4_public = v4_public; |
|
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
109 }; |