AWS KMS 签名 returns 我的 JWT 签名无效
AWS KMS signature returns Invalid Signature for my JWT
我正在尝试生成一个简单的 JWT,使用 ES256 和 KMS。肉眼看起来一切都很好。但是当我通过 jwt.io 测试它时,我得到了“无效签名”。代码很简单:
public async Task<string> GenerateJwt(object payload)
{
var encodedHeader = Base64Encoder.EncodeBase64Url(JsonSerializer.Serialize(_header));
var encodedPayload = Base64Encoder.EncodeBase64Url(JsonSerializer.Serialize(payload));
var signatureData = Encoding.ASCII.GetBytes(encodedHeader + "." + encodedPayload);
var signature = await _signingService.Sign(signatureData);
var encodedSignature = Base64Encoder.ReplaceSpecialUrlCharacters(Convert.ToBase64String(signature));
return encodedHeader + "." + encodedPayload + "." + encodedSignature;
}
SigningService
看起来像这样:
public async Task<byte[]> Sign(byte[] signatureData)
{
using var memoryStream = new MemoryStream(signatureData, 0, signatureData.Length);
var signRequest = new SignRequest()
{
KeyId = _signingKeyId,
Message = memoryStream,
SigningAlgorithm = SigningAlgorithmSpec.ECDSA_SHA_256
};
SignResponse signResponse = await _keyManagementService.SignAsync(signRequest);
return signResponse.Signature.ToArray();
}
_keyManagementService
是来自 AWSSDK.KeyManagementService 3.5.2.6
的 IAmazonKeyManagementService
在 KMS 中,密钥是这样设置的:
- 关键规格:ECC_NIST_P256
- 密钥用法:签名和验证
- 签名算法:ECDSA_SHA_256
Public KMS 密钥(使用 localstack)
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj7Cy/Gbx3jnuPdanuBSjuUmdnr7tQ/BcOytDlFoHWdNA1scc6RwNwqnNbmRE0BmwnlFNDVGxWU5oycTig8p0KQ==
生成的输出示例
eyJhbGciOiJFUzI1NiJ9.eyJ0ZXN0MSI6MSwidGVzdDIiOiJ0d28iLCJ0ZXN0MyI6ZmFsc2V9.MEYCIQCiatnRhYGBKgdJj9LECe7mJ4bhhkVTvFSgpVI3Dm14pwIhAOrHAu0vqKvVwdgpAhaU7KOhiIBZdcEOuzfXrdXldCFQ
如果它使用内置工具对其进行签名(只需替换上面的 signatureData 行),我会在 jwt.io.
中对其进行验证
var ecdsa = ECDsa.Create();
ecdsa.GenerateKey(ECCurve.NamedCurves.nistP256);
var signatureData = ecdsa.SignData(signatureData, HashAlgorithmName.SHA256);
欢迎任何意见,因为感觉我已经测试了所有内容...
问题是 KMS returns 另一种格式的签名:
DER-encoded object as defined by ANS X9.62–2005
而 JWT 的格式应根据 https://www.rfc-editor.org/rfc/rfc7515#appendix-A.3.1
R || S
所以我使用 BouncyCastle 添加了一个转换方法,并在将其转换为 base64url 之前调用了它:
private byte[] ConvertSignature(byte[] signature)
{
var asn1 = Asn1Object.FromByteArray(signature) as DerSequence;
if (asn1 == null)
return Array.Empty<byte>();
if (asn1.Count < 2)
return Array.Empty<byte>();
var r = asn1[0] as DerInteger;
var s = asn1[1] as DerInteger;
if (r == null || s == null)
return Array.Empty<byte>();
return Array.Empty<byte>()
.Concat(r.Value.ToByteArrayUnsigned())
.Concat(s.Value.ToByteArrayUnsigned())
.ToArray();
}
我正在尝试生成一个简单的 JWT,使用 ES256 和 KMS。肉眼看起来一切都很好。但是当我通过 jwt.io 测试它时,我得到了“无效签名”。代码很简单:
public async Task<string> GenerateJwt(object payload)
{
var encodedHeader = Base64Encoder.EncodeBase64Url(JsonSerializer.Serialize(_header));
var encodedPayload = Base64Encoder.EncodeBase64Url(JsonSerializer.Serialize(payload));
var signatureData = Encoding.ASCII.GetBytes(encodedHeader + "." + encodedPayload);
var signature = await _signingService.Sign(signatureData);
var encodedSignature = Base64Encoder.ReplaceSpecialUrlCharacters(Convert.ToBase64String(signature));
return encodedHeader + "." + encodedPayload + "." + encodedSignature;
}
SigningService
看起来像这样:
public async Task<byte[]> Sign(byte[] signatureData)
{
using var memoryStream = new MemoryStream(signatureData, 0, signatureData.Length);
var signRequest = new SignRequest()
{
KeyId = _signingKeyId,
Message = memoryStream,
SigningAlgorithm = SigningAlgorithmSpec.ECDSA_SHA_256
};
SignResponse signResponse = await _keyManagementService.SignAsync(signRequest);
return signResponse.Signature.ToArray();
}
_keyManagementService
是来自 AWSSDK.KeyManagementService 3.5.2.6
IAmazonKeyManagementService
在 KMS 中,密钥是这样设置的:
- 关键规格:ECC_NIST_P256
- 密钥用法:签名和验证
- 签名算法:ECDSA_SHA_256
Public KMS 密钥(使用 localstack)
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj7Cy/Gbx3jnuPdanuBSjuUmdnr7tQ/BcOytDlFoHWdNA1scc6RwNwqnNbmRE0BmwnlFNDVGxWU5oycTig8p0KQ==
生成的输出示例
eyJhbGciOiJFUzI1NiJ9.eyJ0ZXN0MSI6MSwidGVzdDIiOiJ0d28iLCJ0ZXN0MyI6ZmFsc2V9.MEYCIQCiatnRhYGBKgdJj9LECe7mJ4bhhkVTvFSgpVI3Dm14pwIhAOrHAu0vqKvVwdgpAhaU7KOhiIBZdcEOuzfXrdXldCFQ
如果它使用内置工具对其进行签名(只需替换上面的 signatureData 行),我会在 jwt.io.
中对其进行验证var ecdsa = ECDsa.Create();
ecdsa.GenerateKey(ECCurve.NamedCurves.nistP256);
var signatureData = ecdsa.SignData(signatureData, HashAlgorithmName.SHA256);
欢迎任何意见,因为感觉我已经测试了所有内容...
问题是 KMS returns 另一种格式的签名:
DER-encoded object as defined by ANS X9.62–2005
而 JWT 的格式应根据 https://www.rfc-editor.org/rfc/rfc7515#appendix-A.3.1
R || S
所以我使用 BouncyCastle 添加了一个转换方法,并在将其转换为 base64url 之前调用了它:
private byte[] ConvertSignature(byte[] signature)
{
var asn1 = Asn1Object.FromByteArray(signature) as DerSequence;
if (asn1 == null)
return Array.Empty<byte>();
if (asn1.Count < 2)
return Array.Empty<byte>();
var r = asn1[0] as DerInteger;
var s = asn1[1] as DerInteger;
if (r == null || s == null)
return Array.Empty<byte>();
return Array.Empty<byte>()
.Concat(r.Value.ToByteArrayUnsigned())
.Concat(s.Value.ToByteArrayUnsigned())
.ToArray();
}