OpenSSL CONF 库可被用于读取配置文件。该库可用于 OpenSSL 主(master)配置文件 openssl.cnf
,还有比如 SPKAC
文件这样的地方,以及 x509
工具的认证扩展文件中。OpenSSL 的应用也可将 CONF 库用于它们自己的用途。
一个配置文件可以被分为多个段(section)。每个段都以一行 [ 段名 ]
作为起始,并以另一个段的起始或者文件结束作为结尾。一个段名可以包含字母、数字字符,以及下划线。
配置文件的第一个段比较特殊,被称为 default
(默认)段。该段通常不会有名字,并从文件头一直延续至第一个具名段。当查找一个键(key)时,它先在具名段中查找,若找不到再在默认段查找。
环境变量会被映射至 ENV
段。
井号 #
表示注释的开始。
包含其他文件可以用 .include
指令(directive)后缀一个路径来实现。若路径指向一个文件夹,文件夹中所有以 .cnf
或 .conf
后缀的文件均会被包含进来。不支持目录下文件的递归包含。这意味着,被包含的文件也可以具有 .include
指令,但该指令只会包含指定目录下的常规文件。对目录的包含是基于 POSIX IO 的。
强烈建议在 .include
指令中使用绝对路径。相对路径是基于应用当前的工作路径的,除非包含 .include
指令的配置文件是应用特有的,否则它就不能正常工作。
可以在 .include
指令和路径之间添加可选的等号 =
以及白空格,来提高该配置文件对不支持 .include
语法的旧版 OpenSSL 的兼容性。旧版软件会对不加等号的配置报错,但会直接忽略加了等号的包含语句。
配置文件的每个段都包括了一系列型如 键=值
的键值对。
键字符串可以包含任意字母数字字符,以及少量的标点符号,例如 .
/ ,
/ ;
/ _
。
值字符串是等号之后、行尾之前的字符串,任何首位的白空格都会被忽略。
值字符串会执行变量扩展。可以通过 $var
或者 ${var}
的形式来产生:该形式会在当前的段中查找该键对应的变量值。也可以使 $section::name
或者 ${section::name}
形式的语法来引用其他段的变量。以 $ENV::name
的形式来获取环境变量中的值。也可以用 ENV::name
来设置环境变量值,这种方法仅对调用 CONF
库来查找环境变量时有效,对于直接调用 getenv() 无效。在变量扩展后,值字符串的长度不应该超过 64k,否则会出错。
可以用任何形式的引号或者反斜线 \
来转义特定的字符。在值字符串的行尾使用 \
,让该值跨行。也可以识别转义序列 \n
/ \r
/ \b
/ \t
。
上文中所有运用于值的的扩展和转义规则都适用于 .include
指令的路径中。
通过主 OpenSSL 配置文件,或者一个替换的配置文件,应用可以自动配置 OpenSSL 的特定部分。openssl
工具具有这样的功能:任何子命令都会使用主 OpenSSL 配置文件,除非子命令中通过选项指定了一个替换配置文件。
要启用库配置,默认段需要包含一个正确的行,用来指向主配置段。在 openssl
工具中,默认的键名为 openssl_conf
。其他应用可以使用其它的键名,比如 myapplication_conf
。所有库配置行均出现在配置文件头部的默认段中。
配置段应该有一系列包含特定模块配置信息的键值对。键表示配置模块的名称。而_值的含义则是模块特定的:举例来说,它可以表示一个在下方定义的、包含了配置模块特定信息的配置段:
# 这段配置必须出现在默认段中
openssl_conf = openssl_init
[openssl_init]
oid_section = new_oids
engines = engine_section
[new_oids]
... 新的 oid ...
[engine_section]
... 引擎相关 ...
每个配置模块的特性在下方描述。
该模块具有名称 oid_section
。该变量的值指向一个包含 OID 键值对的段:键名为 OID 长名或短名,值为数值格式的 OID。虽然有些 openssl
工具的子命令已有它们自己的 ASN1 OBJECT 段,但并非每个都有。使用了 ASN1 OBJECT 配置模块后,所有的 openssl
工具的子命令和合规的应用都可以看见这些新的ui想。举例:
[new_oids]
some_new_oid = 1.2.3.4
seome_other_oid = 1.2.3.5
也可以将值设置为长名称后跟随一个逗号,和一个数字形式的 OID。例如:
shortName = some object long name, 1.2.3.4
该 ENGINE 配置模块具有键名 engines
。该变量的值指向一个包含更多 ENGINE 配置信息的段。
由 engines
指向的段包含一个引擎名的表(参见下方的 engine_id
)以及每个 ENGINE 特定的配置信息段。
每个 ENGINE 的特定段用于设置默认的算法、载入动态库(dynamic)、执行初始化、以及发送控制(ctrls)。实际会执行的操作依照 command 名,也就是键值对的键名。当前支持的命令见下方列表。
举例:
[engine_section]
# 配置名为 “foo” 的 ENGINE
foo = foo_section
# 配置名为 “bar” 的 ENGINE
bar = bar_section
[foo_section]
... foo ENGINE 特定的命令 ...
[bar_section]
... bar ENGINE 特定的命令 ...
engine_id
命令用于指定 ENGINE 的名称。若要使用该命令,则该命令必须首先出现。举例:
[engine_section]
# 一般来说因该由名为 “foo” 的 ENGINE 来处理
foo = foo_section
[foo_section]
# 覆盖默认的名称,并用 “myfoo” 替代
engine_id = foo
dynamic_path
命令从给出的路径中加载并添加一个 ENGINE。它等价于顺次发送以下的控制:附带路径参数的 SO_PATH
,值为 2
的 LIST_ADD
,对动态 ENGINE 的 LOAD
。若该操作不符合需求,也可以直接通过控制命令向动态 ENGINE 发送替换的控制。
init
命令决定是否要初始化 ENGINE。若值为 0
,则 ENGINE 不会被初始化,若为 1
,则尝试立刻初始化 ENGINE。若未出现 init
命令,则在一个 ENGINE 段中所有的命令都执行完成后,尝试执行一次初始化。
default_algorithms
命令设置了会通过 ENGINE_set_default_string() 函数设置的 ENGINE 的默认算法。
若键名不匹配上述任何一个命令名,则该键将作为控制命令发送至 ENGINE。命令的值就是控制命令的值。若命令的值为字符串 EMPTY
,则向命令发送一个不具有值的控制。
举例:
[engine_section]
# 配置名为 “foo” 的 ENGINE
foo = foo_section
[foo_section]
# 从 DSO 中加载引擎
dynamic_path = /some/path/fooengine.so
# foo 特定的控制
some_ctrl = some_value
# 另一个不具有值的控制
other_ctrl = EMPTY
# 提供全部的默认算法
default_algorithms = ALL
该模块具有键名 alg_section
,指向一个具有算法的名称。
当前支持的算法命令仅为 fips_mode
,其值仅为布尔字符串 off
。若 fips_mode
设置为 on
,将报错,应为该库与 FIPS 不兼容。
该模块具有键名 ssl_conf
,其指向一个具有 SSL 配置的段。
SSL 配置段的每一行包含配置的名称,和包含它的段。
每个配置段包含 SSL_CONF
需要的命令-值段。若以合适的配置名调用了 SSL_CTX_config() 或 SSL_config(),每个对将传入一个 SSL_CTX
或 SSL
结构。
注意:配置段中首个点号之前的字符将被忽略,这样相同的命令就可以被多次使用。
举例:
ssl_conf = ssl_sect
[ssl_sect]
server = server_section
[server_section]
RSA.Certificate = server-rsa.pem
ECDSA.Certificate = server-ecdsa.pem
Ciphers = ALL:!RC4
系统默认配置具有名称 system_default
,若出现则用于任何 SSL_CTX
结构体的创建中。
使用了系统默认值的配置案例:
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
MinProtocol = TLSv1.2
MinProtocol = DTLSv1.2
若配置文件尝试扩展一个不存在的变量,则会报错,该文件将不会被载入。可能发生在扩展一个不存在的环境变量中。举例来说,在前一个版本的 OpenSSL 中,默认的 OpenSSL 主配置文件会使用 HOME
的值,该变量在非 Unix 系统上不一定会出现,而导致错误。
可以包含一个默认段来提供默认值:则当环境变量查找失败时,会转而使用默认值。要让其正确执行,默认值必须先于扩展定义于配置文件中。参见 案例 段来了解如何使用。
若相同的变量存在与相同的段,则仅使用最后一次定义,前序的定义会被忽略。在特定的情况下相同的变量会出现多次,比如对 DN 的指定。绕行的办法是,在初始的点号之前添加字符,例:
1.OU="My first OU"
2.OU="My Second OU"
运用了上述部分特性的案例配置文件
# 此处为默认段
HOME=/temp
RANDFILE = ${env::HOME}/.rnd
configdir = $ENV::HOME/config
[ section_one ]
# 此时我们呢在 section one
# 引号可接受前序和后续的白空格
any = " any variable name "
other = A string that can \
conver serval lines \
by including \\ characters
message = Hello World\n
[ section_two ]
greeting = $section_one::message
下个案例展示了如何安全地扩展环境变量。
假设你向让名为 tmpfile
的变量指向一个临时文件名。放置它的文件夹可以通过 TEMP
或者 TMP
环境变量取得,但它们可能完全没有被设置。若你使用了该环境变量,而该环境变量没有被定义,则在尝试载入该配置文件时会报错。在使用默认段之后,两个值均会首先查找 TEMP
,若两者均不存在则使用 /tmp
:
TMP=/tmp
# 上述值在环境中不存在 TMP 时被使用
TEMP=$ENV::TMP
# 上述值在环境中不存在 TEMP 时被使用
tmpfile=${ENV::TEMP}/tmp.filename
进入 FIPS 模式的 OpenSSL 库配置简单案例:
# Default appname: should match "appname" parameter (if any)
# supplied to CONF_modules_load_file et al.
openssl_conf = openssl_conf_section
[openssl_conf_section]
# Configuration module list
alg_section = evp_sect
[evp_sect]
# Set to "yes" to enter FIPS mode if supported
fips_mode = yes
注意:上述案例在不兼容 FIPS 模式的 OpenSSL 版本上会报错
逐一设置系统使用的最低版本为 TLS 1.2 和 DTLS 1.2:
# openssl(包括 libssl)顶层的段
openssl_conf = default_conf_section
[default_conf_section]
# 我们仅指定 “ssl 模块” 的配置
ssl_conf = ssl_section
[ssl_section]
system_default = system_default_section
[system_default_section]
MibProtocol = TLSv1.2
MinProtocol = DTLSv1.2
最小 TLS 协议应用于基于 TLS 的 SSL_CTX
对象,最小的 DTLS 协议应用于那些基于 DTLS 的。最大的版本可以通过 MaxProtocol
设置。
更复杂的 OpenSSL 库配置。添加了 OID,且不进入 FIPS 模式:
# Default appname: should match "appname" parameter (if any)
# supplied to CONF_modules_load_file et al.
openssl_conf = openssl_conf_section
[openssl_conf_section]
# Configuration module list
alg_section = evp_sect
oid_section = new_oids
[evp_sect]
# This will have no effect as FIPS mode is off by default.
# Set to "yes" to enter FIPS mode, if supported
fips_mode = no
[new_oids]
# New OID, just short name
newoid1 = 1.2.3.4.1
# New OID shortname and long name
newoid2 = New OID 2 long name, 1.2.3.4.2
所有的上述案例可以用于任何支持库配置的应用中,只要 “openssl_conf” 被修改值匹配任何合规的 “appname”。
举例来说,若上述第二个案例保存为 “exanple.cnf”,那么命令行:
OPENSSL_CONF=example.cnf openssl asn1parse -genstr OID;1.2.3.4.1
将输出:
0:d=0 hl=2 l=4 prim: OBJECT :newoid1
显示 OID “newoid1” 已经作为 “1.2.3.4.1” 添加。