Annotate

util/jwt.lua @ 13238:26327eac56dc

util.datamanager: Always reset index after list shift Shifting the index does not work reliably yet, better to rebuild it from scratch. Since there is minimal parsing involved in that, it should be more efficient anyway.
author Kim Alvefur <zash@zash.se>
date Sat, 22 Jul 2023 14:02:01 +0200
parent 12975:d10957394a3c
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;
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