[tor-commits] [metrics-lib/master] Parse certs and everything we need to verify consensuses.
karsten at torproject.org
karsten at torproject.org
Thu Apr 26 14:15:27 UTC 2012
commit 47e771f2b772f21563d38a98bb7c7fe284b474d8
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date: Thu Apr 26 16:07:55 2012 +0200
Parse certs and everything we need to verify consensuses.
---
.../descriptor/DirectoryKeyCertificate.java | 45 ++++
.../torproject/descriptor/DirectorySignature.java | 16 ++
.../descriptor/RelayNetworkStatusConsensus.java | 6 +-
.../descriptor/RelayNetworkStatusVote.java | 2 +-
.../torproject/descriptor/impl/DescriptorImpl.java | 4 +-
.../impl/DirectoryKeyCertificateImpl.java | 270 ++++++++++++++++++++
.../descriptor/impl/DirectorySignatureImpl.java | 91 +++++++
.../descriptor/impl/NetworkStatusImpl.java | 50 +---
.../impl/RelayNetworkStatusConsensusImpl.java | 33 +++
9 files changed, 479 insertions(+), 38 deletions(-)
diff --git a/src/org/torproject/descriptor/DirectoryKeyCertificate.java b/src/org/torproject/descriptor/DirectoryKeyCertificate.java
new file mode 100644
index 0000000..9a4aeae
--- /dev/null
+++ b/src/org/torproject/descriptor/DirectoryKeyCertificate.java
@@ -0,0 +1,45 @@
+/* Copyright 2012 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor;
+
+public interface DirectoryKeyCertificate extends Descriptor {
+
+ /* Return the directory key certificate version. */
+ public int getDirKeyCertificateVersion();
+
+ /* Return the IP address, or null if the certificate does not contain an
+ * address. */
+ public String getAddress();
+
+ /* Return the directory port, or -1 if the certificate does not contain
+ * one. */
+ public int getPort();
+
+ /* Return the directory identity fingerprint. */
+ public String getFingerprint();
+
+ /* Return the directory identity key. */
+ public String getDirIdentityKey();
+
+ /* Return the directory key certificate publication timestamp. */
+ public long getDirKeyPublishedMillis();
+
+ /* Return the directory key certificate expiration timestamp. */
+ public long getDirKeyExpiresMillis();
+
+ /* Return the directory signing key digest. */
+ public String getDirSigningKey();
+
+ /* Return the signature of the directory identity key made using the
+ * directory signing key, or null if the certificate does not contain
+ * this signature. */
+ public String getDirKeyCrosscert();
+
+ /* Return the certificate signature made using the directory identity
+ * key. */
+ public String getDirKeyCertification();
+
+ /* Return the calculated certificate digest. */
+ public String getCertificateDigest();
+}
+
diff --git a/src/org/torproject/descriptor/DirectorySignature.java b/src/org/torproject/descriptor/DirectorySignature.java
new file mode 100644
index 0000000..29eb055
--- /dev/null
+++ b/src/org/torproject/descriptor/DirectorySignature.java
@@ -0,0 +1,16 @@
+/* Copyright 2012 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor;
+
+public interface DirectorySignature {
+
+ /* Return the directory identity fingerprint. */
+ public String getIdentity();
+
+ /* Return the directory signing key digest. */
+ public String getSigningKeyDigest();
+
+ /* Return the directory signature made using the signing key. */
+ public String getSignature();
+}
+
diff --git a/src/org/torproject/descriptor/RelayNetworkStatusConsensus.java b/src/org/torproject/descriptor/RelayNetworkStatusConsensus.java
index 2c0ff4f..4a1634f 100644
--- a/src/org/torproject/descriptor/RelayNetworkStatusConsensus.java
+++ b/src/org/torproject/descriptor/RelayNetworkStatusConsensus.java
@@ -60,10 +60,14 @@ public interface RelayNetworkStatusConsensus extends Descriptor {
public NetworkStatusEntry getStatusEntry(String fingerprint);
/* Return directory signatures. */
- public SortedMap<String, String> getDirectorySignatures();
+ public SortedMap<String, DirectorySignature> getDirectorySignatures();
/* Return bandwidth weights or null if the consensus doesn't contain
* bandwidth weights. */
public SortedMap<String, Integer> getBandwidthWeights();
+
+ /* Return the consensus digest that directory authorities use to sign
+ * the consensus. */
+ public String getConsensusDigest();
}
diff --git a/src/org/torproject/descriptor/RelayNetworkStatusVote.java b/src/org/torproject/descriptor/RelayNetworkStatusVote.java
index f9635e2..eda0cef 100644
--- a/src/org/torproject/descriptor/RelayNetworkStatusVote.java
+++ b/src/org/torproject/descriptor/RelayNetworkStatusVote.java
@@ -92,6 +92,6 @@ public interface RelayNetworkStatusVote extends Descriptor {
public NetworkStatusEntry getStatusEntry(String fingerprint);
/* Return directory signatures. */
- public SortedMap<String, String> getDirectorySignatures();
+ public SortedMap<String, DirectorySignature> getDirectorySignatures();
}
diff --git a/src/org/torproject/descriptor/impl/DescriptorImpl.java b/src/org/torproject/descriptor/impl/DescriptorImpl.java
index 33b94e9..6b1b167 100644
--- a/src/org/torproject/descriptor/impl/DescriptorImpl.java
+++ b/src/org/torproject/descriptor/impl/DescriptorImpl.java
@@ -60,7 +60,9 @@ public abstract class DescriptorImpl implements Descriptor {
parseDescriptors(rawDescriptorBytes,
failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("dir-key-certificate-version ")) {
- /* TODO Implement parsing of directory certificates. */
+ parsedDescriptors.addAll(DirectoryKeyCertificateImpl.
+ parseDescriptors(rawDescriptorBytes,
+ failUnrecognizedDescriptorLines));
} else if (firstLines.startsWith("ExitNode ")) {
parsedDescriptors.add(new ExitListImpl(rawDescriptorBytes, fileName,
failUnrecognizedDescriptorLines));
diff --git a/src/org/torproject/descriptor/impl/DirectoryKeyCertificateImpl.java b/src/org/torproject/descriptor/impl/DirectoryKeyCertificateImpl.java
new file mode 100644
index 0000000..2483aa1
--- /dev/null
+++ b/src/org/torproject/descriptor/impl/DirectoryKeyCertificateImpl.java
@@ -0,0 +1,270 @@
+/* Copyright 2012 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor.impl;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Scanner;
+import java.util.Set;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.torproject.descriptor.DirectoryKeyCertificate;
+
+/* TODO Add test class. */
+
+public class DirectoryKeyCertificateImpl extends DescriptorImpl
+ implements DirectoryKeyCertificate {
+
+ protected static List<DirectoryKeyCertificate> parseDescriptors(
+ byte[] descriptorsBytes, boolean failUnrecognizedDescriptorLines)
+ throws DescriptorParseException {
+ List<DirectoryKeyCertificate> parsedDescriptors =
+ new ArrayList<DirectoryKeyCertificate>();
+ List<byte[]> splitDescriptorsBytes =
+ DirectoryKeyCertificateImpl.splitRawDescriptorBytes(
+ descriptorsBytes, "dir-key-certificate-version ");
+ for (byte[] descriptorBytes : splitDescriptorsBytes) {
+ DirectoryKeyCertificate parsedDescriptor =
+ new DirectoryKeyCertificateImpl(descriptorBytes,
+ failUnrecognizedDescriptorLines);
+ parsedDescriptors.add(parsedDescriptor);
+ }
+ return parsedDescriptors;
+ }
+
+ protected DirectoryKeyCertificateImpl(byte[] rawDescriptorBytes,
+ boolean failUnrecognizedDescriptorLines)
+ throws DescriptorParseException {
+ super(rawDescriptorBytes, failUnrecognizedDescriptorLines);
+ this.parseDescriptorBytes();
+ this.calculateDigest();
+ Set<String> exactlyOnceKeywords = new HashSet<String>(Arrays.asList((
+ "dir-key-certificate-version,fingerprint,dir-identity-key,"
+ + "dir-key-published,dir-key-expires,dir-signing-key,"
+ + "dir-key-certification").split(",")));
+ this.checkExactlyOnceKeywords(exactlyOnceKeywords);
+ Set<String> atMostOnceKeywords = new HashSet<String>(Arrays.asList((
+ "dir-address,dir-key-crosscert").split(",")));
+ this.checkAtMostOnceKeywords(atMostOnceKeywords);
+ this.checkFirstKeyword("dir-key-certificate-version");
+ this.checkLastKeyword("dir-key-certification");
+ }
+
+ private void parseDescriptorBytes() throws DescriptorParseException {
+ Scanner s = new Scanner(new String(this.rawDescriptorBytes)).
+ useDelimiter("\n");
+ String nextCrypto = null;
+ StringBuilder crypto = null;
+ while (s.hasNext()) {
+ String line = s.next();
+ String[] parts = line.split(" ");
+ String keyword = parts[0];
+ if (keyword.equals("dir-key-certificate-version")) {
+ this.parseDirKeyCertificateVersionLine(line, parts);
+ } else if (keyword.equals("dir-address")) {
+ this.parseDirAddressLine(line, parts);
+ } else if (keyword.equals("fingerprint")) {
+ this.parseFingerprintLine(line, parts);
+ } else if (keyword.equals("dir-identity-key")) {
+ this.parseDirIdentityKeyLine(line, parts);
+ nextCrypto = "dir-identity-key";
+ } else if (keyword.equals("dir-key-published")) {
+ this.parseDirKeyPublishedLine(line, parts);
+ } else if (keyword.equals("dir-key-expires")) {
+ this.parseDirKeyExpiresLine(line, parts);
+ } else if (keyword.equals("dir-signing-key")) {
+ this.parseDirSigningKeyLine(line, parts);
+ nextCrypto = "dir-signing-key";
+ } else if (keyword.equals("dir-key-crosscert")) {
+ this.parseDirKeyCrosscertLine(line, parts);
+ nextCrypto = "dir-key-crosscert";
+ } else if (keyword.equals("dir-key-certification")) {
+ this.parseDirKeyCertificationLine(line, parts);
+ nextCrypto = "dir-key-certification";
+ } else if (line.startsWith("-----BEGIN")) {
+ crypto = new StringBuilder();
+ crypto.append(line + "\n");
+ } else if (line.startsWith("-----END")) {
+ crypto.append(line + "\n");
+ String cryptoString = crypto.toString();
+ crypto = null;
+ if (nextCrypto.equals("dir-identity-key")) {
+ this.dirIdentityKey = cryptoString;
+ } else if (nextCrypto.equals("dir-signing-key")) {
+ this.dirSigningKey = cryptoString;
+ } else if (nextCrypto.equals("dir-key-crosscert")) {
+ this.dirKeyCrosscert = cryptoString;
+ } else if (nextCrypto.equals("dir-key-certification")) {
+ this.dirKeyCertification = cryptoString;
+ } else {
+ throw new DescriptorParseException("Unrecognized crypto "
+ + "block in directory key certificate.");
+ }
+ nextCrypto = null;
+ } else if (crypto != null) {
+ crypto.append(line + "\n");
+ } else {
+ if (this.failUnrecognizedDescriptorLines) {
+ throw new DescriptorParseException("Unrecognized line '"
+ + line + "' in directory key certificate.");
+ } else {
+ if (this.unrecognizedLines == null) {
+ this.unrecognizedLines = new ArrayList<String>();
+ }
+ this.unrecognizedLines.add(line);
+ }
+ }
+ }
+ }
+
+ private void parseDirKeyCertificateVersionLine(String line,
+ String[] parts) throws DescriptorParseException {
+ if (!line.equals("dir-key-certificate-version 3")) {
+ throw new DescriptorParseException("Illegal directory key "
+ + "certificate version number in line '" + line + "'.");
+ }
+ this.dirKeyCertificateVersion = 3;
+ }
+
+ private void parseDirAddressLine(String line, String[] parts)
+ throws DescriptorParseException {
+ if (parts.length != 2 || parts[1].split(":").length != 2) {
+ throw new DescriptorParseException("Illegal line '" + line
+ + "' in directory key certificate.");
+ }
+ this.address = ParseHelper.parseIpv4Address(line,
+ parts[1].split(":")[0]);
+ this.port = ParseHelper.parsePort(line, parts[1].split(":")[1]);
+ }
+
+ private void parseFingerprintLine(String line, String[] parts)
+ throws DescriptorParseException {
+ if (parts.length != 2) {
+ throw new DescriptorParseException("Illegal line '" + line
+ + "' in directory key certificate.");
+ }
+ this.fingerprint = ParseHelper.parseTwentyByteHexString(line,
+ parts[1]);
+ }
+
+ private void parseDirIdentityKeyLine(String line, String[] parts)
+ throws DescriptorParseException {
+ if (!line.equals("dir-identity-key")) {
+ throw new DescriptorParseException("Illegal line '" + line + "'.");
+ }
+ }
+
+ private void parseDirKeyPublishedLine(String line, String[] parts)
+ throws DescriptorParseException {
+ this.dirKeyPublishedMillis = ParseHelper.parseTimestampAtIndex(line,
+ parts, 1, 2);
+ }
+
+ private void parseDirKeyExpiresLine(String line, String[] parts)
+ throws DescriptorParseException {
+ this.dirKeyExpiresMillis = ParseHelper.parseTimestampAtIndex(line,
+ parts, 1, 2);
+ }
+
+ private void parseDirSigningKeyLine(String line, String[] parts)
+ throws DescriptorParseException {
+ if (!line.equals("dir-signing-key")) {
+ throw new DescriptorParseException("Illegal line '" + line + "'.");
+ }
+ }
+
+ private void parseDirKeyCrosscertLine(String line, String[] parts)
+ throws DescriptorParseException {
+ if (!line.equals("dir-key-crosscert")) {
+ throw new DescriptorParseException("Illegal line '" + line + "'.");
+ }
+ }
+
+ private void parseDirKeyCertificationLine(String line, String[] parts)
+ throws DescriptorParseException {
+ if (!line.equals("dir-key-certification")) {
+ throw new DescriptorParseException("Illegal line '" + line + "'.");
+ }
+ }
+
+ private void calculateDigest() throws DescriptorParseException {
+ try {
+ String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
+ String startToken = "dir-key-certificate-version ";
+ String sigToken = "\ndir-key-certification\n";
+ int start = ascii.indexOf(startToken);
+ int sig = ascii.indexOf(sigToken) + sigToken.length();
+ if (start >= 0 && sig >= 0 && sig > start) {
+ byte[] forDigest = new byte[sig - start];
+ System.arraycopy(this.getRawDescriptorBytes(), start,
+ forDigest, 0, sig - start);
+ this.certificateDigest = DigestUtils.shaHex(forDigest);
+ }
+ } catch (UnsupportedEncodingException e) {
+ /* Handle below. */
+ }
+ if (this.certificateDigest == null) {
+ throw new DescriptorParseException("Could not calculate "
+ + "certificate digest.");
+ }
+ }
+
+ private int dirKeyCertificateVersion;
+ public int getDirKeyCertificateVersion() {
+ return this.dirKeyCertificateVersion;
+ }
+
+ private String address;
+ public String getAddress() {
+ return this.address;
+ }
+
+ private int port = -1;
+ public int getPort() {
+ return this.port;
+ }
+
+ private String fingerprint;
+ public String getFingerprint() {
+ return this.fingerprint;
+ }
+
+ private String dirIdentityKey;
+ public String getDirIdentityKey() {
+ return this.dirIdentityKey;
+ }
+
+ private long dirKeyPublishedMillis;
+ public long getDirKeyPublishedMillis() {
+ return this.dirKeyPublishedMillis;
+ }
+
+ private long dirKeyExpiresMillis;
+ public long getDirKeyExpiresMillis() {
+ return this.dirKeyExpiresMillis;
+ }
+
+ private String dirSigningKey;
+ public String getDirSigningKey() {
+ return this.dirSigningKey;
+ }
+
+ private String dirKeyCrosscert;
+ public String getDirKeyCrosscert() {
+ return this.dirKeyCrosscert;
+ }
+
+ private String dirKeyCertification;
+ public String getDirKeyCertification() {
+ return this.dirKeyCertification;
+ }
+
+ private String certificateDigest;
+ public String getCertificateDigest() {
+ return this.certificateDigest;
+ }
+}
+
diff --git a/src/org/torproject/descriptor/impl/DirectorySignatureImpl.java b/src/org/torproject/descriptor/impl/DirectorySignatureImpl.java
new file mode 100644
index 0000000..d205345
--- /dev/null
+++ b/src/org/torproject/descriptor/impl/DirectorySignatureImpl.java
@@ -0,0 +1,91 @@
+/* Copyright 2012 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+import org.torproject.descriptor.DirectorySignature;
+
+public class DirectorySignatureImpl implements DirectorySignature {
+
+ private byte[] directorySignatureBytes;
+ public byte[] getDirectorySignatureBytes() {
+ return this.directorySignatureBytes;
+ }
+
+ private boolean failUnrecognizedDescriptorLines;
+ private List<String> unrecognizedLines;
+ protected List<String> getAndClearUnrecognizedLines() {
+ List<String> lines = this.unrecognizedLines;
+ this.unrecognizedLines = null;
+ return lines;
+ }
+
+ protected DirectorySignatureImpl(byte[] directorySignatureBytes,
+ boolean failUnrecognizedDescriptorLines)
+ throws DescriptorParseException {
+ this.directorySignatureBytes = directorySignatureBytes;
+ this.failUnrecognizedDescriptorLines =
+ failUnrecognizedDescriptorLines;
+ this.parseDirectorySignatureBytes();
+ }
+
+ private void parseDirectorySignatureBytes()
+ throws DescriptorParseException {
+ Scanner s = new Scanner(new String(this.directorySignatureBytes)).
+ useDelimiter("\n");
+ StringBuilder crypto = null;
+ while (s.hasNext()) {
+ String line = s.next();
+ if (line.startsWith("directory-signature ")) {
+ String[] parts = line.split(" ", -1);
+ if (parts.length != 3) {
+ throw new DescriptorParseException("Illegal line '" + line
+ + "'.");
+ }
+ this.identity = ParseHelper.parseTwentyByteHexString(line,
+ parts[1]);
+ this.signingKeyDigest = ParseHelper.parseTwentyByteHexString(
+ line, parts[2]);
+ } else if (line.startsWith("-----BEGIN")) {
+ crypto = new StringBuilder();
+ crypto.append(line + "\n");
+ } else if (line.startsWith("-----END")) {
+ crypto.append(line + "\n");
+ String cryptoString = crypto.toString();
+ crypto = null;
+ this.signature = cryptoString;
+ } else if (crypto != null) {
+ crypto.append(line + "\n");
+ } else {
+ if (this.failUnrecognizedDescriptorLines) {
+ throw new DescriptorParseException("Unrecognized line '"
+ + line + "' in dir-source entry.");
+ } else {
+ if (this.unrecognizedLines == null) {
+ this.unrecognizedLines = new ArrayList<String>();
+ }
+ this.unrecognizedLines.add(line);
+ }
+ }
+ }
+ }
+
+ private String identity;
+ public String getIdentity() {
+ return this.identity;
+ }
+
+ private String signingKeyDigest;
+ public String getSigningKeyDigest() {
+ return this.signingKeyDigest;
+ }
+
+ private String signature;
+ public String getSignature() {
+ return this.signature;
+ }
+}
+
diff --git a/src/org/torproject/descriptor/impl/NetworkStatusImpl.java b/src/org/torproject/descriptor/impl/NetworkStatusImpl.java
index f080171..d27e651 100644
--- a/src/org/torproject/descriptor/impl/NetworkStatusImpl.java
+++ b/src/org/torproject/descriptor/impl/NetworkStatusImpl.java
@@ -4,11 +4,11 @@ package org.torproject.descriptor.impl;
import java.util.ArrayList;
import java.util.List;
-import java.util.Scanner;
import java.util.SortedMap;
import java.util.TreeMap;
import org.torproject.descriptor.DirSourceEntry;
+import org.torproject.descriptor.DirectorySignature;
import org.torproject.descriptor.NetworkStatusEntry;
/* Parse the common parts of v3 consensuses, v3 votes, v3 microdesc
@@ -195,39 +195,19 @@ public abstract class NetworkStatusImpl extends DescriptorImpl {
protected void parseDirectorySignature(byte[] directorySignatureBytes)
throws DescriptorParseException {
if (this.directorySignatures == null) {
- this.directorySignatures = new TreeMap<String, String>();
+ this.directorySignatures = new TreeMap<String,
+ DirectorySignature>();
}
- Scanner s = new Scanner(new String(directorySignatureBytes)).
- useDelimiter("\n");
- boolean skipCrypto = false;
- while (s.hasNext()) {
- String line = s.next();
- if (line.startsWith("directory-signature ")) {
- String[] parts = line.split(" ", -1);
- if (parts.length != 3) {
- throw new DescriptorParseException("Illegal line '" + line
- + "'.");
- }
- String identity = ParseHelper.parseTwentyByteHexString(line,
- parts[1]);
- String signingKeyDigest = ParseHelper.parseTwentyByteHexString(
- line, parts[2]);
- this.directorySignatures.put(identity, signingKeyDigest);
- } else if (line.startsWith("-----BEGIN")) {
- skipCrypto = true;
- } else if (line.startsWith("-----END")) {
- skipCrypto = false;
- } else if (!skipCrypto) {
- if (this.failUnrecognizedDescriptorLines) {
- throw new DescriptorParseException("Unrecognized line '"
- + line + "' in dir-source entry.");
- } else {
- if (this.unrecognizedLines == null) {
- this.unrecognizedLines = new ArrayList<String>();
- }
- this.unrecognizedLines.add(line);
- }
+ DirectorySignatureImpl signature = new DirectorySignatureImpl(
+ directorySignatureBytes, failUnrecognizedDescriptorLines);
+ this.directorySignatures.put(signature.getIdentity(), signature);
+ List<String> unrecognizedStatusEntryLines = signature.
+ getAndClearUnrecognizedLines();
+ if (unrecognizedStatusEntryLines != null) {
+ if (this.unrecognizedLines == null) {
+ this.unrecognizedLines = new ArrayList<String>();
}
+ this.unrecognizedLines.addAll(unrecognizedStatusEntryLines);
}
}
@@ -249,10 +229,10 @@ public abstract class NetworkStatusImpl extends DescriptorImpl {
return this.statusEntries.get(fingerprint);
}
- private SortedMap<String, String> directorySignatures;
- public SortedMap<String, String> getDirectorySignatures() {
+ private SortedMap<String, DirectorySignature> directorySignatures;
+ public SortedMap<String, DirectorySignature> getDirectorySignatures() {
return this.directorySignatures == null ? null :
- new TreeMap<String, String>(this.directorySignatures);
+ new TreeMap<String, DirectorySignature>(this.directorySignatures);
}
}
diff --git a/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java b/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
index 564beb2..3d2af37 100644
--- a/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
+++ b/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
@@ -2,6 +2,7 @@
* See LICENSE for licensing information */
package org.torproject.descriptor.impl;
+import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -13,6 +14,7 @@ import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
+import org.apache.commons.codec.digest.DigestUtils;
import org.torproject.descriptor.RelayNetworkStatusConsensus;
/* Contains a network status consensus. */
@@ -49,6 +51,32 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
+ "bandwidth-weights").split(",")));
this.checkAtMostOnceKeywords(atMostOnceKeywords);
this.checkFirstKeyword("network-status-version");
+ this.calculateDigest();
+ }
+
+ private void calculateDigest() throws DescriptorParseException {
+ try {
+ String ascii = new String(this.getRawDescriptorBytes(), "US-ASCII");
+ String startToken = "network-status-version ";
+ String sigToken = "\ndirectory-signature ";
+ if (!ascii.contains(sigToken)) {
+ return;
+ }
+ int start = ascii.indexOf(startToken);
+ int sig = ascii.indexOf(sigToken) + sigToken.length();
+ if (start >= 0 && sig >= 0 && sig > start) {
+ byte[] forDigest = new byte[sig - start];
+ System.arraycopy(this.getRawDescriptorBytes(), start,
+ forDigest, 0, sig - start);
+ this.consensusDigest = DigestUtils.shaHex(forDigest);
+ }
+ } catch (UnsupportedEncodingException e) {
+ /* Handle below. */
+ }
+ if (this.consensusDigest == null) {
+ throw new DescriptorParseException("Could not calculate consensus "
+ + "digest.");
+ }
}
protected void parseHeader(byte[] headerBytes)
@@ -238,6 +266,11 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
1);
}
+ private String consensusDigest;
+ public String getConsensusDigest() {
+ return this.consensusDigest;
+ }
+
private int networkStatusVersion;
public int getNetworkStatusVersion() {
return this.networkStatusVersion;
More information about the tor-commits
mailing list