Package br.net.woodstock.rockframework.security.cert.impl

Source Code of br.net.woodstock.rockframework.security.cert.impl.OCSPCertificateValidator

/*
* This file is part of rockframework.
*
* rockframework is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* rockframework 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>;.
*/
package br.net.woodstock.rockframework.security.cert.impl;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.ocsp.OCSPResponseStatus;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.ocsp.BasicOCSPResp;
import org.bouncycastle.cert.ocsp.CertificateID;
import org.bouncycastle.cert.ocsp.CertificateStatus;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.cert.ocsp.OCSPReq;
import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.cert.ocsp.RevokedStatus;
import org.bouncycastle.cert.ocsp.SingleResp;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;

import br.net.woodstock.rockframework.core.util.Assert;
import br.net.woodstock.rockframework.core.utils.Codecs;
import br.net.woodstock.rockframework.core.utils.Collections;
import br.net.woodstock.rockframework.core.utils.Conditions;
import br.net.woodstock.rockframework.core.utils.IO;
import br.net.woodstock.rockframework.security.cert.CertificateException;
import br.net.woodstock.rockframework.security.cert.CertificateValidator;
import br.net.woodstock.rockframework.security.cert.RevokeReason;
import br.net.woodstock.rockframework.security.cert.ValidationError;
import br.net.woodstock.rockframework.security.timestamp.impl.URLTimeStampProcessor;
import br.net.woodstock.rockframework.security.util.BouncyCastleProviderHelper;

public class OCSPCertificateValidator implements CertificateValidator {

  public static final String  VALIDATOR_NAME            = "OCSP Validator";

  private static final String  CONTENT_TYPE_PROPERTY        = "Content-Type";

  private static final String  CONTENT_TYPE_VALUE          = "application/ocsp-request";

  private static final String  CONTENT_TRANSFER_ENCODING_PROPERTY  = "Content-Transfer-Encoding";

  private static final String  CONTENT_TRANSFER_ENCODING_BINARY  = "binary";

  private URL          url;

  public OCSPCertificateValidator() {
    super();
  }

  public OCSPCertificateValidator(final URL url) {
    super();
    Assert.notNull(url, "url");
    this.url = url;
  }

  @Override
  public ValidationError[] validate(final Certificate[] chain) {
    Assert.notEmpty(chain, "chain");
    if (chain.length < 2) {
      return new ValidationError[] { new ValidationError(OCSPCertificateValidator.VALIDATOR_NAME, "Certificate chain must be greater than 1(certificate and issuer certificate") };
    }
    try {
      X509Certificate x509Certificate = (X509Certificate) chain[0];
      X509Certificate x509Issuer = (X509Certificate) chain[1];
      URL url = null;

      if (this.url == null) {
        URL[] urls = OCSPCertificateValidator.getOCSPUrl(x509Certificate);
        if (Conditions.isNotEmpty(urls)) {
          url = urls[0];
        }
      } else {
        url = this.url;
      }

      if (url == null) {
        return new ValidationError[] { new ValidationError(OCSPCertificateValidator.VALIDATOR_NAME, "No url found for validation") };
      }

      OCSPReq req = this.buildRequest(x509Certificate, x509Issuer);
      OCSPResp resp = this.sendRequest(req, url);
      if (resp.getStatus() != OCSPResponseStatus.SUCCESSFUL) {
        return new ValidationError[] { new ValidationError(OCSPCertificateValidator.VALIDATOR_NAME, "Response invalid") };
      }

      Object responseObject = resp.getResponseObject();

      if (responseObject instanceof BasicOCSPResp) {
        BasicOCSPResp basicOCSPResp = (BasicOCSPResp) responseObject;
        SingleResp[] singleResps = basicOCSPResp.getResponses();
        List<ValidationError> errors = new ArrayList<ValidationError>();
        for (SingleResp singleResp : singleResps) {
          CertificateStatus status = singleResp.getCertStatus();
          if (status != null) {
            RevokeReason revokeReason = null;
            if (status instanceof RevokedStatus) {
              RevokedStatus revokedStatus = (RevokedStatus) status;
              revokeReason = RevokeReason.getByCode(revokedStatus.getRevocationReason());
            }

            if (revokeReason != null) {
              errors.add(new ValidationError(OCSPCertificateValidator.VALIDATOR_NAME, "Certificate revoked(" + revokeReason.name() + ")"));
            } else {
              errors.add(new ValidationError(OCSPCertificateValidator.VALIDATOR_NAME, "Certificate revoked(Unknow)"));
            }
          }
        }

        return Collections.toArray(errors, ValidationError.class);
      }

      return new ValidationError[0];
    } catch (Exception e) {
      throw new CertificateException(e);
    }
  }

