Example usage for org.bouncycastle.asn1.x509 GeneralNames GeneralNames

List of usage examples for org.bouncycastle.asn1.x509 GeneralNames GeneralNames

Introduction

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

Prototype

private GeneralNames(ASN1Sequence seq) 

Source Link

Usage

From source file:org.cesecore.util.CertToolsTest.java

License:Open Source License

/**
 * Tests the following methods://from w  w w. ja v  a 2 s  . c  o m
 * <ul>
 * <li>{@link CertTools.checkNameConstraints}</li>
 * <li>{@link NameConstraint.parseNameConstraintsList}</li>
 * <li>{@link NameConstraint.toGeneralSubtrees}</li>
 * </ul>
 */
@Test
public void testNameConstraints() throws Exception {
    final String permitted = "C=SE,CN=example.com\n" + "example.com\n" + "@mail.example\n" + "user@host.com\n"
            + "10.0.0.0/8\n" + "   C=SE,  CN=spacing    \n";
    final String excluded = "forbidden.example.com\n" + "postmaster@mail.example\n" + "10.1.0.0/16\n" + "::/0"; // IPv6

    final List<Extension> extensions = new ArrayList<Extension>();
    GeneralSubtree[] permittedSubtrees = NameConstraint
            .toGeneralSubtrees(NameConstraint.parseNameConstraintsList(permitted));
    GeneralSubtree[] excludedSubtrees = NameConstraint
            .toGeneralSubtrees(NameConstraint.parseNameConstraintsList(excluded));
    byte[] extdata = new NameConstraints(permittedSubtrees, excludedSubtrees).toASN1Primitive().getEncoded();
    extensions.add(new Extension(Extension.nameConstraints, false, extdata));

    final KeyPair testkeys = KeyTools.genKeys("512", AlgorithmConstants.KEYALGORITHM_RSA);
    X509Certificate cacert = CertTools.genSelfCertForPurpose("C=SE,CN=Test Name Constraints CA", 365, null,
            testkeys.getPrivate(), testkeys.getPublic(), AlgorithmConstants.SIGALG_SHA1_WITH_RSA, true,
            X509KeyUsage.keyCertSign + X509KeyUsage.cRLSign, null, null, "BC", true, extensions);

    // Allowed subject DNs
    final X500Name validDN = new X500Name("C=SE,CN=example.com"); // re-used below
    CertTools.checkNameConstraints(cacert, validDN, null);
    CertTools.checkNameConstraints(cacert, new X500Name("C=SE,CN=spacing"), null);

    // Allowed subject alternative names
    CertTools.checkNameConstraints(cacert, validDN,
            new GeneralNames(new GeneralName(GeneralName.dNSName, "example.com")));
    CertTools.checkNameConstraints(cacert, validDN,
            new GeneralNames(new GeneralName(GeneralName.dNSName, "x.sub.example.com")));
    CertTools.checkNameConstraints(cacert, validDN,
            new GeneralNames(new GeneralName(GeneralName.rfc822Name, "someuser@mail.example")));
    CertTools.checkNameConstraints(cacert, validDN,
            new GeneralNames(new GeneralName(GeneralName.rfc822Name, "user@host.com")));
    CertTools.checkNameConstraints(cacert, validDN, new GeneralNames(new GeneralName(GeneralName.iPAddress,
            new DEROctetString(InetAddress.getByName("10.0.0.1").getAddress()))));
    CertTools.checkNameConstraints(cacert, validDN, new GeneralNames(new GeneralName(GeneralName.iPAddress,
            new DEROctetString(InetAddress.getByName("10.255.255.255").getAddress()))));

    // Disallowed subject DN
    checkNCException(cacert, new X500Name("C=DK,CN=example.com"), null,
            "Disallowed DN (wrong field value) was accepted");
    checkNCException(cacert, new X500Name("C=SE,O=Company,CN=example.com"), null,
            "Disallowed DN (extra field) was accepted");

    // Disallowed SAN
    // The commented out lines are allowed by BouncyCastle but disallowed by the RFC
    checkNCException(cacert, validDN, new GeneralName(GeneralName.dNSName, "bad.com"),
            "Disallowed SAN (wrong DNS name) was accepted");
    checkNCException(cacert, validDN, new GeneralName(GeneralName.dNSName, "forbidden.example.com"),
            "Disallowed SAN (excluded DNS subdomain) was accepted");
    checkNCException(cacert, validDN, new GeneralName(GeneralName.rfc822Name, "wronguser@host.com"),
            "Disallowed SAN (wrong e-mail) was accepted");
    checkNCException(cacert, validDN,
            new GeneralName(GeneralName.iPAddress,
                    new DEROctetString(InetAddress.getByName("10.1.0.1").getAddress())),
            "Disallowed SAN (excluded IPv4 address) was accepted");
    checkNCException(cacert, validDN,
            new GeneralName(GeneralName.iPAddress,
                    new DEROctetString(InetAddress.getByName("192.0.2.1").getAddress())),
            "Disallowed SAN (wrong IPv4 address) was accepted");
    checkNCException(cacert, validDN,
            new GeneralName(GeneralName.iPAddress,
                    new DEROctetString(InetAddress.getByName("2001:DB8::").getAddress())),
            "Disallowed SAN (IPv6 address) was accepted");
}

