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

org.hyperledger.fabric.sdk.security.certgen.TLSCertificateBuilder Maven / Gradle / Ivy

There is a newer version: 2.2.26
Show newest version
/*
 *
 *  Copyright 2018 IBM - All Rights Reserved.
 *
 *  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 org.hyperledger.fabric.sdk.security.certgen;

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.UUID;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

/****
 * Creates both client and server TLS certificates
 */
public class TLSCertificateBuilder {
    private static final SecureRandom rand = new SecureRandom();
    private static final String defaultSignatureAlgorithm = "SHA256withECDSA";
    private static final String defaultKeyType = "EC";

    private String commonName;
    private String signatureAlgorithm;
    private String keyType;

    /***
     * Creates a TLSCertificateBuilder, which is used for creating certificates
     */
    public TLSCertificateBuilder() {
        // Initialize a default random common name
        commonName = UUID.randomUUID().toString();
        // Initialize the signature algorithm to be ECDSA over SHA256 by default
        signatureAlgorithm = defaultSignatureAlgorithm;
        // Initialize the key type to be elliptic curve by default
        keyType = defaultKeyType;
    }

    /***
     * Creates a TLS client certificate key pair
     * @return a TLSCertificateKeyPair
     */
    public TLSCertificateKeyPair clientCert() {
        try {
            return createCert(CertType.CLIENT, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /***
     * Creates a TLS server certificate key pair with the given DNS subject alternative name
     * @param subjectAlternativeName the DNS SAN to be encoded in the certificate
     * @return a TLSCertificateKeyPair
     */
    public TLSCertificateKeyPair serverCert(String subjectAlternativeName) {
        try {
            return createCert(CertType.SERVER, subjectAlternativeName);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private TLSCertificateKeyPair createCert(CertType certType, String subjectAlternativeName) throws Exception {
        KeyPair keyPair = createKeyPair();
        X509Certificate cert = createSelfSignedCertificate(certType, keyPair, subjectAlternativeName);
        return TLSCertificateKeyPair.fromX509CertKeyPair(cert, keyPair);
    }

    private X509Certificate createSelfSignedCertificate(CertType certType, KeyPair keyPair, String san) throws Exception {
        X509v3CertificateBuilder certBuilder = createCertBuilder(keyPair);

        // Basic constraints
        BasicConstraints constraints = new BasicConstraints(false);
        certBuilder.addExtension(
                Extension.basicConstraints,
                true,
                constraints.getEncoded());
        // Key usage
        KeyUsage usage = new KeyUsage(KeyUsage.keyEncipherment | KeyUsage.digitalSignature);
        certBuilder.addExtension(Extension.keyUsage, false, usage.getEncoded());
        // Extended key usage
        certBuilder.addExtension(
                Extension.extendedKeyUsage,
                false,
                certType.keyUsage().getEncoded());

        if (san != null) {
            addSAN(certBuilder, san);
        }

        ContentSigner signer = new JcaContentSignerBuilder(signatureAlgorithm)
                .build(keyPair.getPrivate());
        X509CertificateHolder holder = certBuilder.build(signer);

        JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
        converter.setProvider(new BouncyCastleProvider());
        return converter.getCertificate(holder);
    }

    private void addSAN(X509v3CertificateBuilder certBuilder, String san) throws CertIOException {
        ASN1Encodable[] subjectAlternativeNames = new ASN1Encodable[]{new GeneralName(GeneralName.dNSName, san)};
        certBuilder.addExtension(Extension.subjectAlternativeName, false, new DERSequence(subjectAlternativeNames));
    }

    private X509v3CertificateBuilder createCertBuilder(KeyPair keyPair) {
        X500Name subject = new X500NameBuilder(BCStyle.INSTANCE)
                .addRDN(BCStyle.CN, commonName)
                .build();

        Calendar notBefore = new GregorianCalendar();
        notBefore.add(Calendar.DAY_OF_MONTH, -1);
        Calendar notAfter = new GregorianCalendar();
        notAfter.add(Calendar.YEAR, 10);

        return new JcaX509v3CertificateBuilder(
                subject,
                new BigInteger(160, rand),
                notBefore.getTime(),
                notAfter.getTime(),
                subject,
                keyPair.getPublic());
    }

    private KeyPair createKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keypairGen = KeyPairGenerator.getInstance(keyType);
        keypairGen.initialize(256, rand);
        return keypairGen.generateKeyPair();
    }


    private enum CertType {
        CLIENT, SERVER;

        ExtendedKeyUsage keyUsage() {
            KeyPurposeId[] kpid = new KeyPurposeId[]{KeyPurposeId.id_kp_clientAuth};
            if (this.ordinal() == 1) {
                kpid[0] = KeyPurposeId.id_kp_serverAuth;
            }
            return new ExtendedKeyUsage(kpid);
        }
    }

    private static class SelfSignedKeyIdentifier {
        private static SecureRandom rand = new SecureRandom();

        private byte[] bytes;

        SelfSignedKeyIdentifier() {
            bytes = new byte[20];
            rand.nextBytes(bytes);
        }

        byte[] authorityKeyIdentifier() {
            return bytes;
        }

        byte[] subjectKeyIdentifier() {
            return bytes;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy