annotate util/paseto.lua @ 13652:a08065207ef0

net.server_epoll: Call :shutdown() on TLS sockets when supported Comment from Matthew: This fixes a potential issue where the Prosody process gets blocked on sockets waiting for them to close. Unlike non-TLS sockets, closing a TLS socket sends layer 7 data, and this can cause problems for sockets which are in the process of being cleaned up. This depends on LuaSec changes which are not yet upstream. From Martijn's original email: So first my analysis of luasec. in ssl.c the socket is put into blocking mode right before calling SSL_shutdown() inside meth_destroy(). My best guess to why this is is because meth_destroy is linked to the __close and __gc methods, which can't exactly be called multiple times and luasec does want to make sure that a tls session is shutdown as clean as possible. I can't say I disagree with this reasoning and don't want to change this behaviour. My solution to this without changing the current behaviour is to introduce a shutdown() method. I am aware that this overlaps in a conflicting way with tcp's shutdown method, but it stays close to the OpenSSL name. This method calls SSL_shutdown() in the current (non)blocking mode of the underlying socket and returns a boolean whether or not the shutdown is completed (matching SSL_shutdown()'s 0 or 1 return values), and returns the familiar ssl_ioerror() strings on error with a false for completion. This error can then be used to determine if we have wantread/wantwrite to finalize things. Once meth_shutdown() has been called once a shutdown flag will be set, which indicates to meth_destroy() that the SSL_shutdown() has been handled by the application and it shouldn't be needed to set the socket to blocking mode. I've left the SSL_shutdown() call in the LSEC_STATE_CONNECTED to prevent TOCTOU if the application reaches a timeout for the shutdown code, which might allow SSL_shutdown() to clean up anyway at the last possible moment. Another thing I've changed to luasec is the call to socket_setblocking() right before calling close(2) in socket_destroy() in usocket.c. According to the latest POSIX[0]: Note that the requirement for close() on a socket to block for up to the current linger interval is not conditional on the O_NONBLOCK setting. Which I read to mean that removing O_NONBLOCK on the socket before close doesn't impact the behaviour and only causes noise in system call tracers. I didn't touch the windows bits of this, since I don't do windows. For the prosody side of things I've made the TLS shutdown bits resemble interface:onwritable(), and put it under a combined guard of self._tls and self.conn.shutdown. The self._tls bit is there to prevent getting stuck on this condition, and self.conn.shutdown is there to prevent the code being called by instances where the patched luasec isn't deployed. The destroy() method can be called from various places and is read by me as the "we give up" error path. To accommodate for these unexpected entrypoints I've added a single call to self.conn:shutdown() to prevent the socket being put into blocking mode. I have no expectations that there is any other use here. Same as previous, the self.conn.shutdown check is there to make sure it's not called on unpatched luasec deployments and self._tls is there to make sure we don't call shutdown() on tcp sockets. I wouldn't recommend logging of the conn:shutdown() error inside close(), since a lot of clients simply close the connection before SSL_shutdown() is done.
author Martijn van Duren <martijn@openbsd.org>
date Thu, 06 Feb 2025 15:04:38 +0000
parents d10957394a3c
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
12975
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
1 local crypto = require "prosody.util.crypto";
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
2 local json = require "prosody.util.json";
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
3 local hashes = require "prosody.util.hashes";
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
4 local base64_encode = require "prosody.util.encodings".base64.encode;
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
5 local base64_decode = require "prosody.util.encodings".base64.decode;
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
6 local secure_equals = require "prosody.util.hashes".equals;
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
7 local bit = require "prosody.util.bitcompat";
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
8 local hex = require "prosody.util.hex";
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
9 local rand = require "prosody.util.random";
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12840
diff changeset
10 local s_pack = require "prosody.util.struct".pack;
12694
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
11
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
12 local s_gsub = string.gsub;
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 = {};
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
15
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
16 local b64url_rep = { ["+"] = "-", ["/"] = "_", ["="] = "", ["-"] = "+", ["_"] = "/" };
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
17 local function b64url(data)
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
18 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
19 end
12838
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
20
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
21 local valid_tails = {
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
22 nil; -- Always invalid
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
23 "^.[AQgw]$"; -- b??????00
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
24 "^..[AQgwEUk0IYo4Mcs8]$"; -- b????0000
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
25 }
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
26
12694
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
27 local function unb64url(data)
12838
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
28 local rem = #data%4;
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
29 if data:sub(-1,-1) == "=" or rem == 1 or (rem > 1 and not data:sub(-rem):match(valid_tails[rem])) then
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
30 return nil;
2e71b76ac299 util.paseto: Stricter base64 decoding, as per spec
Matthew Wild <mwild1@gmail.com>
parents: 12716
diff changeset
31 end
12694
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
32 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
33 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
34
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
35 local function le64(n)
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
36 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
37 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
38
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
39 local function pae(parts)
12716
0b68b021ce46 util.paseto: Do strict type check in pae() function
Kim Alvefur <zash@zash.se>
parents: 12713
diff changeset
40 if type(parts) ~= "table" then
0b68b021ce46 util.paseto: Do strict type check in pae() function
Kim Alvefur <zash@zash.se>
parents: 12713
diff changeset
41 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
42 end
12694
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
43 local o = { le64(#parts) };
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
44 for _, part in ipairs(parts) do
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
45 table.insert(o, le64(#part)..part);
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
46 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
47 return table.concat(o);
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
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
50 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
51 if type(m) ~= "table" then
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
52 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
53 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
54 m = json.encode(m);
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
55 local h = "v4.public.";
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
56 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
57 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
58 if not f or f == "" then
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
59 return h..b64url(m..sig);
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
60 else
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
61 return h..b64url(m..sig).."."..b64url(f);
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 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
64
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
65 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
66 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
67 if not h then
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
68 return nil, "invalid-token-format";
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
69 end
12709
b3f7c77c1f08 util.paseto: Fix to decode footer before comparison
Matthew Wild <mwild1@gmail.com>
parents: 12694
diff changeset
70 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
71 if expected_f then
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
72 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
73 return nil, "invalid-footer";
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
74 end
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 local raw_sm = unb64url(sm);
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
77 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
78 return nil, "invalid-token-format";
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
79 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
80 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
81 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
82 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
83 if not ok then
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
84 return nil, "invalid-token";
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
85 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
86 local payload, err = json.decode(m);
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
87 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
88 return nil, "json-decode-error";
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
89 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
90 return payload;
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
91 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
92
12713
52eead170bb8 util.paseto: Drop custom wrappers around key objects
Matthew Wild <mwild1@gmail.com>
parents: 12711
diff changeset
93 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
94 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
95 function v4_public.new_keypair()
12713
52eead170bb8 util.paseto: Drop custom wrappers around key objects
Matthew Wild <mwild1@gmail.com>
parents: 12711
diff changeset
96 return crypto.generate_ed25519_keypair();
12694
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
97 end
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
98
12711
9e9f158d6699 util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents: 12710
diff changeset
99 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
100 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
101 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
102 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
103 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
104 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
105 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
106 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
107 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
108 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
109 end;
9e9f158d6699 util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents: 12710
diff changeset
110 end
9e9f158d6699 util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents: 12710
diff changeset
111
9e9f158d6699 util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents: 12710
diff changeset
112 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
113 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
114 end
9e9f158d6699 util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents: 12710
diff changeset
115
9e9f158d6699 util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents: 12710
diff changeset
116 function v4_public.new_verifier(public_key_pem, options)
12839
7db1c1da7bfd util.paseto: Fix omitted parameter
Matthew Wild <mwild1@gmail.com>
parents: 12838
diff changeset
117 return (select(2, v4_public.init(nil, public_key_pem, options)));
12711
9e9f158d6699 util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents: 12710
diff changeset
118 end
9e9f158d6699 util.paseto: Export similar API to new util.jwt for ease and consistency
Matthew Wild <mwild1@gmail.com>
parents: 12710
diff changeset
119
12840
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
120 local v3_local = { _key_mt = {} };
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
121
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
122 local function v3_local_derive_keys(k, n)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
123 local tmp = hashes.hkdf_hmac_sha384(48, k, nil, "paseto-encryption-key"..n);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
124 local Ek = tmp:sub(1, 32);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
125 local n2 = tmp:sub(33);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
126 local Ak = hashes.hkdf_hmac_sha384(48, k, nil, "paseto-auth-key-for-aead"..n);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
127 return Ek, Ak, n2;
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
128 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
129
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
130 function v3_local.encrypt(m, k, f, i)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
131 assert(#k == 32)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
132 if type(m) ~= "table" then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
133 return nil, "PASETO payloads must be a table";
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
134 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
135 m = json.encode(m);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
136 local h = "v3.local.";
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
137 local n = rand.bytes(32);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
138 local Ek, Ak, n2 = v3_local_derive_keys(k, n);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
139
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
140 local c = crypto.aes_256_ctr_encrypt(Ek, n2, m);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
141 local m2 = pae({ h, n, c, f or "", i or "" });
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
142 local t = hashes.hmac_sha384(Ak, m2);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
143
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
144 if not f or f == "" then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
145 return h..b64url(n..c..t);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
146 else
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
147 return h..b64url(n..c..t).."."..b64url(f);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
148 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
149 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
150
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
151 function v3_local.decrypt(tok, k, expected_f, i)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
152 assert(#k == 32)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
153
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
154 local h, sm, f = tok:match("^(v3%.local%.)([^%.]+)%.?(.*)$");
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
155 if not h then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
156 return nil, "invalid-token-format";
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
157 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
158 f = f and unb64url(f) or nil;
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
159 if expected_f then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
160 if not f or not secure_equals(expected_f, f) then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
161 return nil, "invalid-footer";
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
162 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
163 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
164 local m = unb64url(sm);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
165 if not m or #m <= 80 then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
166 return nil, "invalid-token-format";
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
167 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
168 local n, c, t = m:sub(1, 32), m:sub(33, -49), m:sub(-48);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
169 local Ek, Ak, n2 = v3_local_derive_keys(k, n);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
170 local preAuth = pae({ h, n, c, f or "", i or "" });
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
171 local t2 = hashes.hmac_sha384(Ak, preAuth);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
172 if not secure_equals(t, t2) then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
173 return nil, "invalid-token";
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
174 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
175 local m2 = crypto.aes_256_ctr_decrypt(Ek, n2, c);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
176 if not m2 then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
177 return nil, "invalid-token";
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
178 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
179
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
180 local payload, err = json.decode(m2);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
181 if err ~= nil or type(payload) ~= "table" then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
182 return nil, "json-decode-error";
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
183 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
184 return payload;
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
185 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
186
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
187 function v3_local.new_key()
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
188 return "secret-token:paseto.v3.local:"..hex.encode(rand.bytes(32));
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
189 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
190
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
191 function v3_local.init(key, options)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
192 local encoded_key = key:match("^secret%-token:paseto%.v3%.local:(%x+)$");
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
193 if not encoded_key or #encoded_key ~= 64 then
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
194 return error("invalid key for v3.local");
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
195 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
196 local raw_key = hex.decode(encoded_key);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
197 local default_footer = options and options.default_footer;
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
198 local default_assertion = options and options.default_implicit_assertion;
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
199 return function (token, token_footer, token_assertion)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
200 return v3_local.encrypt(token, raw_key, token_footer or default_footer, token_assertion or default_assertion);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
201 end, function (token, token_footer, token_assertion)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
202 return v3_local.decrypt(token, raw_key, token_footer or default_footer, token_assertion or default_assertion);
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
203 end;
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
204 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
205
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
206 function v3_local.new_signer(key, options)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
207 return (v3_local.init(key, options));
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
208 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
209
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
210 function v3_local.new_verifier(key, options)
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
211 return (select(2, v3_local.init(key, options)));
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
212 end
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
213
12694
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
214 return {
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
215 pae = pae;
12840
33d902b093f0 util.paseto: Add support for v3.local tokens
Matthew Wild <mwild1@gmail.com>
parents: 12839
diff changeset
216 v3_local = v3_local;
12694
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
217 v4_public = v4_public;
26a004c96ef8 util.paseto: Implementation of PASETO v4.public tokens
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
218 };