Example usage for org.bouncycastle.asn1.x509 Extension basicConstraints

List of usage examples for org.bouncycastle.asn1.x509 Extension basicConstraints

Introduction

In this page you can find the example usage for org.bouncycastle.asn1.x509 Extension basicConstraints.

Prototype

ASN1ObjectIdentifier basicConstraints

To view the source code for org.bouncycastle.asn1.x509 Extension basicConstraints.

Click Source Link

Document

Basic Constraints

Usage

From source file:net.maritimecloud.pki.CertificateBuilder.java

License:Apache License

/**
 * Builds and signs a certificate. The certificate will be build on the given subject-public-key and signed with
 * the given issuer-private-key. The issuer and subject will be identified in the strings provided.
 *
 * @param serialNumber The serialnumber of the new certificate.
 * @param signerPrivateKey Private key for signing the certificate
 * @param signerPublicKey Public key of the signing certificate
 * @param subjectPublicKey Public key for the new certificate
 * @param issuer DN of the signing certificate
 * @param subject DN of the new certificate
 * @param customAttrs The custom MC attributes to include in the certificate
 * @param type Type of certificate, can be "ROOT", "INTERMEDIATE" or "ENTITY".
 * @param ocspUrl OCSP endpoint/*from   w w  w. ja  v a2  s .c o  m*/
 * @param crlUrl CRL endpoint - can be null
 * @return A signed X509Certificate
 * @throws Exception Throws exception on certificate generation errors.
 */
public X509Certificate buildAndSignCert(BigInteger serialNumber, PrivateKey signerPrivateKey,
        PublicKey signerPublicKey, PublicKey subjectPublicKey, X500Name issuer, X500Name subject,
        Map<String, String> customAttrs, String type, String ocspUrl, String crlUrl) throws Exception {
    // Dates are converted to GMT/UTC inside the cert builder
    Calendar cal = Calendar.getInstance();
    Date now = cal.getTime();
    Date expire = new GregorianCalendar(CERT_EXPIRE_YEAR, 0, 1).getTime();
    X509v3CertificateBuilder certV3Bldr = new JcaX509v3CertificateBuilder(issuer, serialNumber, now, // Valid from now...
            expire, // until CERT_EXPIRE_YEAR
            subject, subjectPublicKey);
    JcaX509ExtensionUtils extensionUtil = new JcaX509ExtensionUtils();
    // Create certificate extensions
    if ("ROOTCA".equals(type)) {
        certV3Bldr = certV3Bldr.addExtension(Extension.basicConstraints, true, new BasicConstraints(true))
                .addExtension(Extension.keyUsage, true,
                        new X509KeyUsage(X509KeyUsage.digitalSignature | X509KeyUsage.nonRepudiation
                                | X509KeyUsage.keyEncipherment | X509KeyUsage.keyCertSign
                                | X509KeyUsage.cRLSign));
    } else if ("INTERMEDIATE".equals(type)) {
        certV3Bldr = certV3Bldr.addExtension(Extension.basicConstraints, true, new BasicConstraints(true))
                .addExtension(Extension.keyUsage, true,
                        new X509KeyUsage(X509KeyUsage.digitalSignature | X509KeyUsage.nonRepudiation
                                | X509KeyUsage.keyEncipherment | X509KeyUsage.keyCertSign
                                | X509KeyUsage.cRLSign));
    } else {
        // Subject Alternative Name
        GeneralName[] genNames = null;
        if (customAttrs != null && !customAttrs.isEmpty()) {
            genNames = new GeneralName[customAttrs.size()];
            Iterator<Map.Entry<String, String>> it = customAttrs.entrySet().iterator();
            int idx = 0;
            while (it.hasNext()) {
                Map.Entry<String, String> pair = it.next();
                if (PKIConstants.X509_SAN_DNSNAME.equals(pair.getKey())) {
                    genNames[idx] = new GeneralName(GeneralName.dNSName, pair.getValue());
                } else {
                    //genNames[idx] = new GeneralName(GeneralName.otherName, new DERUTF8String(pair.getKey() + ";" + pair.getValue()));
                    DERSequence othernameSequence = new DERSequence(
                            new ASN1Encodable[] { new ASN1ObjectIdentifier(pair.getKey()),
                                    new DERTaggedObject(true, 0, new DERUTF8String(pair.getValue())) });
                    genNames[idx] = new GeneralName(GeneralName.otherName, othernameSequence);
                }
                idx++;
            }
        }
        if (genNames != null) {
            certV3Bldr = certV3Bldr.addExtension(Extension.subjectAlternativeName, false,
                    new GeneralNames(genNames));
        }
    }
    // Basic extension setup
    certV3Bldr = certV3Bldr
            .addExtension(Extension.authorityKeyIdentifier, false,
                    extensionUtil.createAuthorityKeyIdentifier(signerPublicKey))
            .addExtension(Extension.subjectKeyIdentifier, false,
                    extensionUtil.createSubjectKeyIdentifier(subjectPublicKey));
    // CRL Distribution Points
    DistributionPointName distPointOne = new DistributionPointName(
            new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, crlUrl)));
    DistributionPoint[] distPoints = new DistributionPoint[1];
    distPoints[0] = new DistributionPoint(distPointOne, null, null);
    certV3Bldr.addExtension(Extension.cRLDistributionPoints, false, new CRLDistPoint(distPoints));
    // OCSP endpoint - is not available for the CAs
    if (ocspUrl != null) {
        GeneralName ocspName = new GeneralName(GeneralName.uniformResourceIdentifier, ocspUrl);
        AuthorityInformationAccess authorityInformationAccess = new AuthorityInformationAccess(
                X509ObjectIdentifiers.ocspAccessMethod, ocspName);
        certV3Bldr.addExtension(Extension.authorityInfoAccess, false, authorityInformationAccess);
    }
    // Create the key signer
    JcaContentSignerBuilder builder = new JcaContentSignerBuilder(SIGNER_ALGORITHM);
    builder.setProvider(BC_PROVIDER_NAME);
    ContentSigner signer = builder.build(signerPrivateKey);
    return new JcaX509CertificateConverter().setProvider(BC_PROVIDER_NAME)
            .getCertificate(certV3Bldr.build(signer));
}

