Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pkix/src/main/java/org/spongycastle/dvcs')
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java32
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java48
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java34
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java40
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java20
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java28
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java22
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java20
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java134
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java131
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java38
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java237
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java74
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java38
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java35
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java45
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java18
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java76
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java51
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java49
-rw-r--r--pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java66
21 files changed, 1236 insertions, 0 deletions
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java
new file mode 100644
index 00000000..e48dd2a3
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java
@@ -0,0 +1,32 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.ServiceType;
+
+/**
+ * Builder of CCPD requests (Certify Claim of Possession of Data).
+ */
+public class CCPDRequestBuilder
+ extends DVCSRequestBuilder
+{
+ public CCPDRequestBuilder()
+ {
+ super(new DVCSRequestInformationBuilder(ServiceType.CCPD));
+ }
+
+ /**
+ * Builds CCPD request.
+ *
+ * @param messageImprint - the message imprint to include.
+ * @return
+ * @throws DVCSException
+ */
+ public DVCSRequest build(MessageImprint messageImprint)
+ throws DVCSException
+ {
+ Data data = new Data(messageImprint.toASN1Structure());
+
+ return createDVCRequest(data);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java
new file mode 100644
index 00000000..202dd774
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java
@@ -0,0 +1,48 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.Data;
+
+/**
+ * Data piece of DVCRequest for CCPD service (Certify Claim of Possession of Data).
+ * It contains CCPD-specific selector interface.
+ * <p/>
+ * This objects are constructed internally,
+ * to build DVCS request to CCPD service use CCPDRequestBuilder.
+ */
+public class CCPDRequestData
+ extends DVCSRequestData
+{
+ /**
+ * Construct from corresponding ASN.1 Data structure.
+ * Note, that data should have messageImprint choice,
+ * otherwise DVCSConstructionException is thrown.
+ *
+ * @param data
+ * @throws DVCSConstructionException
+ */
+ CCPDRequestData(Data data)
+ throws DVCSConstructionException
+ {
+ super(data);
+ initDigest();
+ }
+
+ private void initDigest()
+ throws DVCSConstructionException
+ {
+ if (data.getMessageImprint() == null)
+ {
+ throw new DVCSConstructionException("DVCSRequest.data.messageImprint should be specified for CCPD service");
+ }
+ }
+
+ /**
+ * Get MessageImprint value
+ *
+ * @return
+ */
+ public MessageImprint getMessageImprint()
+ {
+ return new MessageImprint(data.getMessageImprint());
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java
new file mode 100644
index 00000000..0b0b8189
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java
@@ -0,0 +1,34 @@
+package org.spongycastle.dvcs;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.ServiceType;
+
+/**
+ * Builder of DVCSRequests to CPD service (Certify Possession of Data).
+ */
+public class CPDRequestBuilder
+ extends DVCSRequestBuilder
+{
+ public CPDRequestBuilder()
+ {
+ super(new DVCSRequestInformationBuilder(ServiceType.CPD));
+ }
+
+ /**
+ * Build CPD request.
+ *
+ * @param messageBytes - data to be certified
+ * @return
+ * @throws DVCSException
+ */
+ public DVCSRequest build(byte[] messageBytes)
+ throws DVCSException, IOException
+ {
+ Data data = new Data(messageBytes);
+
+ return createDVCRequest(data);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java
new file mode 100644
index 00000000..a7c1f5a8
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java
@@ -0,0 +1,40 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.Data;
+
+/**
+ * Data piece of DVCRequest for CPD service (Certify Possession of Data).
+ * It contains CPD-specific selector interface.
+ * <p/>
+ * This objects are constructed internally,
+ * to build DVCS request to CPD service use CPDRequestBuilder.
+ */
+public class CPDRequestData
+ extends DVCSRequestData
+{
+ CPDRequestData(Data data)
+ throws DVCSConstructionException
+ {
+ super(data);
+ initMessage();
+ }
+
+ private void initMessage()
+ throws DVCSConstructionException
+ {
+ if (data.getMessage() == null)
+ {
+ throw new DVCSConstructionException("DVCSRequest.data.message should be specified for CPD service");
+ }
+ }
+
+ /**
+ * Get contained message (data to be certified).
+ *
+ * @return
+ */
+ public byte[] getMessage()
+ {
+ return data.getMessage().getOctets();
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java
new file mode 100644
index 00000000..73e6b0dc
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java
@@ -0,0 +1,20 @@
+package org.spongycastle.dvcs;
+
+/**
+ * Exception thrown when failed to initialize some DVCS-related staff.
+ */
+public class DVCSConstructionException
+ extends DVCSException
+{
+ private static final long serialVersionUID = 660035299653583980L;
+
+ public DVCSConstructionException(String message)
+ {
+ super(message);
+ }
+
+ public DVCSConstructionException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java
new file mode 100644
index 00000000..5aa8f51e
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java
@@ -0,0 +1,28 @@
+package org.spongycastle.dvcs;
+
+/**
+ * General DVCSException.
+ */
+public class DVCSException
+ extends Exception
+{
+ private static final long serialVersionUID = 389345256020131488L;
+
+ private Throwable cause;
+
+ public DVCSException(String message)
+ {
+ super(message);
+ }
+
+ public DVCSException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java
new file mode 100644
index 00000000..6758f359
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java
@@ -0,0 +1,22 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.ContentInfo;
+
+public abstract class DVCSMessage
+{
+ private final ContentInfo contentInfo;
+
+ protected DVCSMessage(ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return contentInfo.getContentType();
+ }
+
+ public abstract ASN1Encodable getContent();
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java
new file mode 100644
index 00000000..e1452576
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java
@@ -0,0 +1,20 @@
+package org.spongycastle.dvcs;
+
+/**
+ * DVCS parsing exception - thrown when failed to parse DVCS message.
+ */
+public class DVCSParsingException
+ extends DVCSException
+{
+ private static final long serialVersionUID = -7895880961377691266L;
+
+ public DVCSParsingException(String message)
+ {
+ super(message);
+ }
+
+ public DVCSParsingException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java
new file mode 100644
index 00000000..f8658ab5
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java
@@ -0,0 +1,134 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.SignedData;
+import org.spongycastle.asn1.dvcs.DVCSObjectIdentifiers;
+import org.spongycastle.asn1.dvcs.ServiceType;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cms.CMSSignedData;
+
+/**
+ * DVCRequest is general request to DVCS (RFC 3029).
+ * It represents requests for all types of services.
+ * Requests for different services differ in DVCData structure.
+ */
+public class DVCSRequest
+ extends DVCSMessage
+{
+ private org.spongycastle.asn1.dvcs.DVCSRequest asn1;
+ private DVCSRequestInfo reqInfo;
+ private DVCSRequestData data;
+
+ /**
+ * Constructs DVCRequest from CMS SignedData object.
+ *
+ * @param signedData the CMS SignedData object containing the request
+ * @throws DVCSConstructionException
+ */
+ public DVCSRequest(CMSSignedData signedData)
+ throws DVCSConstructionException
+ {
+ this(SignedData.getInstance(signedData.toASN1Structure().getContent()).getEncapContentInfo());
+ }
+
+ /**
+ * Construct a DVCS Request from a ContentInfo
+ *
+ * @param contentInfo the contentInfo representing the DVCSRequest
+ * @throws DVCSConstructionException
+ */
+ public DVCSRequest(ContentInfo contentInfo)
+ throws DVCSConstructionException
+ {
+ super(contentInfo);
+
+ if (!DVCSObjectIdentifiers.id_ct_DVCSRequestData.equals(contentInfo.getContentType()))
+ {
+ throw new DVCSConstructionException("ContentInfo not a DVCS Request");
+ }
+
+ try
+ {
+ if (contentInfo.getContent().toASN1Primitive() instanceof ASN1Sequence)
+ {
+ this.asn1 = org.spongycastle.asn1.dvcs.DVCSRequest.getInstance(contentInfo.getContent());
+ }
+ else
+ {
+ this.asn1 = org.spongycastle.asn1.dvcs.DVCSRequest.getInstance(ASN1OctetString.getInstance(contentInfo.getContent()).getOctets());
+ }
+ }
+ catch (Exception e)
+ {
+ throw new DVCSConstructionException("Unable to parse content: " + e.getMessage(), e);
+ }
+
+ this.reqInfo = new DVCSRequestInfo(asn1.getRequestInformation());
+
+ int service = reqInfo.getServiceType();
+ if (service == ServiceType.CPD.getValue().intValue())
+ {
+ this.data = new CPDRequestData(asn1.getData());
+ }
+ else if (service == ServiceType.VSD.getValue().intValue())
+ {
+ this.data = new VSDRequestData(asn1.getData());
+ }
+ else if (service == ServiceType.VPKC.getValue().intValue())
+ {
+ this.data = new VPKCRequestData(asn1.getData());
+ }
+ else if (service == ServiceType.CCPD.getValue().intValue())
+ {
+ this.data = new CCPDRequestData(asn1.getData());
+ }
+ else
+ {
+ throw new DVCSConstructionException("Unknown service type: " + service);
+ }
+ }
+
+ /**
+ * Return the ASN.1 DVCSRequest structure making up the body of this request.
+ *
+ * @return an org.spongycastle.asn1.dvcs.DVCSRequest object.
+ */
+ public ASN1Encodable getContent()
+ {
+ return asn1;
+ }
+
+ /**
+ * Get RequestInformation envelope.
+ *
+ * @return the request info object.
+ */
+ public DVCSRequestInfo getRequestInfo()
+ {
+ return reqInfo;
+ }
+
+ /**
+ * Get data of DVCRequest.
+ * Depending on type of the request it could be different subclasses of DVCRequestData.
+ *
+ * @return the request Data object.
+ */
+ public DVCSRequestData getData()
+ {
+ return data;
+ }
+
+ /**
+ * Get the transaction identifier of request.
+ *
+ * @return the GeneralName representing the Transaction Identifier.
+ */
+ public GeneralName getTransactionIdentifier()
+ {
+ return asn1.getTransactionIdentifier();
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java
new file mode 100644
index 00000000..f1982b91
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java
@@ -0,0 +1,131 @@
+package org.spongycastle.dvcs;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.dvcs.DVCSObjectIdentifiers;
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+
+/**
+ * Common base class for client DVCRequest builders.
+ * This class aims at DVCSRequestInformation and TransactionIdentifier construction,
+ * and its subclasses - for Data field construction (as it is specific for the requested service).
+ */
+public abstract class DVCSRequestBuilder
+{
+ private final ExtensionsGenerator extGenerator = new ExtensionsGenerator();
+ private final CMSSignedDataGenerator signedDataGen = new CMSSignedDataGenerator();
+
+ protected final DVCSRequestInformationBuilder requestInformationBuilder;
+
+ protected DVCSRequestBuilder(DVCSRequestInformationBuilder requestInformationBuilder)
+ {
+ this.requestInformationBuilder = requestInformationBuilder;
+ }
+
+ /**
+ * Set a nonce for this request,
+ *
+ * @param nonce
+ */
+ public void setNonce(BigInteger nonce)
+ {
+ requestInformationBuilder.setNonce(nonce);
+ }
+
+ /**
+ * Set requester name.
+ *
+ * @param requester
+ */
+ public void setRequester(GeneralName requester)
+ {
+ requestInformationBuilder.setRequester(requester);
+ }
+
+ /**
+ * Set DVCS name to generated requests.
+ *
+ * @param dvcs
+ */
+ public void setDVCS(GeneralName dvcs)
+ {
+ requestInformationBuilder.setDVCS(dvcs);
+ }
+
+ /**
+ * Set DVCS name to generated requests.
+ *
+ * @param dvcs
+ */
+ public void setDVCS(GeneralNames dvcs)
+ {
+ requestInformationBuilder.setDVCS(dvcs);
+ }
+
+ /**
+ * Set data location to generated requests.
+ *
+ * @param dataLocation
+ */
+ public void setDataLocations(GeneralName dataLocation)
+ {
+ requestInformationBuilder.setDataLocations(dataLocation);
+ }
+
+ /**
+ * Set data location to generated requests.
+ *
+ * @param dataLocations
+ */
+ public void setDataLocations(GeneralNames dataLocations)
+ {
+ requestInformationBuilder.setDataLocations(dataLocations);
+ }
+
+ /**
+ * Add a given extension field.
+ *
+ * @param oid the OID defining the extension type.
+ * @param isCritical true if the extension is critical, false otherwise.
+ * @param value the ASN.1 structure that forms the extension's value.
+ * @return this builder object.
+ * @throws DVCSException if there is an issue encoding the extension for adding.
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean isCritical,
+ ASN1Encodable value)
+ throws DVCSException
+ {
+ try
+ {
+ extGenerator.addExtension(oid, isCritical, value);
+ }
+ catch (IOException e)
+ {
+ throw new DVCSException("cannot encode extension: " + e.getMessage(), e);
+ }
+ }
+
+ protected DVCSRequest createDVCRequest(Data data)
+ throws DVCSException
+ {
+ if (!extGenerator.isEmpty())
+ {
+ requestInformationBuilder.setExtensions(extGenerator.generate());
+ }
+
+ org.spongycastle.asn1.dvcs.DVCSRequest request = new org.spongycastle.asn1.dvcs.DVCSRequest(requestInformationBuilder.build(), data);
+
+ return new DVCSRequest(new ContentInfo(DVCSObjectIdentifiers.id_ct_DVCSRequestData, request));
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java
new file mode 100644
index 00000000..35cdd325
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java
@@ -0,0 +1,38 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.Data;
+
+/**
+ * Data piece of DVCRequest object (DVCS Data structure).
+ * Its contents depend on the service type.
+ * Its subclasses define the service-specific interface.
+ * <p/>
+ * The concrete objects of DVCRequestData are created by buildDVCRequestData static method.
+ */
+public abstract class DVCSRequestData
+{
+ /**
+ * The underlying data object is accessible by subclasses.
+ */
+ protected Data data;
+
+ /**
+ * The constructor is accessible by subclasses.
+ *
+ * @param data
+ */
+ protected DVCSRequestData(Data data)
+ {
+ this.data = data;
+ }
+
+ /**
+ * Convert to ASN.1 structure (Data).
+ *
+ * @return
+ */
+ public Data toASN1Structure()
+ {
+ return data;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java
new file mode 100644
index 00000000..1f51e3e6
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java
@@ -0,0 +1,237 @@
+package org.spongycastle.dvcs;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.dvcs.DVCSRequestInformation;
+import org.spongycastle.asn1.dvcs.DVCSTime;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.util.Arrays;
+
+/**
+ * Information piece of DVCS requests.
+ * It is common for all types of DVCS requests.
+ */
+public class DVCSRequestInfo
+{
+ private DVCSRequestInformation data;
+
+ /**
+ * Constructs DVCRequestInfo from byte array (DER encoded DVCSRequestInformation).
+ *
+ * @param in
+ */
+ public DVCSRequestInfo(byte[] in)
+ {
+ this(DVCSRequestInformation.getInstance(in));
+ }
+
+ /**
+ * Constructs DVCRequestInfo from DVCSRequestInformation ASN.1 structure.
+ *
+ * @param data
+ */
+ public DVCSRequestInfo(DVCSRequestInformation data)
+ {
+ this.data = data;
+ }
+
+ /**
+ * Converts to corresponding ASN.1 structure (DVCSRequestInformation).
+ *
+ * @return
+ */
+ public DVCSRequestInformation toASN1Structure()
+ {
+ return data;
+ }
+
+ //
+ // DVCRequestInfo selector interface
+ //
+
+ /**
+ * Get DVCS version of request.
+ *
+ * @return
+ */
+ public int getVersion()
+ {
+ return data.getVersion();
+ }
+
+ /**
+ * Get requested service type.
+ *
+ * @return one of CPD, VSD, VPKC, CCPD (see constants).
+ */
+ public int getServiceType()
+ {
+ return data.getService().getValue().intValue();
+ }
+
+ /**
+ * Get nonce if it is set.
+ * Note: this field can be set (if not present) or extended (if present) by DVCS.
+ *
+ * @return nonce value, or null if it is not set.
+ */
+ public BigInteger getNonce()
+ {
+ return data.getNonce();
+ }
+
+ /**
+ * Get request generation time if it is set.
+ *
+ * @return time of request, or null if it is not set.
+ * @throws DVCSParsingException if a request time is present but cannot be extracted.
+ */
+ public Date getRequestTime()
+ throws DVCSParsingException
+ {
+ DVCSTime time = data.getRequestTime();
+
+ if (time == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ if (time.getGenTime() != null)
+ {
+ return time.getGenTime().getDate();
+ }
+ else
+ {
+ TimeStampToken token = new TimeStampToken(time.getTimeStampToken());
+
+ return token.getTimeStampInfo().getGenTime();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new DVCSParsingException("unable to extract time: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Get names of requesting entity, if set.
+ *
+ * @return
+ */
+ public GeneralNames getRequester()
+ {
+ return data.getRequester();
+ }
+
+ /**
+ * Get policy, under which the validation is requested.
+ *
+ * @return policy identifier or null, if any policy is acceptable.
+ */
+ public PolicyInformation getRequestPolicy()
+ {
+ if (data.getRequestPolicy() != null)
+ {
+ return data.getRequestPolicy();
+ }
+ return null;
+ }
+
+ /**
+ * Get names of DVCS servers.
+ * Note: this field can be set by DVCS.
+ *
+ * @return
+ */
+ public GeneralNames getDVCSNames()
+ {
+ return data.getDVCS();
+ }
+
+ /**
+ * Get data locations, where the copy of request Data can be obtained.
+ * Note: the exact meaning of field is up to applications.
+ * Note: this field can be set by DVCS.
+ *
+ * @return
+ */
+ public GeneralNames getDataLocations()
+ {
+ return data.getDataLocations();
+ }
+
+ /**
+ * Compares two DVCRequestInfo structures: one from DVCRequest, and one from DVCResponse.
+ * This function implements RFC 3029, 9.1 checks of reqInfo.
+ *
+ * @param requestInfo - DVCRequestInfo of DVCRequest
+ * @param responseInfo - DVCRequestInfo of DVCResponse
+ * @return true if server's requestInfo matches client's requestInfo
+ */
+ public static boolean validate(DVCSRequestInfo requestInfo, DVCSRequestInfo responseInfo)
+ {
+ // RFC 3029, 9.1
+ // The DVCS MAY modify the fields:
+ // 'dvcs', 'requester', 'dataLocations', and 'nonce' of the ReqInfo structure.
+
+ DVCSRequestInformation clientInfo = requestInfo.data;
+ DVCSRequestInformation serverInfo = responseInfo.data;
+
+ if (clientInfo.getVersion() != serverInfo.getVersion())
+ {
+ return false;
+ }
+ if (!clientEqualsServer(clientInfo.getService(), serverInfo.getService()))
+ {
+ return false;
+ }
+ if (!clientEqualsServer(clientInfo.getRequestTime(), serverInfo.getRequestTime()))
+ {
+ return false;
+ }
+ if (!clientEqualsServer(clientInfo.getRequestPolicy(), serverInfo.getRequestPolicy()))
+ {
+ return false;
+ }
+ if (!clientEqualsServer(clientInfo.getExtensions(), serverInfo.getExtensions()))
+ {
+ return false;
+ }
+
+ // RFC 3029, 9.1. The only modification allowed to a 'nonce'
+ // is the inclusion of a new field if it was not present,
+ // or to concatenate other data to the end (right) of an existing value.
+
+ if (clientInfo.getNonce() != null)
+ {
+ if (serverInfo.getNonce() == null)
+ {
+ return false;
+ }
+ byte[] clientNonce = clientInfo.getNonce().toByteArray();
+ byte[] serverNonce = serverInfo.getNonce().toByteArray();
+ if (serverNonce.length < clientNonce.length)
+ {
+ return false;
+ }
+ if (!Arrays.areEqual(clientNonce, Arrays.copyOfRange(serverNonce, 0, clientNonce.length)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // null-protected compare of any two objects
+ private static boolean clientEqualsServer(Object client, Object server)
+ {
+ return (client == null && server == null) || (client != null && client.equals(server));
+ }
+}
+
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java
new file mode 100644
index 00000000..f7185519
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java
@@ -0,0 +1,74 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.SignedData;
+import org.spongycastle.asn1.dvcs.DVCSObjectIdentifiers;
+import org.spongycastle.cms.CMSSignedData;
+
+/**
+ * DVCResponse is general response to DVCS (RFC 3029).
+ * It represents responses for all types of services.
+ */
+public class DVCSResponse
+ extends DVCSMessage
+{
+ private org.spongycastle.asn1.dvcs.DVCSResponse asn1;
+
+ /**
+ * Constructs DVCRequest from CMS SignedData object.
+ *
+ * @param signedData the CMS SignedData object containing the request
+ * @throws org.spongycastle.dvcs.DVCSConstructionException
+ */
+ public DVCSResponse(CMSSignedData signedData)
+ throws DVCSConstructionException
+ {
+ this(SignedData.getInstance(signedData.toASN1Structure().getContent()).getEncapContentInfo());
+ }
+
+ /**
+ * Construct a DVCS Request from a ContentInfo
+ *
+ * @param contentInfo the contentInfo representing the DVCSRequest
+ * @throws org.spongycastle.dvcs.DVCSConstructionException
+ */
+ public DVCSResponse(ContentInfo contentInfo)
+ throws DVCSConstructionException
+ {
+ super(contentInfo);
+
+ if (!DVCSObjectIdentifiers.id_ct_DVCSResponseData.equals(contentInfo.getContentType()))
+ {
+ throw new DVCSConstructionException("ContentInfo not a DVCS Request");
+ }
+
+ try
+ {
+ if (contentInfo.getContent().toASN1Primitive() instanceof ASN1Sequence)
+ {
+ this.asn1 = org.spongycastle.asn1.dvcs.DVCSResponse.getInstance(contentInfo.getContent());
+ }
+ else
+ {
+ this.asn1 = org.spongycastle.asn1.dvcs.DVCSResponse.getInstance(ASN1OctetString.getInstance(contentInfo.getContent()).getOctets());
+ }
+ }
+ catch (Exception e)
+ {
+ throw new DVCSConstructionException("Unable to parse content: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Return the ASN.1 DVCSResponse structure making up the body of this response.
+ *
+ * @return an org.spongycastle.asn1.dvcs.DVCSResponse object.
+ */
+ public ASN1Encodable getContent()
+ {
+ return asn1;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java b/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java
new file mode 100644
index 00000000..c9793880
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java
@@ -0,0 +1,38 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.x509.DigestInfo;
+
+public class MessageImprint
+{
+ private final DigestInfo messageImprint;
+
+ public MessageImprint(DigestInfo messageImprint)
+ {
+ this.messageImprint = messageImprint;
+ }
+
+ public DigestInfo toASN1Structure()
+ {
+ return messageImprint;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (o instanceof MessageImprint)
+ {
+ return messageImprint.equals(((MessageImprint)o).messageImprint);
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return messageImprint.hashCode();
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java
new file mode 100644
index 00000000..f7dc987e
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java
@@ -0,0 +1,35 @@
+package org.spongycastle.dvcs;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.operator.DigestCalculator;
+
+public class MessageImprintBuilder
+{
+ private final DigestCalculator digestCalculator;
+
+ public MessageImprintBuilder(DigestCalculator digestCalculator)
+ {
+ this.digestCalculator = digestCalculator;
+ }
+
+ public MessageImprint build(byte[] message)
+ throws DVCSException
+ {
+ try
+ {
+ OutputStream dOut = digestCalculator.getOutputStream();
+
+ dOut.write(message);
+
+ dOut.close();
+
+ return new MessageImprint(new DigestInfo(digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest()));
+ }
+ catch (Exception e)
+ {
+ throw new DVCSException("unable to build MessageImprint: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java b/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java
new file mode 100644
index 00000000..2378bcf2
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java
@@ -0,0 +1,45 @@
+package org.spongycastle.dvcs;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+
+public class SignedDVCSMessageGenerator
+{
+ private final CMSSignedDataGenerator signedDataGen;
+
+ public SignedDVCSMessageGenerator(CMSSignedDataGenerator signedDataGen)
+ {
+ this.signedDataGen = signedDataGen;
+ }
+
+ /**
+ * Creates a CMSSignedData object containing the passed in DVCSMessage
+ *
+ * @param message the request to be signed.
+ * @return an encapsulating SignedData object.
+ * @throws DVCSException in the event of failure to encode the request or sign it.
+ */
+ public CMSSignedData build(DVCSMessage message)
+ throws DVCSException
+ {
+ try
+ {
+ byte[] encapsulatedData = message.getContent().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+
+ return signedDataGen.generate(new CMSProcessableByteArray(message.getContentType(), encapsulatedData), true);
+ }
+ catch (CMSException e)
+ {
+ throw new DVCSException("Could not sign DVCS request", e);
+ }
+ catch (IOException e)
+ {
+ throw new DVCSException("Could not encode DVCS request", e);
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java b/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java
new file mode 100644
index 00000000..d45714f3
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java
@@ -0,0 +1,18 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.TargetEtcChain;
+
+public class TargetChain
+{
+ private final TargetEtcChain certs;
+
+ public TargetChain(TargetEtcChain certs)
+ {
+ this.certs = certs;
+ }
+
+ public TargetEtcChain toASN1Structure()
+ {
+ return certs;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java
new file mode 100644
index 00000000..9a68b7d3
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java
@@ -0,0 +1,76 @@
+package org.spongycastle.dvcs;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.spongycastle.asn1.dvcs.CertEtcToken;
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.DVCSTime;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.ServiceType;
+import org.spongycastle.asn1.dvcs.TargetEtcChain;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.X509CertificateHolder;
+
+/**
+ * Builder of DVC requests to VPKC service (Verify Public Key Certificates).
+ */
+public class VPKCRequestBuilder
+ extends DVCSRequestBuilder
+{
+ private List chains = new ArrayList();
+
+ public VPKCRequestBuilder()
+ {
+ super(new DVCSRequestInformationBuilder(ServiceType.VPKC));
+ }
+
+ /**
+ * Adds a TargetChain representing a X.509 certificate to the request.
+ *
+ * @param cert the certificate to be added
+ */
+ public void addTargetChain(X509CertificateHolder cert)
+ {
+ chains.add(new TargetEtcChain(new CertEtcToken(CertEtcToken.TAG_CERTIFICATE, cert.toASN1Structure())));
+ }
+
+ /**
+ * Adds a TargetChain representing a single X.509 Extension to the request
+ *
+ * @param extension the extension to be added.
+ */
+ public void addTargetChain(Extension extension)
+ {
+ chains.add(new TargetEtcChain(new CertEtcToken(extension)));
+ }
+
+ /**
+ * Adds a X.509 certificate to the request.
+ *
+ * @param targetChain the CertChain object to be added.
+ */
+ public void addTargetChain(TargetChain targetChain)
+ {
+ chains.add(targetChain.toASN1Structure());
+ }
+
+ public void setRequestTime(Date requestTime)
+ {
+ requestInformationBuilder.setRequestTime(new DVCSTime(requestTime));
+ }
+
+ /**
+ * Build DVCS request to VPKC service.
+ *
+ * @throws DVCSException
+ */
+ public DVCSRequest build()
+ throws DVCSException
+ {
+ Data data = new Data((TargetEtcChain[])chains.toArray(new TargetEtcChain[chains.size()]));
+
+ return createDVCRequest(data);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java
new file mode 100644
index 00000000..561f93bf
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java
@@ -0,0 +1,51 @@
+package org.spongycastle.dvcs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.TargetEtcChain;
+
+/**
+ * Data piece of DVCS request to VPKC service (Verify Public Key Certificates).
+ * It contains VPKC-specific interface.
+ * <p/>
+ * This objects are constructed internally,
+ * to build DVCS request to VPKC service use VPKCRequestBuilder.
+ */
+public class VPKCRequestData
+ extends DVCSRequestData
+{
+ private List chains;
+
+ VPKCRequestData(Data data)
+ throws DVCSConstructionException
+ {
+ super(data);
+
+ TargetEtcChain[] certs = data.getCerts();
+
+ if (certs == null)
+ {
+ throw new DVCSConstructionException("DVCSRequest.data.certs should be specified for VPKC service");
+ }
+
+ chains = new ArrayList(certs.length);
+
+ for (int i = 0; i != certs.length; i++)
+ {
+ chains.add(new TargetChain(certs[i]));
+ }
+ }
+
+ /**
+ * Get contained certs choice data..
+ *
+ * @return a list of CertChain objects.
+ */
+ public List getCerts()
+ {
+ return Collections.unmodifiableList(chains);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java
new file mode 100644
index 00000000..f2f7df54
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java
@@ -0,0 +1,49 @@
+package org.spongycastle.dvcs;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.DVCSTime;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.ServiceType;
+import org.spongycastle.cms.CMSSignedData;
+
+/**
+ * Builder of DVCS requests to VSD service (Verify Signed Document).
+ */
+public class VSDRequestBuilder
+ extends DVCSRequestBuilder
+{
+ public VSDRequestBuilder()
+ {
+ super(new DVCSRequestInformationBuilder(ServiceType.VSD));
+ }
+
+ public void setRequestTime(Date requestTime)
+ {
+ requestInformationBuilder.setRequestTime(new DVCSTime(requestTime));
+ }
+
+ /**
+ * Build VSD request from CMS SignedData object.
+ *
+ * @param document
+ * @return
+ * @throws DVCSException
+ */
+ public DVCSRequest build(CMSSignedData document)
+ throws DVCSException
+ {
+ try
+ {
+ Data data = new Data(document.getEncoded());
+
+ return createDVCRequest(data);
+ }
+ catch (IOException e)
+ {
+ throw new DVCSException("Failed to encode CMS signed data", e);
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java
new file mode 100644
index 00000000..21adaa3f
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java
@@ -0,0 +1,66 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSSignedData;
+
+/**
+ * Data piece of DVCS request to VSD service (Verify Signed Document).
+ * It contains VSD-specific selector interface.
+ * Note: the request should contain CMS SignedData object as message.
+ * <p/>
+ * This objects are constructed internally,
+ * to build DVCS request to VSD service use VSDRequestBuilder.
+ */
+public class VSDRequestData
+ extends DVCSRequestData
+{
+ private CMSSignedData doc;
+
+ VSDRequestData(Data data)
+ throws DVCSConstructionException
+ {
+ super(data);
+ initDocument();
+ }
+
+ private void initDocument()
+ throws DVCSConstructionException
+ {
+ if (doc == null)
+ {
+ if (data.getMessage() == null)
+ {
+ throw new DVCSConstructionException("DVCSRequest.data.message should be specified for VSD service");
+ }
+ try
+ {
+ doc = new CMSSignedData(data.getMessage().getOctets());
+ }
+ catch (CMSException e)
+ {
+ throw new DVCSConstructionException("Can't read CMS SignedData from input", e);
+ }
+ }
+ }
+
+ /**
+ * Get contained message (data to be certified).
+ *
+ * @return
+ */
+ public byte[] getMessage()
+ {
+ return data.getMessage().getOctets();
+ }
+
+ /**
+ * Get the CMS SignedData object represented by the encoded message.
+ *
+ * @return
+ */
+ public CMSSignedData getParsedMessage()
+ {
+ return doc;
+ }
+}