# 课程：API 和工具用于安全代码和文件交换

> 原文： [https://docs.oracle.com/javase/tutorial/security/sigcert/index.html](https://docs.oracle.com/javase/tutorial/security/sigcert/index.html)

本课程解释了为什么需要数字签名，证书和密钥库。本课程还比较了工具与 JDK Security API 在生成签名方面的使用情况。此类工具用法将在接下来的两节课中进行演示，[签名代码和授予权限](../toolsign/index.html)和[交换文件](../toolfilex/index.html)。 API 使用情况在[生成和验证签名](../apisign/index.html)课程中进行了演示。

本课包含以下部分

*   [代码和文件安全](#Intro)
*   [工具和 API 说明](#Notes)
*   [使用 JDK Security API 签署文件](#API)
*   [使用工具签署代码或文件](#Tools)

如果您通过电子方式向某人发送重要文档（或文档）或 applet 或应用程序来运行，则收件人需要一种方法来验证文档或代码是否来自您并且未在传输过程中进行修改（例如，恶意用户）拦截它）。数字签名，证书和密钥库都有助于确保您发送的文件的安全性。

使用数字签名的基本思想如下。

1.  您可以使用**私钥**“签署”文档或代码，您可以使用`keytool`或安全 API 方法生成这些私钥。也就是说，您使用`jarsigner`工具或 Security API 方法为文档或代码生成数字签名。
2.  您将签名文档发送给收件人。
3.  您还为收件人提供了**公钥。** 此公钥对应于您最初用于生成签名的私钥。
4.  您的收件人使用您的公钥来验证您的文档是否来自您，并且在它到达他/她之前未进行修改。

收件人需要确保您的公钥 _ 本身 _ 是真实的，然后他/她才能使用它来验证您的签名是否真实。因此，您通常会提供一个**证书**，其中包含您的公钥以及**证书颁发机构**的密钥，该证书可以保证您密钥的真实性。有关详细信息，请参阅下一节。

有关签名和验证的术语和概念的更多信息，以及有关优点的进一步说明，请参阅“JAR 文件中的打包程序”课程的[签名 JAR 文件](../../deployment/jar/signing.html)部分。

### 证书

证书包含：

*   公钥。
*   身份证明的实体（人，公司等）的“专有名称”信息。该实体被称为证书 _ 主题 _ 或 _ 所有者 _。专有名称信息包括以下属性（或子集）：实体的名称，组织单位，组织，城市或地区，州或省，以及国家/地区代码。
*   数字签名。证书由一个实体 _ 发行人 _ 签署，以保证所附公开密钥是另一个实体 _ 所有者 _ 的实际公钥。
*   签名者（发行人）的专有名称信息。

收件人检查证书是否有效的一种方法是使用其颁发者（签名者）的公钥验证其数字签名。该密钥本身可以存储在另一个证书中，该证书的签名也可以通过使用该下一个证书颁发者的公钥进行验证，并且该密钥可以 _ 也 _ 存储在 _ 另一个 _ 证书中，等等。您可以在到达已经信任的公钥时停止检查，并使用它来验证相应证书上的签名。

如果收件人无法建立信任链，则他/她可以使用`keytool` `-import`或`-printcert`命令计算证书**指纹**。指纹是一个相对较短的数字，可以唯一且可靠地识别证书。 （从技术上讲，指纹是证书信息的哈希值，使用消息摘要功能。）然后，收件人可以给证书所有者打电话，并将收到的证书的指纹值与发送的证书进行比较。如果指纹相同，则证书相同。

因此，您可以确保在传输过程中未修改证书。使用证书时另一个潜在的不确定因素是发件人的身份。有时证书是**自签名**，即使用与证书中的公钥对应的私钥进行签名;发行人与主题相同。

自签名证书对于开发和测试应用程序很有用。但是，在部署到用户之前，请从受信任的第三方（称为证书颁发机构（CA））获取证书。为此，您需要向 CA 发送自签名证书签名请求（CSR）。 CA 可以通过检查您的驾驶执照或其他信息来验证 CSR 上的签名和您的身份。然后，CA 通过颁发证书并使用自己的（CA）私钥对其进行签名来担保您是公钥的所有者。任何信任颁发 CA 的公钥的人现在都可以验证证书上的签名。在许多情况下，颁发 CA 本身可能具有来自 CA 层次结构中较高的 CA 的证书，从而导致**证书链**。

您信任的实体证书通常作为“**可信证书**”导入您的密钥库。然后，可以使用每个这样的证书中的公钥来验证使用相应私钥生成的签名。此类验证可以通过以下方式完成：

*   `jarsigner`工具（如果文档/代码和签名出现在 JAR 文件中），
*   API 方法，或
*   运行时系统，当尝试资源访问时，策略文件指定如果其签名是可信的，则允许对尝试访问的代码进行资源访问。代码的类文件和签名必须位于 JAR 文件中。

如果要将签名的代码或文档发送给其他人，则需要向他们提供包含与用于签署代码/文档的私钥对应的公钥的证书。 `keytool` `-export`命令或 API 方法可以将证书从密钥库导出到文件，然后可以将文件发送给需要它的任何人。接收证书的人可以使用例如 API 方法或`keytool` `-import`命令将其作为可信证书导入密钥库。

如果使用`jarsigner`工具为 JAR 文件生成签名，该工具将从密钥库中检索证书及其支持证书链。然后，该工具将它们与签名一起存储在 JAR 文件中。

私钥及其关联的公钥证书存储在名为**密钥库**的受密码保护的数据库中。密钥库可以包含两种类型的条目：上面讨论的可信证书条目，以及密钥/证书条目，每个条目包含私钥和相应的公钥证书。密钥库中的每个条目都由 _ 别名 _ 标识。

密钥库所有者可以在密钥库中拥有多个密钥，通过不同的别名访问。别名通常以密钥库所有者使用关联密钥的特定字符命名。别名也可以标识密钥的用途。例如，别名`signPersonalEmail`可能用于标识其私钥用于签名个人电子邮件的密钥库条目，别名`signJarFiles`可用于标识其私钥用于签署 JAR 文件的条目。

`keytool`工具可用于

*   创建私钥及其关联的公钥证书
*   发出证书请求，您将其发送给相应的证书颁发机构
*   导入证书回复，从您联系的证书颁发机构获得
*   将属于其他方的公钥证书导入为可信证书
*   管理您的密钥库

API 方法还可用于访问和修改密钥库。

请注意以下有关使用工具和与数字签名相关的 API 的信息。

*   您可以使用 JDK Security API，工具或组合来生成密钥和签名以及导入证书。您可以使用这些 API 或工具功能安全地与他人交换文档。
*   要使用 _ 工具 _ 进行文档交换，必须将文档放在 JAR（Java ARchive）文件中，该文件可以由`jar`工具创建。 JAR 文件是在一个位置封装多个文件的好方法。当文件被“签名”时，产生的数字签名字节需要存储在某处。签名 JAR 文件时，签名可以放在 JAR 文件本身中。当您使用`jarsigner`工具对 JAR 文件进行签名时会发生这种情况。
*   如果要创建要签名的 applet 代码，则需要将其放在 JAR 文件中。如果您正在创建可能通过安全管理器运行应用程序代码而受到类似限制的应用程序代码，情况也是如此。您需要 JAR 文件的原因是，当策略文件指定允许特定实体签名的代码执行一个或多个操作（例如特定文件读取或写入）时，代码应该来自签名的 JAR 文件。 （术语“签名代码”是一种缩写方式，用于表示“出现在已签名的 JAR 文件中的类文件中的代码。”）
*   为了使运行时系统检查代码签名，将首先运行代码的人/组织需要将证明与用于签署代码的私钥相对应的公钥的证书导入其密钥库。
*   为了使`jarsigner`工具验证 JAR 文件签名的真实性，接收 JAR 文件的个人/组织首先需要将证明与用于签署代码的私钥对应的公钥的证书导入其密钥库中。 。
*   目前，没有用于证书创建的 API。

[生成和验证签名](../apisign/index.html)向您展示如何使用 JDK Security API 对文档进行签名。该课程显示由具有原始文档的人执行的一个程序将执行的操作

*   生成密钥，
*   使用私钥生成数据的数字签名，和
*   将公钥和签名导出到文件。

然后它显示了另一个程序的示例，由接收器执行数据，签名和公钥。它显示了该程序

*   导入公钥
*   验证签名的真实性。

本课程还向您展示了导入和提供密钥的其他方法，包括证书。

[签名代码和授予权限](../toolsign/index.html)课程介绍了如何使用 Java 安全工具将代码放入 JAR 文件，对其进行签名并导出公钥。然后，它显示了收件人如何使用这些相同的 Java 工具导入公钥证书，然后将条目添加到策略文件中，该文件将授予您的代码访问收件人控制的系统资源所需的权限。

[交换文件](../toolfilex/index.html)课程介绍如何使用 Java 安全工具签署文档，然后使用`keytool`导出公钥的公钥证书。对应于用于使用`keytool`签署该文档的私钥。然后，它会显示收件人如何通过安装公钥证书然后使用`jarsigner`工具验证您的签名来验证您的签名。

这两个课程有很多共同之处。在这两种情况下，代码或文档发件人的前两个步骤是：

*   使用`jar`工具创建包含文档或类文件的 JAR 文件。
*   使用`keytool` `-genkey`命令生成密钥（如果它们尚不存在）。

接下来的两个步骤是可选的：

*   使用`keytool` `-certreq`命令;然后将生成的证书签名请求发送到 VeriSign 等证书颁发机构（CA）。
*   使用`keytool` `-import`命令导入 CA 的响应。

接下来的两个步骤是必需的：

*   使用`jarsigner`工具和之前生成的私钥对 JAR 文件进行签名。
*   使用`keytool` `-export`命令导出公钥证书。然后将签名的 JAR 文件和证书提供给接收方。

在这两种情况下，签名的 JAR 文件的接收者和证书都应使用`keytool` `-import`命令将证书作为可信证书导入。 `keytool`将尝试从证书构建信任链，以导入密钥库中已经受信任的证书。如果失败，`keytool`将显示证书指纹并提示您进行验证。

如果发送的是代码，则接收方还需要修改策略文件以允许对由导入的证书中的公钥对应的私钥签名的代码进行所需的资源访问。 **策略工具**可用于执行此操作。

如果发送的是一个或多个文档，接收方需要使用`jarsigner`工具验证 JAR 文件签名的真实性。

本课讨论两个可选步骤。其他步骤将在接下来的两节课中介绍，[签名代码和授予权限](../toolsign/index.html)和[交换文件](../toolfilex/index.html)。

当`keytool`用于生成公钥/私钥对时，它会创建一个密钥库条目，其中包含私钥和公钥的自签名证书。 （即，使用相应的私钥对证书进行签名。）在开发和测试应用程序时，这就足够了。

但是，如果证书由证书颁发机构（CA）签名，则证书更可能被其他人信任。要获取 CA 签名的证书，首先要通过以下命令生成证书签名请求（CSR）：

```
keytool -certreq -alias alias -file csrFile 

```

这里 _ 别名 _ 用于访问包含私钥和公钥证书的密钥库条目， _csrFile_ 指定用于此命令创建的 CSR 的名称。

然后，您将此文件提交给 CA，例如 VeriSign，Inc .. CA 会对您，请求者（“主题”）进行身份验证，然后签名并返回验证公钥的证书。通过签署证书，CA 证明您是公钥的所有者。

在某些情况下，CA 将返回一系列证书，每个证书都会对链中先前证书的签名者的公钥进行身份验证。

### 从 CA 导入响应

在向证书颁发机构（CA）提交证书签名请求（CSR）之后，您需要通过导入 CA 返回给您的证书（或证书链）来将密钥库中的原始自签名证书替换为证书链。 。

但首先，您需要在密钥库（或下面描述的`cacerts`密钥库文件）中使用“可信证书”条目来验证 _CA_ 的公钥。通过这样的条目，可以验证 CA 的签名。也就是说，可以验证 CA 在证书上的签名，或者 CA 为响应您的 CSR 而发送给您的链中的最终证书。

在从 CA 导入证书回复之前，您需要在密钥库或`cacerts`文件中包含一个或多个“受信任证书”。

*   如果证书回复是证书链，则只需要链的顶级证书 - 验证 CA 的公钥的“根”CA 证书。
*   如果证书回复是单个证书，则需要颁发 CA（签名证书）的证书。如果该证书不是自签名的，则需要为其签名者提供证书，依此类推，直至自签名的“根”CA 证书。

`cacerts`文件表示具有 CA 证书的系统范围的密钥库。该文件位于 JRE 安全属性目录 `_java.home_ / lib / security` 中，其中 _java.home_ 是 JRE 安装目录。

* * *

**重要：验证您的`cacerts`文件**
由于您信任`cacerts`文件中的 CA 作为签署和向其他实体颁发证书的实体，因此您必须仔细管理`cacerts`文件。 `cacerts`文件应仅包含您信任的 CA 的证书。您有责任验证`cacerts`文件中捆绑的受信任的根 CA 证书，并做出您自己的信任决策。要从`cacerts`文件中删除不受信任的 CA 证书，请使用`keytool`命令的 delete 选项。您可以在 JRE 安装目录中找到`cacerts`文件。如果您没有编辑此文件的权限，请与系统管理员联系。

* * *

`cacerts`文件包含许多可信 CA 证书。如果您将 CSR 发送给其中一个受信任的供应商（例如 VeriSign），则无需将供应商的根证书作为密钥库中的可信证书导入;您可以继续[下一个](#ImportReply)部分，了解如何从 CA 导入证书回复。

来自 CA 的证书通常是自签名的或由另一个 CA 签名，在这种情况下，您还需要一个证书来验证 CA 的公钥。假设公司 ABC，Inc。是一个 CA，并且您获得了一个名为`ABCCA.cer`的文件，据称是来自 ABC 的自签名证书，用于验证该 CA 的公钥。

在将证书导入为“可信”证书之前，请务必确保证书有效！首先查看它（使用`keytool` `-printcert`命令或不带`-noprompt`选项的`keytool` `-import`命令），并确保显示的证书指纹与预期的证书指纹匹配。您可以致电发送证书的人，并将您看到的指纹与他们显示的指纹或安全公钥存储库显示的指纹进行比较。只有当指纹相同时，才能保证证书在传输过程中没有被其他人（例如，攻击者）的证书替换。如果发生此类攻击且您在导入证书之前未检查证书，则最终会信任攻击者已签署的任何内容。

如果您确信证书有效，则可以通过以下命令将其添加到密钥库：

```
keytool -import -alias alias -file ABCCA.cer -keystore storefile 

```

此命令在密钥库中创建“可信证书”条目，其名称在 _storefile_ 中指定。该条目包含文件`ABCCA.cer`中的数据，并为其分配指定的别名。

###  导入证书回复

一旦导入了所需的可信证书（如上一节所述），或者它们已经在您的密钥库或`cacerts`文件中，您可以导入证书回复，从而将您的自签名证书替换为证书链。此链将是 CA 响应您的请求返回的链（如果 CA 回复是链）或构建的链（如果 CA 回复是单个证书），则使用已经可用的证书回复和可信证书在密钥库或`cacerts`密钥库文件中。

例如，假设您已将证书签名请求发送给 VeriSign。然后，您可以通过以下方式导入回复，假定返回的证书位于 _certReplyFile_ 指定的文件中：

```
keytool -import -trustcacerts
    -keystore storefile
    -alias alias 
    -file certReplyFile 

```

在一行上键入此命令。

通过使用来自密钥库的可信证书以及（可选）使用`cacerts`密钥库文件中配置的证书（如果指定了`-trustcacerts`选项）来验证证书回复。使用链中较高级别的下一级证书验证链中的每个证书。您只需要信任链中的顶级“根”CA 证书。如果您还不信任顶级证书，`keytool`将显示该证书的指纹并询问您是否要信任它。

指定的新证书链（通过 _ 别名 _）条目替换与此条目关联的旧证书（或链）。只有在提供有效的 _keypass_ （用于保护条目的私钥的密码）时，才能更换旧链。如果未提供密码，并且私钥密码与密钥库密码不同，则会提示用户输入密码。

有关生成 CSR 和导入证书回复的更多详细信息，请参阅`keytool`文档：

*   使用 Windows 示例的 [keytool 文档](https://docs.oracle.com/javase/8/docs/technotes/tools/windows/keytool.html)
*   [UNIX 示例的 keytool 文档](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html)