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

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

Introduction

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

Prototype

public Extension(ASN1ObjectIdentifier extnId, boolean critical, ASN1OctetString value) 

Source Link

Document

Constructor using an OCTET STRING for the value.

Usage

From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspHttpTest.java

License:Open Source License

/**
 * This test tests that the OCSP response for a status unknown contains the header "cache-control" with the value "no-cache, must-revalidate"
 * //from w  w w .  j av  a 2s  .c om
 * @throws Exception
 */
@Test
public void testUnknownStatusCacheControlHeader() throws Exception {

    // set ocsp configuration
    Map<String, String> map = new HashMap<String, String>();
    map.put(OcspConfiguration.UNTIL_NEXT_UPDATE, "1");
    this.helper.alterConfig(map);

    OCSPReqBuilder gen = new OCSPReqBuilder();
    gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert, new BigInteger("1")));
    OCSPReq req = gen.build();

    String sBaseURL = httpReqPath + '/' + resourceOcsp;
    String urlEnding = "";
    String b64 = new String(Base64.encode(req.getEncoded(), false));
    //String urls = URLEncoder.encode(b64, "UTF-8");    // JBoss/Tomcat will not accept escaped '/'-characters by default
    URL url = new URL(sBaseURL + '/' + b64 + urlEnding);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    if (con.getResponseCode() != 200) {
        log.info("URL when request gave unexpected result: " + url.toString() + " Message was: "
                + con.getResponseMessage());
    }
    assertEquals("Response code did not match. ", 200, con.getResponseCode());
    assertNotNull(con.getContentType());
    assertTrue(con.getContentType().startsWith("application/ocsp-response"));

    assertNotNull("No Cache-Control in reply.", con.getHeaderField("Cache-Control"));
    assertEquals("no-cache, must-revalidate", con.getHeaderField("Cache-Control"));

    // Create a GET request using Nonce extension, in this case we should have no cache-control header
    gen = new OCSPReqBuilder();
    gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert, new BigInteger("1")));
    Extension[] extensions = new Extension[1];
    extensions[0] = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false,
            new DEROctetString("123456789".getBytes()));
    gen.setRequestExtensions(new Extensions(extensions));
    req = gen.build();
    b64 = new String(Base64.encode(req.getEncoded(), false));
    url = new URL(sBaseURL + '/' + b64 + urlEnding);
    con = (HttpURLConnection) url.openConnection();
    if (con.getResponseCode() != 200) {
        log.info("URL when request gave unexpected result: " + url.toString() + " Message was: "
                + con.getResponseMessage());
    }
    assertEquals("Response code did not match. ", 200, con.getResponseCode());
    assertNotNull(con.getContentType());
    assertTrue(con.getContentType().startsWith("application/ocsp-response"));
    OCSPResp response = new OCSPResp(IOUtils.toByteArray(con.getInputStream()));
    BasicOCSPResp brep = (BasicOCSPResp) response.getResponseObject();
    byte[] noncerep = brep.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce).getExtnValue().getEncoded();
    // Make sure we have a nonce in the response, we should have since we sent one in the request
    assertNotNull("Response should have nonce since we sent a nonce in the request", noncerep);
    ASN1InputStream ain = new ASN1InputStream(noncerep);
    ASN1OctetString oct = ASN1OctetString.getInstance(ain.readObject());
    ain.close();
    assertEquals("Response Nonce was not the same as the request Nonce, it must be", "123456789",
            new String(oct.getOctets()));
    assertNull(
            "Cache-Control in reply although we used Nonce in the request. Responses with Nonce should not have a Cache-control header.",
            con.getHeaderField("Cache-Control"));
}

From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspHttpTest.java

License:Open Source License

/**
 * Generate a simple OCSP Request object
 *//*from w  w  w.j  a v  a 2s  .c om*/
private byte[] getValidOcspRequest() throws Exception {
    // Get user and ocspTestCert that we know...
    loadUserCert(caid);
    // And an OCSP request
    OCSPReqBuilder gen = new OCSPReqBuilder();
    gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert,
            ocspTestCert.getSerialNumber()));
    Extension[] extensions = new Extension[1];
    extensions[0] = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false,
            new DEROctetString("123456789".getBytes()));
    gen.setRequestExtensions(new Extensions(extensions));
    OCSPReq req = gen.build();
    return req.getEncoded();
}