From source file:org.cesecore.util.CertToolsTest.java

License:Open Source License

private void checkNCException(X509Certificate cacert, X500Name subjectDNName, GeneralName subjectAltName,
        String message) {//from w w w  . ja  v a 2s  .c  om
    try {
        CertTools.checkNameConstraints(cacert, subjectDNName, new GeneralNames(subjectAltName));
        fail(message);
    } catch (IllegalNameException e) {
        /* NOPMD expected */ }
}

From source file:org.conscrypt.java.security.TestKeyStore.java

License:Apache License

private static X509Certificate createCertificate(PublicKey publicKey, PrivateKey privateKey,
        X500Principal subject, X500Principal issuer, int keyUsage, boolean ca,
        List<KeyPurposeId> extendedKeyUsages, List<Boolean> criticalExtendedKeyUsages,
        List<GeneralName> subjectAltNames, List<GeneralSubtree> permittedNameConstraints,
        List<GeneralSubtree> excludedNameConstraints, BigInteger serialNumber) throws Exception {
    // Note that there is no way to programmatically make a
    // Certificate using java.* or javax.* APIs. The
    // CertificateFactory interface assumes you want to read
    // in a stream of bytes, typically the X.509 factory would
    // allow ASN.1 DER encoded bytes and optionally some PEM
    // formats. Here we use Bouncy Castle's
    // X509V3CertificateGenerator and related classes.

    long millisPerDay = 24 * 60 * 60 * 1000;
    long now = System.currentTimeMillis();
    Date start = new Date(now - millisPerDay);
    Date end = new Date(now + millisPerDay);

    String keyAlgorithm = privateKey.getAlgorithm();
    String signatureAlgorithm;//w  ww .j  a  v a  2 s . c om
    if (keyAlgorithm.equals("RSA")) {
        signatureAlgorithm = "sha256WithRSA";
    } else if (keyAlgorithm.equals("DSA")) {
        signatureAlgorithm = "sha256WithDSA";
    } else if (keyAlgorithm.equals("EC")) {
        signatureAlgorithm = "sha256WithECDSA";
    } else if (keyAlgorithm.equals("EC_RSA")) {
        signatureAlgorithm = "sha256WithRSA";
    } else {
        throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm);
    }

    if (serialNumber == null) {
        byte[] serialBytes = new byte[16];
        new SecureRandom().nextBytes(serialBytes);
        serialNumber = new BigInteger(1, serialBytes);
    }

    X509v3CertificateBuilder x509cg = new X509v3CertificateBuilder(X500Name.getInstance(issuer.getEncoded()),
            serialNumber, start, end, X500Name.getInstance(subject.getEncoded()),
            SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
    if (keyUsage != 0) {
        x509cg.addExtension(Extension.keyUsage, true, new KeyUsage(keyUsage));
    }
    if (ca) {
        x509cg.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
    }
    for (int i = 0; i < extendedKeyUsages.size(); i++) {
        KeyPurposeId keyPurposeId = extendedKeyUsages.get(i);
        boolean critical = criticalExtendedKeyUsages.get(i);
        x509cg.addExtension(Extension.extendedKeyUsage, critical, new ExtendedKeyUsage(keyPurposeId));
    }
    if (!subjectAltNames.isEmpty()) {
        x509cg.addExtension(Extension.subjectAlternativeName, false,
                new GeneralNames(subjectAltNames.toArray(new GeneralName[0])).getEncoded());
    }
    if (!permittedNameConstraints.isEmpty() || !excludedNameConstraints.isEmpty()) {
        x509cg.addExtension(Extension.nameConstraints, true,
                new NameConstraints(
                        permittedNameConstraints.toArray(new GeneralSubtree[permittedNameConstraints.size()]),
                        excludedNameConstraints.toArray(new GeneralSubtree[excludedNameConstraints.size()])));
    }

    X509CertificateHolder x509holder = x509cg
            .build(new JcaContentSignerBuilder(signatureAlgorithm).build(privateKey));
    CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
    X509Certificate x509c = (X509Certificate) certFactory
            .generateCertificate(new ByteArrayInputStream(x509holder.getEncoded()));
    if (StandardNames.IS_RI) {
        /*
         * The RI can't handle the BC EC signature algorithm
         * string of "ECDSA", since it expects "...WITHEC...",
         * so convert from BC to RI X509Certificate
         * implementation via bytes.
         */
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        ByteArrayInputStream bais = new ByteArrayInputStream(x509c.getEncoded());
        Certificate c = cf.generateCertificate(bais);
        x509c = (X509Certificate) c;
    }
    return x509c;
}

