// Path: src/main/java/net/klakegg/pkix/ocsp/api/OcspFetcher.java
// public interface OcspFetcher {
// 
//     OcspFetcherResponse fetch(URI uri, byte[] content) throws IOException;
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/api/OcspFetcherResponse.java
// public interface OcspFetcherResponse extends Closeable {
// 
//     int getStatus() throws IOException;
// 
//     String getContentType() throws IOException;
// 
//     InputStream getContent() throws IOException;
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Properties.java
// public class Properties {
// 
//     private Map<Property<?>, Object> map;
// 
//     protected Properties(Map<Property<?>, Object> map) {
//         this.map = map;
//     }
// 
//     @SuppressWarnings("unchecked")
//     public <S> S get(Property<S> property) {
//         return map.containsKey(property) ? (S) map.get(property) : property.getDefaultValue();
//     }
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Property.java
// public class Property<T> {
// 
//     private final T defaultValue;
// 
//     public static <T> Property<T> create() {
//         return new Property<>(null);
//     }
// 
//     public static <T> Property<T> create(T defaultValue) {
//         return new Property<>(defaultValue);
//     }
// 
//     private Property(T defaultValue) {
//         this.defaultValue = defaultValue;
//     }
// 
//     public T getDefaultValue() {
//         return defaultValue;
//     }
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/fetcher/UrlOcspFetcher.java
// public class UrlOcspFetcher extends AbstractOcspFetcher {
// 
//     /**
//      * Builder to create an instance of OcspFetcher using HttpURLConnection for connectivity.
//      *
//      * @return Prepared fetcher.
//      */
//     public static Builder<OcspFetcher> builder() {
//         return new Builder<>(new BuildHandler<OcspFetcher>() {
//             @Override
//             public OcspFetcher build(Properties properties) {
//                 return new UrlOcspFetcher(properties);
//             }
//         });
//     }
// 
//     public UrlOcspFetcher(Properties properties) {
//         super(properties);
//     }
// 
//     @Override
//     public OcspFetcherResponse fetch(URI uri, byte[] content) throws IOException {
//         HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
//         connection.setConnectTimeout(properties.get(TIMEOUT_CONNECT));
//         connection.setReadTimeout(properties.get(TIMEOUT_READ));
//         connection.setDoOutput(true);
//         connection.setRequestMethod("POST");
//         connection.setRequestProperty("Content-Type", "application/ocsp-request");
//         connection.setRequestProperty("Accept", "application/ocsp-response");
//         connection.getOutputStream().write(content);
// 
//         return new UrlOcspFetcherResponse(connection);
//     }
// 
//     private class UrlOcspFetcherResponse implements OcspFetcherResponse {
// 
//         private HttpURLConnection connection;
// 
//         public UrlOcspFetcherResponse(HttpURLConnection connection) {
//             this.connection = connection;
//         }
// 
//         @Override
//         public int getStatus() throws IOException {
//             return connection.getResponseCode();
//         }
// 
//         @Override
//         public String getContentType() {
//             return connection.getContentType();
//         }
// 
//         @Override
//         public InputStream getContent() throws IOException {
//             return connection.getInputStream();
//         }
// 
//         @Override
//         public void close() throws IOException {
//             // No action.
//         }
//     }
// }


import net.klakegg.pkix.ocsp.api.OcspFetcher;
import net.klakegg.pkix.ocsp.api.OcspFetcherResponse;
import net.klakegg.pkix.ocsp.builder.Properties;
import net.klakegg.pkix.ocsp.builder.Property;
import net.klakegg.pkix.ocsp.fetcher.UrlOcspFetcher;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.x509.extension.X509ExtensionUtil;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
package net.klakegg.pkix.ocsp;



/**
 * This abstract class implements common features related to OCSP verification.
 *
 * @author erlend
 */
class AbstractOcspClient {

    public static final Property<Boolean> EXCEPTION_ON_NO_PATH = Property.create(false);

    public static final Property<OcspFetcher> FETCHER = Property.create(UrlOcspFetcher.builder().build());

    public static final Property<List<X509Certificate>> INTERMEDIATES =
            Property.create(Collections.<X509Certificate>emptyList());

    public static final Property<URI> OVERRIDE_URL = Property.create();

    public static final Property<Boolean> NONCE = Property.create(false);

    /**
     * Properties provided by the builder.
     */
    protected final Properties properties;

