The keytool Command

名称

keytool - 一个密钥和证书管理实用程序

概要

keytool [命令]

命令

keytool 的命令包括以下内容:

  • -certreq: 生成证书请求

  • -changealias: 更改条目的别名

  • -delete: 删除条目

  • -exportcert: 导出证书

  • -genkeypair: 生成密钥对

  • -genseckey: 生成秘密密钥

  • -gencert: 从证书请求生成证书

  • -importcert: 导入证书或证书链

  • -importpass: 导入密码

  • -importkeystore: 从另一个密钥库导入一个或所有条目

  • -keypasswd: 更改条目的密钥密码

  • -list: 列出密钥库中的条目

  • -printcert: 打印证书的内容

  • -printcertreq: 打印证书请求的内容

  • -printcrl: 打印证书吊销列表 (CRL) 文件的内容

  • -storepasswd: 更改密钥库的存储密码

  • -showinfo: 显示与安全相关的信息

  • -version: 打印程序版本

请参阅 命令和选项 以获取这些命令及其选项的描述。

描述

keytool 命令是一个密钥和证书管理实用程序。它使用户能够管理自己的公钥/私钥对和相关证书,用于自身认证(用户向其他用户和服务进行身份验证)或数据完整性和认证服务,通过使用数字签名。keytool 命令还使用户能够缓存其通信对等方的公钥(以证书形式)。

证书是来自某个实体(个人、公司等)的数字签名声明,其中说公钥(和其他一些信息)的某个其他实体具有特定值。当数据被数字签名时,可以验证签名以检查数据的完整性和真实性。完整性意味着数据没有被修改或篡改,真实性意味着数据来自声称已创建和签名它的个人。

keytool 命令还使用户能够管理用于对称加密和解密(数据加密标准)的秘密密钥和口令。它还可以显示其他与安全相关的信息。

keytool 命令将密钥和证书存储在密钥库中。

keytool 命令使用 jdk.certpath.disabledAlgorithmsjdk.security.legacyAlgorithms 安全属性来确定哪些算法被视为安全风险。当使用已禁用或遗留算法时,它会发出警告。 jdk.certpath.disabledAlgorithmsjdk.security.legacyAlgorithms 安全属性在 java.security 文件中定义(位于 JDK 的 $JAVA_HOME/conf/security 目录中)。

命令和选项说明

以下说明适用于 命令和选项 中的描述:

命令和选项

用于创建或向密钥库添加数据的命令

从另一个密钥库导入内容的命令

生成证书请求的命令

导出数据的命令

显示数据的命令

管理密钥库的命令

显示与安全相关信息的命令

显示程序版本的命令

用于创建或向密钥库添加数据的命令

-gencert

以下是-gencert命令的可用选项:

  • {-rfc}: 以RFC(请求评论)样式输出

  • {-infile infile}: 输入文件名

  • {-outfile outfile}: 输出文件名

  • {-alias alias}: 要处理的条目的别名

  • {-sigalg sigalg}: 签名算法名称

  • {-dname dname}: 显著名称

  • {-startdate startdate}: 证书有效起始日期和时间

  • {-ext ext}*: X.509扩展

  • {-validity days}: 有效天数

  • [-keypass arg]: 密钥密码

  • {-keystore keystore}: 密钥库名称

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,并可选配置参数。安全提供者的值是在模块中定义的安全提供者的名称。

    例如,

    keytool -addprovider SunPKCS11 -providerarg some.cfg ...

    注意:

    出于兼容性原因,即使现在在模块中定义了SunPKCS11提供程序,仍然可以使用-providerclass sun.security.pkcs11.SunPKCS11加载SunPKCS11提供程序。这是JDK中唯一需要配置的模块,因此在-providerclass选项中最常用。对于位于类路径上并通过反射加载的传统安全提供者,仍应使用-providerclass

  • {-providerclass class [-providerarg arg]}: 使用完全限定的类名添加安全提供者,并可选配置参数。

    例如,如果MyProvider是通过反射加载的传统提供者,

    keytool -providerclass com.example.MyProvider ...

  • {-providerpath list}: 提供者类路径

  • {-v}: 详细输出

  • {-protected}: 通过受保护机制提供密码

使用-gencert命令生成证书作为对证书请求文件的响应(可以通过keytool -certreq命令创建)。该命令从infile或(如果省略)从标准输入读取请求,使用别名的私钥对其进行签名,并将X.509证书输出到outfile或(如果省略)输出到标准输出。当指定-rfc时,输出格式为Base64编码的PEM;否则,创建二进制DER。

-sigalg值指定应用于签署证书的算法。 startdate参数是证书有效的开始时间和日期。 days参数表示应将证书视为有效的天数。

如果提供dname,则将其用作生成证书的主题。否则,将使用证书请求中的主题。

-ext值显示将嵌入在证书中的X.509扩展。阅读-ext的语法,请参阅常见命令选项

-gencert选项使您能够创建证书链。以下示例创建一个包含三个证书的证书e1

以下命令创建四个名为caca1ca2e1的密钥对:

keytool -alias ca -dname CN=CA -genkeypair -keyalg rsa
keytool -alias ca1 -dname CN=CA -genkeypair -keyalg rsa
keytool -alias ca2 -dname CN=CA -genkeypair -keyalg rsa
keytool -alias e1 -dname CN=E1 -genkeypair -keyalg rsa

以下两个命令创建一系列已签名证书;ca签署ca1ca1签署ca2,所有这些证书都是自签名的:

keytool -alias ca1 -certreq |
    keytool -alias ca -gencert -ext san=dns:ca1 |
    keytool -alias ca1 -importcert

keytool -alias ca2 -certreq |
    keytool -alias ca1 -gencert -ext san=dns:ca2 |
    keytool -alias ca2 -importcert

以下命令创建由ca2签署的证书e1并将其存储在e1.cert文件中。因此,e1应该在其证书链中包含caca1ca2

keytool -alias e1 -certreq | keytool -alias ca2 -gencert > e1.cert

-genkeypair

以下是-genkeypair命令的可用选项:

  • {-alias alias}:要处理的条目的别名

  • -keyalg alg:密钥算法名称

  • {-keysize size}:密钥位大小

  • {-groupname name}:组名。例如,椭圆曲线名称。

  • {-sigalg alg}:签名算法名称

  • {-signer alias}:签名者别名

  • [-signerkeypass arg]:签名者密钥密码

  • [-dname name]:专有名称

  • {-startdate date}:证书有效起始日期和时间

  • {-ext value}*:X.509扩展

  • {-validity days}:有效天数

  • [-keypass arg]:密钥密码

  • {-keystore keystore}:密钥库名称

  • [-storepass arg]:密钥库密码

  • {-storetype type}:密钥库类型

  • {-providername name}:提供者名称

  • {-addprovider name [-providerarg arg]}:按名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}:按完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}:提供者类路径

  • {-v}:详细输出

  • {-protected}:通过受保护机制提供密码

使用-genkeypair命令生成密钥对(公钥和相关私钥)。当未指定-signer选项时,公钥将包装在X.509 v3自签名证书中,并存储为单元素证书链。当指定了-signer选项时,将生成新证书,并由指定的签名者签名,并存储为多元素证书链(包含生成的证书本身和签名者的证书链)。证书链和私钥存储在由其别名标识的新密钥库条目中。

-keyalg值指定用于生成密钥对的算法,-keysize值指定要生成的每个密钥的大小。-sigalg值指定应用于签署证书的算法。此算法必须与-keyalg值兼容。

-groupname值指定要生成的密钥的命名组(例如,椭圆曲线的标准或预定义名称)。只能指定-groupname-keysize中的一个。

-signer值指定已存在于密钥库中的签名者的PrivateKeyEntry的别名。此选项用于使用签名者的私钥签署证书。这对于密钥协议算法特别有用(即-keyalg值为XDHX25519X448DH),因为这些密钥不能用于数字签名,因此无法创建自签名证书。

-signerkeypass值指定签名者的私钥密码。如果签名者条目的私钥受到与存储密码不同的密码保护,则可以指定它。

-dname值指定要与-alias的值关联的X.500专有名称。如果未指定-signer选项,则自签名证书的颁发者和主题字段将填充指定的专有名称。如果指定了-signer选项,则证书的主题字段将填充指定的专有名称,颁发者字段将填充签名者证书的主题字段。如果在命令行上未提供专有名称,则会提示用户输入。

