Ssl &引用;“解密错误”;更改TLS 1.2的密码规范,但正确读取MAC

Ssl &引用;“解密错误”;更改TLS 1.2的密码规范,但正确读取MAC,ssl,encryption,tls1.2,Ssl,Encryption,Tls1.2,我正在尝试将一个旧的TLS1.0实现(我没有编写)更新到最新版本,以使用TLS1.2 作为第一步,我整合了TLS 1.1的变更。那没问题。它似乎工作得很好,我可以阅读https://example.com在TLS 1.1以及SSL实验室中 然后,我适应了TLS1.2对伪随机函数的更改(出于最实际的目的)而不是(更复杂和奇怪)。我第一次做错了,得到了一个无效的MAC错误,但这或多或少是我的错别字,我修正了它。然后无效的MAC错误消失了 但尽管如此,在发送ClientKeyExchange->Cha

我正在尝试将一个旧的TLS1.0实现(我没有编写)更新到最新版本,以使用TLS1.2

作为第一步,我整合了TLS 1.1的变更。那没问题。它似乎工作得很好,我可以阅读
https://example.com
在TLS 1.1以及SSL实验室中

然后,我适应了TLS1.2对伪随机函数的更改(出于最实际的目的)而不是(更复杂和奇怪)。我第一次做错了,得到了一个无效的MAC错误,但这或多或少是我的错别字,我修正了它。然后无效的MAC错误消失了

但尽管如此,在发送ClientKeyExchange->ChangeCipherSpec消息后,我从服务器返回了一个“解密错误”(不管是什么警报,
https://google.com
或我尝试过的任何东西)。我收集到ChangeCipherSpec消息只加密了一个字节,将其放入带有填充和MAC等的消息中

如果我将MAC随机调整一个字节,它就会返回到抱怨无效的MAC让我困惑的是

struct {
    opaque IV[SecurityParameters.record_iv_length];
    block-ciphered struct {
        opaque content[TLSCompressed.length];
        opaque MAC[SecurityParameters.mac_length]; // <-- server reads this fine!
        uint8 padding[GenericBlockCipher.padding_length];
        uint8 padding_length;
    };
} GenericBlockCipher;
struct{
不透明IV[安全参数.记录IV长度];
块加密结构{
不透明内容[TLSCompressed.length];

不透明MAC[SecurityParameters.MAC_length];//我可以想到造成此问题的两种不同情况:

  • 发送不正确的
    IV
    IV
    只会影响
    CBC
    模式解密中的第一个块,因此如果您的内容超过16字节(
    AES
    块大小),
    MAC
    部分数据将被正确解密
  • 如果您使用的填充结构不正确,则解密时可能会出错(因为填充验证失败),但内容将正确解密

  • 实际上,
    ChangeCipherSpec
    消息没有任何问题。问题出在消息中。它抱怨消息中解密的
    verify\u数据
    ,与预期的哈希不匹配(尽管加密/解密本身是正确的)

    但Wireshark日志中令人困惑的是,
    Finished
    消息显示在同一个日志行中,但名称为“
    EncryptedHandshakeMessage
    ”,这使它看起来像某种描述ChangeCipherSpec的标签或标签,但它不是。该消息实际上根本没有加密

    从第二个链接:

    实际上,您将看到未加密的客户端Hello、服务器Hello、证书、服务器密钥交换、证书请求、证书验证和客户端密钥交换消息。完成的握手消息是加密的,因为它发生在更改密码规范消息之后


    “希望有人有过将TLS 1.0或1.1升级到1.2的经验,并且可能会遇到类似的问题,原因是更改的版本不超过p_SHA256 MAC,并且版本号不一致”

    它们只提到了在RFC 5246中更新MD5/SHA1组合所需的三个位置中的两个:

    • 伪随机函数(PRF)中的MD5/SHA-1组合已替换为密码套件指定的PRF。本文档中的所有密码套件均使用p_SHA256

    • 数字签名元素中的MD5/SHA-1组合已替换为单个哈希。签名元素现在包含一个字段,该字段显式指定所使用的哈希算法

    (注意:第二种方法适用于证书,如果您还没有进行证书检查,那么您现在还不会进行证书检查。)

    在该部分中,他们没有提到的是第三个位置MD5/SHA-1组合更改,这是一个散列,用于
    Finished
    消息的
    verify_data
    的种子。但是,这一点也是对TLS 1.1的更改,在以下文档中详细描述:

    哈希表示握手消息的哈希。对于第5节中定义的PRF,哈希必须是用作PRF基础的哈希。任何定义不同PRF的密码套件也必须定义要在完成的计算中使用的哈希

    对于一个正式的规范,他们在“作为PRF基础的散列”(是HMAC还是普通散列?)上有点含糊不清,但它是普通散列。所以SHA256,除非密码套件的规范另有规定

    (请注意,密码套件可以规定验证_数据的长度超过12个字节,尽管规范中没有提到这样做。)


    “我有什么办法来找出服务器不满意的原因?”

    但我所做的只是将OpenSSL构建为一个静态调试库,并将其链接到一个简单的服务器。然后我添加了断点和插装,以查看它对什么感到不安。()

    大约2018年9月30日,在普通linux机器上:

    • git://git.openssl.org/openssl.git
    • /config no shared no asm-g3-O0-fno省略帧指针-fno内联函数no-ssl2 no-ssl3
    • make
    我使用的简单服务器来自。根据静态库编译,使用:

    • gcc-g-O0 simple.c-o simple-lssl-lcrypto-ldl-lpthread
    我按照此处生成证书的说明操作,但将AAs更改为
    localhost

    然后,我更改了简单服务器代码中的
    cert.pem=>rootCA.pem
    key.pem=>rootCA.key
    。我能够做到:

    wget https://localhost:4433 --no-check-certificate
    

    并成功返回
    test
    作为响应。因此,接下来的问题只是看看我的客户端在哪里导致了故障。

    Hm…只是猜测,但您使用的填充类型是否正确?如果您使用的填充不正确,则解密时会出错,但解密的数据是正确的。您的MAC将进行验证,但解密会产生错误