All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.idsec.signservice.security.sign.impl.StaticCredentials Maven / Gradle / Ivy

/*
 * Copyright 2019-2024 IDsec Solutions AB
 *
 * 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 se.idsec.signservice.security.sign.impl;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509v1CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509v1CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import se.idsec.signservice.security.certificate.CertificateUtils;
import se.swedenconnect.security.algorithms.Algorithm;
import se.swedenconnect.security.algorithms.AlgorithmRegistry;
import se.swedenconnect.security.algorithms.AlgorithmRegistrySingleton;
import se.swedenconnect.security.algorithms.AlgorithmType;
import se.swedenconnect.security.algorithms.SignatureAlgorithm;
import se.swedenconnect.security.credential.BasicCredential;
import se.swedenconnect.security.credential.PkiCredential;

import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
import java.util.Date;

/**
 * Utility class that holds pre-generated key pairs.
 * 

* Mainly useful for testing, but also when to-be-signed bytes are calculated. *

* * @author Martin Lindström ([email protected]) * @author Stefan Santesson ([email protected]) */ @Slf4j public class StaticCredentials { /** The default number of bits for RSA keys. */ public static final int DEFAULT_RSA_KEY_SIZE = 2048; /** The default curve to use for EC keys. */ public static final String DEFAULT_EC_CURVE = "P-256"; /** Pre-generated RSA key pair. */ private KeyPair rsaKeyPair; /** Pre-generated EC key pair. */ private KeyPair ecKeyPair; /** The number of bits for the generated RSA keys - default is {@value #DEFAULT_RSA_KEY_SIZE}. */ private int rsaKeySize = DEFAULT_RSA_KEY_SIZE; /** The curve to use for EC keys - default is {@value #DEFAULT_EC_CURVE}. */ private String ecCurve = DEFAULT_EC_CURVE; /** Certificate for RSA private key. */ private X509Certificate rsaCertificate; /** Certificate for EC private key. */ private X509Certificate ecCertificate; /** The algorithm registry. */ private AlgorithmRegistry algorithmRegistry; /** * Constructor. */ public StaticCredentials() { } /** * Constructor setting the key size for RSA and curve for EC to use. * * @param rsaKeySize RSA key size in bits (default is {@value #DEFAULT_RSA_KEY_SIZE}) * @param ecCurve identifier for EC curve to use (default is {@value #DEFAULT_EC_CURVE}) */ public StaticCredentials(final int rsaKeySize, final String ecCurve) { this.rsaKeySize = rsaKeySize; if (ecCurve != null) { this.ecCurve = ecCurve; } } /** * Returns a {@link PkiCredential} that can be used to sign using the supplied algorithm. * * @param algorithmUri the signature algorithm URI * @return a PkiCredential instance * @throws NoSuchAlgorithmException if the supplied algorithm is not supported */ public PkiCredential getSigningCredential(final String algorithmUri) throws NoSuchAlgorithmException { final Algorithm algorithm = this.getAlgorithmRegistry().getAlgorithm(algorithmUri); if (algorithm == null || algorithm.getType() != AlgorithmType.SIGNATURE) { final String msg = String.format("Algorithm '%s' is not a registered signature algorithm", algorithmUri); log.error("{}", msg); throw new NoSuchAlgorithmException(msg); } final String algoClass = ((SignatureAlgorithm) algorithm).getKeyType(); try { final BasicCredential cred; if ("RSA".equals(algoClass)) { synchronized (this) { final KeyPair rsaKeyPair = this.getRsaKeyPair(); cred = new BasicCredential(this.getRsaCertificate(), rsaKeyPair.getPrivate()); cred.setName("RSA"); } } else if ("EC".equals(algoClass)) { synchronized (this) { final KeyPair ecKeyPair = this.getEcKeyPair(); cred = new BasicCredential(this.getEcCertificate(), ecKeyPair.getPrivate()); cred.setName("EC"); } } else { final String msg = String.format("Algorithm '%s' is not supported", algorithmUri); log.error("{}", msg); throw new NoSuchAlgorithmException(msg); } return cred; } catch (final InvalidParameterException | InvalidAlgorithmParameterException e) { throw new NoSuchAlgorithmException("Invalid parameter", e); } } /** * Gets the generated RSA key pair. * * @return the RSA key pair. * @throws InvalidParameterException if the keysize is incorrect */ public synchronized KeyPair getRsaKeyPair() throws InvalidParameterException { if (this.rsaKeyPair == null) { this.rsaKeyPair = this.generateRsaKeyPair(this.rsaKeySize); } return this.rsaKeyPair; } /** * Gets the generated EC key pair. * * @return the EC key pair * @throws InvalidAlgorithmParameterException for unsupported curve */ public synchronized KeyPair getEcKeyPair() throws InvalidAlgorithmParameterException { if (this.ecKeyPair == null) { this.ecKeyPair = this.generateEcKeyPair(this.ecCurve); } return this.ecKeyPair; } /** * Assigns the {@link AlgorithmRegistry} to use. If not assigned, the registry configured for * {@link AlgorithmRegistrySingleton} will be used. * * @param algorithmRegistry the registry to use */ public void setAlgorithmRegistry(final AlgorithmRegistry algorithmRegistry) { this.algorithmRegistry = algorithmRegistry; } /** * Gets the {@link AlgorithmRegistry} to use. * * @return the AlgorithmRegistry */ private AlgorithmRegistry getAlgorithmRegistry() { if (this.algorithmRegistry == null) { this.algorithmRegistry = AlgorithmRegistrySingleton.getInstance(); } return this.algorithmRegistry; } /** * Generates an RSA key pair. * * @param keysize the keysize in bits * @return RSA key pair * @throws InvalidParameterException if the bit size is incorrect */ private KeyPair generateRsaKeyPair(final int keysize) throws InvalidParameterException { log.debug("Generating RSA key pair ..."); try { final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(keysize); final KeyPair kp = generator.generateKeyPair(); this.rsaCertificate = this.generateV1Certificate(kp, "RSA"); return kp; } catch (final NoSuchAlgorithmException | OperatorCreationException | CertificateException | IOException e) { throw new SecurityException(e); } } /** * Generates an EC keypair. * * @param ecCurve the curve * @return EC keypair * @throws InvalidAlgorithmParameterException for invalid curve */ private KeyPair generateEcKeyPair(final String ecCurve) throws InvalidAlgorithmParameterException { log.debug("Generating EC key pair ..."); try { final KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider()); generator.initialize(new ECGenParameterSpec(ecCurve), new SecureRandom()); final KeyPair kp = generator.generateKeyPair(); this.ecCertificate = this.generateV1Certificate(kp, "EC"); return kp; } catch (final NoSuchAlgorithmException | OperatorCreationException | CertificateException | IOException e) { throw new SecurityException(e); } } /** * Gets the RSA certificate. * * @return the RSA certificate */ private X509Certificate getRsaCertificate() { return this.rsaCertificate; } /** * Gets the EC certificate. * * @return the EC certificate */ private X509Certificate getEcCertificate() { return this.ecCertificate; } /** * Generates self-signed certificate. * * @param pair key pair * @param algoKey algorithm type * @return certificate for the key pair * @throws OperatorCreationException on error * @throws IOException on error * @throws CertificateException on error */ private X509Certificate generateV1Certificate(final KeyPair pair, final String algoKey) throws OperatorCreationException, IOException, CertificateException { final X509v1CertificateBuilder certGenerator = new JcaX509v1CertificateBuilder( new X500Name("CN=Test Signer"), /* issuer */ BigInteger.valueOf(System.currentTimeMillis()), /* serial */ new Date(System.currentTimeMillis() - 7200000L), /* notBefore */ new Date(System.currentTimeMillis() + (5 * 365 * 24 * 3600000L)), /* notAfter */ new X500Name("CN=Test Signer"), /* subject */ pair.getPublic()); final ContentSigner signer = "RSA".equals(algoKey) ? new JcaContentSignerBuilder("SHA256WITHRSA").build(pair.getPrivate()) : new JcaContentSignerBuilder("SHA256WITHECDSA").build(pair.getPrivate()); return CertificateUtils.decodeCertificate(certGenerator.build(signer).getEncoded()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy