author | Kim Alvefur <zash@zash.se> |
Sat, 22 Jul 2023 14:54:17 +0200 | |
changeset 13243 | f2578a69ccf4 |
parent 12979 | d10957394a3c |
permissions | -rw-r--r-- |
10664
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; |
12979
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12742
diff
changeset
|
2 |
local crypto = require "prosody.util.crypto"; |
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12742
diff
changeset
|
3 |
local json = require "prosody.util.json"; |
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12742
diff
changeset
|
4 |
local hashes = require "prosody.util.hashes"; |
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12742
diff
changeset
|
5 |
local base64_encode = require "prosody.util.encodings".base64.encode; |
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12742
diff
changeset
|
6 |
local base64_decode = require "prosody.util.encodings".base64.decode; |
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12742
diff
changeset
|
7 |
local secure_equals = require "prosody.util.hashes".equals; |
10664
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-_]+)$" |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
18 |
local function decode_jwt(blob, expected_alg) |
10664
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"; |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
26 |
elseif header.alg ~= expected_alg then |
10664
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 |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
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:
11565
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:
11565
diff
changeset
|
31 |
|
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
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:
11565
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:
11565
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:
11565
diff
changeset
|
35 |
|
12710
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
36 |
local function decode_raw_payload(raw_payload) |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
37 |
local payload, err = json.decode(unb64url(raw_payload)); |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
38 |
if err ~= nil then |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
39 |
return nil, "json-decode-error"; |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
40 |
elseif type(payload) ~= "table" then |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
41 |
return nil, "invalid-payload-type"; |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
42 |
end |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
43 |
return true, payload; |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
44 |
end |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
45 |
|
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
46 |
-- HS*** family |
12708
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
47 |
local function new_hmac_algorithm(name) |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
48 |
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:
11565
diff
changeset
|
49 |
|
12708
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
50 |
local hmac = hashes["hmac_sha"..name:sub(-3)]; |
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
51 |
|
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
52 |
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:
11565
diff
changeset
|
53 |
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:
11565
diff
changeset
|
54 |
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:
11565
diff
changeset
|
55 |
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:
11565
diff
changeset
|
56 |
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:
11565
diff
changeset
|
57 |
end |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
58 |
|
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
59 |
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:
11565
diff
changeset
|
60 |
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:
11565
diff
changeset
|
61 |
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:
11565
diff
changeset
|
62 |
|
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
63 |
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:
11565
diff
changeset
|
64 |
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:
11565
diff
changeset
|
65 |
end |
12710
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
66 |
|
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
67 |
return decode_raw_payload(raw_payload); |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
68 |
end |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
69 |
|
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
70 |
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:
11565
diff
changeset
|
71 |
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:
11565
diff
changeset
|
72 |
return key; |
10664
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
73 |
end |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
74 |
|
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
75 |
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:
11565
diff
changeset
|
76 |
end |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
77 |
|
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
78 |
local function new_crypto_algorithm(name, key_type, c_sign, c_verify, sig_encode, sig_decode) |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
79 |
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:
11565
diff
changeset
|
80 |
|
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
81 |
return { |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
82 |
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:
11565
diff
changeset
|
83 |
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:
11565
diff
changeset
|
84 |
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:
11565
diff
changeset
|
85 |
|
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
86 |
local signature = c_sign(private_key, signed); |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
87 |
if sig_encode then |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
88 |
signature = sig_encode(signature); |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
89 |
end |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
90 |
|
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
91 |
return signed.."."..b64url(signature); |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
92 |
end; |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
93 |
|
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
94 |
verify = function (public_key, blob) |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
95 |
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:
11565
diff
changeset
|
96 |
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:
11565
diff
changeset
|
97 |
|
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
98 |
signature = unb64url(signature); |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
99 |
if sig_decode and signature then |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
100 |
signature = sig_decode(signature); |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
101 |
end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
102 |
if not signature then |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
103 |
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:
11565
diff
changeset
|
104 |
end |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
105 |
|
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
106 |
local verify_ok = c_verify(public_key, signed, signature); |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
107 |
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:
11565
diff
changeset
|
108 |
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:
11565
diff
changeset
|
109 |
end |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
110 |
|
12710
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12709
diff
changeset
|
111 |
return decode_raw_payload(raw_payload); |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
112 |
end; |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
113 |
|
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
114 |
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:
11565
diff
changeset
|
115 |
local key = assert(crypto.import_public_pem(public_key_pem)); |
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
116 |
assert(key:get_type() == key_type, "incorrect key type"); |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
117 |
return key; |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
118 |
end; |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
119 |
|
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
120 |
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:
11565
diff
changeset
|
121 |
local key = assert(crypto.import_private_pem(private_key_pem)); |
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
122 |
assert(key:get_type() == key_type, "incorrect key type"); |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
123 |
return key; |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
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:
11565
diff
changeset
|
125 |
}; |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
126 |
end |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
127 |
|
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
128 |
-- RS***, PS*** |
12708
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
129 |
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:
12706
diff
changeset
|
130 |
local function new_rsa_algorithm(name) |
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
131 |
local family, digest_bits = name:match("^(..)(...)$"); |
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
132 |
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:
12706
diff
changeset
|
133 |
local c_verify = crypto[rsa_sign_algos[family].."_sha"..digest_bits.."_verify"]; |
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
134 |
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:
12700
diff
changeset
|
135 |
end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
136 |
|
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
137 |
-- ES*** |
12739
445f7bd6ffc4
util.crypto, util.jwt: Generate consistent signature sizes (via padding)
Matthew Wild <mwild1@gmail.com>
parents:
12711
diff
changeset
|
138 |
local function new_ecdsa_algorithm(name, c_sign, c_verify, sig_bytes) |
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
139 |
local function encode_ecdsa_sig(der_sig) |
12739
445f7bd6ffc4
util.crypto, util.jwt: Generate consistent signature sizes (via padding)
Matthew Wild <mwild1@gmail.com>
parents:
12711
diff
changeset
|
140 |
local r, s = crypto.parse_ecdsa_signature(der_sig, sig_bytes); |
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
141 |
return r..s; |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
142 |
end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
143 |
|
12742
62100f31eb8a
util.jwt: More robust ECDSA signature parsing, fail early on unexpected length
Matthew Wild <mwild1@gmail.com>
parents:
12740
diff
changeset
|
144 |
local expected_sig_length = sig_bytes*2; |
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
145 |
local function decode_ecdsa_sig(jwk_sig) |
12742
62100f31eb8a
util.jwt: More robust ECDSA signature parsing, fail early on unexpected length
Matthew Wild <mwild1@gmail.com>
parents:
12740
diff
changeset
|
146 |
if #jwk_sig ~= expected_sig_length then |
62100f31eb8a
util.jwt: More robust ECDSA signature parsing, fail early on unexpected length
Matthew Wild <mwild1@gmail.com>
parents:
12740
diff
changeset
|
147 |
return nil; |
62100f31eb8a
util.jwt: More robust ECDSA signature parsing, fail early on unexpected length
Matthew Wild <mwild1@gmail.com>
parents:
12740
diff
changeset
|
148 |
end |
62100f31eb8a
util.jwt: More robust ECDSA signature parsing, fail early on unexpected length
Matthew Wild <mwild1@gmail.com>
parents:
12740
diff
changeset
|
149 |
return crypto.build_ecdsa_signature(jwk_sig:sub(1, sig_bytes), jwk_sig:sub(sig_bytes+1)); |
12703
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
150 |
end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
151 |
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:
12700
diff
changeset
|
152 |
end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12700
diff
changeset
|
153 |
|
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
154 |
local algorithms = { |
12708
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
155 |
HS256 = new_hmac_algorithm("HS256"), HS384 = new_hmac_algorithm("HS384"), HS512 = new_hmac_algorithm("HS512"); |
12739
445f7bd6ffc4
util.crypto, util.jwt: Generate consistent signature sizes (via padding)
Matthew Wild <mwild1@gmail.com>
parents:
12711
diff
changeset
|
156 |
ES256 = new_ecdsa_algorithm("ES256", crypto.ecdsa_sha256_sign, crypto.ecdsa_sha256_verify, 32); |
12740
ad4ab01f9b11
util.jwt: Add support for ES512 (+ tests)
Matthew Wild <mwild1@gmail.com>
parents:
12739
diff
changeset
|
157 |
ES512 = new_ecdsa_algorithm("ES512", crypto.ecdsa_sha512_sign, crypto.ecdsa_sha512_verify, 66); |
12708
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
158 |
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:
12706
diff
changeset
|
159 |
PS256 = new_rsa_algorithm("PS256"), PS384 = new_rsa_algorithm("PS384"), PS512 = new_rsa_algorithm("PS512"); |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
160 |
}; |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
161 |
|
12709
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
162 |
local function new_signer(algorithm, key_input, options) |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
163 |
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:
11565
diff
changeset
|
164 |
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:
11565
diff
changeset
|
165 |
local sign = impl.sign; |
12709
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
166 |
local default_ttl = (options and options.default_ttl) or 3600; |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
167 |
return function (payload) |
12709
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
168 |
local issued_at; |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
169 |
if not payload.iat then |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
170 |
issued_at = os.time(); |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
171 |
payload.iat = issued_at; |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
172 |
end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
173 |
if not payload.exp then |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
174 |
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:
12708
diff
changeset
|
175 |
end |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
176 |
return sign(key, payload); |
10664
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
177 |
end |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
178 |
end |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
179 |
|
12709
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
180 |
local function new_verifier(algorithm, key_input, options) |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
181 |
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:
11565
diff
changeset
|
182 |
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:
11565
diff
changeset
|
183 |
local verify = impl.verify; |
12709
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
184 |
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:
12708
diff
changeset
|
185 |
local claim_verifier = options and options.claim_verifier; |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
186 |
return function (token) |
12709
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
187 |
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:
12708
diff
changeset
|
188 |
if ok then |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
189 |
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:
12708
diff
changeset
|
190 |
if expires_at then |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
191 |
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:
12708
diff
changeset
|
192 |
return nil, "invalid-expiry"; |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
193 |
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:
12708
diff
changeset
|
194 |
return nil, "token-expired"; |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
195 |
end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
196 |
end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
197 |
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:
12708
diff
changeset
|
198 |
return nil, "incorrect-claims"; |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
199 |
end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
200 |
end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12708
diff
changeset
|
201 |
return ok, payload; |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
202 |
end |
10664
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
203 |
end |
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
204 |
|
12711
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
205 |
local function init(algorithm, private_key, public_key, options) |
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
206 |
return new_signer(algorithm, private_key, options), new_verifier(algorithm, public_key or private_key, options); |
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
207 |
end |
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
208 |
|
10664
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
209 |
return { |
12711
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
210 |
init = init; |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
211 |
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:
11565
diff
changeset
|
212 |
new_verifier = new_verifier; |
12711
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12710
diff
changeset
|
213 |
-- Exported mainly for tests |
12708
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
214 |
_algorithms = algorithms; |
12700
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
215 |
-- Deprecated |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11565
diff
changeset
|
216 |
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:
11565
diff
changeset
|
217 |
verify = algorithms.HS256.verify; |
10664
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
218 |
}; |
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
219 |