Annotate

util/jwt.lua @ 12705:008a7097fdc5

util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime) To avoid every user of the library needing to add and verify expiry info, this is now handled by util.jwt itself (if not overridden or disabled). Issuing tokens that are valid forever is bad practice and rarely desired, and the default token lifetime is now 3600s (1 hour).
author Matthew Wild <mwild1@gmail.com>
date Mon, 11 Jul 2022 13:28:29 +0100
parent 12704:31a2bd84191d
child 12706:108b1758bd8d
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
10660
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
1 local s_gsub = string.gsub;
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
2 local crypto = require "util.crypto";
10660
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
3 local json = require "util.json";
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
4 local hashes = require "util.hashes";
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
5 local base64_encode = require "util.encodings".base64.encode;
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
6 local base64_decode = require "util.encodings".base64.decode;
11561
d2f33b8fdc96 util.jwt: Use constant-time comparison with expected signature
Matthew Wild <mwild1@gmail.com>
parents: 10660
diff changeset
7 local secure_equals = require "util.hashes".equals;
10660
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
8
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
9 local b64url_rep = { ["+"] = "-", ["/"] = "_", ["="] = "", ["-"] = "+", ["_"] = "/" };
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
10 local function b64url(data)
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
11 return (s_gsub(base64_encode(data), "[+/=]", b64url_rep));
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
12 end
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
13 local function unb64url(data)
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
14 return base64_decode(s_gsub(data, "[-_]", b64url_rep).."==");
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
15 end
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
16
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
17 local jwt_pattern = "^(([A-Za-z0-9-_]+)%.([A-Za-z0-9-_]+))%.([A-Za-z0-9-_]+)$"
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
18 local function decode_jwt(blob, expected_alg)
10660
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
19 local signed, bheader, bpayload, signature = string.match(blob, jwt_pattern);
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
20 if not signed then
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
21 return nil, "invalid-encoding";
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
22 end
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
23 local header = json.decode(unb64url(bheader));
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
24 if not header or type(header) ~= "table" then
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
25 return nil, "invalid-header";
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
26 elseif header.alg ~= expected_alg then
10660
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
27 return nil, "unsupported-algorithm";
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
28 end
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
29 return signed, signature, bpayload;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
30 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
31
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
32 local function new_static_header(algorithm_name)
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
33 return b64url('{"alg":"'..algorithm_name..'","typ":"JWT"}') .. '.';
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
34 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
35
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
36 -- HS*** family
12704
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
37 local function new_hmac_algorithm(name)
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
38 local static_header = new_static_header(name);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
39
12704
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
40 local hmac = hashes["hmac_sha"..name:sub(-3)];
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
41
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
42 local function sign(key, payload)
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
43 local encoded_payload = json.encode(payload);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
44 local signed = static_header .. b64url(encoded_payload);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
45 local signature = hmac(key, signed);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
46 return signed .. "." .. b64url(signature);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
47 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
48
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
49 local function verify(key, blob)
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
50 local signed, signature, raw_payload = decode_jwt(blob, name);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
51 if not signed then return nil, signature; end -- nil, err
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
52
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
53 if not secure_equals(b64url(hmac(key, signed)), signature) then
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
54 return false, "signature-mismatch";
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
55 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
56 local payload, err = json.decode(unb64url(raw_payload));
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
57 if err ~= nil then
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
58 return nil, "json-decode-error";
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
59 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
60 return true, payload;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
61 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
62
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
63 local function load_key(key)
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
64 assert(type(key) == "string", "key must be string (long, random, secure)");
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
65 return key;
10660
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
66 end
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
67
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
68 return { sign = sign, verify = verify, load_key = load_key };
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
69 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
70
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
71 local function new_crypto_algorithm(name, key_type, c_sign, c_verify, sig_encode, sig_decode)
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
72 local static_header = new_static_header(name);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
73
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
74 return {
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
75 sign = function (private_key, payload)
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
76 local encoded_payload = json.encode(payload);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
77 local signed = static_header .. b64url(encoded_payload);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
78
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
79 local signature = c_sign(private_key, signed);
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
80 if sig_encode then
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
81 signature = sig_encode(signature);
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
82 end
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
83
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
84 return signed.."."..b64url(signature);
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
85 end;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
86
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
87 verify = function (public_key, blob)
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
88 local signed, signature, raw_payload = decode_jwt(blob, name);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
89 if not signed then return nil, signature; end -- nil, err
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
90
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
91 signature = unb64url(signature);
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
92 if sig_decode and signature then
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
93 signature = sig_decode(signature);
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
94 end
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
95 if not signature then
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
96 return false, "signature-mismatch";
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
97 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
98
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
99 local verify_ok = c_verify(public_key, signed, signature);
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
100 if not verify_ok then
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
101 return false, "signature-mismatch";
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
102 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
103
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
104 local payload, err = json.decode(unb64url(raw_payload));
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
105 if err ~= nil then
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
106 return nil, "json-decode-error";
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
107 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
108
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
109 return true, payload;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
110 end;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
111
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
112 load_public_key = function (public_key_pem)
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
113 local key = assert(crypto.import_public_pem(public_key_pem));
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
114 assert(key:get_type() == key_type, "incorrect key type");
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
115 return key;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
116 end;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
117
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
118 load_private_key = function (private_key_pem)
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
119 local key = assert(crypto.import_private_pem(private_key_pem));
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
120 assert(key:get_type() == key_type, "incorrect key type");
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
121 return key;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
122 end;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
123 };
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
124 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
125
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
126 -- RS***, PS***
12704
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
127 local rsa_sign_algos = { RS = "rsassa_pkcs1", PS = "rsassa_pss" };
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
128 local function new_rsa_algorithm(name)
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
129 local family, digest_bits = name:match("^(..)(...)$");
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
130 local c_sign = crypto[rsa_sign_algos[family].."_sha"..digest_bits.."_sign"];
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
131 local c_verify = crypto[rsa_sign_algos[family].."_sha"..digest_bits.."_verify"];
12699
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
132 return new_crypto_algorithm(name, "rsaEncryption", c_sign, c_verify);
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
133 end
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
134
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
135 -- ES***
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
136 local function new_ecdsa_algorithm(name, c_sign, c_verify)
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
137 local function encode_ecdsa_sig(der_sig)
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
138 local r, s = crypto.parse_ecdsa_signature(der_sig);
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
139 return r..s;
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
140 end
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
141
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
142 local function decode_ecdsa_sig(jwk_sig)
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
143 return crypto.build_ecdsa_signature(jwk_sig:sub(1, 32), jwk_sig:sub(33, 64));
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
144 end
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
145 return new_crypto_algorithm(name, "id-ecPublicKey", c_sign, c_verify, encode_ecdsa_sig, decode_ecdsa_sig);
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
146 end
b3d0c1457584 util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents: 12696
diff changeset
147
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
148 local algorithms = {
12704
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
149 HS256 = new_hmac_algorithm("HS256"), HS384 = new_hmac_algorithm("HS384"), HS512 = new_hmac_algorithm("HS512");
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
150 ES256 = new_ecdsa_algorithm("ES256", crypto.ecdsa_sha256_sign, crypto.ecdsa_sha256_verify);
12704
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
151 RS256 = new_rsa_algorithm("RS256"), RS384 = new_rsa_algorithm("RS384"), RS512 = new_rsa_algorithm("RS512");
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
152 PS256 = new_rsa_algorithm("PS256"), PS384 = new_rsa_algorithm("PS384"), PS512 = new_rsa_algorithm("PS512");
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
153 };
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
154
12705
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
155 local function new_signer(algorithm, key_input, options)
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
156 local impl = assert(algorithms[algorithm], "Unknown JWT algorithm: "..algorithm);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
157 local key = (impl.load_private_key or impl.load_key)(key_input);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
158 local sign = impl.sign;
12705
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
159 local default_ttl = (options and options.default_ttl) or 3600;
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
160 return function (payload)
12705
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
161 local issued_at;
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
162 if not payload.iat then
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
163 issued_at = os.time();
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
164 payload.iat = issued_at;
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
165 end
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
166 if not payload.exp then
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
167 payload.exp = (issued_at or os.time()) + default_ttl;
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
168 end
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
169 return sign(key, payload);
10660
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
170 end
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
171 end
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
172
12705
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
173 local function new_verifier(algorithm, key_input, options)
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
174 local impl = assert(algorithms[algorithm], "Unknown JWT algorithm: "..algorithm);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
175 local key = (impl.load_public_key or impl.load_key)(key_input);
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
176 local verify = impl.verify;
12705
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
177 local check_expiry = not (options and options.accept_expired);
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
178 local claim_verifier = options and options.claim_verifier;
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
179 return function (token)
12705
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
180 local ok, payload = verify(key, token);
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
181 if ok then
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
182 local expires_at = check_expiry and payload.exp;
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
183 if expires_at then
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
184 if type(expires_at) ~= "number" then
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
185 return nil, "invalid-expiry";
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
186 elseif expires_at < os.time() then
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
187 return nil, "token-expired";
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
188 end
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
189 end
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
190 if claim_verifier and not claim_verifier(payload) then
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
191 return nil, "incorrect-claims";
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
192 end
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
193 end
008a7097fdc5 util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents: 12704
diff changeset
194 return ok, payload;
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
195 end
10660
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
196 end
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
197
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
198 return {
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
199 new_signer = new_signer;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
200 new_verifier = new_verifier;
12704
31a2bd84191d util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents: 12702
diff changeset
201 _algorithms = algorithms;
12696
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
202 -- Deprecated
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
203 sign = algorithms.HS256.sign;
27a72982e331 util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents: 11561
diff changeset
204 verify = algorithms.HS256.verify;
10660
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
205 };
c4ded3be7cc0 util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff changeset
206