-keypass的值是用于保护生成的密钥对的私钥的密码。如果未提供密码,则会提示用户输入。如果在提示符处按下Return键,则密钥密码将设置为与密钥库密码相同的密码。 -keypass值必须至少包含六个字符。

-startdate的值指定证书的发行时间,也称为X.509证书有效性字段的“Not Before”值。

选项值可以以以下两种形式之一设置:

([+-]nnn[ymdHMS])+

[yyyy/mm/dd] [HH:MM:SS]

使用第一种形式,发行时间将根据当前时间的指定值进行偏移。该值是一系列子值的串联。在每个子值内部,加号(+)表示向前移动,减号(-)表示向后移动。要移动的时间是nnn年、月、日、小时、分钟或秒的单位(分别用ymdHMS表示)。通过在每个子值上从左到右使用java.util.GregorianCalendar.add(int field, int amount)方法计算发行时间的确切值。例如,可以通过以下方式指定发行时间:

Calendar c = new GregorianCalendar();
c.add(Calendar.YEAR, -1);
c.add(Calendar.MONTH, 1);
c.add(Calendar.DATE, -1);
return c.getTime()

使用第二种形式,用户以两部分设置确切的发行时间,年/月/日和小时:分钟:秒(使用本地时区)。用户只能提供一部分,这意味着另一部分与当前日期(或时间)相同。用户必须提供格式定义中显示的确切位数的数字(长度不足时用0填充)。当提供日期和时间时,两部分之间有一个(且仅有一个)空格字符。小时应始终以24小时制提供。

当未提供该选项时,起始日期为当前时间。该选项只能提供一次。

date的值指定证书应被视为有效的天数(从由-startdate指定的日期开始,或当未指定-startdate时为当前日期)。

-genseckey

以下是-genseckey命令的可用选项:

  • {-alias alias}:要处理的条目的别名

  • [-keypass arg]:密钥密码

  • -keyalg alg:密钥算法名称

  • {-keysize size}:密钥位大小

  • {-keystore keystore}:密钥库名称

  • [-storepass arg]:密钥库密码

  • {-storetype type}:密钥库类型

  • {-providername name}:提供者名称

  • {-addprovider name [-providerarg arg]}:按名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}:按完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}:提供者类路径

  • {-v}:详细输出

  • {-protected}:通过受保护机制提供密码

使用-genseckey命令生成一个秘密密钥,并将其存储在由alias标识的新KeyStore.SecretKeyEntry中。

-keyalg的值指定用于生成秘密密钥的算法,-keysize的值指定生成的密钥的大小。 -keypass的值是保护秘密密钥的密码。如果未提供密码,则会提示用户输入。如果在提示符处按下Return键,则密钥密码将设置为用于-keystore的相同密码。 -keypass的值必须至少包含六个字符。

-importcert

以下是-importcert命令的可用选项:

  • {-noprompt}: 不提示

  • {-trustcacerts}: 信任cacerts中的证书

  • {-protected}: 通过受保护的机制提供密码

  • {-alias alias}: 要处理的条目的别名

  • {-file file}: 输入文件名

  • [-keypass arg]: 密钥密码

  • {-keystore keystore}: 密钥库名称

  • {-cacerts}: 访问cacerts密钥库

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供程序名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供程序,带有可选的配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定的类名添加安全提供程序,带有可选的配置参数。

  • {-providerpath list}: 提供程序类路径

  • {-v}: 详细输出

使用-importcert命令从-file file中读取证书或证书链(如果后者以PKCS#7格式的回复或一系列X.509证书的形式提供),并将其存储在由-alias标识的keystore条目中。如果未指定-file file,则从stdin中读取证书或证书链。

keytool命令可以导入X.509 v1、v2和v3证书,以及由该类型证书组成的PKCS#7格式的证书链。要导入的数据必须以二进制编码格式或由Internet RFC 1421标准定义的可打印编码格式(也称为Base64编码)提供。在后一种情况下,编码必须在开始时由一个以-----BEGIN开头的字符串界定,并在结束时由一个以-----END开头的字符串界定。

导入证书有两个原因:将其添加到受信任证书列表中,以及导入从证书颁发机构(CA)接收的证书回复,作为向该CA提交证书签名请求(CSR)的结果。请参阅生成证书请求的命令中的-certreq命令。

导入类型由-alias选项的值表示。如果别名不指向密钥条目,则keytool命令会假定您正在添加受信任的证书条目。在这种情况下,别名不应该已经存在于密钥库中。如果别名已经存在,则keytool命令会输出错误,因为该别名已经存在受信任的证书,并且不会导入证书。如果-alias指向密钥条目,则keytool命令会假定您正在导入证书回复。

-importpass

以下是-importpass命令的可用选项:

  • {-alias alias}: 要处理的条目的别名

  • [-keypass arg]: 密钥密码

  • {-keyalg alg}: 密钥算法名称

  • {-keysize size}: 密钥位大小

  • {-keystore keystore}: 密钥库名称

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供程序名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供程序,带有可选的配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定的类名添加安全提供程序,带有可选的配置参数。

  • {-providerpath list}: 提供程序类路径

  • {-v}: 详细输出

  • {-protected}: 通过受保护的机制提供密码

使用-importpass命令导入密码短语,并将其存储在由-alias标识的新的KeyStore.SecretKeyEntry中。密码短语可以通过标准输入流提供;否则将提示用户输入。 -keypass选项提供一个密码来保护导入的密码短语。如果未提供密码,则将提示用户输入。如果在提示时按下Return键,则密钥密码将设置为与用于keystore的密码相同。 -keypass值必须至少包含六个字符。

从另一个密钥库导入内容的命令

-importkeystore

以下是-importkeystore命令的可用选项:

  • -srckeystore keystore: 源密钥库名称

  • {-destkeystore keystore}: 目标密钥库名称

  • {-srcstoretype type}: 源密钥库类型

  • {-deststoretype type}: 目标密钥库类型

  • [-srcstorepass arg]: 源密钥库密码

  • [-deststorepass arg]: 目标密钥库密码

  • {-srcprotected}: 源密钥库密码受保护

  • {-destprotected}: 目标密钥库密码受保护

  • {-srcprovidername name}: 源密钥库提供者名称

  • {-destprovidername name}: 目标密钥库提供者名称

  • {-srcalias alias}: 源别名

  • {-destalias alias}: 目标别名

  • [-srckeypass arg]: 源密钥密码

  • [-destkeypass arg]: 目标密钥密码

  • {-noprompt}: 不提示

  • {-addprovider name [-providerarg arg]: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定类名添加安全提供者,可选配置参数

  • {-providerpath list}: 提供者类路径

  • {-v}: 详细输出

注意:

这是所有选项的第一行:

-srckeystore keystore -destkeystore keystore

使用-importkeystore命令将单个条目或所有条目从源密钥库导入到目标密钥库。

注意:

如果在使用keytool -importkeystore命令时未指定-destkeystore,则使用的默认密钥库是$HOME/.keystore

当提供-srcalias选项时,命令将标识的单个条目导入到目标密钥库。如果未提供目标别名并且使用-destalias,则-srcalias将用作目标别名。如果源条目受密码保护,则使用-srckeypass来恢复该条目。如果未提供-srckeypass,则keytool命令尝试使用-srcstorepass来恢复该条目。如果未提供或不正确,则提示用户输入密码。目标条目受-destkeypass保护。如果未提供-destkeypass,则目标条目受源条目密码保护。例如,大多数第三方工具要求PKCS#12密钥库中的storepasskeypass相同。为这些工具创建PKCS#12密钥库时,始终指定与-deststorepass相同的-destkeypass

如果未提供-srcalias选项,则将源密钥库中的所有条目导入目标密钥库。每个目标条目存储在源条目的别名下。如果源条目受密码保护,则使用-srcstorepass来恢复该条目。如果未提供或不正确,则提示用户输入密码。如果目标密钥库不支持源密钥库条目类型,或者在将条目存储到目标密钥库时发生错误,则提示用户要么跳过该条目并继续,要么退出。目标条目受源条目密码保护。

如果目标别名已存在于目标密钥库中,则提示用户要么覆盖该条目,要么使用不同的别名创建新条目。

如果提供了-noprompt选项,则不会提示用户输入新的目标别名。现有条目将使用目标别名名称进行覆盖。无法导入的条目将被跳过,并显示警告。

生成证书请求的命令

-certreq

以下是-certreq命令的可用选项:

  • {-alias alias}: 要处理的条目的别名

  • {-sigalg alg}: 签名算法名称

  • {-file file}: 输出文件名

  • [ -keypass arg]: 密钥密码

  • {-keystore keystore}: 密钥库名称

  • {-dname name}: 区别名称

  • {-ext value}: X.509扩展

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}: 提供者类路径

  • {-v}: 详细输出

  • {-protected}: 通过受保护机制提供密码

使用-certreq命令使用PKCS#10格式生成证书签名请求(CSR)。

CSR旨在发送给CA。 CA对证书请求者进行身份验证(通常是离线),并返回证书或证书链以替换密钥库中现有证书链(最初是自签名证书)。

alias关联的私钥用于创建PKCS#10证书请求。要访问私钥,必须提供正确的密码。如果在命令行上未提供-keypass并且与用于保护密钥库完整性的密码不同,则会提示用户输入。如果提供了-dname,则将其用作CSR中的主题。否则,将使用与别名关联的X.500区别名称。

-sigalg值指定应用于签署CSR的算法。

CSR存储在-file file中。如果未指定文件,则CSR将输出到-stdout

使用-importcert命令导入CA的响应。

导出数据的命令

-exportcert

以下是-exportcert命令的可用选项:

  • {-rfc}: 以RFC样式输出

  • {-alias alias}: 要处理的条目的别名

  • {-file file}: 输出文件名

  • {-keystore keystore}: 密钥库名称

  • {-cacerts}: 访问cacerts密钥库

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg] }: 通过完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}: 提供者类路径

  • {-v}: 详细输出

  • {-protected}: 通过受保护机制提供密码

