【问题标题】:AWS KMS signature returns Invalid Signature for my JWTAWS KMS 签名为我的 JWT 返回无效签名
【发布时间】:2021-02-15 17:01:59
【问题描述】:

我正在尝试使用 ES256 和 KMS 生成一个简单的 JWT。肉眼看起来一切都很好。但是当我通过 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

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

欢迎任何意见,因为感觉就像我已经测试了所有内容......

【问题讨论】:

  • 您将什么放入 jwt.io 作为要验证的公钥?如果我没记错的话,这很痛苦,因为 jwt.io 期望密钥例如有页眉和页脚:-----BEGIN PUBLIC KEY----------END PUBLIC KEY-----...
  • 在 KMS 中有一个公钥选项卡,其中包含页眉和页脚。所以每当我尝试过时,我都会确保它们在那里。
  • 您可以在此处发布该公钥和使用该密钥签名的令牌之一,以便我们对其进行验证。顺便说一句:您应该使用库来创建和解压缩 jwt 令牌,例如正确处理 iatexp 的库,以及 iss...

标签: amazon-web-services .net-core jwt .net-core-3.1 amazon-kms


【解决方案1】:

问题在于 KMS 以另一种格式返回签名:

ANS X9.62–2005 定义的 DER 编码对象

而根据https://www.rfc-editor.org/rfc/rfc7515#appendix-A.3.1,JWT 的格式应该是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();
}

【讨论】:

    猜你喜欢
    • 2021-02-28
    • 2020-03-13
    • 2016-12-29
    • 2020-01-21
    • 2018-05-08
    • 2018-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多