    /**
     * Constructor accepting properties provided by the builder.
     *
     * @param properties Properties provided by the builder.
     */
// Path: src/main/java/net/klakegg/pkix/ocsp/api/OcspFetcher.java
// public interface OcspFetcher {
// 
//     OcspFetcherResponse fetch(URI uri, byte[] content) throws IOException;
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/api/OcspFetcherResponse.java
// public interface OcspFetcherResponse extends Closeable {
// 
//     int getStatus() throws IOException;
// 
//     String getContentType() throws IOException;
// 
//     InputStream getContent() throws IOException;
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Properties.java
// public class Properties {
// 
//     private Map<Property<?>, Object> map;
// 
//     protected Properties(Map<Property<?>, Object> map) {
//         this.map = map;
//     }
// 
//     @SuppressWarnings("unchecked")
//     public <S> S get(Property<S> property) {
//         return map.containsKey(property) ? (S) map.get(property) : property.getDefaultValue();
//     }
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Property.java
// public class Property<T> {
// 
//     private final T defaultValue;
// 
//     public static <T> Property<T> create() {
//         return new Property<>(null);
//     }
// 
//     public static <T> Property<T> create(T defaultValue) {
//         return new Property<>(defaultValue);
//     }
// 
//     private Property(T defaultValue) {
//         this.defaultValue = defaultValue;
//     }
// 
//     public T getDefaultValue() {
//         return defaultValue;
//     }
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/fetcher/UrlOcspFetcher.java
// public class UrlOcspFetcher extends AbstractOcspFetcher {
// 
//     /**
//      * Builder to create an instance of OcspFetcher using HttpURLConnection for connectivity.
//      *
//      * @return Prepared fetcher.
//      */
//     public static Builder<OcspFetcher> builder() {
//         return new Builder<>(new BuildHandler<OcspFetcher>() {
//             @Override
//             public OcspFetcher build(Properties properties) {
//                 return new UrlOcspFetcher(properties);
//             }
//         });
//     }
// 
//     public UrlOcspFetcher(Properties properties) {
//         super(properties);
//     }
// 
//     @Override
//     public OcspFetcherResponse fetch(URI uri, byte[] content) throws IOException {
//         HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
//         connection.setConnectTimeout(properties.get(TIMEOUT_CONNECT));
//         connection.setReadTimeout(properties.get(TIMEOUT_READ));
//         connection.setDoOutput(true);
//         connection.setRequestMethod("POST");
//         connection.setRequestProperty("Content-Type", "application/ocsp-request");
//         connection.setRequestProperty("Accept", "application/ocsp-response");
//         connection.getOutputStream().write(content);
// 
//         return new UrlOcspFetcherResponse(connection);
//     }
// 
//     private class UrlOcspFetcherResponse implements OcspFetcherResponse {
// 
//         private HttpURLConnection connection;
// 
//         public UrlOcspFetcherResponse(HttpURLConnection connection) {
//             this.connection = connection;
//         }
// 
//         @Override
//         public int getStatus() throws IOException {
//             return connection.getResponseCode();
//         }
// 
//         @Override
//         public String getContentType() {
//             return connection.getContentType();
//         }
// 
//         @Override
//         public InputStream getContent() throws IOException {
//             return connection.getInputStream();
//         }
// 
//         @Override
//         public void close() throws IOException {
//             // No action.
//         }
//     }
// }


// Path: src/main/java/net/klakegg/pkix/ocsp/AbstractOcspClient.java
import net.klakegg.pkix.ocsp.api.OcspFetcher;
import net.klakegg.pkix.ocsp.api.OcspFetcherResponse;
import net.klakegg.pkix.ocsp.builder.Properties;
import net.klakegg.pkix.ocsp.builder.Property;
import net.klakegg.pkix.ocsp.fetcher.UrlOcspFetcher;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.x509.extension.X509ExtensionUtil;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

package net.klakegg.pkix.ocsp;



/**
 * This abstract class implements common features related to OCSP verification.
 *
 * @author erlend
 */
class AbstractOcspClient {

    public static final Property<Boolean> EXCEPTION_ON_NO_PATH = Property.create(false);

    public static final Property<OcspFetcher> FETCHER = Property.create(UrlOcspFetcher.builder().build());

    public static final Property<List<X509Certificate>> INTERMEDIATES =
            Property.create(Collections.<X509Certificate>emptyList());

    public static final Property<URI> OVERRIDE_URL = Property.create();

    public static final Property<Boolean> NONCE = Property.create(false);

    /**
     * Properties provided by the builder.
     */
    protected final Properties properties;

    /**
     * Constructor accepting properties provided by the builder.
     *
     * @param properties Properties provided by the builder.
     */
    protected AbstractOcspClient(Properties properties) {