如何解决使用System.IdentityModel.Tokens.Jwt使用x5c标头参数创建JWT令牌 #Edit
我的项目正在基于.NET Core和System.IdentityModel.Tokens.Jwt
nuget包构建身份验证服务。我们要创建包含公共密钥证书(或证书链)的JWT令牌,这些令牌可用于验证JWT数字签名。商业身份提供者(SaaS)可以做到这一点,并且在JWT规范中通过称为“ x5c”的标头参数来支持。但是到目前为止,我无法使用System.IdentityModel.Tokens.Jwt
使它正常工作。
我能够创建使用证书签名的JWT令牌。证书是自签名的,并使用openssl(下面包含的命令)创建。 我在C#中的测试代码如下:
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
// more usings..
public static string GenerateJwtToken(int exampleAccountId,string x509CertFilePath,string x509CertFilePassword)
{
var tokenHandler = new JwtSecurityTokenHandler();
var signingCert = new X509Certificate2(x509CertFilePath,x509CertFilePassword);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name,exampleAccountId.ToString()) }),Expires = DateTime.UtcNow.AddDays(30),Audience = "myapp:1",Issuer = "self",SigningCredentials = new X509SigningCredentials(signingCert,SecurityAlgorithms.RsaSha512Signature),Claims = new Dictionary<string,object>()
{
["test1"] = "hello world",["test2"] = new List<int> { 1,2,4,9 }
}
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
生成的令牌标头在jwt.io中反序列化为此:
{
"alg": "RS512","kid": "193A49ED67F22850F4A95258FF07571A985BFCBE","x5t": "GTpJ7WfyKFD0qVJY_wdXGphb_L4","typ": "JWT"
}
问题是,我也希望获得“ x5c”标头参数输出。这样做的原因是,我的项目正在尝试将证书与公共密钥包括在一起,以验证令牌本身内部的令牌签名,而“ x5c”是实现此目的的好方法。但是我无法使它正常工作。
我曾尝试在AdditionalHeaderClaims
上与SecurityTokenDescriptor
一起手动添加x5c,但是它并未在令牌中输出。
有人知道如何做到这一点吗?或者您可以向我指出有关该主题的一些扎实资源吗?
顺便说一下,这就是我生成使用的证书的方式(在Windows上):
openssl genrsa -out private2048b.key 2048
openssl req -new -key private2048b.key -out myrequest2048.csr -config <path to openssl.cfg>
openssl x509 -req -days 3650 -in myrequest2048.csr -signkey private2048b.key -out public2048b.crt
openssl pkcs12 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in public2048b.crt -inkey private2048b.key -out mypkcs2048.pfx -name "Testtest"
PFX是代码中正在读取和使用的文件。
后代更新
使用Abdulrahman Falyoun的答案,在序列化JWT令牌之前,将代码的最后部分更新为使用token.Header.Add
手动添加“ x5c”标头参数。令牌必须转换为JwtSecurityToken。
这项工作有效,并在https://jwt.io中创建了一个有效的令牌(并具有可以立即验证的签名):
// create JwtSecurityTokenHandler and SecurityTokenDescriptor instance before here..
var exportedCertificate = Convert.ToBase64String(signingCert.Export(X509ContentType.Cert,x509CertFilePassword));
// Add x5c header parameter containing the signing certificate:
var token = tokenHandler.CreateToken(tokenDescriptor) as JwtSecurityToken;
token.Header.Add(JwtHeaderParameterNames.X5c,new List<string> { exportedCertificate });
return tokenHandler.WriteToken(token);
解决方法
什么是x5c?
“ x5c”(X.509证书链)标头参数包含与用于对JWS进行数字签名的密钥相对应的X.509公钥证书或证书链[RFC5280]。证书或证书链表示为证书值字符串的JSON数组。数组中的每个字符串都是以base64编码(不是base64url编码)的DER [ITU.X690.2008] PKIX证书值。包含与用于对JWS进行数字签名的密钥相对应的公用密钥的证书必须是第一证书。可以附加其他证书,每一个后续证书都是用来证明前一个证书的证书。接收者必须根据RFC 5280 [RFC5280]验证证书链,并且如果发生任何验证失败,则认为证书或证书链无效。此标头参数的使用是可选的。
注意
从安全角度考虑-不要使用x5c证书直接验证签名。在那种情况下,任何人都可以提供自己的证书并欺骗任何身份。 如果x5t / x5t#S256标头用于标识签名者,请检查是否信任x5c或x5t#S256(或其发行者)在指定的iss下提供的证书,然后才应验证签名。
所以要建立X509链
X509Chain chain = new X509Chain()
bool success = chain.Build(cert);
if (!success) throw Error
然后对于每个chain.ChainElements
值,使用Certificate属性RawValue
属性(并使用base64对其进行编码)。
最后,您获得了x5c
的字符串,应仅将其提供给jwt
的标头。
请参阅以下链接
Create JWK Set Containing Certificates
Generate x5c certificate chain from JWK
How to obtain JWKs and use them in JWT signing?
How to get x5c from RSACryptoServiceProvider
希望它有用。
#Edit
如果问题是向标头提供x5c
,则必须使用
token.Header.Add(name,value)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。