Software /
code /
prosody
Annotate
util/jwt.lua @ 13252:84c7779618b6
core.portmanager: Join strings broken into multiple lines
Improves readability. Reduces line count. What's not to like?
The code style and luacheck rules allows longer lines, and these strings
aren't long enough to need breaking into multiple lines like this.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sat, 29 Jul 2023 02:04:24 +0200 |
parent | 12975:d10957394a3c |
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; |
12975
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12738
diff
changeset
|
2 local crypto = require "prosody.util.crypto"; |
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12738
diff
changeset
|
3 local json = require "prosody.util.json"; |
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12738
diff
changeset
|
4 local hashes = require "prosody.util.hashes"; |
d10957394a3c
util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents:
12738
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:
12738
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:
12738
diff
changeset
|
7 local secure_equals = require "prosody.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 |
12706
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12705
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:
12705
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:
12705
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:
12705
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:
12705
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:
12705
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:
12705
diff
changeset
|
42 end |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12705
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:
12705
diff
changeset
|
44 end |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12705
diff
changeset
|
45 |
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
|
46 -- HS*** family |
12704
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12702
diff
changeset
|
47 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
|
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:
11561
diff
changeset
|
49 |
12704
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12702
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:
12702
diff
changeset
|
51 |
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
|
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:
11561
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:
11561
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:
11561
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:
11561
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:
11561
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:
11561
diff
changeset
|
58 |
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 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
|
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:
11561
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:
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 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
|
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:
11561
diff
changeset
|
65 end |
12706
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12705
diff
changeset
|
66 |
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12705
diff
changeset
|
67 return decode_raw_payload(raw_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
|
68 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
|
69 |
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 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
|
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:
11561
diff
changeset
|
72 return key; |
10660
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
73 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
|
74 |
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 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
|
76 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
|
77 |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
78 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
|
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:
11561
diff
changeset
|
80 |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11561
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:
11561
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:
11561
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:
11561
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:
11561
diff
changeset
|
85 |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
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:
12696
diff
changeset
|
87 if sig_encode then |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
88 signature = sig_encode(signature); |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
89 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
|
90 |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
91 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
|
92 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
|
93 |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
94 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
|
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:
11561
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:
11561
diff
changeset
|
97 |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
98 signature = unb64url(signature); |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
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:
12696
diff
changeset
|
100 signature = sig_decode(signature); |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
101 end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
102 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
|
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:
11561
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:
11561
diff
changeset
|
105 |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
106 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
|
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:
11561
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:
11561
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:
11561
diff
changeset
|
110 |
12706
108b1758bd8d
util.jwt: Consolidate payload parsing, ensure it's always a valid object
Matthew Wild <mwild1@gmail.com>
parents:
12705
diff
changeset
|
111 return decode_raw_payload(raw_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
|
112 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
|
113 |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11561
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:
11561
diff
changeset
|
115 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
|
116 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
|
117 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
|
118 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
|
119 |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11561
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:
11561
diff
changeset
|
121 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
|
122 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
|
123 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
|
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 }; |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11561
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:
11561
diff
changeset
|
127 |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
128 -- RS***, PS*** |
12704
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12702
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:
12702
diff
changeset
|
130 local function new_rsa_algorithm(name) |
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12702
diff
changeset
|
131 local family, digest_bits = name:match("^(..)(...)$"); |
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12702
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:
12702
diff
changeset
|
133 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
|
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:
12696
diff
changeset
|
135 end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
136 |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
137 -- ES*** |
12735
445f7bd6ffc4
util.crypto, util.jwt: Generate consistent signature sizes (via padding)
Matthew Wild <mwild1@gmail.com>
parents:
12707
diff
changeset
|
138 local function new_ecdsa_algorithm(name, c_sign, c_verify, sig_bytes) |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
139 local function encode_ecdsa_sig(der_sig) |
12735
445f7bd6ffc4
util.crypto, util.jwt: Generate consistent signature sizes (via padding)
Matthew Wild <mwild1@gmail.com>
parents:
12707
diff
changeset
|
140 local r, s = crypto.parse_ecdsa_signature(der_sig, sig_bytes); |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
141 return r..s; |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
142 end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
143 |
12738
62100f31eb8a
util.jwt: More robust ECDSA signature parsing, fail early on unexpected length
Matthew Wild <mwild1@gmail.com>
parents:
12736
diff
changeset
|
144 local expected_sig_length = sig_bytes*2; |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
145 local function decode_ecdsa_sig(jwk_sig) |
12738
62100f31eb8a
util.jwt: More robust ECDSA signature parsing, fail early on unexpected length
Matthew Wild <mwild1@gmail.com>
parents:
12736
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:
12736
diff
changeset
|
147 return nil; |
62100f31eb8a
util.jwt: More robust ECDSA signature parsing, fail early on unexpected length
Matthew Wild <mwild1@gmail.com>
parents:
12736
diff
changeset
|
148 end |
62100f31eb8a
util.jwt: More robust ECDSA signature parsing, fail early on unexpected length
Matthew Wild <mwild1@gmail.com>
parents:
12736
diff
changeset
|
149 return crypto.build_ecdsa_signature(jwk_sig:sub(1, sig_bytes), jwk_sig:sub(sig_bytes+1)); |
12699
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
150 end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
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:
12696
diff
changeset
|
152 end |
b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
Matthew Wild <mwild1@gmail.com>
parents:
12696
diff
changeset
|
153 |
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
|
154 local algorithms = { |
12704
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12702
diff
changeset
|
155 HS256 = new_hmac_algorithm("HS256"), HS384 = new_hmac_algorithm("HS384"), HS512 = new_hmac_algorithm("HS512"); |
12735
445f7bd6ffc4
util.crypto, util.jwt: Generate consistent signature sizes (via padding)
Matthew Wild <mwild1@gmail.com>
parents:
12707
diff
changeset
|
156 ES256 = new_ecdsa_algorithm("ES256", crypto.ecdsa_sha256_sign, crypto.ecdsa_sha256_verify, 32); |
12736
ad4ab01f9b11
util.jwt: Add support for ES512 (+ tests)
Matthew Wild <mwild1@gmail.com>
parents:
12735
diff
changeset
|
157 ES512 = new_ecdsa_algorithm("ES512", crypto.ecdsa_sha512_sign, crypto.ecdsa_sha512_verify, 66); |
12704
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12702
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:
12702
diff
changeset
|
159 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
|
160 }; |
27a72982e331
util.jwt: Add support/tests for ES256 via improved API and using util.crypto
Matthew Wild <mwild1@gmail.com>
parents:
11561
diff
changeset
|
161 |
12705
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12704
diff
changeset
|
162 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
|
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:
11561
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:
11561
diff
changeset
|
165 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
|
166 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
|
167 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
|
168 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
|
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:
12704
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:
12704
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:
12704
diff
changeset
|
172 end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12704
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:
12704
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:
12704
diff
changeset
|
175 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
|
176 return sign(key, payload); |
10660
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
177 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
|
178 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
|
179 |
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 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
|
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:
11561
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:
11561
diff
changeset
|
183 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
|
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:
12704
diff
changeset
|
185 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
|
186 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
|
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:
12704
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:
12704
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:
12704
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:
12704
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:
12704
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:
12704
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:
12704
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:
12704
diff
changeset
|
195 end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12704
diff
changeset
|
196 end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12704
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:
12704
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:
12704
diff
changeset
|
199 end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12704
diff
changeset
|
200 end |
008a7097fdc5
util.jwt: Provide built-in token expiry support (defaults to 3600s lifetime)
Matthew Wild <mwild1@gmail.com>
parents:
12704
diff
changeset
|
201 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
|
202 end |
10660
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 |
12707
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12706
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:
12706
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:
12706
diff
changeset
|
207 end |
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
208 |
10660
c4ded3be7cc0
util.jwt: Basic JSON Web Token library supporting HS256 tokens
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
209 return { |
12707
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
210 init = init; |
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
|
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:
11561
diff
changeset
|
212 new_verifier = new_verifier; |
12707
f75235110045
util.jwt: Add new init() convenience method to obtain both signer and verifier
Matthew Wild <mwild1@gmail.com>
parents:
12706
diff
changeset
|
213 -- Exported mainly for tests |
12704
31a2bd84191d
util.jwt: All the algorithms (+ all the tests!)
Matthew Wild <mwild1@gmail.com>
parents:
12702
diff
changeset
|
214 _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
|
215 -- 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
|
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:
11561
diff
changeset
|
217 verify = algorithms.HS256.verify; |
10660
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 |