March 2, 2020

Creating X509 Certificate with Bouncy Castle

Bouncy Castle has X509 Certificate builder but in my opinion it is still quite low tech.


package se.magnuskkarlsson.example.bouncycastle;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.util.Calendar;
import java.util.Date;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.CertificatePolicies;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.asn1.x509.Time;
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

// org.bouncycastle.cert.X509v3CertificateBuilder
public class X509CertificateBuilder {

    public static final ASN1ObjectIdentifier MSUPN_OID = new ASN1ObjectIdentifier("1.3.6.1.4.1.311.20.2.3");

    private V3TBSCertificateGenerator tbsGen;
    private ExtensionsGenerator extGenerator;

    public X509CertificateBuilder() {
        this.tbsGen = new V3TBSCertificateGenerator();
        this.extGenerator = new ExtensionsGenerator();
    }

    // ----------------------- Logic Methods -----------------------

    //
    // Mandatory Fields
    //

    public X509CertificateBuilder setSerialNumber(BigInteger serialNumber) {
        tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
        return this;
    }

    public X509CertificateBuilder setIssuerDN(X500Name issuerDN) {
        this.tbsGen.setIssuer(issuerDN);
        return this;
    }

    public X509CertificateBuilder setValidity(int numberOfYears) {
        Date validityNotBefore = new Date(System.currentTimeMillis());
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(validityNotBefore);
        // calendar.add(Calendar.DAY_OF_YEAR, numberOfYears);
        calendar.add(Calendar.YEAR, numberOfYears);
        Date validityNotAfter = calendar.getTime();
        this.tbsGen.setStartDate(new Time(validityNotBefore));
        this.tbsGen.setEndDate(new Time(validityNotAfter));
        return this;
    }

    public X509CertificateBuilder setSubjectDN(X500Name subjectDN) {
        this.tbsGen.setSubject(subjectDN);
        return this;
    }

    public X509CertificateBuilder setSubjectPublicKeyInfo(PublicKey publicKey) {
        SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
        this.tbsGen.setSubjectPublicKeyInfo(subjectPublicKeyInfo);
        return this;
    }

    //
    // Certificate Extensions
    //

    public X509CertificateBuilder setBasicContraints(boolean ca, boolean critical) throws IOException {
        this.extGenerator.addExtension(Extension.basicConstraints, critical, new BasicConstraints(ca));
        return this;
    }

    public X509CertificateBuilder setAuthorityKeyIdentifier(PublicKey caPublicKey, boolean critical)
            throws NoSuchAlgorithmException, IOException {

        this.extGenerator.addExtension(Extension.authorityKeyIdentifier, critical,
                new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(caPublicKey));
        return this;
    }

    public X509CertificateBuilder setSubjectKeyIdentifier(PublicKey publicKey, boolean critical)
            throws NoSuchAlgorithmException, IOException {

        this.extGenerator.addExtension(Extension.subjectKeyIdentifier, critical,
                new JcaX509ExtensionUtils().createSubjectKeyIdentifier(publicKey));
        return this;
    }

    public X509CertificateBuilder setAuthorityInformationAccess(String ocspUri, String caIssuersUri, boolean critical)
            throws IOException {

        GeneralName ocspName = new GeneralName(GeneralName.uniformResourceIdentifier, ocspUri);
        GeneralName caIssuersName = new GeneralName(GeneralName.uniformResourceIdentifier, caIssuersUri);

        AccessDescription ocsp = new AccessDescription(AccessDescription.id_ad_ocsp, ocspName);
        AccessDescription caIssuers = new AccessDescription(AccessDescription.id_ad_caIssuers, caIssuersName);

        AuthorityInformationAccess authorityInformationAccess = new AuthorityInformationAccess(
                new AccessDescription[] { ocsp, caIssuers });
        this.extGenerator.addExtension(Extension.authorityInfoAccess, critical, authorityInformationAccess);
        return this;
    }