  protected OCSPReq buildRequest(final X509Certificate certificate, final X509Certificate issuer) throws CertificateEncodingException, IOException, OperatorCreationException, OCSPException {
    OCSPReqBuilder builder = new OCSPReqBuilder();
    DigestCalculatorProvider provider = new BcDigestCalculatorProvider();
    X509CertificateHolder holder = new X509CertificateHolder(issuer.getEncoded());
    CertificateID certificateID = new CertificateID(provider.get(CertificateID.HASH_SHA1), holder, certificate.getSerialNumber());
    BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis());

    builder.addRequest(certificateID);
    ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
    extensionsGenerator.addExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString(nonce.toByteArray()));

    return builder.build();
  }

  protected OCSPResp sendRequest(final OCSPReq req, final URL url) throws IOException {
    URLConnection connection = url.openConnection();

    connection.setDoInput(true);
    connection.setDoOutput(true);
    connection.setUseCaches(false);

    this.setConnectionProperties(connection);

    byte[] requestBytes = req.getEncoded();

    OutputStream outputStream = connection.getOutputStream();

    this.writeBytes(outputStream, requestBytes);

    outputStream.close();

    InputStream inputStream = connection.getInputStream();

    String encoding = connection.getContentEncoding();

    byte[] bytes = this.readBytes(inputStream, encoding);
    OCSPResp resp = new OCSPResp(bytes);
    return resp;
  }

  protected void setConnectionProperties(final URLConnection connection) {
    connection.setRequestProperty(OCSPCertificateValidator.CONTENT_TYPE_PROPERTY, OCSPCertificateValidator.CONTENT_TYPE_VALUE);
    connection.setRequestProperty(OCSPCertificateValidator.CONTENT_TRANSFER_ENCODING_PROPERTY, OCSPCertificateValidator.CONTENT_TRANSFER_ENCODING_BINARY);
  }

  protected void writeBytes(final OutputStream outputStream, final byte[] bytes) throws IOException {
    outputStream.write(bytes);
  }

  protected byte[] readBytes(final InputStream inputStream, final String encoding) throws IOException {
    byte[] bytes = IO.toByteArray(inputStream);
    if (URLTimeStampProcessor.CONTENT_TRANSFER_ENCODING_BASE64.equals(encoding)) {
      bytes = Codecs.fromBase64(bytes);
    }
    return bytes;
  }

  public static URL[] getOCSPUrl(final Certificate certificate) throws IOException {
    X509Certificate x509Certificate = (X509Certificate) certificate;
    byte[] bytes = x509Certificate.getExtensionValue(X509Extension.authorityInfoAccess.getId());

    if (bytes == null) {
      return new URL[0];
    }

    Set<URL> urls = new HashSet<URL>();
    DEROctetString octetString = (DEROctetString) BouncyCastleProviderHelper.toASN1Primitive(bytes);
    ASN1Sequence sequence = (ASN1Sequence) BouncyCastleProviderHelper.toASN1Primitive(octetString.getOctets());
    AuthorityInformationAccess informationAccess = AuthorityInformationAccess.getInstance(sequence);
    AccessDescription[] accessDescriptions = informationAccess.getAccessDescriptions();

    // Colocar aqui 1.3.6.1.5.5.7.48.1
    for (AccessDescription description : accessDescriptions) {
      if (description.getAccessMethod().getId().equals(OCSPObjectIdentifiers.pkix_ocsp)) {
        GeneralName generalName = description.getAccessLocation();
        DERTaggedObject taggedObject = (DERTaggedObject) generalName.toASN1Primitive();
        DERIA5String ia5String = DERIA5String.getInstance(taggedObject.getObject());
        String urlStr = ia5String.getString();
        URL url = new URL(urlStr);
        urls.add(url);
      }
    }

    return Collections.toArray(urls, URL.class);
  }
}
TOP

Related Classes of br.net.woodstock.rockframework.security.cert.impl.OCSPCertificateValidator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.