Skip to content

Commit 2030214

Browse files
committed
modified ERSGeneration to produce EvidenceRecords in order of data entry (leaves still sorted).
1 parent 339e981 commit 2030214

File tree

14 files changed

+268
-130
lines changed

14 files changed

+268
-130
lines changed

pkix/src/main/java/org/bouncycastle/tsp/ers/ERSArchiveTimeStamp.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public AlgorithmIdentifier getDigestAlgorithmIdentifier()
9999
public void validatePresent(ERSData data, Date atDate)
100100
throws ERSException
101101
{
102-
validatePresent(data instanceof ERSDataGroup, data.getHash(digCalc), atDate);
102+
validatePresent(data instanceof ERSDataGroup, data.getHash(digCalc, previousChainsDigest), atDate);
103103
}
104104

105105
public boolean isContaining(ERSData data, Date atDate)
@@ -130,11 +130,6 @@ public void validatePresent(boolean isDataGroup, byte[] hash, Date atDate)
130130
throw new ArchiveTimeStampValidationException("timestamp generation time is in the future");
131131
}
132132

133-
if (previousChainsDigest != null)
134-
{
135-
hash = ERSUtil.concatPreviousHashes(digCalc, previousChainsDigest, hash);
136-
}
137-
138133
checkContainsHashValue(isDataGroup, hash, digCalc);
139134

140135
PartialHashtree[] partialTree = archiveTimeStamp.getReducedHashTree();

pkix/src/main/java/org/bouncycastle/tsp/ers/ERSArchiveTimeStampGenerator.java

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import java.math.BigInteger;
66
import java.util.ArrayList;
77
import java.util.HashSet;
8-
import java.util.Iterator;
98
import java.util.List;
109
import java.util.Set;
1110