    public X509CertificateBuilder setCRLDistributionPoints(String cdpUri, boolean critical) throws IOException {
        GeneralNames generalNames = new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, cdpUri));
        DistributionPoint[] distPoints = new DistributionPoint[] {
                new DistributionPoint(new DistributionPointName(generalNames), null, null) };
        this.extGenerator.addExtension(Extension.cRLDistributionPoints, critical, new CRLDistPoint(distPoints));
        return this;
    }

    public X509CertificateBuilder setCertificatePolicies(String[] certificatePolicyIds, boolean critical)
            throws IOException {

        PolicyInformation[] policyInfos = new PolicyInformation[certificatePolicyIds.length];
        for (int i = 0; i < certificatePolicyIds.length; ++i) {
            policyInfos[i] = new PolicyInformation(new ASN1ObjectIdentifier(certificatePolicyIds[i]));
        }
        this.extGenerator.addExtension(Extension.certificatePolicies, critical, new CertificatePolicies(policyInfos));
        return this;
    }

    public X509CertificateBuilder setKeyUsage(KeyUsage keyUsage1, boolean critical) throws IOException {
        this.extGenerator.addExtension(Extension.keyUsage, critical,
                new org.bouncycastle.asn1.x509.KeyUsage(keyUsage1.getValue()));
        return this;
    }

    public X509CertificateBuilder setKeyUsage(KeyUsage keyUsage1, KeyUsage keyUsage2, boolean critical)
            throws IOException {

        this.extGenerator.addExtension(Extension.keyUsage, critical,
                new org.bouncycastle.asn1.x509.KeyUsage(keyUsage1.getValue() | keyUsage2.getValue()));
        return this;
    }

    public X509CertificateBuilder setKeyUsage(KeyUsage keyUsage1, KeyUsage keyUsage2, KeyUsage keyUsage3,
            boolean critical) throws IOException {

        this.extGenerator.addExtension(Extension.keyUsage, critical, new org.bouncycastle.asn1.x509.KeyUsage(
                keyUsage1.getValue() | keyUsage2.getValue() | keyUsage3.getValue()));
        return this;
    }

    public X509CertificateBuilder setExtendedKeyUsage(KeyPurposeId[] keyPurposeIds, boolean critical)
            throws IOException {

        this.extGenerator.addExtension(Extension.extendedKeyUsage, critical, new ExtendedKeyUsage(keyPurposeIds));
        return this;
    }

    public X509CertificateBuilder setSubjectAlternativeNamesDNS(String[] hostnames, boolean critical)
            throws IOException {

        GeneralName[] generalNames = new GeneralName[hostnames.length];
        for (int i = 0; i < hostnames.length; ++i) {
            generalNames[i] = new GeneralName(GeneralName.dNSName, hostnames[i]);
        }
        this.extGenerator.addExtension(Extension.subjectAlternativeName, critical, new GeneralNames(generalNames));
        return this;
    }

    public X509CertificateBuilder setSubjectAlternativeNamesUPN(String upn, boolean critical) throws IOException {
        this.extGenerator.addExtension(Extension.subjectAlternativeName, critical, new GeneralNames(new GeneralName(
                GeneralName.otherName,
                new DERSequence(new ASN1Encodable[] { MSUPN_OID, new DERTaggedObject(0, new DERUTF8String(upn)) }))));
        return this;
    }

    public java.security.cert.X509Certificate build(PrivateKey caPrivateKey, String signatureAlgorithm)
            throws OperatorCreationException, CertificateException, NoSuchAlgorithmException, IOException {

        ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm)
                .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(caPrivateKey);

        this.tbsGen.setSignature(contentSigner.getAlgorithmIdentifier());
        this.tbsGen.setExtensions(this.extGenerator.generate());

        TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
        X509CertificateHolder X509CertificateHolder = new X509CertificateHolder(generateStructure(tbsCert,
                contentSigner.getAlgorithmIdentifier(), generateSig(contentSigner, tbsCert)));

        return new JcaX509CertificateConverter().getCertificate(X509CertificateHolder);
    }

    // ----------------------- Helper Methods -----------------------

    // org.bouncycastle.asn1.x509.KeyUsage
    public enum KeyUsage {

        DIGITAL_SIGNATURE(org.bouncycastle.asn1.x509.KeyUsage.digitalSignature), //
        NON_REPUDIATION(org.bouncycastle.asn1.x509.KeyUsage.nonRepudiation), //
        KEY_ENCIPHERMENT(org.bouncycastle.asn1.x509.KeyUsage.keyEncipherment), //
        DATA_ENCIPHERMENT(org.bouncycastle.asn1.x509.KeyUsage.dataEncipherment), //
        KEY_AGREEMENT(org.bouncycastle.asn1.x509.KeyUsage.keyAgreement), //
        KEY_CERT_SIGN(org.bouncycastle.asn1.x509.KeyUsage.keyCertSign), //
        CRL_SIGN(org.bouncycastle.asn1.x509.KeyUsage.cRLSign);

        private final int value;

        KeyUsage(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

    protected byte[] generateSig(ContentSigner signer, ASN1Object tbsObj) throws IOException {
        OutputStream sOut = signer.getOutputStream();
        tbsObj.encodeTo(sOut, ASN1Encoding.DER);
        sOut.close();
        return signer.getSignature();
    }

    protected Certificate generateStructure(TBSCertificate tbsCert, AlgorithmIdentifier sigAlgId, byte[] signature) {
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(tbsCert);
        v.add(sigAlgId);
        v.add(new DERBitString(signature));
        return Certificate.getInstance(new DERSequence(v));
    }

    // ----------------------- Get and Set Methods -----------------------

}

And certificate profile builder.


package se.magnuskkarlsson.example.bouncycastle;

import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.operator.OperatorCreationException;

import se.magnuskkarlsson.example.bouncycastle.X509CertificateBuilder.KeyUsage;

public class X509CertificateProfile {

    // ----------------------- Logic Methods -----------------------

    public X509Certificate createCA(KeyPair caKeyPair, X500Name subjectDN, String cdpUri)
            throws OperatorCreationException, CertificateException, NoSuchAlgorithmException, IOException {

        return new X509CertificateBuilder() //
                // mandatory fields
                .setSerialNumber(getSerialNumber()) //
                .setIssuerDN(subjectDN) //
                .setValidity(10) //
                .setSubjectDN(subjectDN) //
                .setSubjectPublicKeyInfo(caKeyPair.getPublic()) //
                // certificate extensions
                .setBasicContraints(true, true) //
                .setAuthorityKeyIdentifier(caKeyPair.getPublic(), false) //
                .setSubjectKeyIdentifier(caKeyPair.getPublic(), false) //
                .setCRLDistributionPoints(cdpUri, false) //
                .setKeyUsage(KeyUsage.DIGITAL_SIGNATURE, KeyUsage.KEY_CERT_SIGN, KeyUsage.CRL_SIGN, true) //
                .build(caKeyPair.getPrivate(), CAKeyStore.SHA256_RSA_SIGNATURE);
    }

    public X509Certificate createServer(KeyPair caKeyPair, KeyPair keyPair, X500Name issuerDN, X500Name subjectDN,
            String ocspUri, String caIssuersUri, String cdpUri, String[] hostnames)
            throws OperatorCreationException, CertificateException, NoSuchAlgorithmException, IOException {

        return new X509CertificateBuilder() //
                // mandatory fields
                .setSerialNumber(getSerialNumber()) //
                .setIssuerDN(issuerDN) //
                .setValidity(1) //
                .setSubjectDN(subjectDN) //
                .setSubjectPublicKeyInfo(keyPair.getPublic()) //
                // certificate extensions
                .setBasicContraints(false, true) //
                .setAuthorityKeyIdentifier(caKeyPair.getPublic(), false) //
                .setSubjectKeyIdentifier(keyPair.getPublic(), false) //
                .setAuthorityInformationAccess(ocspUri, caIssuersUri, false) //
                .setCRLDistributionPoints(cdpUri, false) //
                .setKeyUsage(KeyUsage.DIGITAL_SIGNATURE, KeyUsage.KEY_ENCIPHERMENT, false) //
                .setExtendedKeyUsage(new KeyPurposeId[] { KeyPurposeId.id_kp_serverAuth }, false)
                .setSubjectAlternativeNamesDNS(hostnames, false) //
                .build(caKeyPair.getPrivate(), CAKeyStore.SHA256_RSA_SIGNATURE);
    }

    public X509Certificate createClient(KeyPair caKeyPair, KeyPair keyPair, X500Name issuerDN, X500Name subjectDN,
            String ocspUri, String caIssuersUri, String cdpUri, String upn)
            throws OperatorCreationException, CertificateException, NoSuchAlgorithmException, IOException {

        return new X509CertificateBuilder() //
                // mandatory fields
                .setSerialNumber(getSerialNumber()) //
                .setIssuerDN(issuerDN) //
                .setValidity(1) //
                .setSubjectDN(subjectDN) //
                .setSubjectPublicKeyInfo(keyPair.getPublic()) //
                // certificate extensions
                .setBasicContraints(false, true) //
                .setAuthorityKeyIdentifier(caKeyPair.getPublic(), false) //
                .setSubjectKeyIdentifier(keyPair.getPublic(), false) //
                .setAuthorityInformationAccess(ocspUri, caIssuersUri, false) //
                .setCRLDistributionPoints(cdpUri, false) //
                .setKeyUsage(KeyUsage.DIGITAL_SIGNATURE, KeyUsage.NON_REPUDIATION, KeyUsage.KEY_ENCIPHERMENT, true) //
                .setExtendedKeyUsage(new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth }, false)
                .setSubjectAlternativeNamesUPN(upn, false) //
                .build(caKeyPair.getPrivate(), CAKeyStore.SHA256_RSA_SIGNATURE);
    }

    // ----------------------- Helper Methods -----------------------

    protected BigInteger getSerialNumber() {
        // RFC 5280 and X.690

        // Effective September 30, 2016, CAs SHALL generate non-sequential Certificate serial numbers greater than zero
        // (0) containing at least 64 bits of output from a CSPRNG.
        return BigInteger.valueOf(System.currentTimeMillis());
    }

    // ----------------------- Get and Set Methods -----------------------

}

