为什么 IDP 对客户端断言 JWT 响应无效签名

问题描述 投票:0回答:1

我正在使用 Dart JsonWebToken 库 https://pub.dev/packages/dart_jsonwebtoken 为 OAuth2 客户端凭证授予生成客户端断言 JWT。

JWT 似乎正确生成,并根据 JWT.IO 正确签名,并使用公钥和私钥进行测试。

但是,当在 client_assertion 字段中使用客户端凭据授予提交时,它会返回无效的令牌签名。

错误:

“invalid_client”“无效的令牌签名”

我已经使用 KJUR 库与邮递员进行了测试,并且在请求中使用了相同的密钥、声明和算法,它有效。因此,我呼吁社区提供帮助,为我指明正确的方向。

代码示例:(Dart - 无效签名)

 Future<String> _generateJWT() async {
    final current_time = DateTime.now();
    final expiration_time = current_time.add(Duration(minutes: 50));
    final issued_time = current_time;
    final uuid = Uuid();
    final jwt = JWT(
      header: Map.from({
        'alg': 'PS512',
        'kid': 'kid1234546',
        'typ': 'JWT',
      }),
      {
        'sub': clientID,
        'aud':
            'https://provider.com/oauth/v2.0/token',
        'iss': clientID,
        'exp': (expiration_time.millisecondsSinceEpoch ~/ 1000),
        'iat': (issued_time.millisecondsSinceEpoch ~/ 1000) - 120,
        'jti': uuid.v4(),
      },
    );

    final token = jwt.sign(
      RSAPrivateKey(privateKey),
      algorithm: JWTAlgorithm.PS512,
    );

    return token;
  }

代码示例:工作(Postman/KJUR)

const clientAssertionJwt = utils.generateSignedRequestJWT(
  KJUR.jws.JWS.sign,
  {
    alg: 'PS512',
    kid,
    typ: 'JWT',
  },
  {
    sub: clientId,
    aud,
    iss: clientId,
    exp: Math.floor(Date.now() / 1000) + 3590,
    iat: Math.floor(Date.now() / 1000) - 120,
    jti: v4(),
  },
  privateKey,
);

库实用函数

const generateSignedRequestJWT = (sign, header, payload, privateKey) => {
  if (!header || !payload || !privateKey) {
    throw new Error(
      `utils.generateSignedRequestJWT - Missing required argument. Following arguments have been provided: header: ${!!header}, payload: ${!!payload}, privateKey: ${!!privateKey}`,
    );
  }

  try {
    // KJUR.jws.JWS.sign
    return sign(
      header.alg,
      JSON.stringify(header),
      JSON.stringify(payload),
      privateKey,
    );
  } catch (err) {
    console.error(
      'utils.generateSignedRequestJWT - Failed to generate signed request JWT',
      err,
      {
        header,
        payload,
        privateKeyDefined: !!privateKey,
      },
    );

    return null;
  }
};
flutter dart oauth-2.0 openid-connect
1个回答
0
投票

这是 Dart 库中的一个错误。除了PS512之外,PS384也不能使用。另一方面,PS256 可以工作。
原因是该库对 PSS 使用 32 字节的固定盐长度,请参阅此处
但是,32 字节对于 PS384 和 PS512 来说是不正确的。 RFC 7518 在章节3.5 使用 RSASSA-PSS 进行数字签名中定义:

盐值的大小与 哈希函数输出。

这意味着对于以 SHA-256 作为摘要的 PS256,盐长度必须为 32 字节,对于以 SHA-384 作为摘要的 PS384,盐长度必须为 48 字节,对于以 SHA-512 作为摘要的 PS512,盐长度必须为 64 字节。因此PS256可以工作,但PS384和PS512不行。

这也可以通过使用 RSA/PSS 显式验证 PS512 签名来进行检查。 PointyCastle 并应用 32 字节的盐长度。则验证成功。


显然您已经提交了问题(#58)。

请注意,使用 KJUR 生成的签名令牌较小,因为由于某种原因 KJUR 没有考虑

jti
声明。签名本身(第三部分)大小相同。

您应该删除这部分,因为这只会分散对实际问题的注意力,而是将固定盐长度命名为原因。

© www.soinside.com 2019 - 2024. All rights reserved.