From source file:net.ripe.rpki.commons.provisioning.x509.pkcs10.RpkiCaCertificateRequestBuilder.java

License:BSD License

private Extensions createExtensions() throws IOException {
    // Make extension for SIA in request. See here:
    // http://www.bouncycastle.org/wiki/display/JA1/X.509+Public+Key+Certificate+and+Certification+Request+Generation
    List<Extension> extensions = new ArrayList<Extension>();

    X509CertificateInformationAccessDescriptor[] descriptors = new X509CertificateInformationAccessDescriptor[] {
            new X509CertificateInformationAccessDescriptor(
                    X509CertificateInformationAccessDescriptor.ID_AD_CA_REPOSITORY, caRepositoryUri),
            new X509CertificateInformationAccessDescriptor(
                    X509CertificateInformationAccessDescriptor.ID_AD_RPKI_MANIFEST, manifestUri), };
    AccessDescription[] subjectInformationAccess = X509CertificateInformationAccessDescriptor
            .convertAccessDescriptors(descriptors);
    DERSequence derSequence = new DERSequence(subjectInformationAccess);

    extensions.add(//from  w  w  w  .  j  a  v a 2s.  co  m
            new Extension(Extension.subjectInfoAccess, false, new DEROctetString(derSequence.getEncoded())));
    KeyUsage keyUsage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign);
    extensions.add(new Extension(Extension.keyUsage, true, new DEROctetString(keyUsage)));

    extensions.add(
            new Extension(Extension.basicConstraints, true, new DEROctetString(new BasicConstraints(true))));

    return new Extensions(extensions.toArray(new Extension[extensions.size()]));
}

From source file:net.sf.portecle.crypto.X509Ext.java

License:Open Source License

/**
 * Get extension value as a string./*from w w  w.j av a 2  s .co m*/
 * 
 * @return Extension value as a string
 * @throws IOException If an I/O problem occurs
 * @throws ParseException If a date formatting problem occurs
 */
