

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用客户端 SDK 3 AWS CloudHSM 与 Java Keytool 和 Jarsigner 集成
<a name="keystore-third-party-tools"></a>

AWS CloudHSM 密钥存储是一种特殊用途的 JCE 密钥存储区，它通过第三方工具（如和）使用与硬件安全模块 (HSM) 上的密钥关联的证书。`keytool` `jarsigner` AWS CloudHSM 不在 HSM 上存储证书，因为证书是公开的非机密数据。 AWS CloudHSM 密钥库将证书存储在本地文件中，并将证书映射到您的 HSM 上的相应密钥。

当您使用密 AWS CloudHSM 钥库生成新密钥时，本地密钥存储文件中不会生成任何条目——密钥是在 HSM 上创建的。同样，当您使用 AWS CloudHSM 密钥库搜索密钥时，搜索将传递到 HSM。当您将证书存储在 AWS CloudHSM 密钥库中时，提供程序会验证 HSM 上是否存在具有相应别名的密钥对，然后将提供的证书与相应的密钥对相关联。

**Topics**
+ [先决条件](keystore-prerequisites.md)
+ [将密钥库与 Keytool 结合使用](using_keystore_with_keytool.md)
+ [将密钥库与 jarsigner 结合使用](using_keystore_jarsigner.md)
+ [已知问题](known-issues-keytool-jarsigner.md)
+ [向密钥库注册预先存在的密钥](register-pre-existing-keys-with-keystore.md)

# 使用客户端 SDK AWS CloudHSM 与 Java Keytool 和 Jarsigner 集成的先决条件 3
<a name="keystore-prerequisites"></a>

要使用 AWS CloudHSM 密钥库，必须先初始化并配置 AWS CloudHSM JCE SDK。请按照以下步骤进行操作。

## 步骤 1：安装 JCE
<a name="prereq-step-one"></a>

要安装 JCE，包括 AWS CloudHSM 客户端先决条件，请按照[安装 Java 库](java-library-install.md)的步骤进行操作。

## 步骤 2：将 HSM 登录凭证添加到环境变量
<a name="prereq-step-two"></a>

设置环境变量以包含 HSM 登录凭证。

```
export HSM_PARTITION=PARTITION_1
export HSM_USER=<HSM user name> 
export HSM_PASSWORD=<HSM password>
```

**注意**  
CloudHSM JCE 提供各种登录选项。要将 AWS CloudHSM 密钥存储用于第三方应用程序，必须使用带环境变量的隐式登录。如果要通过应用程序代码使用显式登录，则必须使用 AWS CloudHSM 密钥库构建自己的应用程序。有关更多信息，请参阅有关[使用 AWS CloudHSM 密钥库](alternative-keystore.md)的文章。

## 步骤 3：注册 JCE 提供程序
<a name="prereq-step-three"></a>

要注册 JCE 提供程序，请在 Java CloudProvider 配置中进行注册。

1. 在 Java 安装中打开 java.security 配置文件进行编辑。

1. 在 java.security 配置文件中，添加 `com.cavium.provider.CaviumProvider` 作为最后一个提供程序。例如，如果 java.security 文件中有 9 个提供程序，则将以下提供程序添加为本部分中的最后一个提供程序。将 Cavium 提供程序添加为一个更高的优先级可能会对您的系统性能产生负面影响。

   `security.provider.10=com.cavium.provider.CaviumProvider`
**注意**  
使用 keytool 时，高级用户可能习惯于指定 `-providerName`、`-providerclass` 和 `-providerpath` 命令行选项，而不是更新安全配置文件。如果您在使用密钥存储库生成密钥时尝试指定命令行选项，则会导致错误。 AWS CloudHSM 

# 使用客户端 SDK 3 将 AWS CloudHSM 密钥库与 keytool 配合使用
<a name="using_keystore_with_keytool"></a>

[Keytool](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html) 是一个常见的命令行实用程序，用于 Linux 系统上的常见密钥和证书任务。有关 keytool 的完整教程不在 AWS CloudHSM 文档的讨论范围内。本文介绍了在通过密钥库用作信任根时，应与各种 AWS CloudHSM 密钥工具函数一起使用的特定参数。 AWS CloudHSM 

