TLS 1.2 ECDHE_RSA подпись

В настоящее время я работаю на сервере TLS Java. Я пытаюсь заставить работать следующий CipherSuite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

Когда я тестирую его с помощью openssl s_client, я получаю следующую ошибку после сообщения ServerKeyExchange:

140735242416208: ошибка:1414D172: процедуры SSL:tls12_check_peer_sigalg: неверный тип подписи:t1_lib.c:1130:

Вот сообщение TLS, увиденное в Wireshark Сообщение TLS, как видно в Wireshark

Рукопожатие терпит неудачу при фатальной ошибке decode_error.

Поэтому я думаю, что клиенту не нравится выбранный алгоритм подписи.

Но я пока что использую только SignatureAndHashAlgorithm по умолчанию в соответствии с RFC 5246, раздел 7.4.1.4.1.

Если согласованный алгоритм обмена ключами является одним из (RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), ведите себя так, как если бы клиент отправил значение {sha1, rsa}.

(Я все еще проверяю, предлагает ли клиент эти значения по умолчанию, хотя)

Так как я делаю ECDHE_RSA, я считаю, что должен хешировать и подписать сервер ECDHparams в соответствии с RFC 4492, раздел 5.4 (первый пост здесь, так что только 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 ответ

Решение

Это снова я, я, кажется, исправил свою проблему 2 вещи, которые я заметил:

  1. Что касается моего Java-кода, то класс MessageDigest не выполняет хэширование, поэтому я теперь использую класс Signature.
  2. Кажется, мне нужно только подписать с использованием SHA1 в TLS1.2 Мне вообще не нужно делать 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 по умолчанию.

Другие вопросы по тегам