eu.europa.esig.dss.spi.x509.revocation.OfflineRevocationSource Maven / Gradle / Ivy
/**
* 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.spi.x509.revocation;
import eu.europa.esig.dss.enumerations.RevocationOrigin;
import eu.europa.esig.dss.enumerations.RevocationRefOrigin;
import eu.europa.esig.dss.model.identifier.EncapsulatedRevocationTokenIdentifier;
import eu.europa.esig.dss.model.identifier.TokenIdentifier;
import eu.europa.esig.dss.model.x509.CertificateToken;
import eu.europa.esig.dss.model.x509.revocation.Revocation;
import eu.europa.esig.dss.utils.Utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
/**
* Represents a revocation sources for a data obtained from an offline source (e.g. signature)
*
* @param the revocation class type (CRL/OCSP)
*/
public abstract class OfflineRevocationSource implements RevocationSource, MultipleRevocationSource {
private static final long serialVersionUID = 8270762277613989997L;
/** The map between revocation token identifiers and corresponding origins */
private final Map, Set> binaryOrigins = new HashMap<>();
/** A map between computed {@code RevocationToken}s and their origins */
private final Map, Set> tokenOrigins = new HashMap<>();
/** A map between revocation references and their origins */
private final Map, Set> referenceOrigins = new HashMap<>();
/** The use RevocationTokenRefMatcher */
private final RevocationTokenRefMatcher tokenRefMatcher;
/**
* The default constructor
*
* @param tokenRefMatcher {@link RevocationTokenRefMatcher} used to match tokens and their corresponding references
*/
protected OfflineRevocationSource(RevocationTokenRefMatcher tokenRefMatcher) {
Objects.requireNonNull(tokenRefMatcher);
this.tokenRefMatcher = tokenRefMatcher;
}
/**
* This method adds a token binary with its origin
*
* @param binary the binary token to be added
* @param origin the origin where the token has been found
*/
public void addBinary(EncapsulatedRevocationTokenIdentifier binary, RevocationOrigin origin) {
Objects.requireNonNull(binary, "The binary is null");
Objects.requireNonNull(origin, "The origin is null");
binaryOrigins.computeIfAbsent(binary, k -> new HashSet<>()).add(origin);
}
/**
* This method adds a revocation token with its origin
*
* @param token the revocation token to be added
* @param origin the origin where the token has been found
*/
public void addRevocation(RevocationToken token, RevocationOrigin origin) {
Objects.requireNonNull(token, "The token is null");
Objects.requireNonNull(origin, "The origin is null");
tokenOrigins.computeIfAbsent(token, k -> new HashSet<>()).add(origin);
}
/**
* This method adds a {@code RevocationToken} from the binary
*
* @param token the token to be added
* @param binary the binary where the token has been extracted
*/
public void addRevocation(RevocationToken token, EncapsulatedRevocationTokenIdentifier binary) {
Objects.requireNonNull(token, "The token is null");
Objects.requireNonNull(binary, "The origin is null");
Set origins = getAllRevocationBinariesWithOrigins().get(binary);
if (origins == null) {
throw new IllegalStateException(String.format("Unable to find the binary '%s'", binary.asXmlId()));
}
for (RevocationOrigin origin : origins) {
addRevocation(token, origin);
}
}
/**
* This method adds a revocation reference with its origin
*
* @param reference the revocation reference to be added
* @param origin the origin where the reference has been found
*/
public void addRevocationReference(RevocationRef reference, RevocationRefOrigin origin) {
Objects.requireNonNull(reference, "The reference is null");
Objects.requireNonNull(origin, "The origin is null");
referenceOrigins.computeIfAbsent(reference, k -> new HashSet<>()).add(origin);
}
/**
* Retrieves all found revocation binaries
*
* @return a Set of {@code EncapsulatedRevocationTokenIdentifier}
*/
public Set> getAllRevocationBinaries() {
return getAllRevocationBinariesWithOrigins().keySet();
}
/**
* Retrieves all found revocation binaries with their origins
*
* @return a Map of {@code EncapsulatedRevocationTokenIdentifier} with their
* origins
*/
public Map, Set> getAllRevocationBinariesWithOrigins() {
return binaryOrigins;
}
/**
* Retrieves a Set of all found {@code RevocationToken}
*
* @return all {@code RevocationToken}
*/
public Set> getAllRevocationTokens() {
return getAllRevocationTokensWithOrigins().keySet();
}
/**
* Returns all tokens with their origins
*
* @return a map of tokens with the different origins
*/
public Map, Set> getAllRevocationTokensWithOrigins() {
return tokenOrigins;
}
/**
* Returns a Map of unique {@code RevocationToken} based on binary (a same
* binary can cover several certificates) with their origins
*
* @return a map of tokens with the different origins
*/
public Map, Set> getUniqueRevocationTokensWithOrigins() {
Map, Set> result = new HashMap<>();
List knownIds = new ArrayList<>();
for (Entry, Set> entry : getAllRevocationTokensWithOrigins().entrySet()) {
TokenIdentifier currentId = entry.getKey().getDSSId();
if (!knownIds.contains(currentId)) {
result.put(entry.getKey(), entry.getValue());
knownIds.add(currentId);
}
}
return result;
}
/**
* Retrieves a Set of all found {@code RevocationRef}
*
* @return all {@code RevocationRef}
*/
public Set> getAllRevocationReferences() {
return getRevocationReferencesWithOrigins().keySet();
}
/**
* Returns a map of revocation references with the corresponding origins
*
* @return a map between {@link RevocationRef}s and a set of {@link RevocationRefOrigin}s
*/
protected Map, Set> getRevocationReferencesWithOrigins() {
return referenceOrigins;
}
/**
* This method returns the latest issued revocation token from a set of all revocation data found for
* the given {@code certificateToken}.
* Returns NULL, if no corresponding revocation data found for the certificate.
*
* @param certificateToken
* The {@code CertificateToken} for which the
* request is made
* @param issuerCertificateToken
* The {@code CertificateToken} which is the
* issuer of the certificateToken
* @return {@link RevocationToken}
*/
@Override
public RevocationToken getRevocationToken(CertificateToken certificateToken, CertificateToken issuerCertificateToken) {
RevocationToken latestRevocationToken = null;
final List> revocationTokens = getRevocationTokens(certificateToken, issuerCertificateToken);
if (Utils.isCollectionNotEmpty(revocationTokens)) {
for (RevocationToken revocationToken : revocationTokens) {
if (latestRevocationToken == null || (revocationToken.getThisUpdate() != null
&& latestRevocationToken.getThisUpdate().before(revocationToken.getThisUpdate()))) {
latestRevocationToken = revocationToken;
}
}
}
return latestRevocationToken;
}
/**
* Retrieves the list of all {@code EncapsulatedRevocationTokenIdentifier}s
* present in the CMS SignedData
*
* NOTE: Applicable only for CAdES revocation sources
*
* @return list of {@code EncapsulatedRevocationTokenIdentifier}s
*/
public List> getCMSSignedDataRevocationBinaries() {
return getBinariesByOrigin(RevocationOrigin.CMS_SIGNED_DATA);
}
/**
* Retrieves the list of all {@code RevocationToken}s present in the CMS
* SignedData
*
* NOTE: Applicable only for CAdES revocation sources
*
* @return list of {@code RevocationToken}s
*/
public List> getCMSSignedDataRevocationTokens() {
return getTokensByOrigin(RevocationOrigin.CMS_SIGNED_DATA);
}
/**
* Retrieves the list of all {@code EncapsulatedRevocationTokenIdentifier}s
* present in 'RevocationValues' element
*
* @return list of {@code EncapsulatedRevocationTokenIdentifier}s
*/
public List> getRevocationValuesBinaries() {
return getBinariesByOrigin(RevocationOrigin.REVOCATION_VALUES);
}
/**
* Retrieves the list of all {@code RevocationToken}s present in
* 'RevocationValues' element
*
* @return list of {@code RevocationToken}s
*/
public List> getRevocationValuesTokens() {
return getTokensByOrigin(RevocationOrigin.REVOCATION_VALUES);
}
/**
* Retrieves the list of all {@code EncapsulatedRevocationTokenIdentifier}s
* present in 'AttributeRevocationValues' element
*
* @return list of {@code EncapsulatedRevocationTokenIdentifier}s
*/
public List> getAttributeRevocationValuesBinaries() {
return getBinariesByOrigin(RevocationOrigin.ATTRIBUTE_REVOCATION_VALUES);
}
/**
* Retrieves the list of all {@code RevocationToken}s present in
* 'AttributeRevocationValues' element
*
* @return list of {@code RevocationToken}s
*/
public List> getAttributeRevocationValuesTokens() {
return getTokensByOrigin(RevocationOrigin.ATTRIBUTE_REVOCATION_VALUES);
}
/**
* Retrieves the list of all {@code EncapsulatedRevocationTokenIdentifier}s
* present in 'TimestampValidationData' element
*
* @return list of {@code EncapsulatedRevocationTokenIdentifier}s
*/
public List> getTimestampValidationDataBinaries() {
return getBinariesByOrigin(RevocationOrigin.TIMESTAMP_VALIDATION_DATA);
}
/**
* Retrieves the list of all {@code RevocationToken}s present in
* 'TimestampValidationData' element
*
* @return list of {@code RevocationToken}s
*/
public List> getTimestampValidationDataTokens() {
return getTokensByOrigin(RevocationOrigin.TIMESTAMP_VALIDATION_DATA);
}
/**
* Retrieves the list of all {@code EncapsulatedRevocationTokenIdentifier}s
* present in 'AnyValidationData' element
*
* @return list of {@code EncapsulatedRevocationTokenIdentifier}s
*/
public List> getAnyValidationDataBinaries() {
return getBinariesByOrigin(RevocationOrigin.ANY_VALIDATION_DATA);
}
/**
* Retrieves the list of all {@code RevocationToken}s present in
* 'AnyValidationData' element
*
* @return list of {@code RevocationToken}s
*/
public List> getAnyValidationDataTokens() {
return getTokensByOrigin(RevocationOrigin.ANY_VALIDATION_DATA);
}
/**
* Retrieves the list of all {@code EncapsulatedRevocationTokenIdentifier}s
* present in 'DSS' dictionary
*
* NOTE: Applicable only for PAdES revocation source
*
* @return list of {@code RevocationToken}s
*/
public List> getDSSDictionaryBinaries() {
return getBinariesByOrigin(RevocationOrigin.DSS_DICTIONARY);
}
/**
* Retrieves the list of all {@code RevocationToken}s present in 'DSS'
* dictionary
*
* NOTE: Applicable only for PAdES revocation source
*
* @return list of {@code RevocationToken}s
*/
public List> getDSSDictionaryTokens() {
return getTokensByOrigin(RevocationOrigin.DSS_DICTIONARY);
}
/**
* Retrieves the list of all {@code EncapsulatedRevocationTokenIdentifier}s
* present in 'VRI' dictionary
*
* NOTE: Applicable only for PAdES revocation source
*
* @return list of {@code RevocationToken}s
*/
public List> getVRIDictionaryBinaries() {
return getBinariesByOrigin(RevocationOrigin.VRI_DICTIONARY);
}
/**
* Retrieves the list of all {@code RevocationToken}s present in 'VRI'
* dictionary
*
* NOTE: Applicable only for PAdES revocation source
*
* @return list of {@code RevocationToken}s
*/
public List> getVRIDictionaryTokens() {
return getTokensByOrigin(RevocationOrigin.VRI_DICTIONARY);
}
/**
* Retrieves the list of all {@code EncapsulatedRevocationTokenIdentifier}s
* present in the ADBE signed attribute
*
* @return list of {@code EncapsulatedRevocationTokenIdentifier}s
*/
public List> getADBERevocationValuesBinaries() {
return getBinariesByOrigin(RevocationOrigin.ADBE_REVOCATION_INFO_ARCHIVAL);
}
/**
* Retrieves the list of all {@code RevocationToken}s present in
* the ADBE signed attribute
*
* NOTE: Applicable only for PAdES revocation source
*
* @return list of {@code RevocationToken}s
*/
public List> getADBERevocationValuesTokens() {
return getTokensByOrigin(RevocationOrigin.ADBE_REVOCATION_INFO_ARCHIVAL);
}
/**
* Retrieves the list of all {@code RevocationRef}s present in the signature
* 'complete-revocation-references' attribute (used in CAdES and XAdES)
*
* @return list of {@code RevocationRef}s
*/
public List> getCompleteRevocationRefs() {
return getReferencesByOrigin(RevocationRefOrigin.COMPLETE_REVOCATION_REFS);
}
/**
* Retrieves the list of all {@code RevocationRef}s present in the signature
* 'attribute-revocation-references' attribute (used in CAdES and XAdES)
*
* @return list of {@code RevocationRef}s
*/
public List> getAttributeRevocationRefs() {
return getReferencesByOrigin(RevocationRefOrigin.ATTRIBUTE_REVOCATION_REFS);
}
/**
* Retrieves a Map of found {@code RevocationRef} with their origins for the
* given {@code RevocationToken}
*
* @param revocationToken {@code RevocationToken} to get references for
* @return Map of {@code RevocationRef}s with their origins
*/
public Map, Set> findRefsAndOriginsForRevocationToken(RevocationToken revocationToken) {
Map, Set> result = new HashMap<>();
for (Entry, Set> entry : getRevocationReferencesWithOrigins().entrySet()) {
RevocationRef currentReference = entry.getKey();
if (tokenRefMatcher.match(revocationToken, currentReference)) {
result.put(entry.getKey(), entry.getValue());
}
}
return result;
}
/**
* Retrieves a Map of orphan {@code RevocationRef} with their
* {@code RevocationRefOrigin}s for a given
* {@code EncapsulatedRevocationTokenIdentifier}
*
* @param identifier {@link EncapsulatedRevocationTokenIdentifier}
* @return a Map of orphan references with their origins
*/
public Map, Set> findRefsAndOriginsForBinary(
EncapsulatedRevocationTokenIdentifier identifier) {
Map, Set> result = new HashMap<>();
for (Entry, Set> entry : getRevocationReferencesWithOrigins().entrySet()) {
RevocationRef currentReference = entry.getKey();
if (tokenRefMatcher.match(identifier, currentReference)) {
result.put(currentReference, entry.getValue());
}
}
return result;
}
/**
* Returns the linked {@code EncapsulatedRevocationTokenIdentifier} for a given
* {@code RevocationRef}
*
* @param ref the {@code RevocationRef} to find
* @return the related {@code EncapsulatedRevocationTokenIdentifier}
*/
public EncapsulatedRevocationTokenIdentifier findBinaryForReference(RevocationRef ref) {
for (EncapsulatedRevocationTokenIdentifier binary : getAllRevocationBinariesWithOrigins().keySet()) {
if (tokenRefMatcher.match(binary, ref)) {
return binary;
}
}
return null;
}
/**
* Retrieves a Map of orphan {@code RevocationRef} with their
* {@code RevocationRefOrigin}s
*
* @return a Map of orphan references with their origins
*/
public Map, Set> getOrphanRevocationReferencesWithOrigins() {
Map, Set> result = new HashMap<>();
for (Entry, Set> entry : getRevocationReferencesWithOrigins().entrySet()) {
RevocationRef ref = entry.getKey();
if (isOrphan(ref)) {
result.put(ref, entry.getValue());
}
}
return result;
}
/**
* This method verifies if a given {@code RevocationRef} is an orphan (not
* linked to a complete {@code RevocationToken}
*
* @param reference the reference to be tested
*
* @return true if the given reference is an orphan
*/
public boolean isOrphan(RevocationRef reference) {
for (RevocationToken token : getAllRevocationTokensWithOrigins().keySet()) {
if (tokenRefMatcher.match(token, reference)) {
return false;
}
}
return true;
}
/**
* Retrieves the Set of tokens which have a reference
*
* @return a Set of Token Identifiers which are referenced
*/
public Set> getAllReferencedRevocationBinaries() {
Set> result = new HashSet<>();
for (RevocationRef reference : getRevocationReferencesWithOrigins().keySet()) {
for (EncapsulatedRevocationTokenIdentifier identifier : getAllRevocationBinariesWithOrigins().keySet()) {
if (tokenRefMatcher.match(identifier, reference)) {
result.add(identifier);
}
}
}
return result;
}
/**
* This method checks if the revocation source is empty
*
* @return true if the source is empty
*/
public boolean isEmpty() {
return Utils.isMapEmpty(getAllRevocationBinariesWithOrigins())
&& Utils.isMapEmpty(getAllRevocationTokensWithOrigins())
&& Utils.isMapEmpty(getRevocationReferencesWithOrigins());
}
/**
* Retrieves a List of {@code EncapsulatedRevocationTokenIdentifier} for a given
* {@code RevocationOrigin}
*
* @param origin the origin to find
*
* @return a list of {@code EncapsulatedRevocationTokenIdentifier}
*/
private List> getBinariesByOrigin(RevocationOrigin origin) {
List> result = new ArrayList<>();
for (Entry, Set> entry : getAllRevocationBinariesWithOrigins().entrySet()) {
Set currentOrigins = entry.getValue();
if (Utils.isCollectionNotEmpty(currentOrigins) && currentOrigins.contains(origin)) {
result.add(entry.getKey());
}
}
return result;
}
/**
* Retrieves a List of {@code RevocationToken} for a given
* {@code RevocationOrigin}
*
* @param origin the origin to find
*
* @return a list of {@code RevocationToken}
*/
private List> getTokensByOrigin(RevocationOrigin origin) {
List> result = new ArrayList<>();
for (Entry, Set> entry : getAllRevocationTokensWithOrigins().entrySet()) {
Set currentOrigins = entry.getValue();
if (Utils.isCollectionNotEmpty(currentOrigins) && currentOrigins.contains(origin)) {
result.add(entry.getKey());
}
}
return result;
}
/**
* Retrieves a List of {@code RevocationRef} for a given
* {@code RevocationRefOrigin}
*
* @param origin the origin to find
*
* @return a list of {@code RevocationRef}
*/
private List> getReferencesByOrigin(RevocationRefOrigin origin) {
List> result = new ArrayList<>();
for (Entry, Set> entry : getRevocationReferencesWithOrigins().entrySet()) {
Set currentOrigins = entry.getValue();
if (Utils.isCollectionNotEmpty(currentOrigins) && currentOrigins.contains(origin)) {
result.add(entry.getKey());
}
}
return result;
}
}