From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspSignedHttpTest.java

License:Open Source License

/** Tests ocsp message
 * @throws Exception error// w w w . j  a  v  a 2  s. c om
 */
@Test
public void test01OcspGood() throws Exception {
    log.trace(">test01OcspGood()");

    // find a CA (TestCA?) create a user and generate his cert
    // send OCSP req to server and get good response
    // change status of cert to bad status
    // send OCSP req and get bad status
    // (send crap message and get good error)

    // Make user that we know...
    boolean userExists = endEntityManagementSession.existsUser(END_ENTITY_NAME);
    if (!userExists) {
        endEntityManagementSession.addUser(admin, END_ENTITY_NAME, "foo123", "C=SE,O=AnaTom,CN=OCSPTest", null,
                "ocsptest@anatom.se", false, SecConst.EMPTY_ENDENTITYPROFILE,
                CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER, EndEntityTypes.ENDUSER.toEndEntityType(),
                SecConst.TOKEN_SOFT_PEM, 0, caid);
        log.debug("created user: ocsptest, foo123, C=SE, O=AnaTom, CN=OCSPTest");
    } else {
        log.debug("User ocsptest already exists.");
        EndEntityInformation userData = new EndEntityInformation(END_ENTITY_NAME, "C=SE,O=AnaTom,CN=OCSPTest",
                caid, null, "ocsptest@anatom.se", EndEntityConstants.STATUS_NEW,
                EndEntityTypes.ENDUSER.toEndEntityType(), SecConst.EMPTY_ENDENTITYPROFILE,
                CertificateProfileConstants.CERTPROFILE_FIXED_ENDUSER, null, null, SecConst.TOKEN_SOFT_PEM, 0,
                null);
        userData.setPassword("foo123");
        endEntityManagementSession.changeUser(admin, userData, false);
        log.debug("Reset status to NEW");
    }
    try {
        // Generate certificate for the new user
        KeyPair keys = KeyTools.genKeys("512", "RSA");

        // user that we know exists...
        ocspTestCert = (X509Certificate) signSession.createCertificate(admin, "ocsptest", "foo123",
                new PublicKeyWrapper(keys.getPublic()));
        assertNotNull("Failed to create a certificate", ocspTestCert);

        // And an OCSP request
        OCSPReqBuilder gen = new OCSPReqBuilder();
        gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert,
                ocspTestCert.getSerialNumber()));
        Extension[] extensions = new Extension[1];
        extensions[0] = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false,
                new DEROctetString("123456789".getBytes()));
        gen.setRequestExtensions(new Extensions(extensions));
        X509CertificateHolder chain[] = new JcaX509CertificateHolder[2];
        chain[0] = new JcaX509CertificateHolder(ocspTestCert);
        chain[1] = new JcaX509CertificateHolder(cacert);
        gen.setRequestorName(chain[0].getSubject());
        OCSPReq req = gen.build(new BufferingContentSigner(new JcaContentSignerBuilder("SHA1withRSA")
                .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(keys.getPrivate()), 20480), chain);
        // Send the request and receive a singleResponse
        SingleResp[] singleResps = helper.sendOCSPPost(req.getEncoded(), "123456789",
                OCSPResponseStatus.SUCCESSFUL, 200);
        assertEquals("Number of of SingResps should be 1.", 1, singleResps.length);
        SingleResp singleResp = singleResps[0];

        CertificateID certId = singleResp.getCertID();
        assertEquals("Serno in response does not match serno in request.", certId.getSerialNumber(),
                ocspTestCert.getSerialNumber());
        Object status = singleResp.getCertStatus();
        assertEquals("Status is not null (good)", null, status);

        // Try with an unsigned request, we should get a status code 5 back from the server (signature required)
        req = gen.build();
        // Send the request and receive a singleResponse, this response should have error code SIGNATURE_REQUIRED
        singleResps = helper.sendOCSPPost(req.getEncoded(), "123456789", OCSPResponseStatus.SIG_REQUIRED, 200);
        assertNull(singleResps);

        // sign with a keystore where the CA-certificate is not known
        KeyStore store = KeyStore.getInstance("PKCS12", "BC");
        ByteArrayInputStream fis = new ByteArrayInputStream(ks3);
        store.load(fis, "foo123".toCharArray());
        Certificate[] certs = KeyTools.getCertChain(store, "privateKey");
        chain[0] = new JcaX509CertificateHolder((X509Certificate) certs[0]);
        chain[1] = new JcaX509CertificateHolder((X509Certificate) certs[1]);
        PrivateKey pk = (PrivateKey) store.getKey("privateKey", "foo123".toCharArray());
        req = gen.build(new BufferingContentSigner(new JcaContentSignerBuilder("SHA1withRSA").build(pk), 20480),
                chain);
        // Send the request and receive a singleResponse, this response should have error code UNAUTHORIZED (6)
        singleResps = helper.sendOCSPPost(req.getEncoded(), "123456789", OCSPResponseStatus.UNAUTHORIZED, 200);
        assertNull(singleResps);
    } finally {
        endEntityManagementSession.deleteUser(roleMgmgToken, END_ENTITY_NAME);
    }
    log.trace("<test01OcspGood()");
}