使用-exportcert命令从与-alias alias关联的密钥库中读取证书并将其存储在-file file中。如果未指定文件,则证书将输出到stdout

默认情况下,证书以二进制编码输出。如果指定了-rfc选项,则输出为Internet RFC 1421证书编码标准定义的可打印编码格式。

如果-alias指的是受信任的证书,则输出该证书。否则,-alias指的是具有关联证书链的密钥条目。在这种情况下,返回链中的第一个证书。此证书验证由-alias指定的实体的公钥。

显示数据的命令

-list

以下是-list命令的可用选项:

  • {-rfc}: 以RFC样式输出

  • {-alias alias}: 要处理的条目的别名

  • {-keystore keystore}: 密钥库名称

  • {-cacerts}: 访问cacerts密钥库

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg] }: 通过完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}: 提供者类路径

  • {-v}: 详细输出

  • {-protected}: 通过受保护机制提供密码

使用-list命令将标识为-alias alias的密钥库条目的内容打印到stdout。如果未指定-alias alias,则打印整个密钥库的内容。

默认情况下,此命令打印证书的SHA-256指纹。如果指定了-v选项,则以人类可读格式打印证书,包括所有者、颁发者、序列号和任何扩展等附加信息。如果指定了-rfc选项,则使用Internet RFC 1421证书编码标准定义的可打印编码格式打印证书内容。

注意:

不能在同一命令中同时指定-v-rfc。否则,将报告错误。

-printcert

以下是-printcert命令的可用选项:

  • {-rfc}: 以RFC样式输出

  • {-file cert_file}: 输入文件名

  • {-sslserver server[:port]}:: 安全套接字层(SSL)服务器主机和端口

  • {-jarfile JAR_file}: 签名的.jar文件

  • {-keystore keystore}: 密钥库名称

  • {-trustcacerts}: 信任cacerts的证书

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}: 提供者类路径

  • {-protected}: 通过受保护机制提供密码

  • {-v}: 详细输出

使用-printcert命令从-file cert_file、位于-sslserver server[:port]的SSL服务器或由-jarfile JAR_file指定的签名JAR文件中读取并打印证书。它以人类可读格式打印其内容。当未指定端口时,假定使用标准的HTTPS端口443。

注意:

不能在同一命令中同时提供-sslserver-file选项。否则,将报告错误。如果未指定任何选项,则从stdin读取证书。

当指定-rfc时,keytool命令将按照Internet RFC 1421证书编码标准定义的PEM模式打印证书。

如果从文件或stdin读取证书,则它可能是二进制编码或按照RFC 1421证书编码标准定义的可打印编码格式。

如果SSL服务器位于防火墙后,则可以在命令行上指定-J-Dhttps.proxyHost=proxyhost-J-Dhttps.proxyPort=proxyport选项进行代理隧道。

注意:

此命令可以独立于密钥库使用。此命令不会检查证书签名算法的弱点,如果它是用户密钥库(由-keystore指定)或cacerts密钥库(如果指定了-trustcacerts)中的受信任证书。

-printcertreq

以下是-printcertreq命令的可用选项:

  • {-file file}: 输入文件名

  • {-v}: 详细输出

使用-printcertreq命令打印PKCS#10格式证书请求的内容,该请求可以由keytool -certreq命令生成。该命令从文件中读取请求。如果没有文件,则从标准输入读取请求。

-printcrl

以下是-printcrl命令的可用选项:

  • {-file crl}: 输入文件名

  • {-keystore keystore}: 密钥库名称

  • {-trustcacerts}: 信任cacerts的证书

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}: 提供者类路径

  • {-protected}: 通过受保护机制提供密码

  • {-v}: 详细输出

使用-printcrl命令从-file crl读取证书吊销列表(CRL)。CRL是由颁发它们的CA吊销的数字证书列表。CA生成crl文件。

注意:

此命令可以独立于密钥库使用。此命令尝试使用用户密钥库(由-keystore指定)或cacerts密钥库(如果指定了-trustcacerts)中的证书验证CRL,并在无法验证时打印警告。

管理密钥库的命令

-storepasswd

以下是-storepasswd命令的可用选项:

  • [-new arg]: 新密码

  • {-keystore keystore}: 密钥库名称

  • {-cacerts}: 访问cacerts密钥库

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}: 提供者类路径

  • {-v}: 详细输出

使用-storepasswd命令更改用于保护密钥库内容完整性的密码。新密码由-new arg设置,必须至少包含六个字符。

-keypasswd

以下是-keypasswd命令的可用选项:

  • {-alias alias}: 要处理的条目的别名

  • [-keypass old_keypass]: 密钥密码

  • [-new new_keypass]: 新密码

  • {-keystore keystore}: 密钥库名称

  • {-storepass arg}: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}: 提供者类路径

  • {-v}: 详细输出

使用-keypasswd命令将用于保护由-alias标识的私钥/秘密密钥的密码从-keypass old_keypass更改为-new new_keypass。密码值必须至少包含六个字符。

如果在命令行中未提供-keypass选项,并且-keypass密码与密钥库密码(-storepass arg)不同,则会提示用户输入。

如果在命令行中未提供-new选项,则会提示用户输入。

-delete

以下是-delete命令的可用选项:

  • [-alias alias]: 要处理的条目的别名

  • {-keystore keystore}: 密钥库名称

  • {-cacerts}: 访问cacerts密钥库

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}: 提供者类路径

  • {-v}: 详细输出

  • {-protected}: 通过受保护机制提供密码

使用-delete命令从密钥库中删除-alias alias条目。当未在命令行中提供时,会提示用户输入alias

-changealias

以下是-changealias命令的可用选项:

  • {-alias alias}: 要处理的条目的别名

  • [-destalias alias]: 目标别名

  • [-keypass arg]: 密钥密码

  • {-keystore keystore}: 密钥库名称

  • {-cacerts}: 访问cacerts密钥库

  • [-storepass arg]: 密钥库密码

  • {-storetype type}: 密钥库类型

  • {-providername name}: 提供者名称

  • {-addprovider name [-providerarg arg]}: 通过名称(如SunPKCS11)添加安全提供者,可选配置参数。

  • {-providerclass class [-providerarg arg]}: 通过完全限定类名添加安全提供者,可选配置参数。

  • {-providerpath list}: 提供者类路径

  • {-v}: 详细输出

  • {-protected}: 通过受保护机制提供密码