From source file:org.cryptable.pki.communication.PKICMPMessagesTest.java

License:Open Source License

/**
 * Check the extensions in the certification request
 *
 * @throws OperatorCreationException//from  ww  w. j  a v a 2 s  . c  o m
 * @throws PKICMPMessageException
 * @throws CertificateEncodingException
 * @throws IOException
 * @throws CRMFException
 * @throws CMPException
 * @throws CMSException
 */
@Test
public void testCertificationWithExtensions()
        throws OperatorCreationException, PKICMPMessageException, CertificateEncodingException, IOException,
        CRMFException, CMPException, CMSException, NoSuchFieldException, IllegalAccessException {
    String distinguishedName = pki.getTestUser1Cert().getSubjectX500Principal().getName();

    KeyPair keyPair = new KeyPair(pki.getTestUser1Cert().getPublicKey(), pki.getTestUser1CertPrivateKey());

    List<Extension> extensionList = new ArrayList<Extension>();
    // KeyUsage
    extensionList.add(new Extension(X509Extension.keyUsage, true,
            new KeyUsage(KeyUsage.digitalSignature | KeyUsage.nonRepudiation).getEncoded()));
    // Extended keyUsage
    List<KeyPurposeId> keyPurposeIds = new ArrayList<KeyPurposeId>();
    keyPurposeIds.add(KeyPurposeId.getInstance(KeyPurposeId.id_kp_clientAuth));
    keyPurposeIds.add(KeyPurposeId.getInstance(KeyPurposeId.id_kp_emailProtection));
    extensionList.add(new Extension(X509Extension.extendedKeyUsage, false,
            new ExtendedKeyUsage(keyPurposeIds.toArray(new KeyPurposeId[keyPurposeIds.size()])).getEncoded()));
    // Subject alternative names
    List<GeneralName> generalNames = new ArrayList<GeneralName>();
    generalNames.add(new GeneralName(GeneralName.dNSName, "www1.cryptable.org"));
    generalNames.add(new GeneralName(GeneralName.dNSName, "www2.cryptable.org"));
    GeneralNames subjectAlternativeName = new GeneralNames(
            generalNames.toArray(new GeneralName[generalNames.size()]));
    extensionList.add(
            new Extension(X509Extension.subjectAlternativeName, false, subjectAlternativeName.getEncoded()));

    PKICMPMessages pkiMessages = new PKICMPMessages();
    pkiMessages.setPkiKeyStore(pkiKeyStoreRA);
    pkiMessages.setExtensions(extensionList.toArray(new Extension[extensionList.size()]));
    byte[] result = pkiMessages.createCertificateMessageWithLocalKey(distinguishedName, keyPair);

    ASN1InputStream asn1InputStream = new ASN1InputStream(result);
    ASN1Primitive asn1Primitive = asn1InputStream.readObject();
    PKIMessage pkiMessage = PKIMessage.getInstance(asn1Primitive);

    CertReqMsg[] certReqMsgs = CertReqMessages.getInstance(pkiMessage.getBody().getContent())
            .toCertReqMsgArray();
    // KeyUsage
    KeyUsage verifyKeyUsage = KeyUsage.getInstance(certReqMsgs[0].getCertReq().getCertTemplate().getExtensions()
            .getExtensionParsedValue(Extension.keyUsage));
    Assert.assertEquals(KeyUsage.digitalSignature | KeyUsage.nonRepudiation,
            verifyKeyUsage.getBytes()[0] & 0xFF);
    // Extended KeyUsage
    ExtendedKeyUsage verifyExtendedKeyUsage = ExtendedKeyUsage
            .fromExtensions(certReqMsgs[0].getCertReq().getCertTemplate().getExtensions());
    Assert.assertTrue(verifyExtendedKeyUsage.hasKeyPurposeId(KeyPurposeId.id_kp_clientAuth));
    Assert.assertTrue(verifyExtendedKeyUsage.hasKeyPurposeId(KeyPurposeId.id_kp_emailProtection));
    // Subject Alternative Name
    GeneralNames verifyGeneralNames = GeneralNames.fromExtensions(
            certReqMsgs[0].getCertReq().getCertTemplate().getExtensions(), Extension.subjectAlternativeName);
    Assert.assertTrue(generalNames.contains(verifyGeneralNames.getNames()[0]));
    Assert.assertTrue(generalNames.contains(verifyGeneralNames.getNames()[1]));
}

