Software /
code /
prosody
Comparison
util/jwt.lua @ 12699:b3d0c1457584
util.jwt: Add support for RSA-based algorithms (RS256, PS256)
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sat, 02 Jul 2022 12:26:43 +0100 |
parent | 12696:27a72982e331 |
child | 12702:f63176781940 |
comparison
equal
deleted
inserted
replaced
12698:999663b4e39d | 12699:b3d0c1457584 |
---|---|
64 end | 64 end |
65 | 65 |
66 return { sign = sign, verify = verify, load_key = load_key }; | 66 return { sign = sign, verify = verify, load_key = load_key }; |
67 end | 67 end |
68 | 68 |
69 -- ES*** family | 69 local function new_crypto_algorithm(name, key_type, c_sign, c_verify, sig_encode, sig_decode) |
70 local function new_ecdsa_algorithm(name, c_sign, c_verify) | |
71 local static_header = new_static_header(name); | 70 local static_header = new_static_header(name); |
72 | 71 |
73 return { | 72 return { |
74 sign = function (private_key, payload) | 73 sign = function (private_key, payload) |
75 local encoded_payload = json.encode(payload); | 74 local encoded_payload = json.encode(payload); |
76 local signed = static_header .. b64url(encoded_payload); | 75 local signed = static_header .. b64url(encoded_payload); |
77 | 76 |
78 local der_sig = c_sign(private_key, signed); | 77 local signature = c_sign(private_key, signed); |
78 if sig_encode then | |
79 signature = sig_encode(signature); | |
80 end | |
79 | 81 |
80 local r, s = crypto.parse_ecdsa_signature(der_sig); | 82 return signed.."."..b64url(signature); |
81 | |
82 return signed.."."..b64url(r..s); | |
83 end; | 83 end; |
84 | 84 |
85 verify = function (public_key, blob) | 85 verify = function (public_key, blob) |
86 local signed, signature, raw_payload = decode_jwt(blob, name); | 86 local signed, signature, raw_payload = decode_jwt(blob, name); |
87 if not signed then return nil, signature; end -- nil, err | 87 if not signed then return nil, signature; end -- nil, err |
88 | 88 |
89 local raw_signature = unb64url(signature); | 89 signature = unb64url(signature); |
90 | 90 if sig_decode and signature then |
91 local der_sig = crypto.build_ecdsa_signature(raw_signature:sub(1, 32), raw_signature:sub(33, 64)); | 91 signature = sig_decode(signature); |
92 if not der_sig then | 92 end |
93 if not signature then | |
93 return false, "signature-mismatch"; | 94 return false, "signature-mismatch"; |
94 end | 95 end |
95 | 96 |
96 local verify_ok = c_verify(public_key, signed, der_sig); | 97 local verify_ok = c_verify(public_key, signed, signature); |
97 if not verify_ok then | 98 if not verify_ok then |
98 return false, "signature-mismatch"; | 99 return false, "signature-mismatch"; |
99 end | 100 end |
100 | 101 |
101 local payload, err = json.decode(unb64url(raw_payload)); | 102 local payload, err = json.decode(unb64url(raw_payload)); |
106 return true, payload; | 107 return true, payload; |
107 end; | 108 end; |
108 | 109 |
109 load_public_key = function (public_key_pem) | 110 load_public_key = function (public_key_pem) |
110 local key = assert(crypto.import_public_pem(public_key_pem)); | 111 local key = assert(crypto.import_public_pem(public_key_pem)); |
111 assert(key:get_type() == "id-ecPublicKey", "incorrect key type"); | 112 assert(key:get_type() == key_type, "incorrect key type"); |
112 return key; | 113 return key; |
113 end; | 114 end; |
114 | 115 |
115 load_private_key = function (private_key_pem) | 116 load_private_key = function (private_key_pem) |
116 local key = assert(crypto.import_private_pem(private_key_pem)); | 117 local key = assert(crypto.import_private_pem(private_key_pem)); |
117 assert(key:get_type() == "id-ecPublicKey", "incorrect key type"); | 118 assert(key:get_type() == key_type, "incorrect key type"); |
118 return key; | 119 return key; |
119 end; | 120 end; |
120 }; | 121 }; |
121 end | 122 end |
122 | 123 |
124 -- RS***, PS*** | |
125 local function new_rsa_algorithm(name, c_sign, c_verify) | |
126 return new_crypto_algorithm(name, "rsaEncryption", c_sign, c_verify); | |
127 end | |
128 | |
129 -- ES*** | |
130 local function new_ecdsa_algorithm(name, c_sign, c_verify) | |
131 local function encode_ecdsa_sig(der_sig) | |
132 local r, s = crypto.parse_ecdsa_signature(der_sig); | |
133 return r..s; | |
134 end | |
135 | |
136 local function decode_ecdsa_sig(jwk_sig) | |
137 return crypto.build_ecdsa_signature(jwk_sig:sub(1, 32), jwk_sig:sub(33, 64)); | |
138 end | |
139 return new_crypto_algorithm(name, "id-ecPublicKey", c_sign, c_verify, encode_ecdsa_sig, decode_ecdsa_sig); | |
140 end | |
141 | |
123 local algorithms = { | 142 local algorithms = { |
124 HS256 = new_hmac_algorithm("HS256", hashes.hmac_sha256); | 143 HS256 = new_hmac_algorithm("HS256", hashes.hmac_sha256); |
125 ES256 = new_ecdsa_algorithm("ES256", crypto.ecdsa_sha256_sign, crypto.ecdsa_sha256_verify); | 144 ES256 = new_ecdsa_algorithm("ES256", crypto.ecdsa_sha256_sign, crypto.ecdsa_sha256_verify); |
145 RS256 = new_rsa_algorithm("RS256", crypto.rsassa_pkcs1_256_sign, crypto.rsassa_pkcs1_256_verify); | |
146 PS256 = new_rsa_algorithm("PS256", crypto.rsassa_pss_256_sign, crypto.rsassa_pss_256_verify); | |
126 }; | 147 }; |
127 | 148 |
128 local function new_signer(algorithm, key_input) | 149 local function new_signer(algorithm, key_input) |
129 local impl = assert(algorithms[algorithm], "Unknown JWT algorithm: "..algorithm); | 150 local impl = assert(algorithms[algorithm], "Unknown JWT algorithm: "..algorithm); |
130 local key = (impl.load_private_key or impl.load_key)(key_input); | 151 local key = (impl.load_private_key or impl.load_key)(key_input); |