为 API 和密钥存储定义内容类型¶
Barbican 的当前实现对于终端用户和开发者来说,关于输入新密钥以及返回密钥的编码方式存在歧义。本规范旨在为每种密钥类型定义编码规范,并定义所有密钥类型。编码规范将允许终端用户和开发者了解如何处理密钥。
问题描述¶
目前存在的主要问题是,从 API 和密钥存储返回的数据定义不明确。例如,公钥。当终端用户请求公钥时,有很多种方式可以返回这些数据。一种方法是只返回公钥(不包括证书),作为 Base64 编码的字符串,但仍然存在问题,即表示密钥的二进制格式是什么。然而,大多数人认为这意味着返回一个证书。然后又提出了如何返回证书的问题。应该使用 PEM 还是 DER 格式。显然,存在很多假设和未解答的问题。
以上存在两个问题。一个是我们需要明确定义所有可能的密钥类型。这将消除公钥与证书的问题。另一个问题是我们需要为每种密钥类型定义编码标准选项。然后,终端用户和密钥存储开发者将知道,如果他们拥有类型为 X 的密钥,那么它具有类型为 Y 的编码。
此蓝图的范围仅限于未加密的密钥。特别是,本规范不涵盖使用传输密钥包装的密钥的编码标准,也不涵盖使用密码短语加密的私钥的编码方案。
提议的变更¶
定义所有密钥类型¶
第一次更改将是修改 SecretType 类,以包含所有可能的密钥类型。SecretType 类表示一个枚举,当前定义的数值是 symmetric(对称密钥)、public(公钥)和 private(私钥)。
本规范建议添加 certificate(证书)、passphrase(密码短语)和 opaque data(不透明数据)类型。证书类型将代表 X.509 证书。当前规范不支持 PGP 证书,主要是因为我对它们了解不多。如果需要支持,我们可以解决这个问题。更有可能的是,如果需要支持除 X509 之外的其他证书,则应该创建一个证书子类型枚举来指示类型,例如 X.509、PGP 等。这将是另一个规范,而本规范将假定仅支持 X.509 证书。
不透明数据类型将代表一个未知的二进制数据块。这是为不是密钥或证书的类型保留的。Barbican 将无法理解有关数据的任何信息。它只是一个数据块。这将用于像 IV 这样的密钥数据。
以下是建议的密钥类型列表
对称密钥
公钥
私钥
密码短语
证书
不透明数据
每种密钥类型的编码内容¶
第二次更改将是为每种密钥类型定义内容编码。类型和建议的编码如下。
对称密钥 - 网络字节顺序中字节数组的 Base64 编码
公钥 - Base64 编码的 DER 编码的 SubjectPublicKeyInfo 结构,如 X.509 RFC 5280 中定义的,带有 PEM 头部和尾部
私钥 - Base64 编码的 PKCS#8 结构,带有 PEM 头部和尾部
密码短语 - UTF-8 编码的文本
证书 - Base64 编码的 DER 编码的 ASN.1 X.509 结构,带有 PEM 头部和尾部
不透明数据 - 网络字节顺序中字节数组的 Base64 编码
公钥和私钥的格式是基于它们的流行度选择的。公钥格式 SubjectPublicKeyInfo 是因为这是 openssl 和 Java 的公钥默认格式。此外,它是常见的 X.509 标准的一部分。
私钥格式 PKCS#8 是 Java 的默认编码。在 openssl 中生成新私钥的默认编码不是 PKCS#8。openssl 中的默认编码在 openssl 文档中称为“传统”格式。术语“传统”含糊不清。实际上是纯私钥结构,因此对于 RSA 来说,它是 PKCS#1 中定义的私钥结构。这是 PKCS#8 结构的一个子集。
openssl 库支持使用 PKCS#8 密钥,这不需要更改任何命令行选项。该库会自动检测编码并使用 PKCS#8 编码或 openssl “传统”编码的密钥。由于这一点以及术语“传统”的含糊性,我建议使用 PKCS#8 格式。它对开发者和用户来说期望的格式很明确。
备选方案¶
另一种选择是保持一切不变。上述识别了这种方法的缺点。
可能还有其他表示密钥的方式。我们可以定义自己的结构而不是使用 ASN.1。我选择使用 ASN.1 和其他标准是因为我认为它们被广泛采用和接受。我认为从现有应用程序导出密钥使这些选择成为最佳选择。
数据模型影响¶
唯一的预期更改是修改 Secret 实体以包含一个类型列。类型列将是以下预定义的密钥类型之一:对称密钥、公钥、私钥、密码短语、证书或不透明数据。
密钥存储当前期望一个 Base64 编码的字节数组,因此我不希望更改密钥存储类。现在唯一的区别是密钥存储将对这些字节的格式有更多的了解。
REST API 影响¶
用于存储密钥的 API 需要设置密钥的 payload_content_type 和 payload_content_encoding。对于每种密钥类型,都需要一组可接受的 payload_content_type 和 payload_content_encoding 值。
这也意味着应该提供密钥类型作为新参数。这是以前缺失的。当前实现只能推断上传的对称密钥的类型,因为它可以使用算法来确定这一点。算法不足以推断非对称密钥的密钥类型,因为它可能是公钥或私钥。因此,应该提供密钥类型。当前实现当前将它们存储为未知。
下表列出了每种密钥类型的可接受的内容类型和内容编码值。每对表示为 (payload_content_type, payload_content_encoding)。未以指定编码接收数据的 API 调用将收到 406 错误代码响应。
对称密钥 (application/octet-stream, Base64)
公钥 (application/octet-stream, Base64)
私钥 (application/pkcs8, Base64)
密码短语 (text/plain, utf-8)
证书 (application/pkix-cert, Base64)
不透明数据 (application/octet-stream, Base64), (text/plain, NULL)
支持向后兼容性¶
新的密钥类型参数将是可选参数,以支持向后兼容性。如果未提供,则将使用不透明数据。不透明数据将是支持多种可接受内容类型的唯一密钥类型。这是为了支持向后兼容性而选择的。
密钥存储影响¶
上述定义了 API 内容类型和内容编码。但是,传递到密钥存储的密钥的格式也需要定义。密钥是从 Barbican Core 使用 SecretDTO 对象传递到密钥存储的。
+-------------+ +-------------+
| SecretType | | KeySpec |
+-------------+ +-------------+
| SYMMETRIC | | algorithm |
| PUBLIC | | bit_length |
| PRIVATE | | passphrase |
| CERTIFICATE | +-------------+
| OPAQUE | ^
+-------------+ |
^ | has
| has |
| |
+---------------+
| SecretDTO |
+---------------+
| type |
| secret |
| key_spec |
| content_type |
| transport_key |
+---------------+
当前的 SecretDTO 具有 content_type 属性和 secret 属性。secret 属性是一个 Python 字符串,它是表示密钥的字节的 Base64 编码。content_type 是从 API 调用接收到的 content_type 参数。由于我们正在为 SecretDTO 的 SecretType 定义单个编码,因此可以删除此参数。编码将与 API 相同,除了不透明数据将是字节的 Base64 编码,不允许为纯文本。
安全影响¶
无
通知与审计影响¶
可以添加审计 Barbican 管理的密钥类型的能力。
其他最终用户影响¶
我们可以在存储之前验证密钥,以验证结构是否正确。这将通过防止用户上传格式不正确的特定类型的密钥来帮助用户。
性能影响¶
除非进行验证,否则不会有任何开销,在这种情况下,验证密钥结构会有轻微的开销。
其他部署者影响¶
无
开发人员影响¶
密钥存储开发者可能需要修改他们的代码以返回指定格式的密钥。
Barbican 客户端需要更新以利用编码并添加新的密钥类型参数。
实现¶
负责人¶
Nathan Reller (rellerreller)
工作项¶
添加密钥类型
修改 API 以接受新的 secret_type 参数。secret_type 必须是预定义的类型之一,因此应该添加一个验证器来验证它。如果未提供,则除非提供对称算法,否则使用不透明数据。
修改 barbican.plugin.resources 以创建具有适当密钥类型的 SecretDTO。
添加基本的密钥类型验证器
添加一些基本的验证器,以确保传递到 API 的密钥格式正确。第一次检查将只是验证 PEM 头部。例如,在传递 RSA 密钥时,这将检查是否包含正确的 PEM 头部。
此步骤不会对传递到 Barbican 的密钥进行深入检查。深入检查将验证每个结构以确保接收到正确的结构。对于 RSA 公钥,这将检查它是否包含模数和公钥指数。
更新 API 文档
更新文档以包含有关预期编码的说明,并包含有关发布密钥的新密钥类型参数的文档。
更新 barbicanclient
更新 barbicanclient 以利用新的密钥类型并符合 API 更改。
依赖项¶
无
测试¶
添加验证器测试以验证 API 是否正确解析新的密钥类型并捕获传递到 API 的密钥使用的编码不正确的实例。
文档影响¶
更新 API 文档以包含有关新的密钥类型 API 参数和每种密钥类型的编码的信息。
参考资料¶
PKCS#8 -https://tools.ietf.org/html/rfc5958 X.509 - https://tools.ietf.org/html/rfc5280 Java Key - http://docs.oracle.com/javase/7/docs/api/java/security/Key.html openssl to pkcs8 - https://www.openssl.org/docs/apps/pkcs8.html