

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Gunakan Client SDK 3 untuk berintegrasi AWS CloudHSM dengan Java Keytool dan Jarsigner
<a name="keystore-third-party-tools"></a>

AWS CloudHSM key store adalah toko kunci JCE tujuan khusus yang menggunakan sertifikat yang terkait dengan kunci pada modul keamanan perangkat keras (HSM) Anda melalui alat pihak ketiga seperti dan. `keytool` `jarsigner` AWS CloudHSM tidak menyimpan sertifikat di HSM, karena sertifikat bersifat publik, data non-rahasia. Toko AWS CloudHSM kunci menyimpan sertifikat dalam file lokal dan memetakan sertifikat ke kunci yang sesuai di HSM Anda. 

Saat Anda menggunakan toko AWS CloudHSM kunci untuk menghasilkan kunci baru, tidak ada entri yang dihasilkan di file penyimpanan kunci lokal — kunci dibuat di HSM. Demikian pula, ketika Anda menggunakan penyimpanan kunci AWS CloudHSM untuk mencari kunci, pencarian diteruskan ke HSM. Ketika Anda menyimpan sertifikat di toko AWS CloudHSM kunci, penyedia memverifikasi bahwa key pair dengan alias yang sesuai ada di HSM, dan kemudian mengaitkan sertifikat yang disediakan dengan key pair yang sesuai. 

**Topics**
+ [Prasyarat](keystore-prerequisites.md)
+ [Gunakan toko kunci dengan keytool](using_keystore_with_keytool.md)
+ [Gunakan toko kunci dengan jarsigner](using_keystore_jarsigner.md)
+ [Masalah yang diketahui](known-issues-keytool-jarsigner.md)
+ [Daftarkan kunci yang sudah ada sebelumnya dengan toko kunci](register-pre-existing-keys-with-keystore.md)

# Prasyarat untuk mengintegrasikan AWS CloudHSM dengan Java Keytool dan Jarsigner menggunakan Client SDK 3
<a name="keystore-prerequisites"></a>

Untuk menggunakan penyimpanan AWS CloudHSM kunci, Anda harus terlebih dahulu menginisialisasi dan mengkonfigurasi AWS CloudHSM JCE SDK. Gunakan langkah-langkah berikut untuk melakukannya. 

## Langkah 1: Instal JCE
<a name="prereq-step-one"></a>

[Untuk menginstal JCE, termasuk prasyarat AWS CloudHSM klien, ikuti langkah-langkah untuk menginstal perpustakaan Java.](java-library-install.md) 

## Langkah 2: Tambahkan kredensial login HSM ke variabel lingkungan
<a name="prereq-step-two"></a>

Atur variabel lingkungan berisi kredensial login HSM Anda. 

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

**catatan**  
CloudHSM JCE menawarkan berbagai pilihan login. Untuk menggunakan penyimpanan AWS CloudHSM kunci dengan aplikasi pihak ketiga, Anda harus menggunakan login implisit dengan variabel lingkungan. Jika Anda ingin menggunakan login eksplisit melalui kode aplikasi, Anda harus membangun aplikasi Anda sendiri menggunakan toko AWS CloudHSM kunci. Untuk informasi tambahan, lihat artikel tentang [Menggunakan AWS CloudHSM Key Store](alternative-keystore.md). 

## Langkah 3: Daftarkan penyedia JCE
<a name="prereq-step-three"></a>

Untuk mendaftarkan penyedia JCE, dalam CloudProvider konfigurasi Java. 

1. Buka file konfigurasi java.security di instalasi Java Anda, untuk mengedit.

1. Dalam file konfigurasi java.security, tambahkan `com.cavium.provider.CaviumProvider` sebagai penyedia terakhir. Misalnya, jika ada sembilan penyedia dalam file.security, tambahkan penyedia berikut sebagai penyedia terakhir di bagian tersebut. Menambahkan penyedia Cavium sebagai prioritas yang lebih tinggi dapat berdampak negatif terhadap performa sistem Anda.

   `security.provider.10=com.cavium.provider.CaviumProvider`
**catatan**  
Power user mungkin terbiasa untuk menentukan opsi baris perintah `-providerName`, `-providerclass`, dan `-providerpath` saat menggunakan keytool, alih-alih memperbarui file konfigurasi keamanan. Jika Anda mencoba menentukan opsi baris perintah saat membuat kunci dengan penyimpanan AWS CloudHSM kunci, itu akan menyebabkan kesalahan. 

# Gunakan AWS CloudHSM key store dengan keytool menggunakan Client SDK 3
<a name="using_keystore_with_keytool"></a>

[Keytool](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html) adalah utilitas baris perintah populer untuk kunci umum dan sertifikat tugas pada sistem Linux. Tutorial lengkap tentang keytool ada di luar lingkup dokumentasi AWS CloudHSM . Artikel ini menjelaskan parameter spesifik yang harus Anda gunakan dengan berbagai fungsi keytool saat memanfaatkan AWS CloudHSM sebagai akar kepercayaan melalui toko AWS CloudHSM kunci.

Saat menggunakan keytool dengan penyimpanan AWS CloudHSM kunci, tentukan argumen berikut ke perintah keytool apa pun:

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

Jika Anda ingin membuat file penyimpanan kunci baru menggunakan toko AWS CloudHSM kunci, lihat[Gunakan AWS CloudHSM KeyStore untuk AWS CloudHSM Client SDK 3](alternative-keystore.md#using_cloudhsm_keystore). Untuk menggunakan penyimpanan kunci yang ada, tentukan namanya (termasuk jalur) menggunakan argumen penyimpanan kunci pada keytool. Jika Anda menentukan file penyimpanan kunci yang tidak ada dalam perintah keytool, toko AWS CloudHSM kunci akan membuat file penyimpanan kunci baru.

# Buat AWS CloudHSM kunci baru dengan keytool
<a name="create_key_keytool"></a>

Anda dapat menggunakan keytool untuk menghasilkan semua jenis kunci yang didukung oleh AWS CloudHSM JCE SDK. Lihat daftar lengkap kunci dan panjang di artikel [Kunci yang Didukung](java-lib-supported.md#java-keys) di Pustaka Java.

**penting**  
Kunci yang dihasilkan melalui keytool dihasilkan dalam perangkat lunak, dan kemudian diimpor AWS CloudHSM sebagai kunci persisten yang dapat diekstraksi.

Petunjuk untuk membuat kunci yang tidak dapat diekstraksi langsung pada modul keamanan perangkat keras (HSM), dan kemudian menggunakannya dengan keytool atau Jarsigner, ditampilkan dalam contoh kode di [Mendaftarkan](register-pre-existing-keys-with-keystore.md) Kunci yang Sudah Ada dengan Key Store. AWS CloudHSM Kami sangat menyarankan untuk membuat bukti kunci non-ekspor di luar keytool, dan kemudian mengimpor sertifikat yang sesuai ke penyimpanan kunci. Jika Anda menggunakan kunci RSA atau EC yang dapat diekstrak melalui keytool dan jarsigner, penyedia mengekspor kunci dari AWS CloudHSM dan kemudian menggunakan kunci secara lokal untuk operasi penandatanganan.

Jika Anda memiliki beberapa instans klien yang tersambung ke klaster CloudHSM Anda, perhatikan bahwa mengimpor sertifikat di penyimpanan kunci satu instans klien tidak akan secara otomatis membuat sertifikat tersebut tersedia pada instans klien lainnya. Untuk mendaftarkan kunci dan sertifikat terkait pada setiap instans klien, Anda perlu menjalankan aplikasi Java seperti yang dijelaskan dalam [Hasilkan CSR menggunakan Keytool](generate_csr_using_keytool.md). Atau, Anda dapat membuat perubahan yang diperlukan pada satu klien dan menyalin file penyimpanan kunci yang dihasilkan untuk setiap instans klien lainnya.

**Contoh 1:** Untuk menghasilkan kunci AES-256 simetris dan menyimpannya dalam file penyimpanan kunci bernama, “example\$1keystore.store”, di direktori kerja. Ganti *<secret label>* dengan label unik.

```
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/
```

**Contoh 2:** Untuk menghasilkan key pair RSA 2048 dan menyimpannya dalam file key store bernama, “example\$1keystore.store” di direktori kerja. Ganti *<RSA key pair label>* dengan label unik.

```
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/
```

**Contoh 3:** Untuk menghasilkan kunci ED p256 dan menyimpannya dalam file penyimpanan kunci bernama, “example\$1keystore.store” di direktori kerja. Ganti *<ec key pair label>* dengan label unik.

```
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/
```

Anda dapat menemukan daftar [algoritme tanda tangan yang didukung](java-lib-supported.md#java-sign-verify) di pustaka Java.

# Hapus AWS CloudHSM kunci menggunakan keytool
<a name="delete_key_using_keytool"></a>

Toko AWS CloudHSM kunci tidak mendukung penghapusan kunci. Untuk menghapus kunci, Anda harus menggunakan `deleteKey` fungsi AWS CloudHSM alat baris perintah,[Hapus AWS CloudHSM kunci menggunakan KMU](key_mgmt_util-deleteKey.md).

# Menghasilkan AWS CloudHSM CSR menggunakan keytool
<a name="generate_csr_using_keytool"></a>

Anda menerima fleksibilitas terbesar dalam membuat permintaan penandatanganan sertifikat (CSR) jika menggunakan [Mesin AWS CloudHSM Dinamis OpenSSL untuk SDK Klien 5](openssl-library.md). Perintah berikut menggunakan keytool untuk menghasilkan CSR untuk pasangan kunci dengan alias, `example-key-pair`.

```
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/
```

**catatan**  
Untuk menggunakan pasangan kunci dari keytool, pasangan kunci itu harus memiliki entri dalam file penyimpanan kunci tertentu. Jika Anda ingin menggunakan pasangan kunci yang dihasilkan di luar keytool, Anda harus mengimpor kunci dan metadata sertifikat ke penyimpanan kunci. Untuk petunjuk tentang mengimpor data keystore, lihat [Mengimpor sertifikat Intermediate dan root ke AWS CloudHSM Key Store](import_cert_using_keytool.md) menggunakan Keytool.

# Gunakan keytool untuk mengimpor sertifikat perantara dan root ke dalam penyimpanan AWS CloudHSM kunci
<a name="import_cert_using_keytool"></a>

Untuk mengimpor sertifikat CA AWS CloudHSM, Anda harus mengaktifkan verifikasi rantai sertifikat lengkap pada sertifikat yang baru diimpor. Perintah berikut menunjukkan sebuah contoh. 

```
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/
```

Jika Anda menghubungkan beberapa instance klien ke AWS CloudHSM klaster Anda, mengimpor sertifikat pada penyimpanan kunci satu instans klien tidak akan secara otomatis membuat sertifikat tersedia pada instance klien lainnya. Anda harus mengimpor sertifikat pada setiap instans klien.

# Gunakan keytool untuk menghapus sertifikat dari toko AWS CloudHSM kunci
<a name="delete_cert_using_keytool"></a>

Perintah berikut menunjukkan contoh cara menghapus AWS CloudHSM sertifikat dari toko kunci keytool Java. 

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

Jika Anda menghubungkan beberapa instance klien ke AWS CloudHSM klaster Anda, menghapus sertifikat pada penyimpanan kunci satu instans klien tidak akan secara otomatis menghapus sertifikat dari instance klien lainnya. Anda harus menghapus sertifikat pada setiap instans klien.

# Impor sertifikat kerja ke toko AWS CloudHSM kunci menggunakan keytool
<a name="import_working_cert_using_keytool"></a>

Setelah permintaan penandatanganan sertifikat (CSR) ditandatangani, Anda dapat mengimpornya ke penyimpanan kunci AWS CloudHSM dan mengaitkannya dengan pasangan kunci yang sesuai. Perintah berikut memberikan sebuah contoh. 

```
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/
```

Alias harus menjadi pasangan kunci dengan sertifikat terkait di penyimpanan kunci. Jika kunci yang dihasilkan di luar keytool, atau dihasilkan pada instans klien yang berbeda, Anda harus terlebih dahulu mengimpor kunci dan metadata sertifikat ke penyimpanan kunci. Untuk petunjuk tentang mengimpor metadata sertifikat, lihat contoh kode di [Mendaftarkan Kunci yang sudah ada sebelumnya](register-pre-existing-keys-with-keystore.md) dengan Key Store. AWS CloudHSM 

Rantai sertifikat harus dapat diverifikasi. Jika Anda tidak dapat memverifikasi sertifikat, Anda mungkin perlu mengimpor sertifikat tanda tangan (otoritas sertifikat) ke penyimpanan kunci sehingga rantai dapat diverifikasi.

# Ekspor sertifikat dari AWS CloudHSM menggunakan keytool
<a name="export_cert_using_keytool"></a>

Contoh berikut menghasilkan sertifikat dalam format X.509 biner. Untuk mengekspor sertifikat yang dapat dibaca manusia dari AWS CloudHSM, tambahkan `-rfc` ke `-exportcert` perintah. 

```
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/
```

# Gunakan toko AWS CloudHSM kunci dengan Jarsigner menggunakan Client SDK 3
<a name="using_keystore_jarsigner"></a>

Jarsigner adalah utilitas baris perintah populer untuk menandatangani file JAR menggunakan kunci yang disimpan dengan aman pada modul keamanan perangkat keras (HSM). Tutorial lengkap tentang Jarsigner berada di luar cakupan dokumentasi. AWS CloudHSM Bagian ini menjelaskan parameter Jarsigner yang harus Anda gunakan untuk menandatangani dan memverifikasi tanda tangan AWS CloudHSM sebagai akar kepercayaan melalui penyimpanan kunci. AWS CloudHSM 

# Siapkan AWS CloudHSM kunci dan sertifikat dengan Jarsigner
<a name="jarsigner_set_up_certificates"></a>

Sebelum Anda dapat menandatangani file AWS CloudHSM JAR dengan Jarsigner, pastikan Anda telah mengatur atau menyelesaikan langkah-langkah berikut: 

1. Ikuti petunjuk di[Prasyarat penyimpanan kunci AWS CloudHSM](keystore-prerequisites.md).

1. Siapkan kunci penandatanganan Anda dan sertifikat terkait serta rantai sertifikat yang harus disimpan di penyimpanan AWS CloudHSM kunci server atau instance klien saat ini. Buat kunci pada AWS CloudHSM dan kemudian impor metadata terkait ke toko AWS CloudHSM kunci Anda. Gunakan contoh kode dalam [Mendaftarkan Kunci yang sudah ada sebelumnya dengan AWS CloudHSM Key Store](register-pre-existing-keys-with-keystore.md) untuk mengimpor metadata ke toko kunci. Jika Anda ingin menggunakan keytool untuk mengatur kunci dan sertifikat, lihat [Buat AWS CloudHSM kunci baru dengan keytool](create_key_keytool.md). Jika Anda menggunakan beberapa instance klien untuk menandatangani JARs, buat kunci dan impor rantai sertifikat. Kemudian, salin file penyimpanan kunci yang dihasilkan ke setiap instans klien. Jika Anda sering membuat kunci baru, Anda mungkin merasa lebih mudah untuk secara individual mengimpor sertifikat ke setiap instans klien.

1. Seluruh rantai sertifikat harus dapat diverifikasi. Agar rantai sertifikat dapat diverifikasi, Anda mungkin perlu menambahkan sertifikat CA dan sertifikat perantara ke toko AWS CloudHSM kunci. Lihat cuplikan kode di [Menandatangani file JAR menggunakan AWS CloudHSM dan Jarsigner](jarsigner_sign_jar_using_hsm_jarsigner.md) untuk instruksi tentang penggunaan kode Java untuk memverifikasi rantai sertifikat. Jika mau, Anda dapat menggunakan keytool untuk mengimpor sertifikat. Untuk petunjuk tentang penggunaan keytool, lihat [Menggunakan Keytool untuk mengimpor sertifikat perantara dan root ke AWS CloudHSM Key Store](import_cert_using_keytool.md). 

# Menandatangani file JAR menggunakan AWS CloudHSM dan Jarsigner
<a name="jarsigner_sign_jar_using_hsm_jarsigner"></a>

Gunakan perintah berikut untuk menandatangani file JAR menggunakan AWS CloudHSM dan jarsigner: 

```
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>
```

Gunakan perintah berikut untuk memverifikasi JAR yang ditandatangani: 

```
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>
```

# Masalah yang diketahui untuk AWS CloudHSM integrasi Java Keytool dan Jarsigner menggunakan Client SDK 3
<a name="known-issues-keytool-jarsigner"></a>

Daftar berikut menyediakan daftar masalah yang diketahui saat ini untuk integrasi dengan AWS CloudHSM dan Java Keytool dan Jarsigner menggunakan Client SDK 3. 
+ Saat membuat kunci menggunakan keytool, penyedia pertama dalam konfigurasi penyedia tidak bisa CaviumProvider. 
+ Ketika menghasilkan kunci menggunakan keytool, penyedia pertama (yang didukung) dalam file konfigurasi keamanan digunakan untuk menghasilkan kunci. Ini umumnya adalah penyedia perangkat lunak. Kunci yang dihasilkan kemudian diberi alias dan diimpor ke AWS CloudHSM HSM sebagai kunci persisten (token) selama proses penambahan kunci. 
+  Saat menggunakan keytool dengan AWS CloudHSM key store, jangan tentukan`-providerName`,`-providerclass`, atau `-providerpath` opsi pada baris perintah. Tentukan opsi ini dalam file penyedia keamanan seperti yang dijelaskan dalam [Prasyarat penyimpanan kunci](keystore-prerequisites.md). 
+ Saat menggunakan kunci EC yang tidak dapat diekstraksi melalui keytool dan Jarsigner, penyedia SunEc removed/disabled harus dari daftar penyedia dalam file java.security. Jika Anda menggunakan kunci EC yang dapat diekstrak melalui keytool dan Jarsigner, penyedia mengekspor bit kunci dari AWS CloudHSM HSM dan menggunakan kunci secara lokal untuk operasi penandatanganan. Kami tidak menyarankan Anda menggunakan kunci yang dapat diekspor dengan keytool atau Jarsigner.

# Daftarkan kunci yang sudah ada sebelumnya dengan toko AWS CloudHSM kunci
<a name="register-pre-existing-keys-with-keystore"></a>

Untuk keamanan dan fleksibilitas maksimum dalam atribut dan pelabelan, kami sarankan Anda membuat kunci AWS CloudHSM penandatanganan menggunakan [key\$1mgmt\$1util](generate-keys.md). Anda juga dapat menggunakan aplikasi Java untuk menghasilkan kunci dalam AWS CloudHSM.

Bagian berikut menyediakan contoh kode yang menunjukkan cara menghasilkan key pair baru pada HSM dan mendaftarkannya menggunakan kunci yang ada yang diimpor ke toko AWS CloudHSM kunci. Kunci yang diimpor tersedia untuk digunakan dengan alat pihak ketiga seperti keytool dan Jarsigner. 

Untuk menggunakan kunci yang sudah ada sebelumnya, modifikasi sampel kode untuk mencari kunci dengan label bukannya menghasilkan kunci baru. Contoh kode untuk mencari kunci berdasarkan label tersedia di [KeyUtilitiesRunnersampel.java](https://github.com/aws-samples/aws-cloudhsm-jce-examples/blob/master/src/main/java/com/amazonaws/cloudhsm/examples/KeyUtilitiesRunner.java) pada GitHub. 

**penting**  
Mendaftarkan kunci yang disimpan AWS CloudHSM dengan toko kunci lokal tidak mengekspor kunci. Ketika kunci terdaftar, penyimpanan kunci mendaftar alias kunci (atau label) dan menghubungkan objek sertifikat yang disimpan secara lokal dengan pasangan kunci pada AWS CloudHSM. Selama pasangan kunci dibuat sebagai tidak dapat diekspor, bit kunci tidak akan meninggalkan 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());
        }
    }

}
```