public String getStringValue() throws IOException, ParseException {
    // Get octet string from extension
    byte[] bOctets = ((ASN1OctetString) ASN1Primitive.fromByteArray(m_bValue)).getOctets();

    // Octet string processed differently depending on extension type
    if (m_Oid.equals(X509ObjectIdentifiers.commonName)) {
        return getCommonNameStringValue(bOctets);
    } else if (m_Oid.equals(Extension.subjectKeyIdentifier)) {
        return getSubjectKeyIdentifierStringValue(bOctets);
    } else if (m_Oid.equals(Extension.keyUsage)) {
        return getKeyUsageStringValue(bOctets);
    } else if (m_Oid.equals(Extension.privateKeyUsagePeriod)) {
        return getPrivateKeyUsagePeriod(bOctets);
    } else if (m_Oid.equals(Extension.issuerAlternativeName)
            || m_Oid.equals(Extension.subjectAlternativeName)) {
        return getAlternativeName(bOctets);
    } else if (m_Oid.equals(Extension.basicConstraints)) {
        return getBasicConstraintsStringValue(bOctets);
    } else if (m_Oid.equals(Extension.cRLNumber)) {
        return getCrlNumberStringValue(bOctets);
    } else if (m_Oid.equals(Extension.reasonCode)) {
        return getReasonCodeStringValue(bOctets);
    } else if (m_Oid.equals(Extension.instructionCode)) {
        return getHoldInstructionCodeStringValue(bOctets);
    } else if (m_Oid.equals(Extension.invalidityDate)) {
        return getInvalidityDateStringValue(bOctets);
    } else if (m_Oid.equals(Extension.deltaCRLIndicator)) {
        return getDeltaCrlIndicatorStringValue(bOctets);
    } else if (m_Oid.equals(Extension.certificateIssuer)) {
        return getCertificateIssuerStringValue(bOctets);
    } else if (m_Oid.equals(Extension.policyMappings)) {
        return getPolicyMappingsStringValue(bOctets);
    } else if (m_Oid.equals(Extension.authorityKeyIdentifier)) {
        return getAuthorityKeyIdentifierStringValue(bOctets);
    } else if (m_Oid.equals(Extension.policyConstraints)) {
        return getPolicyConstraintsStringValue(bOctets);
    } else if (m_Oid.equals(Extension.extendedKeyUsage)) {
        return getExtendedKeyUsageStringValue(bOctets);
    } else if (m_Oid.equals(Extension.inhibitAnyPolicy)) {
        return getInhibitAnyPolicyStringValue(bOctets);
    } else if (m_Oid.equals(MiscObjectIdentifiers.entrustVersionExtension)) {
        return getEntrustVersionExtensionStringValue(bOctets);
    } else if (m_Oid.equals(PKCSObjectIdentifiers.pkcs_9_at_smimeCapabilities)) {
        return getSmimeCapabilitiesStringValue(bOctets);
    } else if (m_Oid.equals(MicrosoftObjectIdentifiers.microsoftCaVersion)) {
        return getMicrosoftCAVersionStringValue(bOctets);
    } else if (m_Oid.equals(MicrosoftObjectIdentifiers.microsoftPrevCaCertHash)) {
        return getMicrosoftPreviousCACertificateHashStringValue(bOctets);
    } else if (m_Oid.equals(MicrosoftObjectIdentifiers.microsoftCertTemplateV2)) {
        return getMicrosoftCertificateTemplateV2StringValue(bOctets);
    } else if (m_Oid.equals(MicrosoftObjectIdentifiers.microsoftAppPolicies)) {
        return getUnknownOidStringValue(bOctets); // TODO
    }
    // TODO: https://github.com/bcgit/bc-java/pull/92
    else if (m_Oid.toString().equals("1.3.6.1.4.1.311.21.4")) {
        return getMicrosoftCrlNextPublish(bOctets);
    } else if (m_Oid.equals(Extension.authorityInfoAccess) || m_Oid.equals(Extension.subjectInfoAccess)) {
        return getInformationAccessStringValue(bOctets);
    } else if (m_Oid.equals(Extension.logoType)) {
        return getLogotypeStringValue(bOctets);
    } else if (m_Oid.equals(MiscObjectIdentifiers.novellSecurityAttribs)) {
        return getNovellSecurityAttributesStringValue(bOctets);
    } else if (m_Oid.equals(MiscObjectIdentifiers.netscapeCertType)) {
        return getNetscapeCertificateTypeStringValue(bOctets);
    } else if (m_Oid.equals(MiscObjectIdentifiers.netscapeSSLServerName)
            || m_Oid.equals(MiscObjectIdentifiers.netscapeCertComment)
            || m_Oid.equals(MiscObjectIdentifiers.verisignDnbDunsNumber)
            || m_Oid.equals(MicrosoftObjectIdentifiers.microsoftCertTemplateV1)) {
        return getASN1ObjectString(bOctets);
    } else if (m_Oid.equals(MiscObjectIdentifiers.netscapeCApolicyURL)) {
        return getNetscapeExtensionURLValue(bOctets, LinkClass.BROWSER);
    } else if (m_Oid.equals(MiscObjectIdentifiers.netscapeBaseURL)
            || m_Oid.equals(MiscObjectIdentifiers.netscapeRenewalURL)
            || m_Oid.equals(MiscObjectIdentifiers.netscapeRevocationURL)
            || m_Oid.equals(MiscObjectIdentifiers.netscapeCARevocationURL)) {
        return getNetscapeExtensionURLValue(bOctets, LinkClass.CRL);
    } else if (m_Oid.equals(Extension.cRLDistributionPoints)) {
        return getCrlDistributionPointsStringValue(bOctets);
    } else if (m_Oid.equals(Extension.certificatePolicies)) {
        return getCertificatePoliciesStringValue(bOctets);
    }

    // TODO:
    // - CERTIFICATE_POLICIES_OLD_OID
    // - AUTHORITY_KEY_IDENTIFIER_OLD_OID
    // - BASIC_CONSTRAINTS_OLD_0_OID

    // Don't know how to process the extension
    // and clear text
    else {
        return getUnknownOidStringValue(bOctets);
    }
}