使用-changealias命令将现有密钥库条目从-alias alias移动到新的-destalias alias。如果未提供目标别名,则命令会提示您输入一个。如果原始条目受条目密码保护,则可以使用-keypass选项提供密码。如果未提供密钥密码,则首先尝试-storepass(如果提供)。如果尝试失败,则提示用户输入密码。

-showinfo

以下是-showinfo命令的可用选项:

  • {-tls}: 显示TLS配置信息

  • {-v}: 详细输出

使用-showinfo命令显示各种安全相关信息。-tls选项显示TLS配置,如启用的协议列表和密码套件。

用于显示程序版本的命令

您可以使用-version打印keytool的程序版本。

用于显示帮助信息的命令

您可以使用--help显示keytool命令列表或显示关于特定keytool命令的帮助信息。

常见命令选项

除了--help之外,-v选项可以出现在所有命令中。当出现-v选项时,表示详细模式,输出提供更多信息。

-Joption参数可以出现在任何命令中。使用-Joption时,指定的option字符串直接传递给Java解释器。此选项不包含任何空格。它用于调整执行环境或内存使用。要获取可能的解释器选项列表,请在命令行中输入java -hjava -X

这些选项可以出现在所有操作密钥库的命令中:

-storetype 存储类型
此限定符指定要实例化的密钥库的类型。
-keystore 密钥库

密钥库位置。

如果使用JKS storetype 并且尚未存在密钥库文件,则某些 keytool 命令可能会导致创建新的密钥库文件。例如,如果调用 keytool -genkeypair 并且未指定 -keystore 选项,则如果用户的主目录中尚不存在名为 .keystore 的默认密钥库文件,则会创建一个。同样,如果指定了 -keystore ks_file 选项但 ks_file 不存在,则会创建它。有关JKS storetype 的更多信息,请参阅 KeyStore Implementation 部分中的 KeyStore aliases

请注意,从 -keystore 选项的输入流传递给 KeyStore.load 方法。如果将URL指定为 NONE,则将传递一个空流给 KeyStore.load 方法。如果密钥库不基于文件,则应指定 NONE。例如,当密钥库驻留在硬件令牌设备上时。

-cacerts cacerts
操作 cacerts 密钥库。此选项等效于 -keystore path_to_cacerts -storetype type_of_cacerts。如果与 -cacerts 选项一起使用 -keystore-storetype 选项,则会报告错误。
-storepass [:env | :file ] 参数

envfile,则密码的值为 参数,该值必须至少包含六个字符。否则,密码将按以下方式检索:

  • env:从名为 参数 的环境变量中检索密码。

  • file:从名为 参数 的文件中检索密码。

注意:所有需要密码的其他选项,例如 -keypass-srckeypass-destkeypass-srcstorepass-deststorepass,都接受 envfile 修饰符。请记住使用冒号(:)分隔密码选项和修饰符。

-storepass 选项,则会提示用户输入密码。

-providername 名称
用于在安全属性文件中列出时标识加密服务提供程序的名称。
-addprovider 名称
用于按名称(例如SunPKCS11)添加安全提供程序。
-providerclass
用于在安全属性文件中未列出服务提供程序时指定加密服务提供程序的主类文件的名称。
-providerpath 列表
用于指定提供程序类路径。
-providerarg 参数
-addprovider-providerclass 选项一起使用,表示 名的构造函数的可选字符串输入参数。
-protected=true|false
当必须通过受保护的身份验证路径(例如专用PIN阅读器)指定密码时,请将此值指定为 true。由于 -importkeystore 命令涉及两个密钥库,因此为源密钥库和目标密钥库分别提供了以下两个选项,-srcprotected-destprotected
-ext {名称{:critical} {=}}
表示X.509证书扩展。此选项可用于在 -genkeypair-gencert 中将扩展嵌入生成的证书中,或者在 -certreq 中显示请求的证书中请求的扩展。该选项可以多次出现。 名称 参数可以是受支持的扩展名称(请参见支持的命名扩展)或任意OID编号。提供 参数时,表示扩展的参数。当省略 时,扩展的默认值或扩展本身不需要参数。提供 :critical 修饰符时,表示扩展的 isCritical 属性为 true;否则为 false。您可以使用 :c 代替 :critical
-conf 文件
指定预配置的选项文件。

预配置的选项文件

预配置的选项文件是一个Java属性文件,可以使用 -conf 选项指定。每个属性代表一个使用 "keytool.command_name" 作为属性名称的keytool命令的默认选项。名为 "keytool.all" 的特殊属性表示应用于所有命令的默认选项。属性值可以包括 ${prop},它将扩展为与之关联的系统属性。如果选项值包含内部的空格,则应该用引号("或')括起来。所有属性名称必须小写。

keytool 时,如果存在 "keytool.all" 的值,则首先将其前置到 keytool 命令行中,然后是命令名称的值(如果存在),最后是命令行中现有的选项。对于单值选项,这允许特定命令的属性覆盖 "keytool.all" 值,并且在命令行上指定的值覆盖两者。对于多值选项,所有这些选项都将被 keytool 使用。

preconfig 的以下文件:

    # 一个小型的预配置选项文件
    keytool.all = -keystore ${user.home}/ks
    keytool.list = -v
    keytool.genkeypair = -keyalg rsa

keytool -conf preconfig -list 等同于

keytool -keystore ~/ks -v -list

keytool -conf preconfig -genkeypair -alias me 等同于

keytool -keystore ~/ks -keyalg rsa -genkeypair -alias me

keytool -conf preconfig -genkeypair -alias you -keyalg ec 等同于

keytool -keystore ~/ks -keyalg rsa -genkeypair -alias you -keyalg ec

这等同于

keytool -keystore ~/ks -genkeypair -alias you -keyalg ec

因为 -keyalg 是单值选项,命令行上指定的 ec 值会覆盖预配置选项文件。

选项值示例

-alias "mykey"

-keysize
    2048(使用 -genkeypair 且 -keyalg 为 "DSA" 时)
    3072(使用 -genkeypair 且 -keyalg 为 "RSA"、"RSASSA-PSS" 或 "DH" 时)
    384(使用 -genkeypair 且 -keyalg 为 "EC" 时)
    255(使用 -genkeypair 且 -keyalg 为 "EdDSA" 或 "XDH" 时)
    56(使用 -genseckey 且 -keyalg 为 "DES" 时)
    168(使用 -genseckey 且 -keyalg 为 "DESede" 时)

-validity 90

-keystore <用户主目录中名为 .keystore 的文件>

-destkeystore <用户主目录中名为 .keystore 的文件>

-storetype <安全属性文件中的 "keystore.type" 属性值,由 java.security.KeyStore 的静态 getDefaultType 方法返回>

-file
    stdin(读取时)
    stdout(写入时)

-protected false
-sigalg 选项)从底层私钥的算法派生,以提供适当的安全强度,如下所示:

默认签名算法
密钥算法 密钥大小 默认签名算法
DSA 任意大小 SHA256withDSA
RSA < 624 SHA256withRSA(密钥大小太小,无法使用SHA-384)
<= 7680 SHA384withRSA
> 7680 SHA512withRSA
EC < 512 SHA384withECDSA
>= 512 SHA512withECDSA
RSASSA-PSS < 624 RSASSA-PSS(使用SHA-256,密钥大小太小)
使用SHA-384)
<= 7680 RSASSA-PSS(使用SHA-384)
> 7680 RSASSA-PSS(使用SHA-512)
EdDSA 255 Ed25519
448 Ed448
Ed25519 255 Ed25519
Ed448 448 Ed448
  • RSASSA-PSS签名算法使用MessageDigest算法作为其哈希和MGF1算法。

  • EdDSA支持2种密钥大小:Ed25519和Ed448。在使用-keyalg EdDSA生成EdDSA密钥对时,用户可以指定-keysize 255-keysize 448来生成Ed25519或Ed448密钥对。如果未指定-keysize,则生成Ed25519密钥对。用户还可以直接指定-keyalg Ed25519-keyalg Ed448来生成具有预期密钥大小的密钥对。

注意:

为了提高开箱即用的安全性,每个JDK版本发布时默认密钥大小和签名算法名称会定期更新为更强大的值。如果与旧版JDK的互操作性很重要,请确保这些默认值受到支持。或者,您可以使用-keysize-sigalg选项自行覆盖默认值,但需自担风险。

支持的命名扩展

keytool命令支持以下命名扩展。名称不区分大小写。

BCBasicContraints

