Software /
code /
prosody
Annotate
util/paseto.lua @ 12700:899c057781cd
spec: Move test crypto keys to a shared file for clarity and easy maintenance
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sat, 02 Jul 2022 12:36:52 +0100 |
parent | 12694:26a004c96ef8 |
child | 12709:b3f7c77c1f08 |
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 pubkey_methods = {}; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
12 local privkey_methods = {}; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
13 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
14 local v4_public_pubkey_mt = { __index = pubkey_methods }; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
15 local v4_public_privkey_mt = { __index = privkey_methods }; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
16 local v4_public = {}; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
17 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
18 local b64url_rep = { ["+"] = "-", ["/"] = "_", ["="] = "", ["-"] = "+", ["_"] = "/" }; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
19 local function b64url(data) |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
20 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
|
21 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
22 local function unb64url(data) |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
23 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
|
24 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
25 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
26 local function le64(n) |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
27 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
|
28 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
29 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
30 local function pae(parts) |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
31 local o = { le64(#parts) }; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
32 for _, part in ipairs(parts) do |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
33 table.insert(o, le64(#part)..part); |
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 return table.concat(o); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
36 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
37 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
38 function privkey_methods:export() |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
39 return self.key:private_pem(); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
40 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
41 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
42 function pubkey_methods:export() |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
43 return self.key:public_pem(); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
44 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
45 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
46 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
|
47 if getmetatable(sk) ~= v4_public_privkey_mt then |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
48 error("cannot sign v4.public tokens with this key"); |
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 if type(m) ~= "table" then |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
51 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
|
52 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
53 m = json.encode(m); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
54 local h = "v4.public."; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
55 local m2 = pae({ h, m, f or "", i or "" }); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
56 local sig = crypto.ed25519_sign(sk.key, m2); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
57 if not f or f == "" then |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
58 return h..b64url(m..sig); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
59 else |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
60 return h..b64url(m..sig).."."..b64url(f); |
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 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
63 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
64 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
|
65 if getmetatable(pk) ~= v4_public_pubkey_mt then |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
66 error("cannot verify v4.public tokens with this key"); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
67 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
68 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
|
69 if not h then |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
70 return nil, "invalid-token-format"; |
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 if expected_f then |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
73 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
|
74 return nil, "invalid-footer"; |
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 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
77 local raw_sm = unb64url(sm); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
78 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
|
79 return nil, "invalid-token-format"; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
80 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
81 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
|
82 local m2 = pae({ h, m, f or "", i or "" }); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
83 local ok = crypto.ed25519_verify(pk.key, m2, s); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
84 if not ok then |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
85 return nil, "invalid-token"; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
86 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
87 local payload, err = json.decode(m); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
88 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
|
89 return nil, "json-decode-error"; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
90 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
91 return payload; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
92 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
93 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
94 function v4_public.new_keypair() |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
95 local key = crypto.generate_ed25519_keypair(); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
96 return { |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
97 private_key = setmetatable({ |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
98 key = key; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
99 }, v4_public_privkey_mt); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
100 public_key = setmetatable({ |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
101 key = key; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
102 }, v4_public_pubkey_mt); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
103 }; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
104 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
105 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
106 function v4_public.import_public_key(pem) |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
107 local key = crypto.import_public_pem(pem); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
108 return setmetatable({ |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
109 key = key; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
110 }, v4_public_pubkey_mt); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
111 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
112 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
113 function v4_public.import_private_key(pem) |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
114 local key = crypto.import_private_pem(pem); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
115 return setmetatable({ |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
116 key = key; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
117 }, v4_public_privkey_mt); |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
118 end |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
119 |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
120 return { |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
121 pae = pae; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
122 v4_public = v4_public; |
26a004c96ef8
util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
123 }; |