And unit test.


package se.magnuskkarlsson.example.bouncycastle;

import java.io.File;
import java.security.KeyPair;
import java.security.Security;
import java.security.cert.X509Certificate;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class X509CertificateProfileTest {

    private static KeyPair caKeyPair;
    private static X500Name caSubjectDN;
    private String ocspUri = "http://ocsp.mkk.se/";
    private String caIssuersUri = "http://pki.mkk.se/ca.crt";
    private String cdpUri = "http://crl.mkk.se/ca.crl";

    @BeforeClass
    public static void oneTimeSetUp() throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        caKeyPair = new CAKeyStore(new Configurations()).createKeyPair(CAKeyStore.RSA_ALGORITHM, 4096);
        caSubjectDN = new X500NameBuilder() //
                .addRDN(BCStyle.CN, "FOO CA") //
                .addRDN(BCStyle.O, "MKK") //
                .addRDN(BCStyle.C, "SE") //
                .build();
    }

    @Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() {
    }

    @AfterClass
    public static void oneTimeTearDown() throws Exception {
    }

    // ----------------------- Test Methods -----------------------

    @Test
    public void createCA() throws Exception {
        X509Certificate caCert = new X509CertificateProfile().createCA(caKeyPair, caSubjectDN, cdpUri);

        System.out.println(caCert);
        EncryptionUtils.writePEM(caCert, File.createTempFile("caCert-", ".crt.pem"));
    }

    @Test
    public void createServer() throws Exception {
        KeyPair serverKeyPair = new CAKeyStore(new Configurations()).createKeyPair(CAKeyStore.RSA_ALGORITHM, 2048);
        X500Name serverSubjectDN = new X500NameBuilder() //
                .addRDN(BCStyle.CN, "FQDN") //
                .addRDN(BCStyle.OU, "mywebapp") //
                .addRDN(BCStyle.O, "MKK") //
                .addRDN(BCStyle.C, "SE") //
                .build();
        String[] hostnames = new String[] { "localhost", "127.0.0.1" };

        X509Certificate serverCert = new X509CertificateProfile().createServer(caKeyPair, serverKeyPair, caSubjectDN,
                serverSubjectDN, ocspUri, caIssuersUri, cdpUri, hostnames);

        System.out.println(serverCert);
        EncryptionUtils.writePEM(serverCert, File.createTempFile("serverCert-", ".crt.pem"));
    }

    @Test
    public void createClient() throws Exception {
        X509Certificate caCert = new X509CertificateProfile().createCA(caKeyPair, caSubjectDN, cdpUri);

        KeyPair clientKeyPair = new CAKeyStore(new Configurations()).createKeyPair(CAKeyStore.RSA_ALGORITHM, 2048);
        X500Name clientSubjectDN = new X500NameBuilder() //
                .addRDN(BCStyle.CN, "Magnus K Karlsson") //
                .addRDN(BCStyle.OU, "1000") //
                .addRDN(BCStyle.O, "MKK") //
                .addRDN(BCStyle.C, "SE") //
                .build();
        String upn = "1000@mkk.se";

        X509Certificate clientCert = new X509CertificateProfile().createClient(caKeyPair, clientKeyPair, caSubjectDN,
                clientSubjectDN, ocspUri, caIssuersUri, cdpUri, upn);

        System.out.println(clientCert);
        EncryptionUtils.writePEM(clientCert, File.createTempFile("clientCert-", ".cert.pem"));
        System.out.println(EncryptionUtils.getMSUPN(clientCert));
        EncryptionUtils.writeKeyStore("PKCS12", clientKeyPair.getPrivate(), "changeit",
                new X509Certificate[] { clientCert, caCert }, File.createTempFile("clientCert-", ".p12"));
    }

}

