All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itextpdf.signatures.CrlClientOnline Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2024 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see .
 */
package com.itextpdf.signatures;

import com.itextpdf.bouncycastleconnector.BouncyCastleFactoryCreator;
import com.itextpdf.commons.bouncycastle.IBouncyCastleFactory;
import com.itextpdf.io.logs.IoLogMessageConstant;
import com.itextpdf.commons.utils.MessageFormatUtil;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An implementation of the CrlClient that fetches the CRL bytes
 * from an URL.
 */
public class CrlClientOnline implements ICrlClient {

    private static final IBouncyCastleFactory BOUNCY_CASTLE_FACTORY = BouncyCastleFactoryCreator.getFactory();
    /**
     * The Logger instance.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(CrlClientOnline.class);

    /**
     * The URLs of the CRLs.
     */
    protected List urls = new ArrayList<>();

    /**
     * Creates a CrlClientOnline instance that will try to find
     * a single CRL by walking through the certificate chain.
     */
    public CrlClientOnline() {
    }

    /**
     * Creates a CrlClientOnline instance using one or more URLs.
     *
     * @param crls the CRLs as Strings
     */
    public CrlClientOnline(String... crls) {
        for (String url : crls) {
            addUrl(url);
        }
    }

    /**
     * Creates a CrlClientOnline instance using one or more URLs.
     *
     * @param crls the CRLs as URLs
     */
    public CrlClientOnline(URL... crls) {
        for (URL url : crls) {
            addUrl(url);
        }
    }

    /**
     * Creates a CrlClientOnline instance using a certificate chain.
     *
     * @param chain a certificate chain
     */
    public CrlClientOnline(Certificate[] chain) {
        for (Certificate certificate : chain) {
            X509Certificate cert = (X509Certificate) certificate;
            LOGGER.info("Checking certificate: " + cert.getSubjectDN());
            List urls = CertificateUtil.getCRLURLs(cert);
            for (String url : urls) {
                addUrl(url);
            }
        }
    }

    /**
     * Fetches the CRL bytes from an URL.
     * If no url is passed as parameter, the url will be obtained from the certificate.
     * If you want to load a CRL from a local file, subclass this method and pass an
     * URL with the path to the local file to this method. An other option is to use
     * the CrlClientOffline class.
     *
     * @throws CertificateEncodingException if an encoding error occurs in {@link X509Certificate}.
     * @see ICrlClient#getEncoded(java.security.cert.X509Certificate, java.lang.String)
     */
    @Override
    public Collection getEncoded(X509Certificate checkCert, String url) throws CertificateEncodingException {
        if (checkCert == null) {
            return null;
        }
        List urlList = new ArrayList<>(urls);
        if (urlList.isEmpty()) {
            LOGGER.info(MessageFormatUtil.format(
                    "Looking for CRL for certificate {0}", BOUNCY_CASTLE_FACTORY.createX500Name(checkCert)));
            try {
                List urlsList = new ArrayList<>();
                if (url == null) {
                    urlsList = CertificateUtil.getCRLURLs(checkCert);
                } else {
                    urlsList.add(url);
                }
                if (urlsList.isEmpty()) {
                    throw new IllegalArgumentException("Passed url can not be null.");
                }
                for (String urlString : urlsList) {
                    urlList.add(new URL(urlString));
                    LOGGER.info("Found CRL url: " + urlString);
                }
            } catch (Exception e) {
                LOGGER.info("Skipped CRL url: " + e.getMessage());
            }
        }
        List ar = new ArrayList<>();
        for (URL urlt : urlList) {
            try {
                LOGGER.info("Checking CRL: " + urlt);
                InputStream inp = getCrlResponse(checkCert, urlt);
                byte[] buf = new byte[1024];
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                while (true) {
                    int n = inp.read(buf, 0, buf.length);
                    if (n <= 0) {
                        break;
                    }
                    bout.write(buf, 0, n);
                }
                inp.close();
                ar.add(bout.toByteArray());
                LOGGER.info("Added CRL found at: " + urlt);
            } catch (Exception e) {
                LOGGER.info(MessageFormatUtil.format(IoLogMessageConstant.INVALID_DISTRIBUTION_POINT,
                        e.getMessage()));
            }
        }
        return ar;
    }

    /**
     * Get CRL response represented as {@link InputStream}.
     * 
     * @param cert {@link X509Certificate} certificate to get CRL response for
     * @param urlt {@link URL} link, which is expected to be used to get CRL response from
     * 
     * @return CRL response bytes, represented as {@link InputStream}
     * 
     * @throws IOException if an I/O error occurs
     */
    protected InputStream getCrlResponse(X509Certificate cert, URL urlt) throws IOException {
        return SignUtils.getHttpResponse(urlt);
    }

    /**
     * Adds an URL to the list of CRL URLs
     *
     * @param url an URL in the form of a String
     */
    protected void addUrl(String url) {
        try {
            addUrl(new URL(url));
        } catch (MalformedURLException e) {
            LOGGER.info("Skipped CRL url (malformed): " + url);
        }
    }

    /**
     * Adds an URL to the list of CRL URLs
     *
     * @param url an URL object
     */
    protected void addUrl(URL url) {
        if (urls.contains(url)) {
            LOGGER.info("Skipped CRL url (duplicate): " + url);
            return;
        }
        urls.add(url);
        LOGGER.info("Added CRL url: " + url);
    }

    /**
     * Get an amount of URLs provided for this CRL.
     *
     * @return {@code int} number of URLs
     */
    public int getUrlsSize() {
        return urls.size();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy