diff --git a/samples/snippets/cloud-client/src/main/java/privateca/CreateCertificate.java b/samples/snippets/cloud-client/src/main/java/privateca/CreateCertificate.java index 8be4f175..dd716f48 100644 --- a/samples/snippets/cloud-client/src/main/java/privateca/CreateCertificate.java +++ b/samples/snippets/cloud-client/src/main/java/privateca/CreateCertificate.java @@ -18,8 +18,6 @@ // [START privateca_create_certificate] import com.google.api.core.ApiFuture; -import com.google.cloud.kms.v1.CryptoKeyVersionName; -import com.google.cloud.kms.v1.KeyManagementServiceClient; import com.google.cloud.security.privateca.v1.CaPoolName; import com.google.cloud.security.privateca.v1.Certificate; import com.google.cloud.security.privateca.v1.CertificateAuthorityServiceClient; @@ -46,24 +44,14 @@ public static void main(String[] args) throws InterruptedException, ExecutionException, IOException { // TODO(developer): Replace these variables before running the sample. - // To sign and issue a certificate, a public key is essential. Here, we are making use - // of Cloud KMS to retrieve an already created public key. Specify the following details to - // retrieve the key. For more info, see: https://cloud.google.com/kms/docs/retrieve-public-key - String project = "your-project-id"; - String kmsLocation = "kms-location"; - String keyRingId = "your-ring-id"; - String keyId = "your-key-id"; - String keyVersionId = "your-version-id"; - - // Retrieve the public key from Cloud KMS. - ByteString publicKeyBytes = - retrievePublicKey(project, kmsLocation, keyRingId, keyId, keyVersionId); - + // publicKeyBytes: Public key used in signing the certificates. // location: For a list of locations, see: // https://cloud.google.com/certificate-authority-service/docs/locations // caPoolName: Set a unique name for the CA pool. // certificateAuthorityName: The name of the certificate authority which issues the certificate. // certificateName: Set a unique name for the certificate. + String project = "your-project-id"; + ByteString publicKeyBytes = ByteString.copyFrom(new byte[] {}); String location = "ca-location"; String caPoolName = "ca-pool-name"; String certificateAuthorityName = "certificate-authority-name"; @@ -74,7 +62,8 @@ public static void main(String[] args) } // Create a Certificate which is issued by the Certificate Authority present in the CA Pool. - // The key used to sign the certificate is created by the Cloud KMS. + // The public key used to sign the certificate can be generated using any crypto + // library/framework. public static void createCertificate( String project, String location, @@ -99,7 +88,7 @@ public static void createCertificate( String domainName = "dnsname.com"; long certificateLifetime = 1000L; - // Set the Public Key and its format as obtained from the Cloud KMS. + // Set the Public Key and its format. PublicKey publicKey = PublicKey.newBuilder().setKey(publicKeyBytes).setFormat(KeyFormat.PEM).build(); @@ -163,24 +152,5 @@ public static void createCertificate( System.out.println(response.getPemCertificateChainList()); } } - - // Get the public Key used for signing the certificate from Cloud KMS. - public static ByteString retrievePublicKey( - String project, String kmsLocation, String keyRingId, String keyId, String keyVersionId) - throws IOException { - // Initialize client that will be used to send requests. This client only needs to be created - // once, and can be reused for multiple requests. After completing all of your requests, call - // the `client.close()` method on the client to safely - // clean up any remaining background resources. - try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) { - - CryptoKeyVersionName keyVersionName = - CryptoKeyVersionName.of(project, kmsLocation, keyRingId, keyId, keyVersionId); - com.google.cloud.kms.v1.PublicKey publicKey = client.getPublicKey(keyVersionName); - - ByteString publicKeyBytes = publicKey.getPemBytes(); - return publicKeyBytes; - } - } } // [END privateca_create_certificate] diff --git a/samples/snippets/cloud-client/src/test/java/privateca/SnippetsIT.java b/samples/snippets/cloud-client/src/test/java/privateca/SnippetsIT.java index 67645564..f9903a9b 100644 --- a/samples/snippets/cloud-client/src/test/java/privateca/SnippetsIT.java +++ b/samples/snippets/cloud-client/src/test/java/privateca/SnippetsIT.java @@ -18,17 +18,6 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; -import com.google.cloud.kms.v1.CreateKeyRingRequest; -import com.google.cloud.kms.v1.CryptoKey; -import com.google.cloud.kms.v1.CryptoKey.CryptoKeyPurpose; -import com.google.cloud.kms.v1.CryptoKeyVersion; -import com.google.cloud.kms.v1.CryptoKeyVersion.CryptoKeyVersionAlgorithm; -import com.google.cloud.kms.v1.CryptoKeyVersionName; -import com.google.cloud.kms.v1.CryptoKeyVersionTemplate; -import com.google.cloud.kms.v1.KeyManagementServiceClient; -import com.google.cloud.kms.v1.KeyRing; -import com.google.cloud.kms.v1.KeyRingName; -import com.google.cloud.kms.v1.LocationName; import com.google.cloud.security.privateca.v1.CaPoolName; import com.google.cloud.security.privateca.v1.Certificate; import com.google.cloud.security.privateca.v1.CertificateAuthority; @@ -38,11 +27,22 @@ import com.google.protobuf.ByteString; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.PrintStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemWriter; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; @@ -57,15 +57,12 @@ public class SnippetsIT { private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); private static String LOCATION; - private static String KMS_LOCATION; private static String CA_POOL_NAME; private static String CA_POOL_NAME_DELETE; private static String CA_NAME; private static String CA_NAME_DELETE; private static String CERTIFICATE_NAME; - private static String KEY_RING_ID; - private static String KEY_ID; - private static String VERSION_ID; + private static int KEY_SIZE; private ByteArrayOutputStream stdOut; @@ -77,24 +74,24 @@ public static void reqEnvVar(String envVarName) { } @BeforeClass - public static void setUp() throws InterruptedException, ExecutionException, IOException { + public static void setUp() + throws IOException, ExecutionException, NoSuchProviderException, NoSuchAlgorithmException, + InterruptedException { reqEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); reqEnvVar("GOOGLE_CLOUD_PROJECT"); LOCATION = "asia-south1"; - KMS_LOCATION = "global"; CA_POOL_NAME = "ca-pool-" + UUID.randomUUID().toString(); CA_POOL_NAME_DELETE = "ca-pool-" + UUID.randomUUID().toString(); CA_NAME = "ca-name-" + UUID.randomUUID().toString(); CA_NAME_DELETE = "ca-name-" + UUID.randomUUID().toString(); CERTIFICATE_NAME = "certificate-name-" + UUID.randomUUID().toString(); - KEY_RING_ID = "key-ring-id-" + UUID.randomUUID().toString(); - KEY_ID = "key-id-" + UUID.randomUUID().toString(); - VERSION_ID = "1"; + KEY_SIZE = 2048; // Default key size // Create CA Pool. privateca.CreateCaPool.createCaPool(PROJECT_ID, LOCATION, CA_POOL_NAME); privateca.CreateCaPool.createCaPool(PROJECT_ID, LOCATION, CA_POOL_NAME_DELETE); + sleep(5); // Create and Enable Certificate Authorities. privateca.CreateCertificateAuthority.createCertificateAuthority( @@ -105,17 +102,27 @@ public static void setUp() throws InterruptedException, ExecutionException, IOEx privateca.EnableCertificateAuthority.enableCertificateAuthority( PROJECT_ID, LOCATION, CA_POOL_NAME, CA_NAME); - // Create Asymmetric Sign Key used to sign certificate, with Cloud KMS. - createKeyRing(); - sleep(5); - createAsymmetricSignKey(); + // Create an asymmetric key pair using Bouncy Castle crypto framework. + KeyPair asymmetricKeyPair = createAsymmetricKeyPair(); + + // Cast the keys to their respective components. + RSAPublicKey publicKey = (RSAPublicKey) asymmetricKeyPair.getPublic(); + RSAPrivateKey privateKey = (RSAPrivateKey) asymmetricKeyPair.getPrivate(); + + // Construct the PemObject for public and private keys. + PemObject publicKeyPemObject = new PemObject("PUBLIC KEY", publicKey.getEncoded()); + PemObject privateKeyPemObject = new PemObject("PRIVATE KEY", privateKey.getEncoded()); + + // Only the public key will be used to create the certificate. + ByteString publicKeyByteString = convertToPemEncodedByteString(publicKeyPemObject); - // Retrieve public key from Cloud KMS and Create Certificate. - ByteString publicKey = - privateca.CreateCertificate.retrievePublicKey( - PROJECT_ID, KMS_LOCATION, KEY_RING_ID, KEY_ID, VERSION_ID); + // TODO (Developers): Save the private key by writing it to a file and + // TODO (cont): use it to verify the issued certificate. + ByteString privateKeyByteString = convertToPemEncodedByteString(privateKeyPemObject); + + // Create certificate with the above generated public key. privateca.CreateCertificate.createCertificate( - PROJECT_ID, LOCATION, CA_POOL_NAME, CA_NAME, CERTIFICATE_NAME, publicKey); + PROJECT_ID, LOCATION, CA_POOL_NAME, CA_NAME, CERTIFICATE_NAME, publicKeyByteString); sleep(5); } @@ -125,9 +132,6 @@ public static void cleanUp() throws InterruptedException, ExecutionException, IO ByteArrayOutputStream stdOut = new ByteArrayOutputStream(); System.setOut(new PrintStream(stdOut)); - // De-provision public key. - cleanupCertificateSignKey(); - // Delete CA and CA pool. privateca.DeleteCertificateAuthority.deleteCertificateAuthority( PROJECT_ID, LOCATION, CA_POOL_NAME, CA_NAME); @@ -138,71 +142,34 @@ public static void cleanUp() throws InterruptedException, ExecutionException, IO System.setOut(null); } - // Create a new key ring. - public static void createKeyRing() throws IOException { - // Initialize client that will be used to send requests. This client only - // needs to be created once, and can be reused for multiple requests. After - // completing all of your requests, call the "close" method on the client to - // safely clean up any remaining background resources. - try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) { - // Build the parent name from the project and location. - LocationName locationName = LocationName.of(PROJECT_ID, KMS_LOCATION); - - // Build the key ring to create. - KeyRing keyRing = KeyRing.newBuilder().setName(locationName.toString()).build(); - - // Create the key ring. - KeyRing createdKeyRing = - client.createKeyRing( - CreateKeyRingRequest.newBuilder() - .setParent(locationName.toString()) - .setKeyRing(keyRing) - .setKeyRingId(KEY_RING_ID) - .build()); - System.out.printf("Created key ring: %s%n", createdKeyRing.getName()); - } + // Wait for the specified amount of time. + public static void sleep(int seconds) throws InterruptedException { + TimeUnit.SECONDS.sleep(seconds); } - // Create a new asymmetric key for the purpose of signing and verifying data. - public static void createAsymmetricSignKey() throws IOException { - // Initialize client that will be used to send requests. This client only - // needs to be created once, and can be reused for multiple requests. After - // completing all of your requests, call the "close" method on the client to - // safely clean up any remaining background resources. - try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) { - // Build the parent name from the project, location, and key ring. - KeyRingName keyRingName = KeyRingName.of(PROJECT_ID, KMS_LOCATION, KEY_RING_ID); - - // Build the asymmetric key to create. - CryptoKey key = - CryptoKey.newBuilder() - .setPurpose(CryptoKeyPurpose.ASYMMETRIC_SIGN) - .setVersionTemplate( - CryptoKeyVersionTemplate.newBuilder() - .setAlgorithm(CryptoKeyVersionAlgorithm.RSA_SIGN_PKCS1_2048_SHA256)) - .build(); - - // Create the key. - CryptoKey createdKey = client.createCryptoKey(keyRingName, KEY_ID, key); - System.out.printf("Created asymmetric key: %s%n", createdKey.getName()); - } - } + // Create an asymmetric key pair to be used in certificate signing. + public static KeyPair createAsymmetricKeyPair() + throws NoSuchAlgorithmException, NoSuchProviderException { + Security.addProvider(new BouncyCastleProvider()); - public static void cleanupCertificateSignKey() throws IOException, InterruptedException { - try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) { - CryptoKeyVersionName cryptoKeyVersionName = - CryptoKeyVersionName.of(PROJECT_ID, KMS_LOCATION, KEY_RING_ID, KEY_ID, VERSION_ID); - // Destroy the crypto key version. - CryptoKeyVersion cryptoKeyVersion = client.destroyCryptoKeyVersion(cryptoKeyVersionName); - sleep(5); - // If the response has destroy time, then the version is successfully destroyed. - Assert.assertTrue(cryptoKeyVersion.hasDestroyTime()); - } + // Generate the key pair with RSA algorithm using Bouncy Castle (BC). + KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC"); + generator.initialize(KEY_SIZE); + KeyPair keyPair = generator.generateKeyPair(); + + return keyPair; } - // Wait for the specified amount of time. - public static void sleep(int seconds) throws InterruptedException { - TimeUnit.SECONDS.sleep(seconds); + // Convert the encoded PemObject to ByteString. + public static ByteString convertToPemEncodedByteString(PemObject pemEncodedKey) + throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + PemWriter pemWriter = new PemWriter(new OutputStreamWriter(byteArrayOutputStream)); + pemWriter.writeObject(pemEncodedKey); + pemWriter.close(); + ByteString keyByteString = ByteString.copyFrom(byteArrayOutputStream.toByteArray()); + + return keyByteString; } @Before diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 62464ee3..45035eaa 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -54,7 +54,11 @@ google-cloud-security-private-ca 1.1.0 - + + org.bouncycastle + bcpkix-jdk15on + 1.58 + com.google.cloud google-cloud-kms