From source file:net.sf.sahi.ssl.SSLHelper.java

License:Apache License

private X509Certificate buildRootCert(String domain, KeyPair _keyPair) throws Exception {
    X509v3CertificateBuilder certificateBuilder = createX509v3CertificateBuilder(domain, _keyPair);
    certificateBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
    return createX509Certificate(certificateBuilder, _keyPair.getPrivate());
}

From source file:org.apache.accumulo.test.util.CertUtils.java

License:Apache License

private X509CertificateObject generateCert(String keyName, KeyPair kp, boolean isCertAuthority,
        PublicKey signerPublicKey, PrivateKey signerPrivateKey) throws IOException, CertIOException,
        OperatorCreationException, CertificateException, NoSuchAlgorithmException {
    Calendar startDate = Calendar.getInstance();
    Calendar endDate = Calendar.getInstance();
    endDate.add(Calendar.YEAR, 100);

    BigInteger serialNumber = BigInteger.valueOf((startDate.getTimeInMillis()));
    X500Name issuer = new X500Name(IETFUtils.rDNsFromString(issuerDirString, RFC4519Style.INSTANCE));
    JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(issuer, serialNumber,
            startDate.getTime(), endDate.getTime(), issuer, kp.getPublic());
    JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
    certGen.addExtension(Extension.subjectKeyIdentifier, false,
            extensionUtils.createSubjectKeyIdentifier(kp.getPublic()));
    certGen.addExtension(Extension.basicConstraints, false, new BasicConstraints(isCertAuthority));
    certGen.addExtension(Extension.authorityKeyIdentifier, false,
            extensionUtils.createAuthorityKeyIdentifier(signerPublicKey));
    if (isCertAuthority) {
        certGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));
    }//from   w w  w  . jav  a 2 s.  c o m
    X509CertificateHolder cert = certGen
            .build(new JcaContentSignerBuilder(signingAlgorithm).build(signerPrivateKey));
    return new X509CertificateObject(cert.toASN1Structure());
}

From source file:org.apache.ace.authentication.processor.clientcert.MemoryKeyStore.java

License:Apache License

private X509Certificate generateRootCertificate(String commonName, Date notBefore, Date notAfter)
        throws Exception {
    X500Name issuer = new X500Name(commonName);
    BigInteger serial = BigInteger.probablePrime(16, new Random());

    SubjectPublicKeyInfo pubKeyInfo = convertToSubjectPublicKeyInfo(m_caKey.getPublic());

    X509v3CertificateBuilder builder = new X509v3CertificateBuilder(issuer, serial, notBefore, notAfter, issuer,
            pubKeyInfo);/*from  w  ww .j  ava 2 s .  c o m*/
    builder.addExtension(
            new Extension(Extension.basicConstraints, true, new DEROctetString(new BasicConstraints(true))));

    X509CertificateHolder certHolder = builder
            .build(new JcaContentSignerBuilder(SIGNATURE_ALGORITHM).build(m_caKey.getPrivate()));
    return new JcaX509CertificateConverter().getCertificate(certHolder);
}

