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); |