And when run.


[
[
  Version: V3
  Subject: C=SE, O=MKK, OU=1000, CN=Magnus K Karlsson
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 2048 bits
  params: null
  modulus: 25571568211886603124840374772893412632803008320276441343266420556001859527212495329059106511242070860135631150070936589994653782417968024014212169649126808218158560179639047989539457693799118359900429037050920421546627123472786524557783697159392478858239658746621633838155562268034256430543588459559201972100435495705680421356703692111342204230448132868538272476016901917159213800485636336183819543618065791989738031811366034365221624184676389882604646322575407826629234052470133086130458566129601941794090632783578168688778972919128563980379914647410944834699287955276441401709227130144873341655798718948150387040663
  public exponent: 65537
  Validity: [From: Mon Mar 02 20:35:28 CET 2020,
               To: Tue Mar 02 20:35:28 CET 2021]
  Issuer: C=SE, O=MKK, CN=FOO CA
  SerialNumber: [    01709cbf 0140]

Certificate Extensions: 8
[1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
  [
   accessMethod: ocsp
   accessLocation: URIName: http://ocsp.mkk.se/
, 
   accessMethod: caIssuers
   accessLocation: URIName: http://pki.mkk.se/ca.crt
]
]

[2]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 13 5B F4 D2 4E 05 F0 73   9D D0 60 C4 42 A3 80 95  .[..N..s..`.B...
0010: 37 7B 9A 1B                                        7...
]
]

[3]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:false
  PathLen: undefined
]

[4]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://crl.mkk.se/ca.crl]
]]

[5]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  clientAuth
]

[6]: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  DigitalSignature
  Non_repudiation
  Key_Encipherment
]

[7]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  Other-Name: Unrecognized ObjectIdentifier: 1.3.6.1.4.1.311.20.2.3
]

[8]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 63 31 5B A3 22 8C C0 4B   DF 2D 7B 39 4C 43 D2 DB  c1[."..K.-.9LC..
0010: 11 96 37 46                                        ..7F
]
]

]
  Algorithm: [SHA256withRSA]
  Signature:
0000: 85 9B 22 22 44 4E E0 59   44 31 12 53 39 D5 A4 78  ..""DN.YD1.S9..x
0010: DA 39 80 BC 53 47 94 D1   B3 B6 E3 2B 8F D4 39 92  .9..SG.....+..9.
0020: 7B 63 CE FA 48 53 33 BF   B6 4B E7 83 90 47 AA 2D  .c..HS3..K...G.-
0030: 32 B6 02 9F A9 1B EE 27   02 7C 68 B2 9F 50 D4 D2  2......'..h..P..
0040: 55 2C A4 B6 1C 09 F1 BF   AE 0A A6 39 60 DE 93 CA  U,.........9`...
0050: 74 32 54 8F 74 E0 5B F8   0D 32 FE 6E 02 6B 88 9D  t2T.t.[..2.n.k..
0060: 2F D7 0C 9D A7 DE 20 5B   10 0A 08 61 1A 76 B0 35  /..... [...a.v.5
0070: 80 E3 AF C6 4C A9 06 E0   38 2F 9F D8 48 E8 BE DC  ....L...8/..H...
0080: 89 C0 DF 64 E2 F3 72 3C   BC 51 A8 D9 F2 1E 18 4A  ...d..r<.Q.....J
0090: 1B 52 1D E1 2E D7 EA 23   37 4C CA 4C A6 8A E6 85  .R.....#7L.L....
00A0: 60 7D 29 63 4F A0 90 37   29 EE CF 0E 0E 05 0E 85  `.)cO..7).......
00B0: 93 47 63 BC 7C CF CE 58   58 71 72 56 76 45 63 0A  .Gc....XXqrVvEc.
00C0: D6 33 BD EF 53 9A 8C F1   19 EE E7 AE 8E 8E 76 A0  .3..S.........v.
00D0: 37 7B BE 45 B5 C8 7B 72   FD 29 8B 80 0B 74 5E 24  7..E...r.)...t^$
00E0: 71 66 3D C9 39 A0 6B 24   B2 91 09 57 9C B7 2D 2E  qf=.9.k$...W..-.
00F0: 82 B8 D7 CA 7A 71 CF 05   2C 97 89 76 DC 3D 2A B8  ....zq..,..v.=*.
0100: 10 A0 8C 27 8D 49 2A 23   C9 8E FB D1 2B 55 00 6D  ...'.I*#....+U.m
0110: 76 CE 2D 86 8A E1 4D B4   1C 9E 8C 47 15 BC 7F DF  v.-...M....G....
0120: 20 23 D1 09 27 A3 DB 9B   7F AC D9 AE D7 72 D3 A3   #..'........r..
0130: E0 20 63 91 1A 49 A6 77   3E B2 EE F0 B1 57 8D 77  . c..I.w>....W.w
0140: 62 11 3C E2 17 28 6F CB   BE 44 14 A3 06 23 89 74  b.<..(o..D...#.t
0150: DE 05 75 DC CB D7 2A 86   3D 9A FA 29 94 00 82 09  ..u...*.=..)....
0160: 3D B1 DE A9 12 F1 48 30   F2 5C 52 10 0D 81 CA 5A  =.....H0.\R....Z
0170: 69 8A 9B F5 3B 7A F4 CB   8A D7 51 AE 5A CD A1 51  i...;z....Q.Z..Q
0180: FA F8 66 AF FC 02 68 2D   E9 CC D7 AF C1 FA 21 84  ..f...h-......!.
0190: 0C 1B 7A 0F DE B9 3D 9A   8A 1A 61 BC 46 01 3A FD  ..z...=...a.F.:.
01A0: 62 E3 79 35 07 66 64 A7   17 83 5E 82 E9 93 A2 FA  b.y5.fd...^.....
01B0: 6F D7 83 38 99 5F 44 69   6C AA F3 32 E4 B4 48 59  o..8._Dil..2..HY
01C0: 50 EC 64 14 72 51 9A E9   95 BC 4E CE EA 98 B3 BD  P.d.rQ....N.....
01D0: 7C F4 BD D2 60 D3 07 7C   71 26 24 55 94 E5 AA D5  ....`...q&$U....
01E0: 44 A1 8D AC 30 AE 47 CA   FF 96 FD CA 9E 03 25 EC  D...0.G.......%.
01F0: 55 5B 97 5B 27 24 A3 23   8F 0D CD 9A DC 52 29 BA  U[.['$.#.....R).

]
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils writePEM
INFO: Wrote /tmp/clientCert-9146518211353882041.cert.pem
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils getMSUPN
INFO: Read X509 SAN [[0, [1.3.6.1.4.1.311.20.2.3, [0]1000@mkk.se]]]
1000@mkk.se
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils writeKeyStore
INFO: Wrote /tmp/clientCert-14620146327205577598.p12
[
[
  Version: V3
  Subject: C=SE, O=MKK, OU=mywebapp, CN=FQDN
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 2048 bits
  params: null
  modulus: 23472554064383360225540326318244541407904103528288156342671235877676704006249990542080185400202587647452428079635384512450814661982177331214162132359638484764547017758245274776079283522876250682767182225000730754889702275736425322221042334223219623764657811814147865593555449798942802445890347917633973214547390327111222760190458870434688746315828193389701570278446761804026480172159526376218012304574882822703261195947214666386714673839238432567588108434506291951836819612851494156727230958145708637864415669786989760083242288799613934351495483902217961576331883073677917645326766725734237025938297058790630425487583
  public exponent: 65537
  Validity: [From: Mon Mar 02 20:35:28 CET 2020,
               To: Tue Mar 02 20:35:28 CET 2021]
  Issuer: C=SE, O=MKK, CN=FOO CA
  SerialNumber: [    01709cbf 02ae]

Certificate Extensions: 8
[1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
  [
   accessMethod: ocsp
   accessLocation: URIName: http://ocsp.mkk.se/
, 
   accessMethod: caIssuers
   accessLocation: URIName: http://pki.mkk.se/ca.crt
]
]

[2]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 13 5B F4 D2 4E 05 F0 73   9D D0 60 C4 42 A3 80 95  .[..N..s..`.B...
0010: 37 7B 9A 1B                                        7...
]
]

[3]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:false
  PathLen: undefined
]

[4]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://crl.mkk.se/ca.crl]
]]

[5]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  serverAuth
]

[6]: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
  DigitalSignature
  Key_Encipherment
]

[7]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: localhost
  DNSName: 127.0.0.1
]

[8]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: C4 54 8A E7 43 33 30 53   AD B5 7F 07 81 57 17 3F  .T..C30S.....W.?
0010: 74 B2 6A 97                                        t.j.
]
]

]
  Algorithm: [SHA256withRSA]
  Signature:
0000: 5D C5 A5 AC 37 CA F7 AE   A8 34 80 C7 17 DF 27 01  ]...7....4....'.
0010: 12 C1 CB 8A 8D 85 77 98   01 EB FD 44 21 63 1F 98  ......w....D!c..
0020: 51 69 67 E8 96 16 AA CF   9C 2A 6A 10 8B 3B F4 60  Qig......*j..;.`
0030: 8D 5C 66 46 6C E4 C4 A8   A0 60 A6 3E 43 35 40 FC  .\fFl....`.>C5@.
0040: 77 5C 9A DA 13 D8 F9 F1   63 35 FD 0F 4B 6C A4 11  w\......c5..Kl..
0050: 5D 67 CF DA 73 9B E0 A0   35 05 6E 37 7A D9 E2 AF  ]g..s...5.n7z...
0060: 10 80 A1 CA F5 5F D4 01   A7 6B 76 92 99 2F 74 25  ....._...kv../t%
0070: A6 27 D2 67 05 07 D9 E6   27 58 E6 90 D1 C0 2D B1  .'.g....'X....-.
0080: 7A 1B F9 5B 91 6E BE DD   AB A8 AA EB B4 BB AE 96  z..[.n..........
0090: 9E 26 A8 CB 31 CE 4B 02   BE EA D4 6A AC B5 E5 FA  .&..1.K....j....
00A0: 43 76 E4 8E C9 16 BF 55   34 E6 D0 A8 FA 1C 6D 48  Cv.....U4.....mH
00B0: C9 54 65 37 84 89 F6 13   C4 FD 0C 62 41 FF 57 5B  .Te7.......bA.W[
00C0: 88 28 35 AF 83 1C D1 A3   8C A4 1F 7F CD E0 F4 F9  .(5.............
00D0: DA 64 C2 C3 51 D7 C5 56   2C 3D 6C A3 C0 B1 40 1B  .d..Q..V,=l...@.
00E0: 2E 42 B5 6F FF 86 2F DB   F2 1F E6 E0 24 A1 CD 7C  .B.o../.....$...
00F0: A6 94 20 95 B8 95 74 05   0B 0E CE 08 43 2E CF FA  .. ...t.....C...
0100: 43 EE 30 3B 40 2C 3E 10   4F BD B2 BC 48 55 07 23  C.0;@,>.O...HU.#
0110: 2B 06 FB F0 E5 76 A2 15   1D E1 8A 33 E6 76 A2 30  +....v.....3.v.0
0120: 6C 07 4C 2A B4 57 C3 62   51 DE 58 1A 5D 82 11 84  l.L*.W.bQ.X.]...
0130: 3F AF EE 17 EC 8B C9 8F   EA F8 6F E4 C1 6A 1F C8  ?.........o..j..
0140: 41 2A 15 62 4C DC 99 37   49 9E 58 1D 95 E1 A6 2E  A*.bL..7I.X.....
0150: AC F4 D3 4F 7F 44 87 B8   18 CD 34 D0 C5 85 9B A6  ...O.D....4.....
0160: C1 46 CD 68 80 84 BE F0   1D F0 E2 B2 2F 0E D3 A6  .F.h......../...
0170: DB 68 89 FD 4A F8 A5 35   AA CB 6A CC FA 45 9E 20  .h..J..5..j..E. 
0180: 9D AA 1D 04 2F 14 8D D0   A4 2B 78 09 9A 23 DA 44  ..../....+x..#.D
0190: 65 76 54 CF D3 7B 7F 37   78 46 18 45 60 98 0D 63  evT....7xF.E`..c
01A0: 2A 7D F8 0D A6 0C 0B 1A   81 61 B8 2B 1F A3 92 E9  *........a.+....
01B0: F2 9C 5B 26 E9 81 50 6F   D9 79 8B 03 54 64 6C EB  ..[&..Po.y..Tdl.
01C0: AA 4A A1 B6 B3 6F 82 C8   20 9D D1 33 D5 D3 87 DA  .J...o.. ..3....
01D0: 5A 3E 93 2A 22 FA BE 0A   A8 1F B6 A4 5C AA E0 73  Z>.*".......\..s
01E0: 17 76 73 33 61 B0 7E ED   09 5E FD DB 4F B7 5A B4  .vs3a....^..O.Z.
01F0: 76 21 1B FA 43 F0 52 AE   78 DC 3B 09 06 66 45 B2  v!..C.R.x.;..fE.

]
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils writePEM
INFO: Wrote /tmp/serverCert-12014046357869706442.crt.pem
[
[
  Version: V3
  Subject: C=SE, O=MKK, CN=FOO CA
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 4096 bits
  params: null
  modulus: 618097494562805236224635134817934912453172250162709722041733040687097334018651185958049454716082071938067246709420916424794899282956550425042006414596550620844500042869814998708415847406596390541333435551567170239109985394967160893875673187989640416587377196814478200867973805718141593244866119267189530684758333327813430426324393329942084968006256517216438373301377640102657162289647735616023682850661875444729876016663906609090034297679982852109216895370934293109110480164998867564217281544316832079056015576106175918287779836237538131308742105170670592053973122534872165219807886684564067083803402486128679568799840125501397600441124322949161232699891631680388114085515962034617420771247637630876469717153740862760325747621475058600558255078199328046206047780514609430807802825141363344880107809474319017977033492293123813011848757820259401796458615662171411629964165721128392643210117405003344910890867964280963490337780332547309122266515542815534797820516503892594199239179401978336582637760762233031975748737882775045900183794816021065220038962704464619646627020923143975929999810020514328195611426571022736233127780297192743641966846131645647190538362059522204380559481497214913394154203383211767929658852311603605904982991909
  public exponent: 65537
  Validity: [From: Mon Mar 02 20:35:28 CET 2020,
               To: Sat Mar 02 20:35:28 CET 2030]
  Issuer: C=SE, O=MKK, CN=FOO CA
  SerialNumber: [    01709cbf 02c1]

Certificate Extensions: 5
[1]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 13 5B F4 D2 4E 05 F0 73   9D D0 60 C4 42 A3 80 95  .[..N..s..`.B...
0010: 37 7B 9A 1B                                        7...
]
]

[2]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen:2147483647
]

[3]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://crl.mkk.se/ca.crl]
]]

[4]: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  DigitalSignature
  Key_CertSign
  Crl_Sign
]

[5]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 13 5B F4 D2 4E 05 F0 73   9D D0 60 C4 42 A3 80 95  .[..N..s..`.B...
0010: 37 7B 9A 1B                                        7...
]
]

]
  Algorithm: [SHA256withRSA]
  Signature:
0000: 6B 5A 8D 8E 93 F0 97 BC   6C 62 DD 1A 65 22 75 10  kZ......lb..e"u.
0010: D1 E3 95 AF BA B8 C1 93   45 C9 44 0A EB 36 93 A8  ........E.D..6..
0020: FD 3C 6F 62 28 FF 59 68   14 8E 7E 45 BB 8E C9 68  .<ob(.Yh...E...h
0030: 0C F3 ED 7F 6D E1 9B FC   D1 22 58 06 FB 6A EF ED  ....m...."X..j..
0040: DC 34 E9 BA CD 7C 69 A9   73 FB F7 C6 7C FD 7A 43  .4....i.s.....zC
0050: 86 68 8A B9 10 F7 36 BC   1E E5 98 99 C4 1A 9D 43  .h....6........C
0060: 31 00 3B 22 38 BB 7E 96   1C 32 E6 8C 67 F4 66 3A  1.;"8....2..g.f:
0070: 37 D9 58 24 18 74 30 40   9C 4B 0C 23 BE 11 4E B1  7.X$.t0@.K.#..N.
0080: 11 4F AD 1D F2 C0 94 1D   B3 B1 A5 CB FE C9 86 5B  .O.............[
0090: 39 80 C9 B1 86 5A 0F 76   C9 4A 54 04 CC 0D 3B E0  9....Z.v.JT...;.
00A0: 94 0F 51 86 8F D8 5E FE   81 21 20 B7 38 9E 91 C4  ..Q...^..! .8...
00B0: FE B3 78 67 80 BF 0E 95   4F C7 E8 48 59 DB CA 43  ..xg....O..HY..C
00C0: E7 69 48 52 C1 78 DA 89   E1 2E 98 63 5E 5A B5 E6  .iHR.x.....c^Z..
00D0: 7B C5 DB D6 B9 35 4E 8A   52 5E 6F 22 EA AD CE 8E  .....5N.R^o"....
00E0: 8C CF BF D3 41 0A 46 35   66 8A C1 E6 53 BE 1C 00  ....A.F5f...S...
00F0: EF 86 FE D7 C6 D9 62 EF   11 AC 44 49 6B 06 4E EC  ......b...DIk.N.
0100: 59 1F 5B 03 D1 CC 63 2F   05 49 1A B4 B0 66 01 55  Y.[...c/.I...f.U
0110: 93 FF 89 CB F1 DA 1E E5   3A 21 E1 81 A5 9D E1 A5  ........:!......
0120: A5 5F 3D AF CF 7C 88 B6   F9 03 EF C8 23 A5 04 3F  ._=.........#..?
0130: F6 CE EE 3A AB A0 A2 7F   0D 33 69 18 E3 A2 22 D8  ...:.....3i...".
0140: 7A 2E 09 1A B2 E5 7A 7C   EA 15 08 92 3D D5 D8 8A  z.....z.....=...
0150: 83 AE 6F CC 4D 30 73 CB   30 A1 0D D1 CC 47 B8 16  ..o.M0s.0....G..
0160: E3 2A 4B 06 32 79 99 4C   1E DD 92 5A 7D CD CB F3  .*K.2y.L...Z....
0170: 00 07 65 86 33 83 06 9C   F9 5C 45 2C F9 F2 E7 36  ..e.3....\E,...6
0180: BB 78 8C 47 32 B6 A6 8B   6F 11 91 73 CF 92 EF B7  .x.G2...o..s....
0190: 60 22 12 48 2F 01 1F 99   81 6C C0 0D 9B 6F 76 00  `".H/....l...ov.
01A0: D3 CD 1D F9 89 F8 F9 F0   83 7D 34 3E F2 6C 08 41  ..........4>.l.A
01B0: F9 EA 1B 8D BC CF 7A 41   7B A0 89 F4 55 8E 09 94  ......zA....U...
01C0: AC FC 50 4B 99 E6 BA 21   04 CF 33 BD B5 2F B7 B0  ..PK...!..3../..
01D0: 06 38 59 89 8C 04 E8 4D   C0 A4 D1 13 DD 47 25 4A  .8Y....M.....G%J
01E0: 02 CE AC CA BE 75 C3 4A   30 A7 9C 84 0A 7E 1D 59  .....u.J0......Y
01F0: BA 2A AA 6C 58 C7 0C 7B   BA 60 60 B3 77 E2 72 AE  .*.lX....``.w.r.

]
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils writePEM
INFO: Wrote /tmp/caCert-12617038054227389688.crt.pem