From source file:org.apache.cloudstack.utils.security.CertUtils.java

License:Apache License

public static X509Certificate generateV3Certificate(final X509Certificate caCert, final KeyPair caKeyPair,
        final PublicKey clientPublicKey, final String subject, final String signatureAlgorithm,
        final int validityDays, final List<String> dnsNames, final List<String> publicIPAddresses)
        throws IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException,
        InvalidKeyException, SignatureException, OperatorCreationException {

    final DateTime now = DateTime.now(DateTimeZone.UTC);
    final BigInteger serial = generateRandomBigInt();
    final JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
    final X509v3CertificateBuilder certBuilder;
    if (caCert == null) {
        // Generate CA certificate
        certBuilder = new JcaX509v3CertificateBuilder(new X500Name(subject), serial,
                now.minusHours(12).toDate(), now.plusDays(validityDays).toDate(), new X500Name(subject),
                clientPublicKey);/*  ww  w.  j a  v a 2s . co  m*/

        certBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
        certBuilder.addExtension(Extension.keyUsage, true,
                new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign));
    } else {
        // Generate client certificate
        certBuilder = new JcaX509v3CertificateBuilder(caCert, serial, now.minusHours(12).toDate(),
                now.plusDays(validityDays).toDate(), new X500Principal(subject), clientPublicKey);

        certBuilder.addExtension(Extension.authorityKeyIdentifier, false,
                extUtils.createAuthorityKeyIdentifier(caCert));
    }

    certBuilder.addExtension(Extension.subjectKeyIdentifier, false,
            extUtils.createSubjectKeyIdentifier(clientPublicKey));

    final List<ASN1Encodable> subjectAlternativeNames = new ArrayList<ASN1Encodable>();
    if (publicIPAddresses != null) {
        for (final String publicIPAddress : publicIPAddresses) {
            if (Strings.isNullOrEmpty(publicIPAddress)) {
                continue;
            }
            subjectAlternativeNames.add(new GeneralName(GeneralName.iPAddress, publicIPAddress));
        }
    }
    if (dnsNames != null) {
        for (final String dnsName : dnsNames) {
            if (Strings.isNullOrEmpty(dnsName)) {
                continue;
            }
            subjectAlternativeNames.add(new GeneralName(GeneralName.dNSName, dnsName));
        }
    }
    if (subjectAlternativeNames.size() > 0) {
        final GeneralNames subjectAltNames = GeneralNames
                .getInstance(new DERSequence(subjectAlternativeNames.toArray(new ASN1Encodable[] {})));
        certBuilder.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);
    }

    final ContentSigner signer = new JcaContentSignerBuilder(signatureAlgorithm).setProvider("BC")
            .build(caKeyPair.getPrivate());
    final X509CertificateHolder certHolder = certBuilder.build(signer);
    final X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
    if (caCert != null) {
        cert.verify(caCert.getPublicKey());
    } else {
        cert.verify(caKeyPair.getPublic());
    }
    return cert;
}

From source file:org.apache.felix.deploymentadmin.itest.util.CertificateUtil.java

License:Apache License

private static X509Certificate createSelfSignedCert(String commonName, KeyPair keypair) throws Exception {
    PublicKey publicKey = keypair.getPublic();
    String keyAlg = DPSigner.getSignatureAlgorithm(publicKey);

    X500Name issuer = new X500Name(commonName);
    BigInteger serial = BigInteger.probablePrime(16, new Random());
    Date notBefore = new Date(System.currentTimeMillis() - 1000);
    Date notAfter = new Date(notBefore.getTime() + 6000);

    SubjectPublicKeyInfo pubKeyInfo;//from  www  .  j a  v a  2s . c om
    try (ASN1InputStream is = new ASN1InputStream(publicKey.getEncoded())) {
        pubKeyInfo = SubjectPublicKeyInfo.getInstance(is.readObject());
    }

    X509v3CertificateBuilder builder = new X509v3CertificateBuilder(issuer, serial, notBefore, notAfter, issuer,
            pubKeyInfo);
    builder.addExtension(
            new Extension(Extension.basicConstraints, true, new DEROctetString(new BasicConstraints(false))));

    X509CertificateHolder certHolder = builder
            .build(new JcaContentSignerBuilder(keyAlg).build(keypair.getPrivate()));
    return new JcaX509CertificateConverter().getCertificate(certHolder);
}

