TLS 1.2 ECDHE_RSA签名

时间:2016-07-07 08:10:09

标签: ssl java digital-signature rsa diffie-hellman

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

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

  

140735242416208:错误:1414D172:SSL   例程:tls12_check_peer_sigalg:签名类型错误:t1_lib.c:1130:

以下是Wireshark中显示的TLS消息 The TLS message as seen in Wireshark

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

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

但我现在只使用默认的SignatureAndHashAlgorithm RFC 5246 Section-7.4.1.4.1

  

如果协商密钥交换算法是(RSA,DHE_RSA,   DH_RSA,RSA_PSK,ECDH_RSA,ECDHE_RSA),表现得好像客户端已发送   值{sha1,rsa}。

(我还在检查客户端是否确实提供了这些默认值)

由于我正在做ECDHE_RSA,我相信我应该根据RFC 4492第5.4节哈希并签署serverECDHparams(首先发布在这里,所以只有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);

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

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 个答案:

答案 0 :(得分:0)

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

  1. 关于我的Java代码,MessageDigest类只进行哈希没有签名,所以我现在使用Signature类。
  2. 我似乎只需要在TLS1.2中使用SHA1签名我根本不需要做MD5。
  3. 第二项是我应该在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。