Skip to content
This repository has been archived by the owner on Sep 16, 2023. It is now read-only.

Commit

Permalink
fix: changed the crypto public key provider to Bouncy Castle (#223)
Browse files Browse the repository at this point in the history
* fix: changed the crypto public key provider to Bouncy Castle

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/master/packages/owl-bot/README.md

* fix: changed the crypto public key provider to Bouncy Castle

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/master/packages/owl-bot/README.md

* refactor: tweaked key creation acc to review comments

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/master/packages/owl-bot/README.md

* docs: lint changes acc to review comments

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/master/packages/owl-bot/README.md

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
Sita04 and gcf-owl-bot[bot] authored Aug 3, 2021
1 parent e355eaf commit ad386a7
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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";
Expand All @@ -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,
Expand All @@ -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();

Expand Down Expand Up @@ -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]
151 changes: 59 additions & 92 deletions samples/snippets/cloud-client/src/test/java/privateca/SnippetsIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;

Expand All @@ -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(
Expand All @@ -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);
}

Expand All @@ -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);
Expand All @@ -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
Expand Down
6 changes: 5 additions & 1 deletion samples/snippets/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@
<artifactId>google-cloud-security-private-ca</artifactId>
<version>1.1.0</version>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.58</version>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-kms</artifactId>
Expand Down

0 comments on commit ad386a7

Please sign in to comment.