TLS 1.2 ECDHE_RSA 签名

TLS 1.2 ECDHE_RSA signature

我目前正在 Java TLS 服务器上工作。我正在尝试让以下 CipherSuite 工作:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

当我使用 openssl s_client 测试它时,我在 ServerKeyExchange 消息后收到以下错误:

140735242416208:error:1414D172:SSL routines:tls12_check_peer_sigalg:wrong signature type:t1_lib.c:1130:

这是在 Wireshark 中看到的 TLS 消息

握手因 decode_error 致命错误而失败。

所以我猜客户不喜欢选择的签名算法。

但我现在只根据 RFC 5246 Section-7.4.1.4.1

使用默认的 SignatureAndHashAlgorithm

If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), behave as if client had sent the value {sha1,rsa}.

(我仍在检查客户端是否提供这些默认值)

因为我在做 ECDHE_RSA 我相信我应该根据 RFC 4492 第 5.4 节对 serverECDHparams 进行散列和签名(第一个 post 这里只有 2 个链接抱歉:))

ServerKeyExchange.signed_params.sha_hash
        SHA(ClientHello.random + ServerHello.random +
                                          ServerKeyExchange.params);
struct {
    select (KeyExchangeAlgorithm) {
        case ec_diffie_hellman:
            ServerECDHParams params;
            Signature signed_params;
    };
} ServerKeyExchange;

我应该按照 RFC 2246 第 7.4.3 节

select (SignatureAlgorithm) {   
    case rsa:
        digitally-signed struct {
            opaque md5_hash[16];
            opaque sha_hash[20];
        };
} Signature;


md5_hash
MD5(ClientHello.random + ServerHello.random + ServerParams);

sha_hash
SHA(ClientHello.random + ServerHello.random + ServerParams);

我的 Java 关于签署 serverParams 的代码:

private byte[] getSignedParams(ChannelBuffer params)
        throws NoSuchAlgorithmException, DigestException, 
        SignatureException, InvalidKeyException {
    byte[] signedParams = null;
    ChannelBuffer signAlg = ChannelBuffers.buffer(2);
    MessageDigest md5 = MessageDigest.getInstance("MD5");
    MessageDigest sha = MessageDigest.getInstance("SHA-1");
    switch (session.cipherSuite.sign) {
        case rsa:
            signAlg.writeByte(2); // 2 for SHA1
            sha.update(clientRandom);
            sha.update(serverRandom);
            sha.update(params.toByteBuffer());
            md5.update(clientRandom);
            md5.update(serverRandom);
            md5.update(params.toByteBuffer());
            signedParams = concat(md5.digest(), sha.digest());
        break;
    }
    signAlg.writeByte(session.cipherSuite.sign.value); // for RSA he byte is one
    ChannelBuffer signLength = ChannelBuffers.buffer(2);
    signLength.writeShort(signedParams.length);
    return concat(signAlg.array(),concat(signLength.array(),signedParams));
}

所以我的问题基本上是:我对这一切都错了吗?如果是这样,我做错了什么?

感谢您的宝贵时间! :)

又是我,我似乎已经解决了我注意到的两件事:

  1. 关于我的 Java 代码,MessageDigest class 只进行散列而不签名,所以我现在使用签名 class。
  2. 看来我只需要在TLS1.2中使用SHA1签名我根本不需要做MD5。

第二项是我应该在 RFC 中找到但没有找到的(也许它写在某个地方,我不知道)我认为这对人们有用,即使他们没有做 Java;)

我的代码现在的样子:

private byte[] getSignedParams(ChannelBuffer params)
        throws NoSuchAlgorithmException, DigestException, 
        SignatureException, InvalidKeyException {
    byte[] signedParams = null;
    Signature signature = Signature.getInstance(selectedSignAndHash.toString());
    ChannelBuffer signAlg = ChannelBuffers.buffer(2);
    signAlg.writeByte(selectedSignAndHash.hash.value);
    signature.initSign(privateKey);

    signature.update(clientRandom);
    signature.update(serverRandom);
    signature.update(params.toByteBuffer());

    signedParams = signature.sign();

    signAlg.writeByte(session.cipherSuite.sign.value);
    ChannelBuffer signLength = ChannelBuffers.buffer(2);
    signLength.writeShort(signedParams.length);
    return concat(signAlg.array(), concat(signLength.array(), signedParams));
}

代码不同是因为我在两者之间添加了一个函数来从客户端提供的列表中选择要使用的 SignatureAndHashAlgorithm。但是您可以将其修改为仅使用 SHA1withRSA 进行响应,因为这似乎是默认的 HashAndSignatureAlgorithm。