From source file:org.cryptacular.x509.ExtensionReaderTest.java

License:Open Source License

@DataProvider(name = "crl-distribution-points")
public Object[][] getCrlDistributionPoints() {
    return new Object[][] {
            new Object[] { CertUtil.readCertificate(CRT_PATH + "login.live.com.crt"),
                    new DistributionPoint[] { new DistributionPoint(
                            new DistributionPointName(
                                    new GeneralNames(uri("http://EVSecure-crl.verisign.com/EVSecure2006.crl"))),
                            null, null), }, },
            new Object[] { CertUtil.readCertificate(CRT_PATH + "glider.cc.vt.edu.crt"),
                    new DistributionPoint[] { new DistributionPoint(new DistributionPointName(
                            new GeneralNames(uri("http://vtca-p.eprov.seti.vt.edu:8080/ejbca/publicweb/"
                                    + "webdist/certdist?cmd=crl&"
                                    + "issuer=CN=Virginia+Tech+Middleware+CA,O=Virginia+"
                                    + "Polytechnic+Institute+and+State+University," + "DC=vt,DC=edu,C=US"))),
                            null,//from w  w  w  .j a va 2  s .c o m
                            new GeneralNames(dirName("CN=Virginia Tech Middleware CA,O=Virginia Polytechnic "
                                    + "Institute and State University,DC=vt,DC=edu,C=US"))), }, }, };
}

From source file:org.demoiselle.signer.policy.impl.cades.pkcs7.attribute.impl.CertificateRefs.java

License:Open Source License

@Override
public Attribute getValue() throws SignerException {

    try {/*ww w . j a  v a 2 s  .c o  m*/
        int chainSize = certificates.length - 1;
        OtherCertID[] arrayOtherCertID = new OtherCertID[chainSize];
        for (int i = 1; i <= chainSize; i++) {
            X509Certificate issuerCert = null;
            X509Certificate cert = (X509Certificate) certificates[i];
            if (i < chainSize) {
                issuerCert = (X509Certificate) certificates[i + 1];
            } else { // raiz
                issuerCert = (X509Certificate) certificates[i];
            }
            Digest digest = DigestFactory.getInstance().factoryDefault();
            digest.setAlgorithm(DigestAlgorithmEnum.SHA_256);
            byte[] certHash = digest.digest(cert.getEncoded());
            X500Name dirName = new X500Name(issuerCert.getSubjectX500Principal().getName());
            GeneralName name = new GeneralName(dirName);
            GeneralNames issuer = new GeneralNames(name);
            ASN1Integer serialNumber = new ASN1Integer(cert.getSerialNumber());
            IssuerSerial issuerSerial = new IssuerSerial(issuer, serialNumber);
            AlgorithmIdentifier algId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256);
            OtherCertID otherCertID = new OtherCertID(algId, certHash, issuerSerial);
            arrayOtherCertID[i - 1] = otherCertID;
        }

        return new Attribute(new ASN1ObjectIdentifier(identifier),
                new DERSet(new ASN1Encodable[] { new DERSequence(arrayOtherCertID) }));
    } catch (CertificateEncodingException e) {
        throw new SignerException(e.getMessage());
    }
}

From source file:org.demoiselle.signer.policy.impl.cades.pkcs7.attribute.impl.SigningCertificate.java

License:Open Source License

@Override
public Attribute getValue() {
    try {/*from  w ww  .ja v  a 2 s . c  o  m*/
        X509Certificate cert = (X509Certificate) certificates[0];
        Digest digest = DigestFactory.getInstance().factoryDefault();
        digest.setAlgorithm(DigestAlgorithmEnum.SHA_1);
        byte[] hash = digest.digest(cert.getEncoded());
        X500Name dirName = new X500Name(cert.getSubjectDN().getName());
        GeneralName name = new GeneralName(dirName);
        GeneralNames issuer = new GeneralNames(name);
        ASN1Integer serial = new ASN1Integer(cert.getSerialNumber());
        IssuerSerial issuerSerial = new IssuerSerial(issuer, serial);
        ESSCertID essCertId = new ESSCertID(hash, issuerSerial);
        return new Attribute(new ASN1ObjectIdentifier(identifier), new DERSet(new DERSequence(
                new ASN1Encodable[] { new DERSequence(essCertId), new DERSequence(DERNull.INSTANCE) })));

    } catch (CertificateEncodingException ex) {
        throw new SignerException(ex.getMessage());
    }
}

From source file:org.demoiselle.signer.policy.impl.cades.pkcs7.attribute.impl.SigningCertificateV2.java

License:Open Source License

@Override
public Attribute getValue() throws SignerException {
    try {//from  w w  w  . j a v  a2  s .  c  o  m
        X509Certificate cert = (X509Certificate) certificates[0];
        X509Certificate issuerCert = (X509Certificate) certificates[1];
        Digest digest = DigestFactory.getInstance().factoryDefault();
        digest.setAlgorithm(DigestAlgorithmEnum.SHA_256);
        byte[] certHash = digest.digest(cert.getEncoded());
        X500Name dirName = new X500Name(issuerCert.getSubjectX500Principal().getName());
        GeneralName name = new GeneralName(dirName);
        GeneralNames issuer = new GeneralNames(name);
        ASN1Integer serialNumber = new ASN1Integer(cert.getSerialNumber());
        IssuerSerial issuerSerial = new IssuerSerial(issuer, serialNumber);
        AlgorithmIdentifier algId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256);// SHA-256
        ESSCertIDv2 essCertIDv2 = new ESSCertIDv2(algId, certHash, issuerSerial);
        //         return new Attribute(new ASN1ObjectIdentifier(identifier), new DERSet(new DERSequence(essCertIDv2)));
        return new Attribute(new ASN1ObjectIdentifier(identifier),
                new DERSet(new DERSequence(new ASN1Encodable[] { new DERSequence(essCertIDv2) })));
    } catch (CertificateEncodingException ex) {
        throw new SignerException(ex.getMessage());
    }
}

From source file:org.deviceconnect.android.ssl.CertificateAuthority.java

License:MIT License

/**
 * ???? Subject Alternative Names (SANs) ??.
 *
 * @param request ???/*from   w ww. jav  a 2  s  .  c  o  m*/
 * @return SubjectAlternativeNames? {@link GeneralNames} 
 * @throws IOException ?????
 */
private GeneralNames parseSANs(final PKCS10CertificationRequest request) throws IOException {
    List<ASN1Encodable> generalNames = new ArrayList<>();

    CertificationRequestInfo info = request.getCertificationRequestInfo();
    ASN1Set attributes = info.getAttributes();
    for (int i = 0; i < attributes.size(); i++) {
        DEREncodable extensionRequestObj = attributes.getObjectAt(i);
        if (!(extensionRequestObj instanceof DERSequence)) {
            continue;
        }
        DERSequence extensionRequest = (DERSequence) extensionRequestObj;
        if (extensionRequest.size() != 2) {
            continue;
        }
        DEREncodable idObj = extensionRequest.getObjectAt(0);
        DEREncodable contentObj = extensionRequest.getObjectAt(1);
        if (!(idObj instanceof ASN1ObjectIdentifier && contentObj instanceof DERSet)) {
            continue;
        }
        ASN1ObjectIdentifier id = (ASN1ObjectIdentifier) idObj;
        DERSet content = (DERSet) contentObj;
        if (!id.getId().equals("1.2.840.113549.1.9.14")) {
            continue;
        }
        if (content.size() < 1) {
            continue;
        }
        DEREncodable extensionsObj = content.getObjectAt(0);
        if (!(extensionsObj instanceof DERSequence)) {
            continue;
        }
        DERSequence extensions = (DERSequence) extensionsObj;

        for (int k = 0; k < extensions.size(); k++) {
            DEREncodable extensionObj = extensions.getObjectAt(k);
            if (!(extensionObj instanceof DERSequence)) {
                continue;
            }
            DERSequence extension = (DERSequence) extensionObj;
            if (extension.size() != 2) {
                continue;
            }
            DEREncodable extensionIdObj = extension.getObjectAt(0);
            DEREncodable extensionContentObj = extension.getObjectAt(1);
            if (!(extensionIdObj instanceof ASN1ObjectIdentifier)) {
                continue;
            }
            ASN1ObjectIdentifier extensionId = (ASN1ObjectIdentifier) extensionIdObj;
            if (extensionId.getId().equals("2.5.29.17")) {
                DEROctetString san = (DEROctetString) extensionContentObj;

                ASN1StreamParser sanParser = new ASN1StreamParser(san.parser().getOctetStream());
                DEREncodable namesObj = sanParser.readObject().getDERObject();
                if (namesObj instanceof DERSequence) {
                    DERSequence names = (DERSequence) namesObj;
                    for (int m = 0; m < names.size(); m++) {
                        DEREncodable nameObj = names.getObjectAt(m);
                        if (nameObj instanceof DERTaggedObject) {
                            DERTaggedObject name = (DERTaggedObject) nameObj;
                            switch (name.getTagNo()) {
                            case GeneralName.dNSName:
                                generalNames.add(new GeneralName(GeneralName.dNSName,
                                        DERIA5String.getInstance(name, false)));
                                break;
                            case GeneralName.iPAddress:
                                generalNames.add(new GeneralName(GeneralName.iPAddress,
                                        DEROctetString.getInstance(name, true)));
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
    if (generalNames.size() > 0) {
        return new GeneralNames(new DERSequence(generalNames.toArray(new ASN1Encodable[generalNames.size()])));
    }
    return null;
}

From source file:org.deviceconnect.android.ssl.EndPointKeyStoreManager.java

License:MIT License

@Override
public void requestKeyStore(final String ipAddress, final KeyStoreCallback callback) {
    mExecutor.execute(new Runnable() {
        @Override//  w w  w . j  ava  2s .  c o  m
        public void run() {
            if (BuildConfig.DEBUG) {
                mLogger.info("Requested keystore: alias = " + getAlias() + ", IP Address = " + ipAddress);
            }
            try {
                String alias = getAlias();
                if (hasIPAddress(ipAddress)) {
                    if (BuildConfig.DEBUG) {
                        mLogger.info("Certificate is cached for alias: " + alias);
                    }
                    Certificate[] chain = mKeyStore.getCertificateChain(getAlias());
                    callback.onSuccess(mKeyStore, chain[0], chain[1]);
                } else {
                    if (BuildConfig.DEBUG) {
                        mLogger.info("Generating key pair...");
                    }
                    final KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
                    final KeyPair keyPair = keyGenerator.generateKeyPair();

                    if (BuildConfig.DEBUG) {
                        mLogger.info("Generated key pair.");
                        mLogger.info("Executing certificate request...");
                    }

                    final CertificateAuthorityClient localCA = new CertificateAuthorityClient(mContext,
                            mRootCA);

                    final List<ASN1Encodable> names = new ArrayList<>();
                    names.add(new GeneralName(GeneralName.iPAddress, ipAddress));
                    for (SAN cache : mSANs) {
                        if (!cache.mName.equals(ipAddress)) {
                            names.add(new GeneralName(cache.mTagNo, cache.mName));
                        }
                    }
                    names.add(new GeneralName(GeneralName.iPAddress, "0.0.0.0"));
                    names.add(new GeneralName(GeneralName.iPAddress, "127.0.0.1"));
                    names.add(new GeneralName(GeneralName.dNSName, "localhost"));
                    GeneralNames generalNames = new GeneralNames(
                            new DERSequence(names.toArray(new ASN1Encodable[names.size()])));

                    localCA.executeCertificateRequest(createCSR(keyPair, "localhost", generalNames),
                            new CertificateRequestCallback() {
                                @Override
                                public void onCreate(final Certificate cert, final Certificate rootCert) {
                                    if (BuildConfig.DEBUG) {
                                        mLogger.info("Generated server certificate");
                                    }

                                    try {
                                        Certificate[] chain = { cert, rootCert };
                                        setCertificate(chain, keyPair.getPrivate());
                                        saveKeyStore();
                                        if (BuildConfig.DEBUG) {
                                            mLogger.info("Saved server certificate");
                                        }
                                        mSANs.add(new SAN(GeneralName.iPAddress, ipAddress));
                                        callback.onSuccess(mKeyStore, cert, rootCert);
                                    } catch (Exception e) {
                                        mLogger.log(Level.SEVERE, "Failed to save server certificate", e);
                                        callback.onError(KeyStoreError.FAILED_BACKUP_KEYSTORE);
                                    } finally {
                                        localCA.dispose();
                                    }
                                }

                                @Override
                                public void onError() {
                                    mLogger.severe("Failed to generate server certificate");

                                    localCA.dispose();
                                    callback.onError(KeyStoreError.FAILED_BACKUP_KEYSTORE);
                                }
                            });
                }
            } catch (KeyStoreException e) {
                callback.onError(KeyStoreError.BROKEN_KEYSTORE);
            } catch (GeneralSecurityException e) {
                callback.onError(KeyStoreError.UNSUPPORTED_CERTIFICATE_FORMAT);
            }
        }
    });
}