值:

完整形式为ca:{true|false}[,pathlen:len]或len,简写形式为ca:true,pathlen:len

当省略len时,结果值为ca:true

KUKeyUsage

值:

usage(, usage)*

usage可以是以下之一:

  • digitalSignature

  • nonRepudiationcontentCommitment

  • keyEncipherment

  • dataEncipherment

  • keyAgreement

  • keyCertSign

  • cRLSign

  • encipherOnly

  • decipherOnly

除非存在歧义,usage参数可以用前几个字母缩写(例如dig代表digitalSignature)或驼峰式样式(例如dS代表digitalSignaturecRLS代表cRLSign)。usage的值区分大小写。

EKUExtendedKeyUsage

值:

usage(, usage)*

usage可以是以下之一:

  • anyExtendedKeyUsage

  • serverAuth

  • clientAuth

  • codeSigning

  • emailProtection

  • timeStamping

  • OCSPSigning

  • 任何OID字符串

除非存在歧义,usage参数可以用前几个字母缩写或驼峰式样式。usage的值区分大小写。

SANSubjectAlternativeName

值:

type:value(, type:value)*

type可以是以下之一:

  • EMAIL

  • URI

  • DNS

  • IP

  • OID

value参数是type的字符串格式值。

IANIssuerAlternativeName

值:

SANSubjectAlternativeName相同。

SIASubjectInfoAccess

值:

method:location-type:location-value(, method:location-type:location-value)*

method可以是以下之一:

  • timeStamping

  • caRepository

  • 任何OID

location-typelocation-value参数可以是SubjectAlternativeName扩展支持的任何type:value

AIAAuthorityInfoAccess

值:

SIASubjectInfoAccess相同。

method参数可以是以下之一:

  • ocsp

  • caIssuers

  • 任何OID

name为OID时,值是扩展的extnValue的十六进制转储的确定编码规则(DER)编码,不包括OCTET STRING类型和长度字节。除了标准十六进制数字(0-9,a-f,A-F)外,HEX字符串中的任何额外字符都将被忽略。因此,01:02:03:04和01020304都被接受为相同的值。当没有值时,扩展具有空值字段。

特殊名称honored仅在-gencert中使用,表示应如何尊重包含在证书请求中的扩展。此名称的值是all(尊重所有请求的扩展)、name{:[critical|non-critical]}(尊重命名扩展,但使用不同的isCritical属性)和-name(与all一起使用,表示异常)。默认情况下不尊重请求的扩展。

如果除了-ext honored选项外,还提供了另一个命名或OID-ext选项,则此扩展将添加到已尊重的扩展中。但是,如果此名称(或OID)也出现在受尊重的值中,则其值和关键性将覆盖请求中的值。如果通过名称或OID多次提供相同类型的扩展,则仅使用最后一个扩展。

subjectKeyIdentifier扩展始终会被创建。对于非自签名证书,将创建authorityKeyIdentifier

注意:

用户应注意,某些扩展(以及其他证书字段)的组合可能不符合互联网标准。请参阅证书符合性警告

创建密钥库中任务的示例

以下示例描述了创建用于管理来自受信任实体的公钥/私钥对和证书的密钥库的序列操作。

生成密钥对

创建一个密钥库,然后生成密钥对。

您可以将命令输入为单行,如下所示:

keytool -genkeypair -dname "cn=myname, ou=mygroup, o=mycompany, c=mycountry" -alias business -keyalg rsa -keypass password -keystore /working/mykeystore -storepass password -validity 180

该命令在工作目录中创建名为mykeystore的密钥库(如果尚不存在),并为其分配由-keypass指定的密码。它为具有专有名称mynamemygroupmycompany和两个字母国家代码mycountry的实体生成公钥/私钥对。它使用RSA密钥生成算法创建密钥;密钥长度均为3072位。

该命令使用默认的SHA384withRSA签名算法创建一个自签名证书,其中包括公钥和专有名称信息。证书有效期为180天,并与由-alias business引用的密钥库条目中的私钥关联。私钥分配了由-keypass指定的密码。

当接受默认选项时,该命令显著缩短。在这种情况下,只需要-keyalg,未指定的选项将使用默认值。系统会提示您输入任何必需的值。您可以执行以下操作:

keytool -genkeypair -keyalg rsa

在这种情况下,将创建一个别名为mykey的密钥库条目,其中包含一个新生成的密钥对和一个有效期为90天的证书。此条目将放置在名为.keystore的密钥库中的主目录中。如果.keystore尚不存在,则会创建它。系统会提示您输入专有名称信息、密钥库密码和私钥密码。

注意:

其余示例假定您对提示作出的响应与第一个-genkeypair命令中指定的值相等。例如,专有名称为cn=myname, ou=mygroup, o=mycompany, c=mycountry)。

从CA请求签名证书

注意:

生成密钥对会创建一个自签名证书;但是,当证书由CA签名时,其他人更有可能信任证书。

要获得CA签名,请完成以下过程:

  1. 生成CSR:

    keytool -certreq -file myname.csr

    这将为由默认别名mykey标识的实体创建一个CSR,并将请求放入名为myname.csr的文件中。

  2. myname.csr提交给CA,例如DigiCert。

CA对您(通常是离线)进行身份验证,并返回一个由他们签名的证书,用于验证您的公钥。在某些情况下,CA会返回一系列证书,每个证书都验证前一个证书链中签名者的公钥。

导入CA的证书