在密钥库中 AWS CloudHSM 使用 keytool 时，请为任何 keytool 命令指定以下参数：

```
-storetype CLOUDHSM \
		-J-classpath '-J/opt/cloudhsm/java/*' \
		-J-Djava.library.path=/opt/cloudhsm/lib
```

如果要使用 AWS CloudHSM 密钥库创建新的密钥库文件，请参阅[使用 AWS CloudHSM KeyStore 适用于 AWS CloudHSM 客户端 SDK 3](alternative-keystore.md#using_cloudhsm_keystore)。要使用现有密钥库，请使用 keytool 的 –keystore 参数指定密钥库的名称（包括路径）。如果您在 keytool 命令中指定了不存在的密钥存储文件，则 AWS CloudHSM 密钥库会创建一个新的密钥存储文件。

# 使用 keytool 创建新 AWS CloudHSM 密钥
<a name="create_key_keytool"></a>

你可以使用 keytool 生成 AWS CloudHSM JCE SDK 支持的任何类型的密钥。请参阅 Java 库中[支持的密钥](java-lib-supported.md#java-keys)文章中的密钥和长度的完整列表。

**重要**  
通过 keytool 生成的密钥在软件中生成，然后 AWS CloudHSM 作为可提取的永久密钥导入到。

直接在硬件安全模块 (HSM) 上创建不可提取的密钥，然后将其与 keytool 或 Jarsigner 一起使用的说明见向密钥库[注册](register-pre-existing-keys-with-keystore.md)已存在的密钥中的代码示例。 AWS CloudHSM 我们强烈建议在 keytool 之外生成不可导出的密钥，然后将相应的证书导入密钥库。如果您通过 keytool 和 jarsigner 使用可提取的 RSA 或 EC 密钥，则提供程序会从中导出密钥， AWS CloudHSM 然后在本地使用该密钥进行签名操作。

如果您有多个客户端实例连接到 CloudHSM 集群，请注意，在一个客户端实例的密钥库上导入证书不会自动使证书在其他客户端实例上可用。要在每个客户端实例上注册密钥和关联证书，您需要运行 Java 应用程序，如[使用 Keytool 生成 CSR](generate_csr_using_keytool.md) 中所述。或者，您可以在一个客户端上进行必要的更改，并将生成的密钥库文件复制到其他每个客户端实例。

**示例 1：**生成对称 AES-256 密钥，并将其保存在工作目录中名为“example\$1keystore.store”的密钥库文件中。*<secret label>*替换为唯一的标签。

```
keytool -genseckey -alias <secret label> -keyalg aes \
		-keysize 256 -keystore example_keystore.store \
		-storetype CloudHSM -J-classpath '-J/opt/cloudhsm/java/*' \
		-J-Djava.library.path=/opt/cloudhsm/lib/
```

**示例 2：**生成 RSA 2048 密钥对，并将其保存在工作目录中名为“example\$1keystore.store”的密钥库文件中。*<RSA key pair label>*替换为唯一的标签。

```
keytool -genkeypair -alias <RSA key pair label> \
        -keyalg rsa -keysize 2048 \
        -sigalg sha512withrsa \
        -keystore example_keystore.store \
        -storetype CLOUDHSM \
        -J-classpath '-J/opt/cloudhsm/java/*' \
        -J-Djava.library.path=/opt/cloudhsm/lib/
```

**示例 3：**生成 p256 ED 密钥，并将其保存在工作目录中名为“example\$1keystore.store”的密钥库文件中。*<ec key pair label>*替换为唯一的标签。

```
keytool -genkeypair -alias <ec key pair label> \
        -keyalg ec -keysize 256 \
        -sigalg SHA512withECDSA \
        -keystore example_keystore.store \
        -storetype CLOUDHSM \
        -J-classpath '-J/opt/cloudhsm/java/*' \
        -J-Djava.library.path=/opt/cloudhsm/lib/
```

您可以在 Java 库中找到[支持的签名算法](java-lib-supported.md#java-sign-verify)列表。

# 使用 AWS CloudHSM keytool 删除密钥
<a name="delete_key_using_keytool"></a>

密 AWS CloudHSM 钥库不支持删除密钥。要删除密钥，必须使用 AWS CloudHSM的命令行工具的`deleteKey`功能[使用 KM AWS CloudHSM U 删除密钥](key_mgmt_util-deleteKey.md)。

# 使用 keyt AWS CloudHSM ool 生成 CSR
<a name="generate_csr_using_keytool"></a>

如果使用 [适用于 AWS CloudHSM 客户端 SDK 的 OpenSSL 动态引擎 5](openssl-library.md)，您可以在生成证书签名请求 (CSR) 时获得最大的灵活性。以下命令使用 keytool 为具有别名 `example-key-pair` 的密钥对生成 CSR。

```
keytool -certreq -alias <key pair label> \
        -file example_csr.csr \
        -keystore example_keystore.store \
        -storetype CLOUDHSM \
        -J-classpath '-J/opt/cloudhsm/java/*' \
        -J-Djava.library.path=/opt/cloudhsm/lib/
```

**注意**  
要从 keytool 使用密钥对，该密钥对必须在指定的密钥库文件中包含一个条目。如果要使用在 keytool 之外生成的密钥对，则必须将密钥和证书元数据导入密钥库中。有关导入密钥库数据的说明，请参阅[使用 Keytool 将中间证书和根证书导入 AWS CloudHSM 密钥库](import_cert_using_keytool.md)。

# 使用 keytool 将中间证书和根证书导入 AWS CloudHSM 密钥存储库
<a name="import_cert_using_keytool"></a>

要将 CA 证书导入 AWS CloudHSM，必须在新导入的证书上启用对完整证书链的验证。以下命令是一个示例。

```
keytool -import -trustcacerts -alias rootCAcert \
        -file rootCAcert.cert -keystore example_keystore.store \
        -storetype CLOUDHSM \
        -J-classpath '-J/opt/cloudhsm/java/*' \
        -J-Djava.library.path=/opt/cloudhsm/lib/
```

如果您将多个客户端实例连接到 AWS CloudHSM 集群，则在一个客户端实例的密钥库中导入证书不会自动使该证书在其他客户端实例上可用。您必须在每个客户端实例上导入证书。

# 使用 keytool 从 AWS CloudHSM 密钥库中删除证书
<a name="delete_cert_using_keytool"></a>

以下命令显示了如何从 Java keytool 密钥库中删除 AWS CloudHSM 证书的示例。

```
keytool -delete -alias mydomain -keystore \
        -keystore example_keystore.store \
        -storetype CLOUDHSM \
        -J-classpath '-J/opt/cloudhsm/java/*' \
        -J-Djava.library.path=/opt/cloudhsm/lib/
```

如果您将多个客户端实例连接到 AWS CloudHSM 集群，则删除一个客户端实例密钥存储中的证书不会自动从其他客户端实例中删除该证书。您必须删除每个客户端实例上的证书。

# 使用 keytool 将有效的证书导入 AWS CloudHSM 密钥库
<a name="import_working_cert_using_keytool"></a>

签署证书签名请求 (CSR) 后，您可以将其导入 AWS CloudHSM 密钥库并将其与相应的密钥对关联。以下命令是一个示例。

```
keytool -importcert -noprompt -alias <key pair label> \
        -file example_certificate.crt \
        -keystore example_keystore.store
        -storetype CLOUDHSM \
        -J-classpath '-J/opt/cloudhsm/java/*' \
        -J-Djava.library.path=/opt/cloudhsm/lib/
```

别名应该是密钥库中具有关联证书的密钥对。如果密钥是在 keytool 之外生成的，或者在其他客户端实例上生成的，则必须先将密钥和证书元数据导入密钥库中。有关导入证书元数据的说明，请参阅向密钥[库注册已存在的密钥](register-pre-existing-keys-with-keystore.md)中的代码示例。 AWS CloudHSM 

证书链必须是可验证的。如果无法验证证书，则可能需要将签名（证书颁发机构）证书导入密钥库，以便验证证书链。

# AWS CloudHSM 使用 keytool 导出证书
<a name="export_cert_using_keytool"></a>

以下示例生成二进制 X.509 格式的证书。要从中导出人类可读的证书 AWS CloudHSM，请在`-exportcert`命令中`-rfc`添加。

```
keytool -exportcert -alias <key pair label> \
        -file example_exported_certificate.crt \
        -keystore example_keystore.store \
        -storetype CLOUDHSM \
        -J-classpath '-J/opt/cloudhsm/java/*' \
        -J-Djava.library.path=/opt/cloudhsm/lib/
```

# 使用客户端 SDK 3 将 AWS CloudHSM 密钥存储与 Jarsigner 配合使用
<a name="using_keystore_jarsigner"></a>

Jarsigner 是一个流行的命令行实用程序，用于使用安全存储在硬件安全模块（HSM）上的密钥签署 JAR 文件。有关 Jarsigner 的完整教程超出了本文档的 AWS CloudHSM 范围。本节介绍了 Jarsigner 参数，您应该使用这些参数通过 AWS CloudHSM 密钥存储区 AWS CloudHSM 作为信任根进行签名和验证签名。

# 使用 Jarsigner 设置 AWS CloudHSM 密钥和证书
<a name="jarsigner_set_up_certificates"></a>

在使用 AWS CloudHSM Jarsigner 签署 JAR 文件之前，请确保您已经设置或完成了以下步骤：

1. 按照 [AWS CloudHSM 密钥库先决条件](keystore-prerequisites.md)中的指导操作。

1. 设置您的签名密钥以及相关的证书和证书链，这些证书和证书链应存储在当前服务器或客户端实例的 AWS CloudHSM 密钥存储中。在上创建密钥， AWS CloudHSM 然后将关联的元数据导入您的 AWS CloudHSM 密钥存储区。使用向密钥[库注册预先存在的 AWS CloudHSM 密钥](register-pre-existing-keys-with-keystore.md)中的代码示例将元数据导入密钥库。如果要使用 keytool 设置密钥和证书，请参阅 [使用 keytool 创建新 AWS CloudHSM 密钥](create_key_keytool.md)。如果您使用多个客户端实例来签名 JARs，请创建密钥并导入证书链。然后将生成的密钥库文件复制到每个客户端实例。如果您经常生成新密钥，您可能会发现将证书单独导入到每个客户端实例更容易。

1. 整个证书链应该是可验证的。要使证书链可验证，您可能需要将 CA 证书和中间证书添加到 AWS CloudHSM 密钥库中。有关使用 Java 代码验证证书链的说明[，请参阅使用对 Jarsigner 文件进行签名中的代码片段， AWS CloudHSM 以及](jarsigner_sign_jar_using_hsm_jarsigner.md) Jarsigner。如果您愿意，可以使用 keytool 导入证书。有关使用 keytool 的说明，请参阅[使用 Keytool 将中间证书和根证书导入 AWS CloudHSM 密钥](import_cert_using_keytool.md)库。

# 使用 AWS CloudHSM 和 Jarsigner 对 Jarsigner 文件进行签名
<a name="jarsigner_sign_jar_using_hsm_jarsigner"></a>

使用以下命令使用和 jarsigner 对 JAR 文件 AWS CloudHSM 进行签名：

```
jarsigner -keystore example_keystore.store \
        -signedjar signthisclass_signed.jar \
        -sigalg sha512withrsa \
        -storetype CloudHSM \
        -J-classpath '-J/opt/cloudhsm/java/*:/usr/lib/jvm/java-1.8.0/lib/tools.jar' \
        -J-Djava.library.path=/opt/cloudhsm/lib \
        signthisclass.jar <key pair label>
```

使用以下命令验证已签名的 JAR：

```
jarsigner -verify \
        -keystore example_keystore.store \
        -sigalg sha512withrsa \
        -storetype CloudHSM \
        -J-classpath '-J/opt/cloudhsm/java/*:/usr/lib/jvm/java-1.8.0/lib/tools.jar' \
        -J-Djava.library.path=/opt/cloudhsm/lib \
        signthisclass_signed.jar <key pair label>
```

# 使用客户端 SDK AWS CloudHSM 集成 Java Keytool 和 Jarsigner 的已知问题 3
<a name="known-issues-keytool-jarsigner"></a>

以下列表提供了使用客户端 SDK 3 与 Java Keytool AWS CloudHSM 和 Jarsigner 集成的当前已知问题列表。
+ 使用 keytool 生成密钥时，提供程序配置中的第一个提供程序不能是。 CaviumProvider
+ 使用 keytool 生成密钥时，安全配置文件中的第一个（受支持的）提供程序将用于生成密钥。这通常是一个软件提供程序。然后，生成的密钥会被赋予一个别名，并在密钥添加过程中作为永久（令牌）密钥导入到 AWS CloudHSM HSM 中。
+  将 keytool 与 AWS CloudHSM 密钥存储一起使用时`-providerName`，请勿在命令行中指定`-providerclass`、或`-providerpath`选项。在安全提供程序文件中指定这些选项，如[密钥库先决条件](keystore-prerequisites.md)中所述。
+ 通过 keytool 和 Jarsigner 使用不可提取的 EC 密钥时，Sunec 提供程序 removed/disabled 必须位于 java.security 文件中的提供者列表中。如果您通过 keytool 和 Jarsigner 使用可提取的 EC 密钥，则提供程序会从 AWS CloudHSM HSM 中导出密钥位并在本地使用该密钥进行签名操作。我们不建议您将可导出的密钥与 keytool 或 Jarsigner 一起使用。

# 在密钥库中注册先前存在的密 AWS CloudHSM 钥
<a name="register-pre-existing-keys-with-keystore"></a>

为了最大限度地提高属性和标签的安全性和灵活性，我们建议您使用 [key\$1mgmt\$1](generate-keys.md) util 生成 AWS CloudHSM 签名密钥。您还可以使用 Java 应用程序在 AWS CloudHSM中生成密钥。

以下部分提供了一个代码示例，演示如何在 HSM 上生成新的密钥对，并使用导入到密钥库中的 AWS CloudHSM 现有密钥对其进行注册。导入的密钥可与第三方工具（如 keytool 和 Jarsigner）一起使用。

要使用预先存在的密钥，请修改代码示例以通过标签查找密钥，而不是生成新密钥。上的 [KeyUtilitiesRunner.java 示例中提供了按标签查找密钥的 GitHub示例](https://github.com/aws-samples/aws-cloudhsm-jce-examples/blob/master/src/main/java/com/amazonaws/cloudhsm/examples/KeyUtilitiesRunner.java)代码。

**重要**  
在本地密钥存储库中注册存储 AWS CloudHSM 的密钥不会导出该密钥。注册密钥后，密钥库会注册密钥的别名（或标签），并将本地存储证书对象与 AWS CloudHSM上的密钥对关联。只要密钥对创建为不可导出的对象，密钥位就不会离开 HSM。

```
                      	
                      	
                      	//
 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy of this
 // software and associated documentation files (the "Software"), to deal in the Software
 // without restriction, including without limitation the rights to use, copy, modify,
 // merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 // permit persons to whom the Software is furnished to do so.
 //
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
package com.amazonaws.cloudhsm.examples;

import com.cavium.key.CaviumKey;
import com.cavium.key.parameter.CaviumAESKeyGenParameterSpec;
import com.cavium.key.parameter.CaviumRSAKeyGenParameterSpec;
import com.cavium.asn1.Encoder;
import com.cavium.cfm2.Util;

import javax.crypto.KeyGenerator;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;

import java.math.BigInteger;

import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.KeyStore.PasswordProtection;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore.Entry;

import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;

//
// KeyStoreExampleRunner demonstrates how to load a keystore, and associate a certificate with a
// key in that keystore.
//
// This example relies on implicit credentials, so you must setup your environment correctly.
//
// https://docs.aws.amazon.com/cloudhsm/latest/userguide/java-library-install.html#java-library-credentials
//

public class KeyStoreExampleRunner {

     private static byte[] COMMON_NAME_OID = new byte[] { (byte) 0x55, (byte) 0x04, (byte) 0x03 };
     private static byte[] COUNTRY_NAME_OID = new byte[] { (byte) 0x55, (byte) 0x04, (byte) 0x06 };
     private static byte[] LOCALITY_NAME_OID = new byte[] { (byte) 0x55, (byte) 0x04, (byte) 0x07 };
     private static byte[] STATE_OR_PROVINCE_NAME_OID = new byte[] { (byte) 0x55, (byte) 0x04, (byte) 0x08 };
     private static byte[] ORGANIZATION_NAME_OID = new byte[] { (byte) 0x55, (byte) 0x04, (byte) 0x0A };
     private static byte[] ORGANIZATION_UNIT_OID = new byte[] { (byte) 0x55, (byte) 0x04, (byte) 0x0B };

     private static String helpString = "KeyStoreExampleRunner%n" +
            "This sample demonstrates how to load and store keys using a keystore.%n%n" +
            "Options%n" +
            "\t--help\t\t\tDisplay this message.%n" +
            "\t--store <filename>\t\tPath of the keystore.%n" +
            "\t--password <password>\t\tPassword for the keystore (not your CU password).%n" +
            "\t--label <label>\t\t\tLabel to store the key and certificate under.%n" +
            "\t--list\t\t\tList all the keys in the keystore.%n%n";

    public static void main(String[] args) throws Exception {
        Security.addProvider(new com.cavium.provider.CaviumProvider());
        KeyStore keyStore = KeyStore.getInstance("CloudHSM");

        String keystoreFile = null;
        String password = null;
        String label = null;
        boolean list = false;
        for (int i = 0; i < args.length; i++) {
            String arg = args[i];
            switch (args[i]) {
                case "--store":
                    keystoreFile = args[++i];
                    break;
                case "--password":
                    password = args[++i];
                    break;
                case "--label":
                    label = args[++i];
                    break;
                case "--list":
                    list = true;
                    break;
                case "--help":
                    help();
                    return;
            }
        }

        if (null == keystoreFile || null == password) {
            help();
            return;
        }

        if (list) {
            listKeys(keystoreFile, password);
            return;
        }

        if (null == label) {
            label = "Keystore Example Keypair";
        }

        //
        // This call to keyStore.load() will open the pkcs12 keystore with the supplied
        // password and connect to the HSM. The CU credentials must be specified using
        // standard CloudHSM login methods.
        //
        try {
            FileInputStream instream = new FileInputStream(keystoreFile);
            keyStore.load(instream, password.toCharArray());
        } catch (FileNotFoundException ex) {
            System.err.println("Keystore not found, loading an empty store");
            keyStore.load(null, null);
        }

        PasswordProtection passwd = new PasswordProtection(password.toCharArray());
        System.out.println("Searching for example key and certificate...");

        PrivateKeyEntry keyEntry = (PrivateKeyEntry) keyStore.getEntry(label, passwd);
        if (null == keyEntry) {
            //
            // No entry was found, so we need to create a key pair and associate a certificate.
            // The private key will get the label passed on the command line. The keystore alias
            // needs to be the same as the private key label. The public key will have ":public"
            // appended to it. The alias used in the keystore will We associate the certificate
            // with the private key.
            //
            System.out.println("No entry found, creating...");
            KeyPair kp = generateRSAKeyPair(2048, label + ":public", label);
            System.out.printf("Created a key pair with the handles %d/%d%n", ((CaviumKey) kp.getPrivate()).getHandle(), ((CaviumKey) kp.getPublic()).getHandle());

            //
            // Generate a certificate and associate the chain with the private key.
            //
            Certificate self_signed_cert = generateCert(kp);
            Certificate[] chain = new Certificate[1];
            chain[0] = self_signed_cert;
            PrivateKeyEntry entry = new PrivateKeyEntry(kp.getPrivate(), chain);

            //
            // Set the entry using the label as the alias and save the store.
            // The alias must match the private key label.
            //
            keyStore.setEntry(label, entry, passwd);

            FileOutputStream outstream = new FileOutputStream(keystoreFile);
            keyStore.store(outstream, password.toCharArray());
            outstream.close();

            keyEntry = (PrivateKeyEntry) keyStore.getEntry(label, passwd);
        }

        long handle = ((CaviumKey) keyEntry.getPrivateKey()).getHandle();
        String name = keyEntry.getCertificate().toString();
        System.out.printf("Found private key %d with certificate %s%n", handle, name);
    }

    private static void help() {
        System.out.println(helpString);
    }

    //
    // Generate a non-extractable / non-persistent RSA keypair.
    // This method allows us to specify the public and private labels, which
    // will make KeyStore aliases easier to understand.
    //
    public static KeyPair generateRSAKeyPair(int keySizeInBits, String publicLabel, String privateLabel)
            throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {

        boolean isExtractable = false;
        boolean isPersistent = false;
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("rsa", "Cavium");
        CaviumRSAKeyGenParameterSpec spec = new CaviumRSAKeyGenParameterSpec(keySizeInBits, new BigInteger("65537"), publicLabel, privateLabel, isExtractable, isPersistent);

        keyPairGen.initialize(spec);

        return keyPairGen.generateKeyPair();
    }

    //
    // Generate a certificate signed by a given keypair.
    //
    private static Certificate generateCert(KeyPair kp) throws CertificateException {
        CertificateFactory cf = CertificateFactory.getInstance("X509");
        PublicKey publicKey = kp.getPublic();
        PrivateKey privateKey = kp.getPrivate();
        byte[] version = Encoder.encodeConstructed((byte) 0, Encoder.encodePositiveBigInteger(new BigInteger("2"))); // version 1
        byte[] serialNo = Encoder.encodePositiveBigInteger(new BigInteger(1, Util.computeKCV(publicKey.getEncoded())));

        // Use the SHA512 OID and algorithm.
        byte[] signatureOid = new byte[] {
            (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x0D };
        String sigAlgoName = "SHA512WithRSA";

         byte[] signatureId = Encoder.encodeSequence(
                                         Encoder.encodeOid(signatureOid),
                                         Encoder.encodeNull());

         byte[] issuer = Encoder.encodeSequence(
                                     encodeName(COUNTRY_NAME_OID, "<Country>"),
                                     encodeName(STATE_OR_PROVINCE_NAME_OID, "<State>"),
                                     encodeName(LOCALITY_NAME_OID, "<City>"),
                                     encodeName(ORGANIZATION_NAME_OID, "<Organization>"),
                                     encodeName(ORGANIZATION_UNIT_OID, "<Unit>"),
                                     encodeName(COMMON_NAME_OID, "<CN>")
                                 );

         Calendar c = Calendar.getInstance();
         c.add(Calendar.DAY_OF_YEAR, -1);
         Date notBefore = c.getTime();
         c.add(Calendar.YEAR, 1);
         Date notAfter = c.getTime();
         byte[] validity = Encoder.encodeSequence(
                                         Encoder.encodeUTCTime(notBefore),
                                         Encoder.encodeUTCTime(notAfter)
                                     );
         byte[] key = publicKey.getEncoded();

         byte[] certificate = Encoder.encodeSequence(
                                         version,
                                         serialNo,
                                         signatureId,
                                         issuer,
                                         validity,
                                         issuer,
                                         key);
         Signature sig;
         byte[] signature = null;
         try {
             sig = Signature.getInstance(sigAlgoName, "Cavium");
             sig.initSign(privateKey);
             sig.update(certificate);
             signature = Encoder.encodeBitstring(sig.sign());

         } catch (Exception e) {
             System.err.println(e.getMessage());
             return null;
         }

         byte [] x509 = Encoder.encodeSequence(
                         certificate,
                         signatureId,
                         signature
                         );
         return cf.generateCertificate(new ByteArrayInputStream(x509));
    }

     //
     // Simple OID encoder.
     // Encode a value with OID in ASN.1 format
     //
     private static byte[] encodeName(byte[] nameOid, String value) {
         byte[] name = null;
         name = Encoder.encodeSet(
                     Encoder.encodeSequence(
                             Encoder.encodeOid(nameOid),
                             Encoder.encodePrintableString(value)
                     )
                 );
         return name;
     }

    //
    // List all the keys in the keystore.
    //
    private static void listKeys(String keystoreFile, String password) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("CloudHSM");

        try {
            FileInputStream instream = new FileInputStream(keystoreFile);
            keyStore.load(instream, password.toCharArray());
        } catch (FileNotFoundException ex) {
            System.err.println("Keystore not found, loading an empty store");
            keyStore.load(null, null);
        }

        for(Enumeration<String> entry = keyStore.aliases(); entry.hasMoreElements();) {
            System.out.println(entry.nextElement());
        }
    }

}
```