Skip to content
Snippets Groups Projects

#664 Test JWK Generator

Merged Martin Vogel requested to merge feature/664-test-cert-generator into main
3 files
+ 29
12
Compare changes
  • Side-by-side
  • Inline
Files
3
package dev.fitko.fitconnect.cli.keygen;
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.jwk.KeyOperation;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.util.Base64;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import java.math.BigInteger;
import java.security.InvalidParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
* JWK Test Key Generator.
* <p>
* Generates key pairs of public and private keys for encryption and signing.
*/
public class JWKGenerator {
public static final int DEFAULT_KEY_SIZE = 4096;
/**
* Generate a set of public encryption key and private decryption key.
*
* @param keySize size of the RSA key in bits
* @return JWKPair of public and private key
*/
public JWKPair generateEncryptionKeyPair(final int keySize) {
final KeyPair keyPair = getKeyPair(keySize);
final List<Base64> x509CertChain = getX509CertChain(keyPair);
final String keyId = UUID.randomUUID().toString();
final JWEAlgorithm encryptionAlgorithm = JWEAlgorithm.RSA_OAEP_256;
final RSAKey publicEncryptionKey = buildRSAKey(keyId, keyPair, KeyOperation.WRAP_KEY, encryptionAlgorithm, x509CertChain);
final RSAKey privateDecryptionKey = buildRSAKey(keyId, keyPair, KeyOperation.UNWRAP_KEY, encryptionAlgorithm);
return new JWKPair(publicEncryptionKey.toPublicJWK(), privateDecryptionKey);
}
/**
* Generate a set of public signature verification key and private signature key.
*
* @param keySize size of the RSA key in bits
* @return JWKPair of signature and verification key
*/
public JWKPair generateSignatureKeyPair(final int keySize) {
final KeyPair keyPair = getKeyPair(keySize);
final List<Base64> x509CertChain = getX509CertChain(keyPair);
final String keyId = UUID.randomUUID().toString();
final JWSAlgorithm signingAlgorithm = JWSAlgorithm.PS512;
final RSAKey privateSignatureKey = buildRSAKey(keyId, keyPair, KeyOperation.SIGN, signingAlgorithm);
final RSAKey publicSignatureVerificationKey = buildRSAKey(keyId, keyPair, KeyOperation.VERIFY, signingAlgorithm, x509CertChain);
return new JWKPair(publicSignatureVerificationKey.toPublicJWK(), privateSignatureKey);
}
private static List<Base64> getX509CertChain(final KeyPair keyPair) {
final X509Certificate cert = getX509Certificate(keyPair);
try {
return RSAKey.parse(cert).getX509CertChain();
} catch (final JOSEException e) {
throw new RuntimeException(e);
}
}
private static RSAKey buildRSAKey(final String keyId, final KeyPair keyPair, final KeyOperation keyOperation, final Algorithm algorithm, final List<Base64> x509CertChain) {
final RSAKey.Builder builder = new RSAKey.Builder((RSAPublicKey) keyPair.getPublic())
.privateKey(keyPair.getPrivate())
.keyID(keyId)
.keyOperations(Set.of(keyOperation))
.algorithm(algorithm);
return x509CertChain.isEmpty() ? builder.build() : builder.x509CertChain(x509CertChain).build();
}
private static RSAKey buildRSAKey(final String keyId, final KeyPair keyPair, final KeyOperation keyOperation, final Algorithm algorithm) {
return buildRSAKey(keyId, keyPair, keyOperation, algorithm, Collections.emptyList());
}
private static X509Certificate getX509Certificate(final KeyPair keyPair) {
final Instant now = Instant.now();
final Date notBefore = Date.from(now);
final Date notAfter = Date.from(now.plus(Duration.ofDays(365 * 10)));
try {
final ContentSigner contentSigner = new JcaContentSignerBuilder("SHA512withRSA").build(keyPair.getPrivate());
final X500Name x500Name = new X500Name("CN=localhost");
final X500Name x500Subject = new X500Name("C=Test");
final BigInteger serialNr = BigInteger.valueOf(now.toEpochMilli());
final X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(x500Name, serialNr, notBefore, notAfter, x500Subject, keyPair.getPublic());
return new JcaX509CertificateConverter().getCertificate(certificateBuilder.build(contentSigner));
} catch (final CertificateException | OperatorCreationException e) {
throw new RuntimeException(e);
}
}
private static KeyPair getKeyPair(final int keySize) {
try {
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(keySize);
return keyPairGenerator.generateKeyPair();
} catch (final NoSuchAlgorithmException | InvalidParameterException e) {
throw new RuntimeException(e);
}
}
}
Loading