From source file:org.apache.hadoop.yarn.server.resourcemanager.security.TestingRMAppSecurityActions.java

License:Apache License

@Override
public X509SecurityHandler.CertificateBundle sign(PKCS10CertificationRequest csr)
        throws URISyntaxException, IOException, GeneralSecurityException {
    JcaPKCS10CertificationRequest jcaRequest = new JcaPKCS10CertificationRequest(csr);
    X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(caCert,
            BigInteger.valueOf(System.currentTimeMillis()), new Date(),
            new Date(System.currentTimeMillis() + 50000), csr.getSubject(), jcaRequest.getPublicKey());

    JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
    certBuilder/*from w  w  w . ja  v  a  2  s .c o  m*/
            .addExtension(Extension.authorityKeyIdentifier, false,
                    extensionUtils.createAuthorityKeyIdentifier(caCert))
            .addExtension(Extension.subjectKeyIdentifier, false,
                    extensionUtils.createSubjectKeyIdentifier(jcaRequest.getPublicKey()))
            .addExtension(Extension.basicConstraints, true, new BasicConstraints(false))
            .addExtension(Extension.keyUsage, true,
                    new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
    X509Certificate certificate = new JcaX509CertificateConverter().setProvider("BC")
            .getCertificate(certBuilder.build(sigGen));
    return new X509SecurityHandler.CertificateBundle(certificate, caCert);
}

From source file:org.apache.nifi.registry.security.util.CertificateUtils.java

License:Apache License

/**
 * Generates a self-signed {@link X509Certificate} suitable for use as a Certificate Authority.
 *
 * @param keyPair                 the {@link KeyPair} to generate the {@link X509Certificate} for
 * @param dn                      the distinguished name to user for the {@link X509Certificate}
 * @param signingAlgorithm        the signing algorithm to use for the {@link X509Certificate}
 * @param certificateDurationDays the duration in days for which the {@link X509Certificate} should be valid
 * @return a self-signed {@link X509Certificate} suitable for use as a Certificate Authority
 * @throws CertificateException      if there is an generating the new certificate
 */// ww  w .  ja  va  2s  . c om
public static X509Certificate generateSelfSignedX509Certificate(KeyPair keyPair, String dn,
        String signingAlgorithm, int certificateDurationDays) throws CertificateException {
    try {
        ContentSigner sigGen = new JcaContentSignerBuilder(signingAlgorithm)
                .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(keyPair.getPrivate());
        SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
        Date startDate = new Date();
        Date endDate = new Date(startDate.getTime() + TimeUnit.DAYS.toMillis(certificateDurationDays));

        X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(reverseX500Name(new X500Name(dn)),
                getUniqueSerialNumber(), startDate, endDate, reverseX500Name(new X500Name(dn)), subPubKeyInfo);

        // Set certificate extensions
        // (1) digitalSignature extension
        certBuilder.addExtension(Extension.keyUsage, true,
                new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment
                        | KeyUsage.keyAgreement | KeyUsage.nonRepudiation | KeyUsage.cRLSign
                        | KeyUsage.keyCertSign));

        certBuilder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));

        certBuilder.addExtension(Extension.subjectKeyIdentifier, false,
                new JcaX509ExtensionUtils().createSubjectKeyIdentifier(keyPair.getPublic()));

        certBuilder.addExtension(Extension.authorityKeyIdentifier, false,
                new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(keyPair.getPublic()));

        // (2) extendedKeyUsage extension
        certBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(
                new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth }));

        // Sign the certificate
        X509CertificateHolder certificateHolder = certBuilder.build(sigGen);
        return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME)
                .getCertificate(certificateHolder);
    } catch (CertIOException | NoSuchAlgorithmException | OperatorCreationException e) {
        throw new CertificateException(e);
    }
}