@@ -62,7 +61,7 @@ void addPreviousChains(ArchiveTimeStampSequence archiveTimeStampSequence)
6261
public TimeStampRequest generateTimeStampRequest(TimeStampRequestGenerator tspReqGenerator)
6362
throws TSPException, IOException
6463
{
65-
PartialHashtree[] reducedHashTree = getPartialHashtrees();
64+
IndexedPartialHashtree[] reducedHashTree = getPartialHashtrees();
6665

6766
byte[] rootHash = rootNodeCalculator.computeRootHash(digCalc, reducedHashTree);
6867

@@ -72,7 +71,7 @@ public TimeStampRequest generateTimeStampRequest(TimeStampRequestGenerator tspRe
7271
public TimeStampRequest generateTimeStampRequest(TimeStampRequestGenerator tspReqGenerator, BigInteger nonce)
7372
throws TSPException, IOException
7473
{
75-
PartialHashtree[] reducedHashTree = getPartialHashtrees();
74+
IndexedPartialHashtree[] reducedHashTree = getPartialHashtrees();
7675

7776
byte[] rootHash = rootNodeCalculator.computeRootHash(digCalc, reducedHashTree);
7877

@@ -82,7 +81,7 @@ public TimeStampRequest generateTimeStampRequest(TimeStampRequestGenerator tspRe
8281
public ERSArchiveTimeStamp generateArchiveTimeStamp(TimeStampResponse tspResponse)
8382
throws TSPException, ERSException
8483
{
85-
PartialHashtree[] reducedHashTree = getPartialHashtrees();
84+
IndexedPartialHashtree[] reducedHashTree = getPartialHashtrees();
8685
if (reducedHashTree.length != 1)
8786
{
8887
throw new ERSException("multiple reduced hash trees found");
@@ -123,7 +122,7 @@ public ERSArchiveTimeStamp generateArchiveTimeStamp(TimeStampResponse tspRespons
123122
public List<ERSArchiveTimeStamp> generateArchiveTimeStamps(TimeStampResponse tspResponse)
124123
throws TSPException, ERSException
125124
{
126-
PartialHashtree[] reducedHashTree = getPartialHashtrees();
125+
IndexedPartialHashtree[] reducedHashTree = getPartialHashtrees();
127126

128127
byte[] rootHash = rootNodeCalculator.computeRootHash(digCalc, reducedHashTree);
129128

@@ -154,22 +153,30 @@ public List<ERSArchiveTimeStamp> generateArchiveTimeStamps(TimeStampResponse tsp
154153
}
155154
else
156155
{
156+
ERSArchiveTimeStamp[] archiveTimeStamps = new ERSArchiveTimeStamp[reducedHashTree.length];
157+
157158
// we compute the final hash tree by left first traversal.
158159
for (int i = 0; i != reducedHashTree.length; i++)
159160
{
160161
PartialHashtree[] path = rootNodeCalculator.computePathToRoot(digCalc, reducedHashTree[i], i);
161162

162-
atss.add(new ERSArchiveTimeStamp(new ArchiveTimeStamp(digCalc.getAlgorithmIdentifier(), path, timeStamp), digCalc));
163+
archiveTimeStamps[reducedHashTree[i].order] = new ERSArchiveTimeStamp(new ArchiveTimeStamp(digCalc.getAlgorithmIdentifier(), path, timeStamp), digCalc);
164+
}
165+
166+
// fix the ordering
167+
for (int i = 0; i != reducedHashTree.length; i++)
168+
{
169+
atss.add(archiveTimeStamps[i]);
163170
}
164171
}
165172

166173
return atss;
167174
}
168175

169-
private PartialHashtree[] getPartialHashtrees()
176+
private IndexedPartialHashtree[] getPartialHashtrees()
170177
{
171-
List<byte[]> hashes = ERSUtil.buildHashList(digCalc, dataObjects, previousChainHash);
172-
PartialHashtree[] trees = new PartialHashtree[hashes.size()];
178+
List<IndexedHash> hashes = ERSUtil.buildIndexedHashList(digCalc, dataObjects, previousChainHash);
179+
IndexedPartialHashtree[] trees = new IndexedPartialHashtree[hashes.size()];
173180

174181
Set<ERSDataGroup> dataGroupSet = new HashSet<ERSDataGroup>();
175182
for (int i = 0; i != dataObjects.size(); i++)
@@ -183,53 +190,40 @@ private PartialHashtree[] getPartialHashtrees()
183190
// replace groups
184191
for (int i = 0; i != hashes.size(); i++)
185192
{
186-
byte[] hash = (byte[])hashes.get(i);
187-
ERSDataGroup found = null;
193+
byte[] hash = hashes.get(i).digest;
194+
ERSData d = dataObjects.get(hashes.get(i).order);
188195

189-
for (Iterator it = dataGroupSet.iterator(); it.hasNext(); )
190-
{
191-
ERSDataGroup data = (ERSDataGroup)it.next();
192-
193-
byte[] dHash = data.getHash(digCalc);
194-
if (Arrays.areEqual(dHash, hash))
195-
{
196-
List<byte[]> dHashes = data.getHashes(digCalc);
197-
trees[i] = new PartialHashtree((byte[][])dHashes.toArray(new byte[dHashes.size()][]));
198-
found = data;
199-
break;
200-
}
201-
}
202-
if (found == null)
196+
if (d instanceof ERSDataGroup)
203197
{
204-
trees[i] = new PartialHashtree(hash);
198+
ERSDataGroup data = (ERSDataGroup)d;
199+
200+
List<byte[]> dHashes = data.getHashes(digCalc, previousChainHash);
201+
trees[i] = new IndexedPartialHashtree(hashes.get(i).order, (byte[][])dHashes.toArray(new byte[dHashes.size()][]));
205202
}
206203
else
207204
{
208-
dataGroupSet.remove(found);
205+
trees[i] = new IndexedPartialHashtree(hashes.get(i).order, hash);
209206
}
210207
}
211208

212209
return trees;
213210
}
214211

215-
byte[] concatenate(PartialHashtree partialHashtree)
212+
private class IndexedPartialHashtree
213+
extends PartialHashtree
216214
{
217-
try
218-
{
219-
byte[][] values = partialHashtree.getValues();
220-
OutputStream dOut = digCalc.getOutputStream();
215+
final int order;
221216

222-
for (int i = 0; i != values.length; i++)
223-
{
224-
dOut.write(values[i]);
225-
}
226-
dOut.close();
227-
228-
return digCalc.getDigest();
217+
private IndexedPartialHashtree(int order, byte[] partial)
218+
{
219+
super(partial);
220+
this.order = order;
229221
}
230-
catch (IOException e)
222+
223+
private IndexedPartialHashtree(int order, byte[][] partial)
231224
{
232-
throw new IllegalStateException(e.getMessage());
225+
super(partial);
226+
this.order = order;
233227
}
234228
}
235229
}

pkix/src/main/java/org/bouncycastle/tsp/ers/ERSByteData.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,15 @@ public ERSByteData(byte[] content)
1515
this.content = content;
1616
}
1717

18-
protected byte[] calculateHash(DigestCalculator digestCalculator)
18+
protected byte[] calculateHash(DigestCalculator digestCalculator, byte[] previousChainHash)
1919
{
20-
return ERSUtil.calculateDigest(digestCalculator, content);
20+
byte[] hash = ERSUtil.calculateDigest(digestCalculator, content);
21+
22+
if (previousChainHash != null)
23+
{
24+
return ERSUtil.concatPreviousHashes(digestCalculator, previousChainHash, hash);
25+
}
26+
27+
return hash;
2128
}
2229
}

pkix/src/main/java/org/bouncycastle/tsp/ers/ERSCachingData.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,68 @@
55

66
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
77
import org.bouncycastle.operator.DigestCalculator;
8+
import org.bouncycastle.util.Arrays;
89

910
/**
1011
* An ERSData object that caches hash calculations.
1112
*/
1213
public abstract class ERSCachingData
1314
implements ERSData
1415
{
15-
private Map<AlgorithmIdentifier, byte[]> preCalcs = new HashMap<AlgorithmIdentifier, byte[]>();
16+
private Map<CacheIndex, byte[]> preCalcs = new HashMap<CacheIndex, byte[]>();
1617

1718
/**
1819
* Generates a hash for the whole DataGroup.
1920
*
2021
* @param digestCalculator the {@link DigestCalculator} to use for computing the hash
2122
* @return a hash that is representative of the whole DataGroup
2223
*/
23-
public byte[] getHash(DigestCalculator digestCalculator)
24+
public byte[] getHash(DigestCalculator digestCalculator, byte[] previousChainHash)
2425
{
25-
AlgorithmIdentifier digAlgID = digestCalculator.getAlgorithmIdentifier();
26+
CacheIndex digAlgID = new CacheIndex(digestCalculator.getAlgorithmIdentifier(), previousChainHash);
2627
if (preCalcs.containsKey(digAlgID))
2728
{
2829
return (byte[])preCalcs.get(digAlgID);
2930
}
3031

31-
byte[] hash = calculateHash(digestCalculator);
32+
byte[] hash = calculateHash(digestCalculator, previousChainHash);
3233

3334
preCalcs.put(digAlgID, hash);
3435

3536
return hash;
3637
}
3738

38-
protected abstract byte[] calculateHash(DigestCalculator digestCalculator);
39+
protected abstract byte[] calculateHash(DigestCalculator digestCalculator, byte[] previousChainHash);
40+
41+
private class CacheIndex
42+
{
43+
final AlgorithmIdentifier algId;
44+
final byte[] chainHash;
45+
46+
private CacheIndex(AlgorithmIdentifier algId, byte[] chainHash)
47+
{
48+
this.algId = algId;
49+
this.chainHash = chainHash;
50+
}
51+
52+
public boolean equals(Object o)
53+
{
54+
if (this == o)
55+
{
56+
return true;
57+
}
58+
if (!(o instanceof CacheIndex))
59+
{
60+
return false;
61+
}
62+
CacheIndex that = (CacheIndex)o;
63+
return algId.equals(that.algId) && Arrays.areEqual(chainHash, that.chainHash);
64+
}
65+
66+
public int hashCode()
67+
{
68+
int result = algId.hashCode();
69+
return 31 * result + Arrays.hashCode(chainHash);
70+
}
71+
}
3972
}

pkix/src/main/java/org/bouncycastle/tsp/ers/ERSData.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ public interface ERSData
1111
* Return the calculated hash for the Data
1212
*
1313
* @param digestCalculator digest calculator to use.
14+
* @param previousChainHash hash from an earlier chain if it needs to be included.
1415
* @return calculated hash.
1516
*/
16-
byte[] getHash(DigestCalculator digestCalculator);
17+
byte[] getHash(DigestCalculator digestCalculator, byte[] previousChainHash);
1718
}

pkix/src/main/java/org/bouncycastle/tsp/ers/ERSDataGroup.java

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,36 @@ public ERSDataGroup(ERSData dataObject)
5353
}
5454

5555
/**
56-
* Generates hashes for all the data objects included in the data group.
56+
* Generates hashes for all the data objects included in the data group with a previous chain hash.
5757
*
5858
* @param digestCalculator the {@link DigestCalculator} to use for computing the hashes
5959
* @return the set of hashes, in ascending order
6060
*/
6161
public List<byte[]> getHashes(
62-
final DigestCalculator digestCalculator)
62+
final DigestCalculator digestCalculator,
63+
final byte[] previousChainHash)
6364
{
64-
return ERSUtil.buildHashList(digestCalculator, dataObjects);
65+
return ERSUtil.buildHashList(digestCalculator, dataObjects, previousChainHash);
66+
}
67+
68+
/**
69+
* Return the calculated hash for the Data
70+
*
71+
* @param digestCalculator digest calculator to use.
72+
* @param previousChainHash hash from an earlier chain if it needs to be included.
73+
* @return calculated hash.
74+
*/
75+
public byte[] getHash(DigestCalculator digestCalculator, byte[] previousChainHash)
76+
{
77+
List<byte[]> hashes = getHashes(digestCalculator, previousChainHash);
78+
if (hashes.size() > 1)
79+
{
80+
return ERSUtil.calculateDigest(digestCalculator, hashes.iterator());
81+
}
82+
else
83+
{
84+
return hashes.get(0);
85+
}
6586
}
6687

6788
/**
@@ -70,13 +91,18 @@ public List<byte[]> getHashes(
7091
* @param digestCalculator the {@link DigestCalculator} to use for computing the hash
7192
* @return a hash that is representative of the whole DataGroup
7293
*/
73-
protected byte[] calculateHash(DigestCalculator digestCalculator)
94+
protected byte[] calculateHash(DigestCalculator digestCalculator, byte[] previousChainHash)
7495
{
75-
List<byte[]> hashes = getHashes(digestCalculator);
96+
List<byte[]> hashes = getHashes(digestCalculator, previousChainHash);
7697

7798
if (hashes.size() > 1)
7899
{
79-
return ERSUtil.calculateDigest(digestCalculator, hashes.iterator());
100+
List<byte[]> dHashes = new ArrayList<byte[]>(hashes.size());
101+
for (int i = 0; i != dHashes.size(); i++)
102+
{
103+
dHashes.add(hashes.get(i));
104+
}
105+
return ERSUtil.calculateDigest(digestCalculator, dHashes.iterator());
80106
}
81107
else
82108
{

pkix/src/main/java/org/bouncycastle/tsp/ers/ERSEvidenceRecordStore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public Collection<ERSEvidenceRecord> getMatches(Selector<ERSEvidenceRecord> sele
9292
{
9393
if (selector instanceof ERSEvidenceRecordSelector)
9494
{
95-
HashNode node = new HashNode(((ERSEvidenceRecordSelector)selector).getData().getHash(digCalc));
95+
HashNode node = new HashNode(((ERSEvidenceRecordSelector)selector).getData().getHash(digCalc, null));
9696
List<ERSEvidenceRecord> records = (List<ERSEvidenceRecord>)recordMap.get(node);
9797

9898
if (records != null)

pkix/src/main/java/org/bouncycastle/tsp/ers/ERSFileData.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,19 @@ public ERSFileData(File content)
3434
this.content = content;
3535
}
3636

37-
protected byte[] calculateHash(DigestCalculator digestCalculator)
37+
protected byte[] calculateHash(DigestCalculator digestCalculator, byte[] previousChainHash)
3838
{
3939
try
4040
{
4141
InputStream contentStream = new FileInputStream(content);
4242
byte[] hash = ERSUtil.calculateDigest(digestCalculator, contentStream);
4343
contentStream.close();
4444

45+
if (previousChainHash != null)
46+
{
47+
return ERSUtil.concatPreviousHashes(digestCalculator, previousChainHash, hash);
48+
}
49+
4550
return hash;
4651
}
4752
catch (IOException e)

pkix/src/main/java/org/bouncycastle/tsp/ers/ERSInputStreamData.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,16 @@ public ERSInputStreamData(InputStream content)
2929
{
3030
this.content = content;
3131
}
32-
33-
protected byte[] calculateHash(DigestCalculator digestCalculator)
32+
33+
protected byte[] calculateHash(DigestCalculator digestCalculator, byte[] previousChainHash)
3434
{
35-
// TODO: this method may get called twice if the digest calculator changes...
36-
return ERSUtil.calculateDigest(digestCalculator, content);
35+
byte[] hash = ERSUtil.calculateDigest(digestCalculator, content);
36+
37+
if (previousChainHash != null)
38+
{
39+
return ERSUtil.concatPreviousHashes(digestCalculator, previousChainHash, hash);
40+
}
41+
42+
return hash;
3743
}
3844
}

0 commit comments

Comments
 (0)