From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspTestBase.java

License:Open Source License

protected void test10MultipleRequests() throws Exception { // NOPMD, this is not a test class itself
    // Tests that we handle multiple requests in one OCSP request message

    //loadUserCert(this.caid);
    // An OCSP request for a certificate from an unknown CA
    OCSPReqBuilder gen = new OCSPReqBuilder();
    gen.addRequest(/*from   w w  w .  jav  a  2s  .c  o m*/
            new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), unknowncacert, new BigInteger("1")));

    // Get user and ocspTestCert that we know...
    loadUserCert(this.caid);
    gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert,
            ocspTestCert.getSerialNumber()));
    Extension[] extensions = new Extension[1];
    extensions[0] = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false,
            new DEROctetString("123456789".getBytes()));
    gen.setRequestExtensions(new Extensions(extensions));

    OCSPReq req = gen.build();

    // Send the request and receive a singleResponse
    SingleResp[] singleResps = helper.sendOCSPPost(req.getEncoded(), null, 0, 200);
    assertEquals("No of SingleResps should be 2.", 2, singleResps.length);
    SingleResp singleResp1 = singleResps[0];

    CertificateID certId = singleResp1.getCertID();
    assertEquals("Serno in response does not match serno in request.", certId.getSerialNumber(),
            new BigInteger("1"));
    Object status = singleResp1.getCertStatus();
    assertTrue("Status is not Unknown", status instanceof UnknownStatus);

    SingleResp singleResp2 = singleResps[1];
    certId = singleResp2.getCertID();
    assertEquals("Serno in response does not match serno in request.", ocspTestCert.getSerialNumber(),
            certId.getSerialNumber());
    status = singleResp2.getCertStatus();
    assertEquals("Status is not null (good)", null, status);

}

From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspTestBase.java

License:Open Source License

/**
 * In compliance with RFC 2560 on//from  w ww  .  j  av  a 2 s. c  o m
 * "ASN.1 Specification of the OCSP Response": If the value of
 * responseStatus is one of the error conditions, responseBytes are not set.
 *
 * OCSPResponse ::= SEQUENCE { responseStatus OCSPResponseStatus,
 * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
 */
protected void test11MalformedRequest() throws Exception { // NOPMD, this is not a test class itself
    loadUserCert(this.caid);
    OCSPReqBuilder gen = new OCSPReqBuilder();
    // Add 101 OCSP requests.. the Servlet will consider a request with more
    // than 100 malformed..
    // This does not mean that we only should allow 100 in the future, just
    // that we if so need to find
    // another way make the Servlet return
    // OCSPRespBuilder.MALFORMED_REQUEST
    for (int i = 0; i < 101; i++) {
        gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert,
                ocspTestCert.getSerialNumber()));
    }
    Extension[] extensions = new Extension[1];
    extensions[0] = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false,
            new DEROctetString("123456789".getBytes()));
    gen.setRequestExtensions(new Extensions(extensions));
    OCSPReq req = gen.build();
    // Send the request and receive null
    SingleResp[] singleResps = helper.sendOCSPPost(req.getEncoded(), "123456789",
            OCSPRespBuilder.MALFORMED_REQUEST, 200);
    assertNull("No SingleResps should be returned.", singleResps);
}

From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspTestBase.java

License:Open Source License

