util/jwt.lua
changeset 12703 b3d0c1457584
parent 12700 27a72982e331
child 12706 f63176781940
--- a/util/jwt.lua	Sat Jul 02 11:51:24 2022 +0100
+++ b/util/jwt.lua	Sat Jul 02 12:26:43 2022 +0100
@@ -66,8 +66,7 @@
 	return { sign = sign, verify = verify, load_key = load_key };
 end
 
--- ES*** family
-local function new_ecdsa_algorithm(name, c_sign, c_verify)
+local function new_crypto_algorithm(name, key_type, c_sign, c_verify, sig_encode, sig_decode)
 	local static_header = new_static_header(name);
 
 	return {
@@ -75,25 +74,27 @@
 			local encoded_payload = json.encode(payload);
 			local signed = static_header .. b64url(encoded_payload);
 
-			local der_sig = c_sign(private_key, signed);
+			local signature = c_sign(private_key, signed);
+			if sig_encode then
+				signature = sig_encode(signature);
+			end
 
-			local r, s = crypto.parse_ecdsa_signature(der_sig);
-
-			return signed.."."..b64url(r..s);
+			return signed.."."..b64url(signature);
 		end;
 
-	verify = function (public_key, blob)
+		verify = function (public_key, blob)
 			local signed, signature, raw_payload = decode_jwt(blob, name);
 			if not signed then return nil, signature; end -- nil, err
 
-			local raw_signature = unb64url(signature);
-
-			local der_sig = crypto.build_ecdsa_signature(raw_signature:sub(1, 32), raw_signature:sub(33, 64));
-			if not der_sig then
+			signature = unb64url(signature);
+			if sig_decode and signature then
+				signature = sig_decode(signature);
+			end
+			if not signature then
 				return false, "signature-mismatch";
 			end
 
-			local verify_ok = c_verify(public_key, signed, der_sig);
+			local verify_ok = c_verify(public_key, signed, signature);
 			if not verify_ok then
 				return false, "signature-mismatch";
 			end
@@ -108,21 +109,41 @@
 
 		load_public_key = function (public_key_pem)
 			local key = assert(crypto.import_public_pem(public_key_pem));
-			assert(key:get_type() == "id-ecPublicKey", "incorrect key type");
+			assert(key:get_type() == key_type, "incorrect key type");
 			return key;
 		end;
 
 		load_private_key = function (private_key_pem)
 			local key = assert(crypto.import_private_pem(private_key_pem));
-			assert(key:get_type() == "id-ecPublicKey", "incorrect key type");
+			assert(key:get_type() == key_type, "incorrect key type");
 			return key;
 		end;
 	};
 end
 
+-- RS***, PS***
+local function new_rsa_algorithm(name, c_sign, c_verify)
+	return new_crypto_algorithm(name, "rsaEncryption", c_sign, c_verify);
+end
+
+-- ES***
+local function new_ecdsa_algorithm(name, c_sign, c_verify)
+	local function encode_ecdsa_sig(der_sig)
+		local r, s = crypto.parse_ecdsa_signature(der_sig);
+		return r..s;
+	end
+
+	local function decode_ecdsa_sig(jwk_sig)
+		return crypto.build_ecdsa_signature(jwk_sig:sub(1, 32), jwk_sig:sub(33, 64));
+	end
+	return new_crypto_algorithm(name, "id-ecPublicKey", c_sign, c_verify, encode_ecdsa_sig, decode_ecdsa_sig);
+end
+
 local algorithms = {
 	HS256 = new_hmac_algorithm("HS256", hashes.hmac_sha256);
 	ES256 = new_ecdsa_algorithm("ES256", crypto.ecdsa_sha256_sign, crypto.ecdsa_sha256_verify);
+	RS256 = new_rsa_algorithm("RS256", crypto.rsassa_pkcs1_256_sign, crypto.rsassa_pkcs1_256_verify);
+	PS256 = new_rsa_algorithm("PS256", crypto.rsassa_pss_256_sign, crypto.rsassa_pss_256_verify);
 };
 
 local function new_signer(algorithm, key_input)