From 31b4af170576b69d00f05b1166e7dac80ff770ba Mon Sep 17 00:00:00 2001 From: Appu Goundan Date: Thu, 19 May 2022 08:33:38 -0400 Subject: [PATCH] Add signer utilities Signed-off-by: Appu Goundan --- .../encryption/signers/EcdsaSigner.java | 49 +++++++++++++++++++ .../sigstore/encryption/signers/Signer.java | 43 ++++++++++++++++ .../sigstore/encryption/signers/Signers.java | 30 ++++++++++++ .../fulcio/client/FulcioClientTest.java | 36 ++++---------- 4 files changed, 131 insertions(+), 27 deletions(-) create mode 100644 src/main/java/dev/sigstore/encryption/signers/EcdsaSigner.java create mode 100644 src/main/java/dev/sigstore/encryption/signers/Signer.java create mode 100644 src/main/java/dev/sigstore/encryption/signers/Signers.java diff --git a/src/main/java/dev/sigstore/encryption/signers/EcdsaSigner.java b/src/main/java/dev/sigstore/encryption/signers/EcdsaSigner.java new file mode 100644 index 00000000..ab89b2c6 --- /dev/null +++ b/src/main/java/dev/sigstore/encryption/signers/EcdsaSigner.java @@ -0,0 +1,49 @@ +/* + * Copyright 2022 The Sigstore Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dev.sigstore.encryption.signers; + +import java.nio.charset.Charset; +import java.security.*; + +/** ECDSA signer, use {@link Signers#newEcdsaSigner()} to instantiate}. */ +public class EcdsaSigner implements Signer { + + private final KeyPair keyPair; + + EcdsaSigner(KeyPair keyPair) { + this.keyPair = keyPair; + } + + @Override + public PublicKey getPublicKey() { + return keyPair.getPublic(); + } + + @Override + public byte[] sign(String content, Charset charset) + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + return sign(content.getBytes(charset)); + } + + @Override + public byte[] sign(byte[] content) + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + Signature signature = Signature.getInstance("SHA256withECDSA"); + signature.initSign(keyPair.getPrivate()); + signature.update(content); + return signature.sign(); + } +} diff --git a/src/main/java/dev/sigstore/encryption/signers/Signer.java b/src/main/java/dev/sigstore/encryption/signers/Signer.java new file mode 100644 index 00000000..8b697227 --- /dev/null +++ b/src/main/java/dev/sigstore/encryption/signers/Signer.java @@ -0,0 +1,43 @@ +/* + * Copyright 2022 The Sigstore Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dev.sigstore.encryption.signers; + +import java.nio.charset.Charset; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.SignatureException; + +/** A signing helper that wraps common signing operations for use within this library. */ +public interface Signer { + + /** Return the public key associated with this signer. */ + PublicKey getPublicKey(); + + /** + * Sign the content. Implementations should use an algorithm that hashes with sha256 before + * signing. + */ + byte[] sign(String content, Charset charset) + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException; + + /** + * Sign the content. Implementations should use an algorithm that hashes with sha256 before + * signing. + */ + byte[] sign(byte[] content) + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException; +} diff --git a/src/main/java/dev/sigstore/encryption/signers/Signers.java b/src/main/java/dev/sigstore/encryption/signers/Signers.java new file mode 100644 index 00000000..f175e2eb --- /dev/null +++ b/src/main/java/dev/sigstore/encryption/signers/Signers.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 The Sigstore Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dev.sigstore.encryption.signers; + +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; + +/** Factory class for creation of signers. */ +public class Signers { + + /** Create a new ECDSA signer with 256 bit keysize */ + public static EcdsaSigner newEcdsaSigner() throws NoSuchAlgorithmException { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); + keyGen.initialize(256); + return new EcdsaSigner(keyGen.generateKeyPair()); + } +} diff --git a/src/test/java/dev/sigstore/fulcio/client/FulcioClientTest.java b/src/test/java/dev/sigstore/fulcio/client/FulcioClientTest.java index 088a5a81..8d9d7b47 100644 --- a/src/test/java/dev/sigstore/fulcio/client/FulcioClientTest.java +++ b/src/test/java/dev/sigstore/fulcio/client/FulcioClientTest.java @@ -15,13 +15,11 @@ */ package dev.sigstore.fulcio.client; +import dev.sigstore.encryption.signers.Signers; import dev.sigstore.testing.FakeCTLogServer; import dev.sigstore.testing.FulcioWrapper; import dev.sigstore.testing.MockOAuth2ServerExtension; import java.nio.charset.StandardCharsets; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.Signature; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -39,19 +37,11 @@ public void testSigningCert( var token = mockOAuthServerExtension.getOidcToken().getIdToken(); var subject = mockOAuthServerExtension.getOidcToken().getEmailAddress(); - // create an ECDSA p-256 keypair, this is our key that we want to generate certs for - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); - keyGen.initialize(256); - KeyPair keys = keyGen.generateKeyPair(); + var signer = Signers.newEcdsaSigner(); + var signed = signer.sign(subject, StandardCharsets.UTF_8); - // sign the "subject" with our key, this signer already generates asn1 notation - Signature signature = Signature.getInstance("SHA256withECDSA"); - signature.initSign(keys.getPrivate()); - signature.update(subject.getBytes(StandardCharsets.UTF_8)); - byte[] signed = signature.sign(); - - // create a certificate request with our public key, oidc token and our signed "subject" - CertificateRequest cReq = new CertificateRequest(keys.getPublic(), token, signed); + // create a certificate request with our public key and our signed "subject" + CertificateRequest cReq = new CertificateRequest(signer.getPublicKey(), token, signed); // ask fulcio for a signing cert SigningCertificate sc = c.SigningCert(cReq); @@ -73,19 +63,11 @@ public void testSigningCert_NoSct( var token = mockOAuthServerExtension.getOidcToken().getIdToken(); var subject = mockOAuthServerExtension.getOidcToken().getEmailAddress(); - // create an ECDSA p-256 keypair, this is our key that we want to generate certs for - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); - keyGen.initialize(256); - KeyPair keys = keyGen.generateKeyPair(); - - // sign the "subject" with our key, this signer already generates asn1 notation - Signature signature = Signature.getInstance("SHA256withECDSA"); - signature.initSign(keys.getPrivate()); - signature.update(subject.getBytes(StandardCharsets.UTF_8)); - byte[] signed = signature.sign(); + var signer = Signers.newEcdsaSigner(); + var signed = signer.sign(subject, StandardCharsets.UTF_8); - // create a certificate request with our public key, oidc token and our signed "subject" - CertificateRequest cReq = new CertificateRequest(keys.getPublic(), token, signed); + // create a certificate request with our public key and our signed "subject" + CertificateRequest cReq = new CertificateRequest(signer.getPublicKey(), token, signed); // ask fulcio for a signing cert SigningCertificate sc = c.SigningCert(cReq);