OpenSSL作为库的行为记录在SSL_CTX_set_tmp_dh_callback()的手册页中。基本上,库本身不包含预先生成的 DH 参数,并且在提供此类参数之前将拒绝进行任何“DHE”握手。调用者(使用 OpenSSL 运行 SSL 服务器的应用程序)可以抢先提供 DH 参数(或者“附加”到包含服务器证书的结构,或者使用显式SSL_CTX_set_tp_dh()
call),或者通过一个回调函数,该函数将为每个相关的握手调用。回调方法使应用程序有机会根据密码套件和当前正在协商的其他参数调整 DH 参数,特别是它们的大小(这对于正确支持旧的“导出”密码套件很重要,但要少得多时下相关)。
OpenSSL 作为一段 C 代码,也带有命令行应用程序。例如,您可以使用openssl s_server
. 对apps/s_server.c
源文件的检查表明,除非使用显式 DH 参数(-dhparam
选项或附加在服务器的证书文件中)覆盖,否则使用具有 512 位模数 (!) 的默认参数。该模数的出处未指定;但它不能被认为是非常强大的,因为一个 530 位的离散对数至少已经解决了一次。
请注意,该apps/
目录还包含名为dh512.pem
、和的文件dh1024.pem
,它们分别是 512、1024、2048 和 4096 位的 DH 参数。这些显然来自SKIP,这是一个用于 IPsec 相关密钥管理的旧协议,我为此找到了一个 old draft,其中确实包含 OpenSSL 源代码作为和文件包含的 1024 位和 2048 位模数。有趣的是(或不是),使用的 512 位模数与.dh2048.pem
dh4096.pem
dh1024.pem
dh2048.pem
apps/s_server.c
dh512.pem
由于参数是调用者提供的,让我们看看在Apachemod_ssl
的常用 SSL 引擎中发生了什么。让我们长话短说:模数和生成器是硬编码的;它们在源代码中,在. 有 512 位模数和 1024 位模数。如果服务器的公钥长度为 512 位,将使用 512 位模数;1024 位模数将在所有其他情况下使用。因此,在实践中,它始终是 1024 位模数。源代码没有提及这些参数是如何生成的;它们与 OpenSSL 源代码附带的不同。显然,整个世界都使用了未知来源的 1024 位模数(至少,世界的一半依赖于 Apache+mod_ssl)。modules/ssl/ssl_engine_dh.c
我们可能会注意到 Apache 的未来版本,从 2013/09/29 的开发版本 2.5.0-dev 开始,将切换到从RFC 3526复制的 2048、3072 和 4096 位的硬编码 DH 参数。这些 DH 参数应该是有效的(例如,它们使用g = 2作为生成器,并且它们的 64 个最高有效位和最低有效位都是 1,这可能有助于蒙哥马利乘法的某些实现)并且“显然是安全的”。已知使用超过 1024 位的 DH 参数会破坏糟糕的 SSL 客户端实现,特别是 Java 7 之前(包括)Java 附带的客户端实现(Java 的 SSL 实现通常很好,但对于 DHE 支持,它有 1024 位限制,这有点愚蠢,因为 Java 有一个BigInteger
类这完全取决于大尺寸的 DHing 任务)。
必须说生成 DH 参数不需要那么慢。OpenSSL 坚持创建所谓的“安全素数”,其中“安全”更多的是营销而非科学。“安全素数”是一个素数p使得(p-1)/2也是一个素数。这允许使用2..p-2范围内的任何整数作为生成器g,特别是g = 2,这会产生轻微的性能优势。另一方面,产生一个安全素数是具有挑战性的:粗略地说,在处理 1024 位整数时,它们中只有 1/1000 是素数,而这些素数中只有 1/1000 是“安全素数”,因此存在搜索循环它尝试了一百万个潜在值。
从密码学上讲,也可以将 DSA 使用的相同类型的参数用作 DH 参数:p是素数,因此p-1是小得多的素数q的倍数,g是q阶的整数。这些可以在不到 1 秒的时间内生成,对 DH 来说没问题。