要导入CA的证书,请完成以下过程:

  1. 在导入CA的证书回复之前,您需要一个或多个受信任的证书,这些证书可以存在于您的密钥库中或cacerts密钥库文件中。请参阅命令中的-importcert

    • 如果证书回复是证书链,则您需要链中的顶级证书。即验证CA公钥的根CA证书。

    • 如果证书回复是单个证书,则您需要签发该证书的CA的证书。如果该证书不是自签名的,则需要其签发者的证书,依此类推,直到自签名的根CA证书。

    cacerts密钥库中包含由Oracle Java根证书计划的CA颁发的一组根证书。如果您向CA请求签名证书,并且尚未将验证该CA公钥的证书添加到cacerts中,则必须将来自该CA的证书导入为受信任的证书。

    CA的证书通常是自签名的或由另一个CA签名的。如果由另一个CA签名,则需要一个验证该CA公钥的证书。

    例如,您从一家公司获得了一个X.cer文件,该公司是一家CA,该文件应该是一个验证该CA公钥的自签名证书。在将其导入为受信任的证书之前,您应确保该证书有效:

    1. 使用keytool -printcert命令或不使用-noprompt选项的keytool -importcert命令查看它。确保显示的证书指纹与预期的指纹匹配。

    2. 联系发送证书的人,并将您看到的指纹与他们展示的指纹或安全公钥存储库显示的指纹进行比较。

    只有在指纹相等时,才能确保证书在传输过程中未被替换为其他人的证书(例如攻击者的证书)。如果发生这样的攻击,并且在导入证书之前未检查证书,则您将信任攻击者签名的任何内容。

  2. 将自签名证书替换为证书链,其中链中的每个证书都验证前一个证书链中签名者的公钥,直到根CA。

    如果您相信证书有效,则可以通过输入以下命令将其添加到您的密钥库中:

    keytool -importcert -alias alias -file *X*.cer`

    此命令从CA证书文件中的数据创建一个受信任的证书条目,并将alias的值分配给该条目。

导入来自CA的证书回复

在导入验证您提交证书签名请求的CA公钥的证书之后(或cacerts文件中已经存在这样的证书),您可以导入证书回复并用证书链替换您的自签名证书。

证书链可以是以下之一:

  • 当CA回复为链时,由CA返回。

  • 当CA回复为单个证书时构建。此证书链是通过使用证书回复和可用于导入回复的密钥库中的受信任证书或cacerts密钥库文件中的受信任证书构建的。

例如,如果您将证书签名请求发送给DigiCert,则可以通过输入以下命令导入其回复:

注意:

在此示例中,返回的证书名为DCmyname.cer

keytool -importcert -trustcacerts -file DCmyname.cer

导出验证公钥的证书

注意:

如果您使用jarsigner命令对Java存档(JAR)文件进行签名,则使用该文件的客户端将希望验证您的签名。

客户端可以通过将您的公钥证书导入其密钥库作为受信任条目来验证您的签名。然后,您可以导出证书并提供给您的客户端。

例如:

  1. 通过输入以下命令将您的证书复制到名为myname.cer的文件中:

    注意:

    在此示例中,该条目的别名为mykey

    keytool -exportcert -alias mykey -file myname.cer

  2. 使用证书和签名的JAR文件,客户端可以使用jarsigner命令验证您的签名。

导入密钥库

使用importkeystore命令将整个密钥库导入另一个密钥库。这将通过单个命令从源密钥库中导入所有条目,包括密钥和证书,到目标密钥库中。您可以使用此命令从不同类型的密钥库中导入条目。在导入过程中,目标密钥库中的所有新条目都将具有相同的别名和保护密码(用于秘密密钥和私钥)。如果keytool命令无法从源密钥库中恢复私钥或秘密密钥,则会提示您输入密码。如果检测到别名重复,则会要求您提供新别名,您可以指定新别名,或者简单地允许keytool命令覆盖现有别名。

例如,通过输入以下命令,从典型的JKS类型密钥库key.jks中导入条目到基于PKCS#11类型硬件的密钥库:

keytool -importkeystore -srckeystore key.jks -destkeystore NONE -srcstoretype JKS -deststoretype PKCS11 -srcstorepass password -deststorepass password

importkeystore命令还可用于将单个条目从源密钥库导入到目标密钥库。在这种情况下,除了您在上一个示例中使用的选项外,还需要指定要导入的别名。通过指定-srcalias选项,您还可以指定要导入的目标别名、用于秘密或私钥的保护密码,以及您希望的目标保护密码,如下所示:

keytool -importkeystore -srckeystore key.jks -destkeystore NONE -srcstoretype JKS -deststoretype PKCS11 -srcstorepass password -deststorepass password -srcalias myprivatekey -destalias myoldprivatekey -srckeypass password -destkeypass password -noprompt

为SSL服务器生成证书

以下是用于为三个实体生成密钥对和证书的keytool命令:

  • 根CA(root

  • 中间CA(ca

  • SSL服务器(server

确保将所有证书存储在同一个密钥库中。

keytool -genkeypair -keystore root.jks -alias root -ext bc:c -keyalg rsa
keytool -genkeypair -keystore ca.jks -alias ca -ext bc:c -keyalg rsa
keytool -genkeypair -keystore server.jks -alias server -keyalg rsa

keytool -keystore root.jks -alias root -exportcert -rfc > root.pem

keytool -storepass password -keystore ca.jks -certreq -alias ca |
    keytool -storepass password -keystore root.jks
    -gencert -alias root -ext BC=0 -rfc > ca.pem
keytool -keystore ca.jks -importcert -alias ca -file ca.pem

keytool -storepass password -keystore server.jks -certreq -alias server |
    keytool -storepass password -keystore ca.jks -gencert -alias ca
    -ext ku:c=dig,kE -rfc > server.pem
cat root.pem ca.pem server.pem |
    keytool -keystore server.jks -importcert -alias server

术语

密钥库
密钥库是用于存储加密密钥和证书的存储设施。
密钥库条目

密钥库可以包含不同类型的条目。对于keytool命令最适用的两种条目类型包括以下内容:

密钥条目:每个条目保存非常敏感的加密密钥信息,以受保护的格式存储,以防止未经授权的访问。通常,存储在此类型条目中的密钥是一个秘密密钥,或者是附带相应公钥的私钥的证书链。请参阅证书链keytool命令可以处理这两种类型的条目,而jarsigner工具只处理后一种类型的条目,即私钥及其相关的证书链。

受信任的证书条目:每个条目包含属于另一方的单个公钥证书。该条目被称为受信任的证书,因为密钥库所有者相信证书中的公钥属于由证书的主体(所有者)标识的身份。证书的颁发者通过签署证书为此作证。

密钥库别名

所有密钥库条目(密钥和受信任的证书条目)都通过唯一别名访问。

当您使用-genseckey命令生成秘密密钥,-genkeypair命令生成密钥对(公钥和私钥),或-importcert命令将证书或证书链添加到受信任证书列表时,需要指定别名。后续的keytool命令必须使用相同的别名引用实体。

例如,您可以使用别名duke生成新的公钥/私钥对,并将公钥包装成自签名证书,使用以下命令。请参阅证书链

keytool -genkeypair -alias duke -keyalg rsa -keypass passwd

此示例指定后续命令访问与别名duke关联的私钥所需的初始passwd。如果以后要更改Duke的私钥密码,请使用以下命令:

keytool -keypasswd -alias duke -keypass passwd -new newpasswd

这将把初始passwd更改为newpasswd。除非用于测试目的或在安全系统上,否则不应在命令行或脚本中指定密码。如果在命令行上未指定所需的密码选项,则会提示您输入密码。

密钥库实现

提供在java.security包中的KeyStore类提供了访问和修改密钥库中信息的明确定义接口。可能存在多个不同的具体实现,其中每个实现都是特定类型密钥库的实现。

目前,两个命令行工具(keytooljarsigner)使用密钥库实现。由于KeyStore类是public的,用户可以编写使用它的其他安全应用程序。

在JDK 9及更高版本中,默认的密钥库实现是PKCS12。这是基于RSA PKCS12个人信息交换语法标准的跨平台密钥库。该标准主要用于存储或传输用户的私钥、证书和其他秘密信息。还有另一个由Oracle提供的内置实现。它将密钥库实现为具有专有密钥库类型(格式)JKS的文件。它使用单独的密码保护每个私钥,并使用(可能不同的)密码保护整个密钥库的完整性。

密钥库实现是基于提供程序的。更具体地说,由KeyStore提供的应用程序接口是基于服务提供程序接口(SPI)实现的。也就是说,在java.security包中还有一个相应的抽象KeystoreSpi类,它定义了提供程序必须实现的服务提供程序接口方法。术语提供程序指的是提供Java安全API可以访问的一组服务的包或一组包。要提供密钥库实现,客户端必须实现一个提供程序并提供一个KeystoreSpi子类实现,如实现和集成提供程序的步骤中所述。

应用程序可以使用KeyStore类中提供的getInstance工厂方法从不同提供程序中选择不同类型的密钥库实现。密钥库类型定义了密钥库信息的存储和数据格式,以及用于保护密钥库中的私钥/秘密密钥和密钥库完整性的算法。不同类型的密钥库实现不兼容。

keytool命令适用于任何基于文件的密钥库实现。它将传递给它的密钥库位置视为文件名,并将其转换为FileInputStream,从中加载密钥库信息。)jarsigner命令可以从可以用URL指定的任何位置读取密钥库。

对于keytooljarsigner,您可以在命令行上使用-storetype选项指定密钥库类型。

如果未明确指定密钥库类型,则工具将根据安全属性文件中指定的keystore.type属性的值选择密钥库实现。安全属性文件名为java.security,位于安全属性目录中:

  • Linux和macOS: java.home/lib/security

  • Windows: java.home\lib\security

每个工具获取keystore.type值,然后检查所有当前安装的提供程序,直到找到一个实现该类型密钥库的提供程序。然后使用该提供程序的密钥库实现。KeyStore类定义了一个名为getDefaultType的静态方法,允许应用程序检索keystore.type属性的值。以下代码行创建了一个根据keystore.type属性指定的默认密钥库类型的实例:

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

默认的密钥库类型是pkcs12,这是基于RSA PKCS12个人信息交换语法标准的跨平台密钥库。在安全属性文件中通过以下行指定:

keystore.type=pkcs12

要使工具使用除默认之外的密钥库实现,可以更改该行以指定不同的密钥库类型。例如,如果要使用Oracle的jks密钥库实现,则将该行更改为以下内容:

keystore.type=jks

注意:

密钥库类型的指定不区分大小写。例如,JKS将被视为与jks相同。

证书

证书(或公钥证书)是来自一个实体(颁发者)的数字签名声明,说明另一个实体(主体)的公钥和其他一些信息具有特定值。以下术语与证书相关:

  • 公钥:这些是与特定实体相关联的数字,旨在为需要与该实体进行可信交互的所有人知晓。公钥用于验证签名。

  • 数字签名:如果某些数据经过数字签名,则存储有关实体身份和证明该实体了解数据的签名。通过使用实体的私钥签名,数据变得无法伪造。

  • 身份:对实体进行寻址的已知方式。在某些系统中,身份是公钥,而在其他系统中,它可以是从Oracle Solaris UID到电子邮件地址到X.509专有名称的任何内容。

  • 签名:使用实体的私钥对一些数据进行计算的签名。在证书的情况下,签名者也被称为颁发者。

  • 私钥:这些是数字,每个数字只应该为拥有该私钥的特定实体所知(即,应该保密)。在所有公钥加密系统(也称为公钥加密系统)中,私钥和公钥是成对存在的。在典型的公钥加密系统中,如DSA,一个私钥对应于一个公钥。私钥用于计算签名。

  • 实体:实体可以是一个人、组织、程序、计算机、企业、银行或其他您在某种程度上信任的东西。

公钥加密需要访问用户的公钥。在大规模网络环境中,无法保证通信实体之间建立了先前关系,也无法保证存在具有所有使用的公钥的受信任存储库。证书被发明作为解决这个公钥分发问题的解决方案。现在,认证机构(CA)可以充当受信任的第三方。CA是诸如企业之类的实体,被信任为其他实体签署(颁发)证书。假定CA只创建有效和可靠的证书,因为它们受法律协议约束。有许多公共认证机构,如DigiCert、Comodo、Entrust等。

您还可以使用Microsoft Certificate Server或Entrust CA产品为您的组织运行自己的认证机构。使用keytool命令,可以显示、导入和导出证书。还可以生成自签名证书。

keytool命令目前处理X.509证书。

X.509证书

X.509标准定义了证书中可以包含的信息,并描述了如何将其写入(数据格式)。证书中的所有数据都使用两个相关的标准进行编码,称为ASN.1/DER。抽象语法表示法1描述数据。确定编码规则描述了存储和传输数据的单一方式。

除了签名之外,所有X.509证书都包含以下数据:

  • 版本:这标识了适用于此证书的X.509标准版本,这会影响可以在其中指定的信息。到目前为止,已定义了三个版本。keytool命令可以导入和导出v1、v2和v3证书。它生成v3证书。

    • X.509版本1自1988年以来就可用,被广泛部署,是最通用的。

    • X.509版本2引入了主题和颁发者唯一标识的概念,以处理主题或颁发者名称随时间重复使用的可能性。大多数证书配置文件文档强烈建议不要重复使用名称,并且证书不应使用唯一标识。版本2证书并不广泛使用。

    • X.509版本3是最新的(1996年),支持扩展的概念,任何人都可以定义扩展并将其包含在证书中。一些常见的扩展包括:KeyUsage(限制密钥的用途,例如仅用于签名)和AlternativeNames(允许将其他身份与此公钥关联,例如DNS名称、电子邮件地址、IP地址)。扩展可以标记为关键以指示应检查和执行或使用扩展。例如,如果证书的KeyUsage扩展标记为关键并设置为keyCertSign,则在SSL通信期间呈现此证书时,应拒绝该证书,因为证书扩展指示相关私钥仅应用于签署证书,而不用于SSL使用。

  • 序列号:创建证书的实体负责为其分配一个序列号,以将其与发行的其他证书区分开。此信息以多种方式使用。例如,当证书被吊销时,其序列号将放入证书吊销列表(CRL)中。

  • 签名算法标识符:这标识CA用于签署证书的算法。

  • 颁发者名称:签署证书的实体的X.500专有名称。通常是CA。使用此证书意味着信任签署此证书的实体。在某些情况下,例如根或顶级CA证书,颁发者会签署自己的证书。

  • 有效期:每个证书仅在有限的时间内有效。此期间由开始日期和时间以及结束日期和时间描述,可以短至几秒钟或几乎长达一个世纪。所选的有效期取决于许多因素,例如用于签署证书的私钥强度,或者愿意为证书支付的金额。这是实体可以依赖公共值的预期期间,当相关私钥未被破坏时。

  • 主题名称:证书标识的实体的名称。此名称使用X.500标准,因此旨在在互联网上是唯一的。这是实体的X.500专有名称(DN)。例如,

    CN=Java Duke, OU=Java Software Division, O=Oracle Corporation, C=US

    这些是主题的通用名称(CN)、组织单位(OU)、组织(O)和国家(C)。

  • 主题公钥信息:这是被命名实体的公钥,带有指定该密钥所属的公钥加密系统以及任何相关的密钥参数的算法标识符。

证书链

keytool命令可以创建和管理包含私钥和关联证书链的密钥库密钥条目。链中的第一个证书包含与私钥对应的公钥。

当首次生成密钥时,链通常以包含单个元素的形式开始,即自签名证书。请参阅Commands中的-genkeypair。自签名证书是其颁发者(签署者)与主题相同的证书。主题是由证书进行身份验证的公钥的实体。当调用-genkeypair命令生成新的公钥/私钥对时,它还将公钥包装到自签名证书中(除非指定了-signer选项)。

稍后,使用-certreq命令生成了证书签名请求(CSR)并将其发送给认证机构(CA)后,从CA的响应中导入了-importcert,并且自签名证书被一系列证书替换。在链的底部是由CA签发的证书(回复),用于验证主题的公钥。链中的下一个证书是用于验证CA的公钥的证书。

在许多情况下,这是一个自签名证书,即CA签发的证书,用于验证其自己的公钥,并且是链中的最后一个证书。在其他情况下,CA可能返回一系列证书。在这种情况下,链中的底部证书是相同的(由CA签发的证书,用于验证密钥条目的公钥),但链中的第二个证书是由不同CA签发的证书,用于验证您发送CSR的CA的公钥。链中的下一个证书是用于验证第二个CA的密钥的证书,依此类推,直到达到自签名根证书。链中的每个证书(除第一个外)都验证链中前一个证书的签名者的公钥。

许多CA只返回已签发的证书,没有支持链,特别是在扁平层次结构(没有中间CA)的情况下。在这种情况下,必须从已存储在密钥库中的受信任证书信息建立证书链。

另一种回复格式(由PKCS#7标准定义)包括支持证书链以及已签发的证书。keytool命令可以处理这两种回复格式。

顶级(根)CA证书是自签名的。但是,对根公钥的信任不是来自根证书本身,而是来自其他来源,例如报纸。这是因为任何人都可以生成具有DigiCert根CA的专有名称的自签名证书。根CA公钥是广为人知的。它之所以存储在证书中,仅因为这是大多数工具理解的格式,因此在这种情况下,证书仅用作传输根CA公钥的工具。在将根CA证书添加到密钥库之前,应使用-printcert选项查看它,并将显示的指纹与从报纸、根CA网页等获取的众所周知的指纹进行比较。

cacerts证书文件

一个名为cacerts的证书文件位于安全属性目录中:

  • Linux和macOS: JAVA_HOME/lib/security

  • Windows: JAVA_HOME\lib\security

cacerts文件代表具有CA证书的系统范围密钥库。系统管理员可以使用keytool命令通过指定jks作为密钥库类型来配置和管理该文件。cacerts密钥库文件附带了一组默认的根CA证书。对于Linux、macOS和Windows,您可以使用以下命令列出默认证书:

keytool -list -cacerts

cacerts密钥库文件的初始密码是changeit。系统管理员在安装SDK时应更改该密码和该文件的默认访问权限。

注意:

验证您的cacerts文件非常重要。因为您信任cacerts文件中的CA作为签署和颁发证书给其他实体的实体,您必须仔细管理cacerts文件。cacerts文件应仅包含您信任的CA的证书。您有责任验证cacerts文件中捆绑的受信任根CA证书,并做出自己的信任决定。

要从cacerts文件中删除不受信任的CA证书,请使用keytool命令的-delete选项。您可以在JDK的$JAVA_HOME/lib/security目录中找到cacerts文件。如果您没有权限编辑此文件,请联系系统管理员。

互联网RFC 1421证书编码标准

证书通常使用互联网RFC 1421标准定义的可打印编码格式存储,而不是它们的二进制编码。这种证书格式,也称为Base64编码,使得通过电子邮件或其他机制将证书导出到其他应用程序变得容易。

由-importcert和-printcert命令读取的证书可以是此格式或二进制编码。-exportcert命令默认以二进制编码输出证书,但当指定-rfc选项时,将以可打印编码格式输出证书。

-list命令默认打印证书的SHA-256指纹。如果指定了-v选项,则以人类可读格式打印证书。如果指定了-rfc选项,则以可打印编码格式输出证书。

在其可打印编码格式中,编码的证书在开头和结尾被以下文本包围:

-----BEGIN CERTIFICATE-----

编码的证书在此处。

-----END CERTIFICATE-----
X.500专有名称

X.500专有名称用于标识实体,例如X.509证书的subjectissuer(签发者)字段命名的实体。 keytool命令支持以下子部分:

  • commonName: 个人的常用名称,例如Susan Jones。

  • organizationUnit: 小组织(如部门或部门)名称。例如,采购。

  • localityName: 地点(城市)名称,例如Palo Alto。

  • stateName: 州或省名称,例如California。

  • country: 两字母国家代码,例如CH。

当您将专有名称字符串作为-dname选项的值提供,例如对于-genkeypair命令,字符串必须采用以下格式:

CN=cName, OU=orgUnit, O=org, L=city, S=state, C=countryCode

所有以下项目都代表实际值,前面的关键字是以下缩写:

CN=commonName
OU=organizationUnit
O=organizationName
L=localityName
S=stateName
C=country

一个示例专有名称字符串是:

CN=Mark Smith, OU=Java, O=Oracle, L=Cupertino, S=California, C=US

使用此类字符串的示例命令是:

keytool -genkeypair -dname "CN=Mark Smith, OU=Java, O=Oracle, L=Cupertino, S=California, C=US" -alias mark -keyalg rsa

关键字缩写的大小写不重要。例如,CN、cn和Cn都被视为相同。

顺序很重要;每个子组件必须按指定顺序出现。但是,并不需要拥有所有子组件。您可以使用子集,例如:

CN=Smith, OU=Java, O=Oracle, C=US

如果专有名称字符串值包含逗号,则在命令行上指定字符串时,逗号必须由反斜杠(\)字符转义,如:

cn=Jack, ou=Java\, Product Development, o=Oracle, c=US

在命令行上永远不需要指定专有名称字符串。当命令需要专有名称但未在命令行上提供时,用户将提示输入每个子组件。在这种情况下,逗号不需要由反斜杠(\)转义。

警告

导入受信任证书警告

重要:在将证书导入为受信任证书之前,请务必仔细检查证书。

Windows示例:

首先使用-printcert命令或不带-noprompt选项的-importcert命令查看证书。确保显示的证书指纹与预期的一致。例如,假设有人向您发送或通过电子邮件发送了一个证书,您将其放在名为\tmp\cert的文件中。在将证书添加到受信任证书列表之前,您可以执行-printcert命令查看其指纹,如下所示:

  keytool -printcert -file \tmp\cert
    拥有者: CN=ll, OU=ll, O=ll, L=ll, S=ll, C=ll
    颁发者: CN=ll, OU=ll, O=ll, L=ll, S=ll, C=ll
    序列号: 59092b34
    有效期: 从 Thu Jun 24 18:01:13 PDT 2016 到 Wed Jun 23 17:01:13 PST 2016
    证书指纹:

                   SHA-1: 20:B6:17:FA:EF:E5:55:8A:D0:71:1F:E8:D6:9D:C0:37:13:0E:5E:FE
                 SHA-256: 90:7B:70:0A:EA:DC:16:79:92:99:41:FF:8A:FE:EB:90:
                          17:75:E0:90:B2:24:4D:3A:2A:16:A6:E4:11:0F:67:A4

Linux示例:

首先使用-printcert命令或不带-noprompt选项的-importcert命令查看证书。确保显示的证书指纹与预期的一致。例如,假设有人向您发送或通过电子邮件发送了一个证书,您将其放在名为/tmp/cert的文件中。在将证书添加到受信任证书列表之前,您可以执行-printcert命令查看其指纹,如下所示:

  keytool -printcert -file /tmp/cert
    拥有者: CN=ll, OU=ll, O=ll, L=ll, S=ll, C=ll
    颁发者: CN=ll, OU=ll, O=ll, L=ll, S=ll, C=ll
    序列号: 59092b34
    有效期: 从 Thu Jun 24 18:01:13 PDT 2016 到 Wed Jun 23 17:01:13 PST 2016
    证书指纹:

                   SHA-1: 20:B6:17:FA:EF:E5:55:8A:D0:71:1F:E8:D6:9D:C0:37:13:0E:5E:FE
                   SHA-256: 90:7B:70:0A:EA:DC:16:79:92:99:41:FF:8A:FE:EB:90:
                           17:75:E0:90:B2:24:4D:3A:2A:16:A6:E4:11:0F:67:A4

然后致电或以其他方式联系发送证书的人,并将您看到的指纹与他们展示的指纹进行比较。只有当指纹相同时,才能保证证书未在传输过程中被替换为其他人的证书,例如攻击者的证书。如果发生这样的攻击,并且您在导入证书之前未检查证书,则将信任攻击者签名的任何内容,例如,一个包含恶意类文件的JAR文件。

注意:

在导入证书之前,不需要执行-printcert命令。这是因为在将证书添加到密钥库中的受信任证书列表之前,-importcert命令会打印出证书信息并提示您验证。然后您可以停止导入操作。但是,只有在调用不带-noprompt选项的-importcert命令时才能这样做。如果指定了-noprompt选项,则不会与用户交互。

密码警告

大多数操作密钥库的命令都需要存储密码。有些命令需要私钥/秘密密钥密码。密码可以在命令行中使用-storepass-keypass选项指定。但是,除非用于测试,或者您在安全系统上,否则不应在命令行或脚本中指定密码。如果在命令行上未指定所需的密码选项,则会提示您输入密码。

证书符合性警告

Internet X.509公钥基础设施证书和证书吊销列表(CRL)配置文件定义了符合X.509证书的配置文件,其中包括证书字段和扩展的有效值和值组合。

keytool命令不强制执行所有这些规则,因此可能会生成不符合标准的证书,例如用于内部测试目的的自签名证书。不符合标准的证书可能会被JDK或其他应用程序拒绝。用户应确保为-dname-ext等提供正确的选项。

导入新的受信任证书

在将证书添加到密钥库之前,keytool命令通过尝试从已经在密钥库中可用的受信任证书(属于根CA的自签名证书)构建信任链来验证它。

如果指定了-trustcacerts选项,则还会考虑其他证书用于信任链,即名为cacerts的文件中的证书。

如果keytool命令无法从要导入的证书到自签名证书(来自密钥库或cacerts文件)建立信任路径,则会打印证书信息,并提示用户通过比较显示的证书指纹与从其他(受信任)信息源获取的指纹(可能是证书所有者)来验证它。在将证书作为受信任证书导入之前,请务必确保证书有效。然后用户可以选择停止导入操作。如果指定了-noprompt选项,则不会与用户交互。

导入证书回复

当导入证书回复时,证书回复将使用密钥库中的受信任证书进行验证,以及在指定-trustcacerts选项时配置的cacerts密钥库文件中的证书。

确定证书回复是否受信任的方法如下:

  • 如果回复是单个X.509证书,则keytool命令尝试建立信任链,从证书回复开始,到自签名证书(属于根CA)结束。证书回复和证书层次结构用于验证新证书链的证书回复。如果无法建立信任链,则不导入证书回复。在这种情况下,keytool命令不会打印证书并提示用户验证,因为用户很难确定证书回复的真实性。

  • 如果回复是PKCS #7格式的证书链或一系列X.509证书,则链会按照用户证书优先,然后是零个或多个CA证书进行排序。如果链以自签名根CA证书结束,并且指定了-trustcacerts选项,则keytool命令尝试将其与密钥库或cacerts密钥库文件中的任何受信任证书进行匹配。如果链不以自签名根CA证书结束,并且指定了-trustcacerts选项,则keytool命令尝试从密钥库或cacerts密钥库文件中的受信任证书中找到一个,并将其添加到链的末尾。如果未找到证书且未指定-noprompt选项,则会打印链中最后一个证书的信息,并提示用户验证。

如果证书回复中的公钥与用户已存储的alias的公钥匹配,则旧证书链将被回复中的新证书链替换。只有使用有效的keypass才能替换旧链,因此需要提供用于保护条目的私钥的密码。如果未提供密码,并且私钥密码与密钥库密码不同,则会提示用户输入密码。

此命令在早期版本中称为-import。本版本仍支持这个旧名称。新名称-importcert更受欢迎。