com.linkedin.mitm.services.AbstractX509CertificateService.java Source code

Java tutorial

Introduction

Here is the source code for com.linkedin.mitm.services.AbstractX509CertificateService.java

Source

/*
 * Copyright (c) LinkedIn Corporation. All rights reserved. Licensed under the BSD-2 Clause license.
 * See LICENSE in the project root for license information.
 */

package com.linkedin.mitm.services;

import com.linkedin.mitm.model.CertificateAuthority;
import com.linkedin.mitm.model.CertificateValidPeriod;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.bc.BcX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

/**
 * Abstract X509 certificate service that implement functionality that
 * commonly used for other X509 certificate service
 *
 * @author shfeng
 */
public abstract class AbstractX509CertificateService {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    private static final String SIGNATURE_ALGORITHM = "SHA1WithRSAEncryption";

    private final CertificateAuthority _certificateAuthority;
    private final CertificateValidPeriod _certificateValidPeriod;

    protected AbstractX509CertificateService(CertificateAuthority certificateAuthority,
            CertificateValidPeriod certificateValidPeriod) {
        _certificateAuthority = certificateAuthority;
        _certificateValidPeriod = certificateValidPeriod;
    }

    protected BigInteger getSerial() {
        return BigInteger.valueOf(RandomNumberGenerator.getInstance().getSecureRandom().nextLong());
    }

    /**
     * Create subjectKeyIdentifier
     * The Subject Key Identifier extension identifies the public key certified by this certificate.
     * This extension provides a way of distinguishing public keys if more than one is available for
     * a given subject name.
     * i.e.
     *     Identifier: Subject Key Identifier - 2.5.29.14
     *       Critical: no
     *        Key Identifier:
     *          3B:46:83:85:27:BC:F5:9D:8E:63:E3:BE:79:EF:AF:79:
     *          9C:37:85:84
     *
     * */
    protected SubjectKeyIdentifier createSubjectKeyIdentifier(PublicKey publicKey) throws IOException {
        try (ByteArrayInputStream bais = new ByteArrayInputStream(publicKey.getEncoded());
                ASN1InputStream ais = new ASN1InputStream(bais)) {
            ASN1Sequence asn1Sequence = (ASN1Sequence) ais.readObject();
            SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(asn1Sequence);
            return new BcX509ExtensionUtils().createSubjectKeyIdentifier(subjectPublicKeyInfo);
        }
    }

    protected X509Certificate createCertificate(PrivateKey privateKey,
            X509v3CertificateBuilder x509v3CertificateBuilder)
            throws OperatorCreationException, CertificateException {
        ContentSigner contentSigner = new JcaContentSignerBuilder(SIGNATURE_ALGORITHM)
                .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(privateKey);
        X509Certificate x509Certificate = new JcaX509CertificateConverter()
                .setProvider(BouncyCastleProvider.PROVIDER_NAME)
                .getCertificate(x509v3CertificateBuilder.build(contentSigner));
        return x509Certificate;
    }

    protected X500Name getSubject(String commonName) {
        X500NameBuilder x500NameBuilder = new X500NameBuilder(BCStyle.INSTANCE);
        x500NameBuilder.addRDN(BCStyle.CN, commonName);
        x500NameBuilder.addRDN(BCStyle.O, _certificateAuthority.getOrganization());
        x500NameBuilder.addRDN(BCStyle.OU, _certificateAuthority.getOrganizationalUnit());
        return x500NameBuilder.build();
    }

    protected Date getValidDateFrom() {
        return _certificateValidPeriod.getStart();
    }

    protected Date getValidDateTo() {
        return _certificateValidPeriod.getEnd();
    }

    protected void updateKeyStore(KeyStore keystore, PrivateKey privateKey, Certificate[] certificates)
            throws KeyStoreException {
        keystore.setKeyEntry(_certificateAuthority.getAlias(), privateKey, _certificateAuthority.getPassPhrase(),
                certificates);
    }

    /**
     *  Build X.509 v3 Certificate extension
     *  @param x509v3CertificateBuilder  certificate builder
     *  @param publicKey  certificate public key
     * */
    protected abstract void buildExtensions(X509v3CertificateBuilder x509v3CertificateBuilder, PublicKey publicKey)
            throws IOException;
}