protected void test12CorruptRequests() throws Exception { // NOPMD, this is not a test class itself
    log.trace(">test12CorruptRequests()");
    loadUserCert(this.caid);
    // An OCSP request, ocspTestCert is already created in earlier tests
    OCSPReqBuilder gen = new OCSPReqBuilder();
    gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert,
            ocspTestCert.getSerialNumber()));
    Extension[] extensions = new Extension[1];
    extensions[0] = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false,
            new DEROctetString("123456789".getBytes()));
    gen.setRequestExtensions(new Extensions(extensions));
    OCSPReq req = gen.build();//from   w  ww. j a va2 s .  co  m

    // Request 1
    //
    // Send the request and receive a singleResponse
    byte[] orgbytes = req.getEncoded(); // Save original bytes, so we can
    // make different strange values
    byte[] bytes = req.getEncoded();
    // Switch the first byte, now it's a really corrupted request
    bytes[0] = 0x44;
    SingleResp[] singleResps = helper.sendOCSPPost(bytes, "123456789", OCSPRespBuilder.MALFORMED_REQUEST, 200); // error
    // code
    // 1
    // means
    // malformed
    // request
    assertNull("SingleResps should be null.", singleResps);

    // Request 2
    //
    // Remove the last byte, should still be quite corrupted
    // bytes = Arrays.copyOf(orgbytes, orgbytes.length-1); only works in
    // Java 6
    bytes = ArrayUtils.remove(orgbytes, orgbytes.length - 1);
    singleResps = helper.sendOCSPPost(bytes, "123456789", OCSPRespBuilder.MALFORMED_REQUEST, 200); // error
    // code
    // 1
    // means
    // malformed
    // request
    assertNull("SingleResps should be null.", singleResps);

    // Request 3
    //
    // more than 1 million bytes
    // bytes = Arrays.copyOf(orgbytes, 1000010); only works in Java 6
    bytes = ArrayUtils.addAll(orgbytes, new byte[1000010]);
    singleResps = helper.sendOCSPPost(bytes, "123456789", OCSPRespBuilder.MALFORMED_REQUEST, 200); // //
    // error
    // code
    // 1
    // means
    // malformed
    // request
    assertNull("SingleResps should be null.", singleResps);

    // Request 4
    //
    //
    // A completely empty request with no question in it
    gen = new OCSPReqBuilder();
    req = gen.build();
    bytes = req.getEncoded();
    singleResps = helper.sendOCSPPost(bytes, "123456789", 1, 200); //
    assertNull("SingleResps should be null.", singleResps);

    log.trace("<test12CorruptRequests()");
}

From source file:org.jruby.ext.openssl.OCSPBasicResponse.java

License:Common Public License

@JRubyMethod(name = "add_nonce", rest = true)
public OCSPBasicResponse add_nonce(IRubyObject[] args) {
    Ruby runtime = getRuntime();//from www .  j a  v a2s  .c o m

    byte[] tmpNonce;
    if (Arity.checkArgumentCount(runtime, args, 0, 1) == 0) {
        tmpNonce = generateNonce();
    } else {
        RubyString input = (RubyString) args[0];
        tmpNonce = input.getBytes();
    }

    extensions.add(new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, tmpNonce));
    nonce = tmpNonce;

    return this;
}

From source file:org.jruby.ext.openssl.OCSPRequest.java

License:Common Public License

private void addNonceImpl() {
    GeneralName requestorName = null;//w w w.j  ava  2  s . c o m
    ASN1Sequence requestList = new DERSequence();
    Extensions extensions = null;
    Signature sig = null;
    List<Extension> tmpExtensions = new ArrayList<Extension>();

    if (asn1bcReq != null) {
        TBSRequest currentTbsReq = asn1bcReq.getTbsRequest();
        extensions = currentTbsReq.getRequestExtensions();
        sig = asn1bcReq.getOptionalSignature();
        Enumeration<ASN1ObjectIdentifier> oids = extensions.oids();
        while (oids.hasMoreElements()) {
            tmpExtensions.add(extensions.getExtension(oids.nextElement()));
        }
    }

    tmpExtensions.add(new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, nonce));
    Extension[] exts = new Extension[tmpExtensions.size()];
    Extensions newExtensions = new Extensions(tmpExtensions.toArray(exts));
    TBSRequest newTbsReq = new TBSRequest(requestorName, requestList, newExtensions);

    asn1bcReq = new org.bouncycastle.asn1.ocsp.OCSPRequest(newTbsReq, sig);
}

From source file:org.keycloak.common.util.OCSPUtils.java

License:Apache License

/**
 * Requests certificate revocation status using OCSP.
 * @param cert the certificate to be checked
 * @param issuerCertificate the issuer certificate
 * @param responderURIs the OCSP responder URIs
 * @param responderCert the OCSP responder certificate
 * @param date if null, the current time is used.
 * @return a revocation status/*from w  w  w.  ja va 2s . c o  m*/
 * @throws CertPathValidatorException
 */
private static OCSPRevocationStatus check(X509Certificate cert, X509Certificate issuerCertificate,
        List<URI> responderURIs, X509Certificate responderCert, Date date) throws CertPathValidatorException {
    if (responderURIs == null || responderURIs.size() == 0)
        throw new IllegalArgumentException("Need at least one responder");
    try {
        DigestCalculator digCalc = new BcDigestCalculatorProvider()
                .get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1));

        JcaCertificateID certificateID = new JcaCertificateID(digCalc, issuerCertificate,
                cert.getSerialNumber());

        // Create a nounce extension to protect against replay attacks
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        BigInteger nounce = BigInteger.valueOf(Math.abs(random.nextInt()));

        DEROctetString derString = new DEROctetString(nounce.toByteArray());
        Extension nounceExtension = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, derString);
        Extensions extensions = new Extensions(nounceExtension);

        OCSPReq ocspReq = new OCSPReqBuilder().addRequest(certificateID, extensions).build();

        URI responderURI = responderURIs.get(0);
        logger.log(Level.INFO, "OCSP Responder {0}", responderURI);

        try {
            OCSPResp resp = getResponse(ocspReq, responderURI);
            logger.log(Level.FINE, "Received a response from OCSP responder {0}, the response status is {1}",
                    new Object[] { responderURI, resp.getStatus() });
            switch (resp.getStatus()) {
            case OCSPResp.SUCCESSFUL:
                if (resp.getResponseObject() instanceof BasicOCSPResp) {
                    return processBasicOCSPResponse(issuerCertificate, responderCert, date, certificateID,
                            nounce, (BasicOCSPResp) resp.getResponseObject());
                } else {
                    throw new CertPathValidatorException(
                            "OCSP responder returned an invalid or unknown OCSP response.");
                }

            case OCSPResp.INTERNAL_ERROR:
            case OCSPResp.TRY_LATER:
                throw new CertPathValidatorException(
                        "Internal error/try later. OCSP response error: " + resp.getStatus(), (Throwable) null,
                        (CertPath) null, -1,
                        CertPathValidatorException.BasicReason.UNDETERMINED_REVOCATION_STATUS);

            case OCSPResp.SIG_REQUIRED:
                throw new CertPathValidatorException(
                        "Invalid or missing signature. OCSP response error: " + resp.getStatus(),
                        (Throwable) null, (CertPath) null, -1,
                        CertPathValidatorException.BasicReason.INVALID_SIGNATURE);

            case OCSPResp.UNAUTHORIZED:
                throw new CertPathValidatorException(
                        "Unauthorized request. OCSP response error: " + resp.getStatus(), (Throwable) null,
                        (CertPath) null, -1, CertPathValidatorException.BasicReason.UNSPECIFIED);

            case OCSPResp.MALFORMED_REQUEST:
            default:
                throw new CertPathValidatorException(
                        "OCSP request is malformed. OCSP response error: " + resp.getStatus(), (Throwable) null,
                        (CertPath) null, -1, CertPathValidatorException.BasicReason.UNSPECIFIED);
            }
        } catch (IOException e) {
            logger.log(Level.FINE, "OCSP Responder \"{0}\" failed to return a valid OCSP response\n{1}",
                    new Object[] { responderURI, e.getMessage() });
            throw new CertPathValidatorException("OCSP check failed", e);
        }
    } catch (CertificateNotYetValidException | CertificateExpiredException | OperatorCreationException
            | OCSPException | CertificateEncodingException | NoSuchAlgorithmException
            | NoSuchProviderException e) {
        logger.log(Level.FINE, e.getMessage());
        throw new CertPathValidatorException(e.getMessage(), e);
    }
}

From source file:org.metaeffekt.dcc.commons.pki.CertificateManager.java

License:Apache License

protected List<Extension> createExtensions(PublicKey publicKey, X509Certificate issuerCertificate)
        throws CertIOException, NoSuchAlgorithmException, IOException {

    List<Extension> extensions = new ArrayList<>();

    String certType = getProperty(PROPERTY_CERT_TYPE, CERT_TYPE_TLS);

    // backward compatibility
    if (CERT_TYPE_CA_OLD.equals(certType)) {
        certType = CERT_TYPE_CA;// www . j  av  a  2 s. c  o  m
    }

    // subject key identifier
    boolean criticalKeyIdentifier = getProperty(PROPERTY_CERT_CRITICAL_KEY_IDENTIFIER, false);
    extensions.add(new Extension(Extension.subjectKeyIdentifier, criticalKeyIdentifier,
            new JcaX509ExtensionUtils().createSubjectKeyIdentifier(publicKey).getEncoded()));

    // basic constraints
    if (CERT_TYPE_CA.equals(certType)) {
        boolean criticalCaConstraints = getProperty(PROPERTY_CERT_CRITICAL_CA, true);
        int chainLengthConstraint = getProperty(PROPERTY_CERT_CHAIN_LENGTH, 0);
        if (chainLengthConstraint > 0) {
            extensions.add(new Extension(Extension.basicConstraints, criticalCaConstraints,
                    new BasicConstraints(chainLengthConstraint).getEncoded()));
        } else {
            extensions.add(new Extension(Extension.basicConstraints, criticalCaConstraints,
                    new BasicConstraints(true).getEncoded()));
        }
    }

    // key usage
    int keyUsageInt = getKeyUsage(certType);
    if (keyUsageInt != 0) {
        // FIXME: test whether we can default to true here
        boolean criticalKeyUsage = getProperty(PROPERTY_CERT_CRITICAL_KEY_USAGE, false);
        KeyUsage keyUsage = new KeyUsage(keyUsageInt);
        extensions.add(new Extension(Extension.keyUsage, criticalKeyUsage, keyUsage.getEncoded()));
    }

    // extended key usage
    KeyPurposeId[] keyPurposeDefault = null;
    if (CERT_TYPE_TLS.equals(certType)) {
        // defaults for TLS
        keyPurposeDefault = new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth };
    }
    boolean criticalKeyPurpose = getProperty(PROPERTY_CERT_CRITICAL_KEY_PURPOSE, false);
    KeyPurposeId[] keyPurpose = createKeyPurposeIds(keyPurposeDefault);
    if (keyPurpose != null) {
        extensions.add(new Extension(Extension.extendedKeyUsage, criticalKeyPurpose,
                new ExtendedKeyUsage(keyPurpose).getEncoded()));
    }

    // subjectAlternativeName
    List<ASN1Encodable> subjectAlternativeNames = extractAlternativeNames(PROPERTY_PREFIX_CERT_NAME);
    if (!subjectAlternativeNames.isEmpty()) {
        boolean criticalNames = getProperty(PROPERTY_CERT_CRITICAL_NAMES, false);
        DERSequence subjectAlternativeNamesExtension = new DERSequence(
                subjectAlternativeNames.toArray(new ASN1Encodable[subjectAlternativeNames.size()]));
        extensions.add(new Extension(Extension.subjectAlternativeName, criticalNames,
                subjectAlternativeNamesExtension.getEncoded()));
    }

    if (issuerCertificate == null) {
        // crl distribution point
        DistributionPoint[] crlDistributionPoints = createCrlDistributionPoints();
        if (crlDistributionPoints != null) {
            boolean criticalCrlDistPoints = getProperty(PROPERTY_CERT_CRITICAL_CRL_DISTRIBUTION_POINTS, false);
            extensions.add(new Extension(Extension.cRLDistributionPoints, criticalCrlDistPoints,
                    new CRLDistPoint(crlDistributionPoints).getEncoded()));
        }

        // authority information access
        AccessDescription[] accessDescriptions = createAccessDescriptions();
        if (accessDescriptions != null) {
            boolean criticalAuthorityInformationAccess = getProperty(
                    PROPERTY_CERT_CRITICAL_AUTHORITY_INFORMATION_ACCESS, false);
            extensions.add(new Extension(Extension.authorityInfoAccess, criticalAuthorityInformationAccess,
                    new AuthorityInformationAccess(accessDescriptions).getEncoded()));
        }
    } else {
        copyExtension(Extension.cRLDistributionPoints, issuerCertificate, extensions);
        copyExtension(Extension.authorityInfoAccess, issuerCertificate, extensions);
    }
    return extensions;
}