如何在没有 x5c 的情况下从 jwks 验证 JWT 的签名
How to validate signature of JWT from jwks without x5c
我有一个 JWT 安全令牌,需要通过 jwks 端点进行验证。
jwks 中的数据如下所示:
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"alg": "RS256",
"n": "......",
"kid": "2132132-b1e6-47e7-a30f-1831942f74bd"
},
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"alg": "RS256",
"n": "......",
"kid": "tsp-app-a"
},
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"alg": "RS256",
"n": ".....",
"kid": "tsp-app-b"
}
]
}
我已经尝试过第三方 api 但它看起来依赖于 x5c 密钥,而我的情况下不存在。
我的代码是:
public static bool Validate(JwtSecurityToken jsonToken)
{
bool result = false;
try
{
var headers = Jose.JWT.Headers<JWTHeader>(jsonToken.RawData);
var payload = Jose.JWT.Payload<JWTPayload>(jsonToken.RawData);
string jwk = "";
using (HttpClient cli = new HttpClient())
{
jwk = cli.GetStringAsync(MyclientUrlforWellknownjson).Result;
}
var jwkinfo = JsonSerializer.Deserialize<JWKS>(jwk);
//Find right key. Match kid and alg, (To be changed later. It is possible that there are multiple x5c elements in key)
var jwkkey = (from item in jwkinfo.keys where item.kid == headers.kid && item.alg == headers.alg select item).SingleOrDefault();
//If key was found then load its public key
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = null;
if (jwkkey != null)
{
//Get public key from well known information
byte[] key = System.Text.Encoding.ASCII.GetBytes(jwkkey.x5c[0]); //??todo
//Create cert
cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(key);
}
var o = Jose.JWT.Decode(jsonToken.RawData, cert.PublicKey.Key);
}
catch (Exception ex)
{
}
return result;
}
如何在没有 x5c 的情况下通过 jwks 验证 JWT?
使用 x5c
只是一种方法,但您也可以使用参数 e
(public 指数)和 n
检索 public 密钥(模数),也记录在 jose-jwt github page:
//If kid was found then load public key
if (jwkkey != null)
{
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.ImportParameters(new RSAParameters
{
Modulus = Base64Url.Decode(jwkkey.n),
Exponent = Base64Url.Decode(jwkkey.e)
});
}
// get the public key in PEM format, e.g. to use it on jwt.io
var pubkey = Convert.ToBase64String(key.ExportSubjectPublicKeyInfo());
const string pemHeader = "-----BEGIN PUBLIC KEY-----";
const string pemFooter = "-----END PUBLIC KEY-----";
var publicKeyPem = pemHeader + Environment.NewLine + pubkey + Environment.NewLine + pemFooter;
var o = Jose.JWT.Decode(jsonToken.RawData, key);
您还可以再次导出 PEM 格式的 public 密钥,如上面的代码所示,它将如下所示:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgIdJV4qWKyt3wkS66yBG5Ii9ew+eofuPU49TjlRIU5Iu5jX2mRMoHdcI7V78iKYSQHKYxz17cqzQyERxKnEiDgy/gwouStRgvPdm3H4rq//7p0t15SunsG2T1rEVf0sZEDnQ5qRkm7iqs6ZG1NqqIUtnOTd1Pd1MhbEqeENFtaPHvN37eZL82WmsQlJviFH4I9iZQVR/QT4GREQlRro8IjJTaloUyeDQTOQ+4ll1+4+g/ug2tZ+s9xleLzl5L9ZKSVJFhtMLn8WGaVldagarwa7kMLfuiVe8B5Lr7poQa4NCAR54ECPWoOHrABdPZKrkkxjVypTXUzL5cPzmzFC2xwIDAQAB
-----END PUBLIC KEY-----
然后使用该密钥在 https://jwt.io
上手动验证您的令牌
(在来自@Topaco 的 hint 之后更正了密钥导出)
我有一个 JWT 安全令牌,需要通过 jwks 端点进行验证。 jwks 中的数据如下所示:
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"alg": "RS256",
"n": "......",
"kid": "2132132-b1e6-47e7-a30f-1831942f74bd"
},
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"alg": "RS256",
"n": "......",
"kid": "tsp-app-a"
},
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"alg": "RS256",
"n": ".....",
"kid": "tsp-app-b"
}
]
}
我已经尝试过第三方 api 但它看起来依赖于 x5c 密钥,而我的情况下不存在。
我的代码是:
public static bool Validate(JwtSecurityToken jsonToken)
{
bool result = false;
try
{
var headers = Jose.JWT.Headers<JWTHeader>(jsonToken.RawData);
var payload = Jose.JWT.Payload<JWTPayload>(jsonToken.RawData);
string jwk = "";
using (HttpClient cli = new HttpClient())
{
jwk = cli.GetStringAsync(MyclientUrlforWellknownjson).Result;
}
var jwkinfo = JsonSerializer.Deserialize<JWKS>(jwk);
//Find right key. Match kid and alg, (To be changed later. It is possible that there are multiple x5c elements in key)
var jwkkey = (from item in jwkinfo.keys where item.kid == headers.kid && item.alg == headers.alg select item).SingleOrDefault();
//If key was found then load its public key
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = null;
if (jwkkey != null)
{
//Get public key from well known information
byte[] key = System.Text.Encoding.ASCII.GetBytes(jwkkey.x5c[0]); //??todo
//Create cert
cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(key);
}
var o = Jose.JWT.Decode(jsonToken.RawData, cert.PublicKey.Key);
}
catch (Exception ex)
{
}
return result;
}
如何在没有 x5c 的情况下通过 jwks 验证 JWT?
使用 x5c
只是一种方法,但您也可以使用参数 e
(public 指数)和 n
检索 public 密钥(模数),也记录在 jose-jwt github page:
//If kid was found then load public key
if (jwkkey != null)
{
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.ImportParameters(new RSAParameters
{
Modulus = Base64Url.Decode(jwkkey.n),
Exponent = Base64Url.Decode(jwkkey.e)
});
}
// get the public key in PEM format, e.g. to use it on jwt.io
var pubkey = Convert.ToBase64String(key.ExportSubjectPublicKeyInfo());
const string pemHeader = "-----BEGIN PUBLIC KEY-----";
const string pemFooter = "-----END PUBLIC KEY-----";
var publicKeyPem = pemHeader + Environment.NewLine + pubkey + Environment.NewLine + pemFooter;
var o = Jose.JWT.Decode(jsonToken.RawData, key);
您还可以再次导出 PEM 格式的 public 密钥,如上面的代码所示,它将如下所示:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgIdJV4qWKyt3wkS66yBG5Ii9ew+eofuPU49TjlRIU5Iu5jX2mRMoHdcI7V78iKYSQHKYxz17cqzQyERxKnEiDgy/gwouStRgvPdm3H4rq//7p0t15SunsG2T1rEVf0sZEDnQ5qRkm7iqs6ZG1NqqIUtnOTd1Pd1MhbEqeENFtaPHvN37eZL82WmsQlJviFH4I9iZQVR/QT4GREQlRro8IjJTaloUyeDQTOQ+4ll1+4+g/ug2tZ+s9xleLzl5L9ZKSVJFhtMLn8WGaVldagarwa7kMLfuiVe8B5Lr7poQa4NCAR54ECPWoOHrABdPZKrkkxjVypTXUzL5cPzmzFC2xwIDAQAB
-----END PUBLIC KEY-----
然后使用该密钥在 https://jwt.io
上手动验证您的令牌(在来自@Topaco 的 hint 之后更正了密钥导出)