我已经实现(Windows 10.0.17763.0/VS2017/C++)一个客户端/服务器应用程序,该应用程序使用schannel进行安全通信。现在的要求是仅使用一组密码套件进行某些客户端和服务器之间的通信。
使用BCryptAddContextFunction / BCryptRemoveContextFunction API,我可以更改SChannel中支持的密码,但这是系统范围的设置,不仅限于我的应用程序。
为了以编程方式控制它,我尝试在AcquireCredentialsHandle中使用ALG_ID。
以下是我的应用程序应支持的唯一密码套件。

  • TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

  • 所以我构造了如下的ALG_ID。
    std::vector<ALG_ID> algos       = { CALG_AES_256 , CALG_AES_128 , CALG_SHA_384 , CALG_SHA_256,CALG_ECDH_EPHEM,CALG_DH_EPHEM };
    schannelCred.cSupportedAlgs     = static_cast<DWORD>(algos.size());
    schannelCred.palgSupportedAlgs  = &algos[0];
    
    使用Wireshark,我发现以下是我的应用使用上述ALG_ID在客户端中提出的密码套件,
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256

  • 问题是,
  • 如何仅允许 AES_GCM批量加密?当我将CALG_AES添加到列表中时,将同时允许使用AES_GCM和AES_CBC。
  • 我如何控制签名?添加CALG_ECDH_EPHEM启用了TLS_ECDHE_ECDSA以及TLS_ECDHE_RSA(我只需要TLS_ECDHE_RSA)。
    将CALG_RSA_SIGN添加到ALG_ID会删除TLS_ECDHE_ECDSA,但它开始允许TLS_RSA_ *密码套件。
  • 最佳答案

    调用AcquireCredentialsHandle函数时,可以使用SCH_CREDENTIALS结构而不是SCHANNEL_CRED。
    您使用CRYPTO_SETTINGS结构数组创建TLS_PARAMETERS。每个CRYPTO_SETTINGS结构都定义了密钥交换,签名,摘要和批量密码算法的限制。然后,您可以选择满足您的应用程序要求的组合。此结构(SCH_CREDENTIALS)与SCHANNEL_USE_BLACKLIST标志/ approach一起使用,从而禁用了指定TLS session 不需要的功能。通过CRYPTO_SETTINGS结构的eAlgorithmUsage和strCngAlgId成员的正确组合,我认为您可以实现TLS session 所需的行为。
    请参阅https://docs.microsoft.com/zh-cn/windows/win32/api/schannel/ns-schannel-sch_credentials
    https://docs.microsoft.com/en-us/windows/win32/api/schannel/ns-schannel-tls_parameters
    例如,如果您在限制之一中包含AES_CBC,并带有适当的eAlgorithmUsage成员值(在本例中为TlsParametersCngAlgUsageCipher),则应将其作为批量加​​密算法从 session 中排除。确保从该eAlgorithmUsage的限制中排除AES_GCM。
    关于控制签名算法,值为TlsParametersCngAlgUsageSignature的CRYPTO_SETTINGS结构eAlgorithmUsage成员限制使用分配给strCngAlgId成员的算法作为该 session 的签名算法。您还可以确定要限制的最小和最大长度。
    最后,
    “Protocols项下注册表项中的DisabledByDefault值不优先于SCHANNEL_CRED结构中定义的grbitEnabledProtocols值,该结构包含Schannel凭据的数据。” (https://docs.microsoft.com/en-us/troubleshoot/windows-server/windows-security/restrict-cryptographic-algorithms-protocols-schannel)。
    在该TLS session 的TLS_PARAMETER结构的grbitDisabledProtocols成员上也是如此。
    如果您精心设计了签名算法,密钥交换,批量加密和摘要的限制条件的正确组合,则可以从密码套件中的特定位置过滤掉不需要的算法。

    关于c++ - SChannel中的密码套件选择,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63075804/

    10-09 19:53