3. CSR Attributes 处理 (CSR Attributes Handling)
3.1. 对 RFC 7030 第 2.6 节的扩展
本文档将 [RFC7030] 第 2.6 节的第二段替换为以下文本:
这些属性可以提供 EST 服务器自身无法访问的附加信息, 例如 EST 客户端某个接口的媒体访问控制 (Media Access Control, MAC) 地址. EST 服务器也可以提供具体值, 并告知客户端在 CSR 中包含这些值, 例如特定的 X.509 Subject Alternative Name 扩展. 此外, 这些属性还可以指示所包含公钥的类型, 或指示在自签名中要使用哪些密码算法, 例如客户端在生成 CSR 时预期使用的特定椭圆曲线或特定哈希函数.
3.2. 对 RFC 7030 第 4.5.2 节的扩展
EST ([RFC7030] 第 4.5.2 节) 中定义的 CSR Attributes 的 ASN.1 语法如下:
CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID
AttrOrOID ::= CHOICE (oid OBJECT IDENTIFIER, attribute Attribute }
Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
type ATTRIBUTE.&id({IOSet}),
values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) }
该语法保持不变, 因而维持了线上比特 (bits-on-the-wire) 兼容性.
此前不明确的关键部分包括: 在 type 字段中应使用哪个 OID, 以及 values 字段可以包含完整的 X.509 扩展序列.
这类属性在 type 字段中必须使用的 OID 是 id-ExtensionReq, 其值为 1.2.840.113549.1.9.14. 注意, 这与 PKCS#9 [RFC2985] 中定义的 pkcs-9-at-extensionRequest 相同. 此类属性必须只有一个.
该属性的 values 字段必须包含一个恰有一个元素的集合 (set), 且该元素必须是 [RFC5280] 第 4.1 节所规定的 Extensions 类型:
Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
-- contains the DER encoding of an ASN.1 value
-- corresponding to the extension type identified
-- by extnID
}
Extension 由特定 X.509 扩展的 OID (extnID), 可选的 critical 比特, 以及扩展值 (extnValue) 组成.
Extensions 结构是由 Extension 类型元素构成的序列, 对于某个特定 extnID, 它不得包含多个元素.
未使用第 3.4 节基于模板的方法时, 如果要指定对特定类型公钥的要求, 以及可选的大小和其他参数, 必须按如下方式进行: 恰好包含一个 Attribute, 其 type 字段为指定密钥类型的 OID, 例如 ecPublicKey 或 rsaEncryption. values 字段可以为空, 表示对密钥没有进一步要求. 否则, 它必须包含适用于给定密钥类型的参数, 例如包含某个椭圆曲线 (Elliptic Curve, EC) OID 的单元素集合 (如 secp384r1), 或包含 RSA 密钥大小整数值的单元素集合 (如 4096). 第 5 节给出了许多此类示例.
3.3. 对 RFC 9148 的更新
本文档对 EST 的更新在使用 [RFC9148] 所述受限应用协议 (Constrained Application Protocol, CoAP) 作为传输机制时同样适用. 因此, 本文档在 [RFC9148] 第 1 节第二段之后增加以下段落:
[RFC9148] 中规定的 EST over CoAP 原样适用于 [RFC7030], 后者由 RFC 9908 更新. 因此, [RFC9148] 中对 [RFC7030] 的所有引用都假定表示 [RFC7030] 已由 RFC 9908 更新.
3.4. CSR 模板的使用
作为替代 [RFC7030] 第 4.5.2 节所规定的 CSR Attributes 非结构化包含方式的一种方案, [RFC8295] 附录 B 描述了使用 CSR 模板的方法, 以避免该方式的限制和歧义. 该方法返回一个完整的 CSR 对象, 其中部分字段已填充, 其他字段等待填充. 在该方法中, pKCS7PDU 属性包含 PKIData 内容类型 [RFC5272], 后者又包含 CSR [RFC2986], 或包含采用证书请求消息格式 (Certificate Request Message Format, CRMF) 的请求 (详细信息分别见 [RFC6268] 第 5 节或第 9 节).
该方法的一个缺点, 尤其对于 CSR 而言, 是必须包含一些未使用的字段. 具体来说, CSR 上的 signature 字段会用空比特串伪造.
"Internet X.509 Public Key Infrastructure -- Certificate Management Protocol (CMP)" [RFC9810] 和 "Lightweight Certificate Management Protocol (CMP) Profile" ([RFC9483] 第 4.3.3 节) 中定义了类似方法, 它使用为 CRMF [RFC4211] 定义的 CSR 模板. 与前述方法一样, 该方法无法妥善处理缺失的相对可分辨名称 (Relative Distinguished Name, RDN) 值, 因为它会把这些值编码为无效的空字符串. 此外, 将缺失的 subjectPublicKey 值编码为空 BIT STRING, 将缺失的 X.509 扩展值编码为空 OCTET STRING, 可能会给严格的 ASN.1 解析和解码带来问题.
可按如下方式避免这些缺点:
本规范为 CsrAttrs (见第 3.2 节) 定义了新的 Certificate Request Information Template 属性. 它本质上是一个部分填充的 PKCS#10 CSR, 但不带签名包装:
CertificationRequestInfoTemplate ::= SEQUENCE {
version INTEGER { v1(0) } (v1, ... ),
subject NameTemplate OPTIONAL,
subjectPKInfo [0] SubjectPublicKeyInfoTemplate
{{ PKInfoAlgorithms }} OPTIONAL,
attributes [1] Attributes{{ CRIAttributes }}
}
附录 A 包含全部细节.
CertificationRequestInfoTemplate 与 [RFC5912] 第 5 节中的 CertificationRequestInfo 非常相似:
CertificationRequestInfo ::= SEQUENCE {
version INTEGER { v1(0) } (v1,...),
subject Name,
subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
attributes [0] Attributes{{ CRIAttributes }}
}
差异如下:
-
subject字段已改为 OPTIONAL. 如果服务器对 subject name 的 RDN 提出任何要求, 该字段必须存在; 否则, 该字段必须缺失. -
subject字段中的 RDN 可以没有值, 这是通过为 SingleAttributeTemplate 的value字段添加 OPTIONAL 实现的. 如果预期客户端提供某种类型的 RDN, 例如 commonName, 相应 RDN 必须出现在subject字段中; 否则, 它必须缺失. 另外, 如果服务器给出了 RDN 值, 这意味着预期客户端为该 RDN 使用此值; 否则, 预期客户端填入合适的值. 本节末尾的示例包含一个subject字段, 其中同时包含这两种 RDN 规范形式.
SingleAttributeTemplate {ATTRIBUTE:AttrSet} ::= SEQUENCE {
type ATTRIBUTE.&id({AttrSet}),
value ATTRIBUTE.&Type({AttrSet}{@type}) OPTIONAL
}
-
subjectPKInfo字段已改为 OPTIONAL. 如果服务器未对密钥提出要求, 该字段必须缺失; 否则, 该字段必须存在, 且algorithm字段指定预期客户端使用的密钥对类型. -
SubjectPublicKeyInfoTemplate 中包含的
subjectPublicKey字段已改为 OPTIONAL, 因为通常不需要该字段. 如果服务器要求使用 RSA 密钥并且需要指定其大小, 该字段必须存在, 并包含所需 RSA 模数长度的占位公钥值; 否则, subjectPublicKey 必须缺失.
SubjectPublicKeyInfoTemplate{PUBLIC-KEY:IOSet} ::= SEQUENCE {
algorithm AlgorithmIdentifier{PUBLIC-KEY, {IOSet}},
subjectPublicKey BIT STRING OPTIONAL
}
- 定义了新的 OID id-aa-extensionReqTemplate 以及相关的 ExtensionTemplate 结构, 其中
extnValue字段已改为 OPTIONAL. 只有在需要指定由客户端填入值的部分扩展时才需要它; 否则, 对于 X.509 扩展要求, 必须使用 id-ExtensionReq OID 以及相应的 ExtensionReq 类型值.
对于服务器提供的每个 Extension 或 ExtensionTemplate 类型扩展, 预期客户端包含一个由 extnID 给定类型的扩展. 如果 critical 字段存在, 客户端也应该在扩展中使用它. 如果 extnValue 存在 (使用 Extension 类型时总是如此), 客户端应该在其 CSR 中使用给定的扩展值. 使用 ExtensionTemplate 类型时, extnValue 可以缺失; 这时客户端应该在具有给定 extnID 的 Extension 中提供扩展值. 例如, 如果服务器包含一个 extnID 为 subjectAltName 但没有 extnValue 的 ExtensionTemplate, 客户端应该包含一个带有合适值的 SAN 扩展.
如果服务器包含一个 extnID 为 subjectAltName 且 extnValue 已部分填充的 ExtensionTemplate, 例如包含 NULL-DN (即空 RDN 序列) 的 directoryName choice, 或包含空 OCTET STRING 的 iPAddress choice, 这意味着客户端应该填入相应的 GeneralName 值.
ExtensionTemplate {EXTENSION:ExtensionSet} ::= SEQUENCE {
extnID EXTENSION.&id({ExtensionSet}),
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING (CONTAINING
EXTENSION.&ExtnType({ExtensionSet}{@extnID}) OPTIONAL
-- contains the DER encoding of the ASN.1 value
-- corresponding to the extension type identified
-- by extnID when present
}
CertificationRequestInfoTemplate 的 version 字段必须包含 v1 (0).
attributes 字段不得包含多个 id-aa-extensionReqTemplate 属性, 并且不得同时包含 id-ExtensionReq 和 id-aa-extensionReqTemplate 属性.
id-aa-extensionReqTemplate 属性的 values 字段必须包含一个恰有一个元素的集合, 且该元素必须是 ExtensionTemplate 类型.
假设服务器要求 CSR 包含:
-
subject字段, 其中包含一个由 EE 填入的 common name, 以及两个给定值分别为 "myDept" 和 "myGroup" 的 organizational unit name. -
publicKey字段, 其中包含曲线 secp256r1 上的椭圆曲线密码学 (Elliptic Curve Cryptography, ECC) 公钥. -
subjectAltName扩展, 其中包含两个条目: 一个名称为 "www.myServer.com" 的 DNS 条目, 以及一个 IP 条目, 该 IP 地址为空并待填入. -
标记为 critical 的
keyUsage扩展, 其值为 digitalSignature 和 keyAgreement. -
extKeyUsage扩展, 其值待 EE 填入.
那么, 服务器构造的 CertificationRequestInfo 结构如下:
SEQUENCE {
INTEGER 0
SEQUENCE {
SET {
SEQUENCE {
OBJECT IDENTIFIER commonName (2 5 4 3)
}
}
SET {
SEQUENCE {
OBJECT IDENTIFIER organizationalUnitName (2 5 4 11)
UTF8String "myDept"
}
}
SET {
SEQUENCE {
OBJECT IDENTIFIER organizationalUnitName (2 5 4 11)
UTF8String "myGroup"
}
}
}
[0] {
SEQUENCE {
OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
OBJECT IDENTIFIER secp256r1 (1 2 840 10045 3 1 7)
}
}
[1] {
SEQUENCE {
OBJECT IDENTIFIER id-aa-extensionReqTemplate
(1 2 840 113549 1 9 62)
SET {
SEQUENCE {
SEQUENCE {
OBJECT IDENTIFIER subjectAltName (2 5 29 17)
OCTET STRING, encapsulates {
SEQUENCE {
[2] "www.myServer.com"
[7] ""
}
}
}
SEQUENCE {
OBJECT IDENTIFIER keyUsage (2 5 29 15)
BOOLEAN TRUE
OCTET STRING, encapsulates {
BIT STRING 3 unused bits
"10001"B
}
}
SEQUENCE {
OBJECT IDENTIFIER extKeyUsage (2 5 29 37)
}
}
}
}
}
}