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

eu.europa.esig.dss.x509.ocsp.OCSPToken Maven / Gradle / Ivy

Go to download

DSS Service Provider Interface contains the contract interface shared between the applet and the server-side of DSS.

There is a newer version: 6.0.d4j.2
Show newest version
/**
 * DSS - Digital Signature Services
 * Copyright (C) 2015 European Commission, provided under the CEF programme
 *
 * This file is part of the "DSS - Digital Signature Services" project.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package eu.europa.esig.dss.x509.ocsp;

import java.io.IOException;
import java.io.StringWriter;
import java.security.PublicKey;
import java.text.ParseException;
import java.util.Date;
import java.util.List;

import org.bouncycastle.asn1.ASN1GeneralizedTime;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.ocsp.BasicOCSPResp;
import org.bouncycastle.cert.ocsp.CertificateID;
import org.bouncycastle.cert.ocsp.CertificateStatus;
import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.cert.ocsp.RevokedStatus;
import org.bouncycastle.cert.ocsp.SingleResp;
import org.bouncycastle.cert.ocsp.UnknownStatus;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.europa.esig.dss.DSSException;
import eu.europa.esig.dss.DSSRevocationUtils;
import eu.europa.esig.dss.DSSUtils;
import eu.europa.esig.dss.SignatureAlgorithm;
import eu.europa.esig.dss.x509.CertificateToken;
import eu.europa.esig.dss.x509.RevocationToken;
import eu.europa.esig.dss.x509.TokenValidationExtraInfo;
import eu.europa.esig.dss.x509.crl.CRLReasonEnum;

/**
 * OCSP Signed Token which encapsulate BasicOCSPResp (BC).
 */
@SuppressWarnings("serial")
public class OCSPToken extends RevocationToken {

	private static final Logger LOG = LoggerFactory.getLogger(OCSPToken.class);

	private CertificateID certId;

	/**
	 * Status of the OCSP response
	 */
	private OCSPRespStatus responseStatus;

	/**
	 * The OCSP request contained a nonce
	 */
	private boolean useNonce;

	/**
	 * The sent nonce matched with the received one
	 */
	private boolean nonceMatch;

	/**
	 * The encapsulated basic OCSP response.
	 */
	private BasicOCSPResp basicOCSPResp;

	public OCSPToken() {
		this.extraInfo = new TokenValidationExtraInfo();
	}

	public void extractInfo() {
		if (basicOCSPResp != null) {
			this.productionDate = basicOCSPResp.getProducedAt();
			this.signatureAlgorithm = SignatureAlgorithm.forOID(basicOCSPResp.getSignatureAlgOID().getId());
			extractArchiveCutOff();

			SingleResp bestSingleResp = getBestSingleResp(basicOCSPResp, certId);
			if (bestSingleResp != null) {
				this.thisUpdate = bestSingleResp.getThisUpdate();
				this.nextUpdate = bestSingleResp.getNextUpdate();
				extractStatusInfo(bestSingleResp);
			}
		}
	}

	private SingleResp getBestSingleResp(final BasicOCSPResp basicOCSPResp, final CertificateID certId) {
		Date bestUpdate = null;
		SingleResp bestSingleResp = null;
		SingleResp[] responses = getResponses(basicOCSPResp);
		for (final SingleResp singleResp : responses) {
			if (DSSRevocationUtils.matches(certId, singleResp)) {
				final Date thisUpdate = singleResp.getThisUpdate();
				if ((bestUpdate == null) || thisUpdate.after(bestUpdate)) {
					bestSingleResp = singleResp;
					bestUpdate = thisUpdate;
				}
			}
		}
		return bestSingleResp;
	}

	private SingleResp[] getResponses(final BasicOCSPResp basicOCSPResp) {
		SingleResp[] responses = new SingleResp[] {};
		try {
			responses = basicOCSPResp.getResponses();
		} catch (Exception e) {
			LOG.error("Unable to parse the responses object from OCSP", e);
			extraInfo.infoOCSPException("Unable to parse the responses object from OCSP : " + e.getMessage());
		}
		return responses;
	}

	private void extractStatusInfo(SingleResp bestSingleResp) {
		CertificateStatus certStatus = bestSingleResp.getCertStatus();
		if (CertificateStatus.GOOD == certStatus) {
			if (LOG.isInfoEnabled()) {
				LOG.info("OCSP status is good");
			}
			status = true;
		} else if (certStatus instanceof RevokedStatus) {
			if (LOG.isInfoEnabled()) {
				LOG.info("OCSP status revoked");
			}
			final RevokedStatus revokedStatus = (RevokedStatus) certStatus;
			status = false;
			revocationDate = revokedStatus.getRevocationTime();
			int reasonId = 0; // unspecified
			if (revokedStatus.hasRevocationReason()) {
				reasonId = revokedStatus.getRevocationReason();
			}
			reason = CRLReasonEnum.fromInt(reasonId).name();
		} else if (certStatus instanceof UnknownStatus) {
			if (LOG.isInfoEnabled()) {
				LOG.info("OCSP status unknown");
			}
			reason = CRLReasonEnum.unknow.name();
		} else {
			LOG.info("OCSP certificate status: " + certStatus);
		}
	}

	private void extractArchiveCutOff() {
		Extension extension = basicOCSPResp.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_archive_cutoff);
		if (extension != null) {
			ASN1GeneralizedTime archiveCutOffAsn1 = (ASN1GeneralizedTime) extension.getParsedValue();
			try {
				archiveCutOff = archiveCutOffAsn1.getDate();
			} catch (ParseException e) {
				LOG.warn("Unable to extract id_pkix_ocsp_archive_cutoff : " + e.getMessage());
			}
		}
	}

	@Override
	public boolean isSignedBy(final CertificateToken issuerToken) {
		if (this.issuerToken != null) {
			return this.issuerToken.equals(issuerToken);
		}
		if (basicOCSPResp == null) {
			return false;
		}
		try {
			signatureInvalidityReason = "";
			JcaContentVerifierProviderBuilder jcaContentVerifierProviderBuilder = new JcaContentVerifierProviderBuilder();
			jcaContentVerifierProviderBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME);
			final PublicKey publicKey = issuerToken.getCertificate().getPublicKey();
			ContentVerifierProvider contentVerifierProvider = jcaContentVerifierProviderBuilder.build(publicKey);
			signatureValid = basicOCSPResp.isSignatureValid(contentVerifierProvider);
			if (signatureValid) {
				this.issuerToken = issuerToken;
			}
			issuerX500Principal = issuerToken.getSubjectX500Principal();
		} catch (Exception e) {
			signatureInvalidityReason = e.getClass().getSimpleName() + " - " + e.getMessage();
			signatureValid = false;
		}
		return signatureValid;
	}

	public OCSPRespStatus getResponseStatus() {
		return responseStatus;
	}

	public void setResponseStatus(OCSPRespStatus responseStatus) {
		this.responseStatus = responseStatus;
	}

	public boolean isUseNonce() {
		return useNonce;
	}

	public void setUseNonce(boolean useNonce) {
		this.useNonce = useNonce;
	}

	public boolean isNonceMatch() {
		return nonceMatch;
	}

	public void setNonceMatch(boolean nonceMatch) {
		this.nonceMatch = nonceMatch;
	}

	public BasicOCSPResp getBasicOCSPResp() {
		return basicOCSPResp;
	}

	public void setBasicOCSPResp(BasicOCSPResp basicOCSPResp) {
		this.basicOCSPResp = basicOCSPResp;
	}

	public CertificateID getCertId() {
		return certId;
	}

	public void setCertId(CertificateID certId) {
		this.certId = certId;
	}

	/**
	 * Indicates if the token signature is intact.
	 *
	 * @return {@code true} or {@code false}
	 */
	@Override
	public boolean isValid() {
		return signatureValid;
	}

	/**
	 * This method returns the DSS abbreviation of the certificate. It is used
	 * for debugging purpose.
	 *
	 * @return
	 */
	@Override
	public String getAbbreviation() {
		return "OCSPToken[" + (basicOCSPResp == null ? "?" : DSSUtils.formatInternal(basicOCSPResp.getProducedAt())) + ", signedBy="
				+ (issuerToken == null ? "?" : issuerToken.getDSSIdAsString()) + "]";
	}

	@Override
	public String toString(String indentStr) {
		final StringWriter out = new StringWriter();
		out.append(indentStr).append("OCSPToken[");
		out.append("ProductionTime: ").append(DSSUtils.formatInternal(productionDate)).append("; ");
		out.append("ThisUpdate: ").append(DSSUtils.formatInternal(thisUpdate)).append("; ");
		out.append("NextUpdate: ").append(DSSUtils.formatInternal(nextUpdate)).append('\n');
		out.append("SignedBy: ").append(issuerToken != null ? issuerToken.getDSSIdAsString() : null).append('\n');
		indentStr += "\t";
		out.append(indentStr).append("Signature algorithm: ").append(signatureAlgorithm == null ? "?" : signatureAlgorithm.getJCEId()).append('\n');
		out.append(issuerToken != null ? issuerToken.toString(indentStr) : null).append('\n');
		final List validationExtraInfo = extraInfo.getValidationInfo();
		if (validationExtraInfo.size() > 0) {

			for (final String info : validationExtraInfo) {

				out.append('\n').append(indentStr).append("\t- ").append(info);
			}
			out.append('\n');
		}
		indentStr = indentStr.substring(1);
		out.append(indentStr).append("]");
		return out.toString();
	}

	@Override
	public byte[] getEncoded() {
		try {
			if (basicOCSPResp != null) {
				final OCSPResp ocspResp = DSSRevocationUtils.fromBasicToResp(basicOCSPResp);
				return ocspResp.getEncoded();
			} else {
				throw new DSSException("Empty OCSP response");
			}
		} catch (IOException e) {
			throw new DSSException("OCSP encoding error: " + e.getMessage(), e);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy