[tor-commits] [metrics-lib/master] Support (ntor-)onion-key crosscerts.

karsten at torproject.org karsten at torproject.org
Mon Dec 21 19:45:59 UTC 2015


commit f4fca35135482979f85f7891b075b46a194ef37e
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Wed Dec 16 16:09:17 2015 +0100

    Support (ntor-)onion-key crosscerts.
---
 CHANGELOG.md                                       |    2 +
 .../torproject/descriptor/ServerDescriptor.java    |   17 +++++
 .../descriptor/impl/ServerDescriptorImpl.java      |   50 +++++++++++++-
 .../descriptor/impl/ServerDescriptorImplTest.java  |   73 ++++++++++++++++++++
 4 files changed, 139 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index bfda75e..73e9a1e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,8 @@
    - Include RSA-1024 signatures of SHA-1 digests of extra-info
      descriptors, which were parsed and discarded before.
    - Support hidden-service statistics in extra-info descriptors.
+   - Support onion-key and ntor-onion-key cross certificates in server
+     descriptors.
 
 
 # Changes in version 1.0.0 - 2015-12-05
diff --git a/src/org/torproject/descriptor/ServerDescriptor.java b/src/org/torproject/descriptor/ServerDescriptor.java
index 3266e9d..49eaa92 100644
--- a/src/org/torproject/descriptor/ServerDescriptor.java
+++ b/src/org/torproject/descriptor/ServerDescriptor.java
@@ -174,5 +174,22 @@ public interface ServerDescriptor extends Descriptor {
    * the first space after the "router-sig-ed25519" string, prefixed with
    * the string "Tor router descriptor signature v1". */
   public String getRouterSignatureEd25519();
+
+  /* Return an RSA signature, generated using the onion-key, that proves
+   * that the party creating the descriptor had control over the secret
+   * key corresponding to the onion-key, or null if the descriptor does
+   * not contain such a signature. */
+  public String getOnionKeyCrosscert();
+
+  /* Return an Ed25519 signature, generated using the ntor-onion-key, that
+   * proves that the party creating the descriptor had control over the
+   * secret key corresponding to the ntor-onion-key, or null if the
+   * descriptor does not contain such a signature. */
+  public String getNtorOnionKeyCrosscert();
+
+  /* Return the sign of the Ed25519 public key corresponding to the ntor
+   * onion key as 0 or 1, or -1 if the descriptor does not contain this
+   * information. */
+  public int getNtorOnionKeyCrosscertSign();
 }
 
diff --git a/src/org/torproject/descriptor/impl/ServerDescriptorImpl.java b/src/org/torproject/descriptor/impl/ServerDescriptorImpl.java
index 3dd6c40..1484866 100644
--- a/src/org/torproject/descriptor/impl/ServerDescriptorImpl.java
+++ b/src/org/torproject/descriptor/impl/ServerDescriptorImpl.java
@@ -37,9 +37,9 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
         + "hibernating,uptime,contact,family,read-history,write-history,"
         + "eventdns,caches-extra-info,extra-info-digest,"
         + "hidden-service-dir,protocols,allow-single-hop-exits,onion-key,"
-        + "signing-key,ipv6-policy,ntor-onion-key,router-sig-ed25519,"
-        + "router-signature,router-digest-sha256,router-digest").
-        split(",")));
+        + "signing-key,ipv6-policy,ntor-onion-key,onion-key-crosscert,"
+        + "ntor-onion-key-crosscert,router-sig-ed25519,router-signature,"
+        + "router-digest-sha256,router-digest").split(",")));
     this.checkAtMostOnceKeywords(atMostOnceKeywords);
     this.checkFirstKeyword("router");
     if (this.getKeywordCount("accept") == 0 &&
@@ -131,6 +131,12 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
         this.parseMasterKeyEd25519Line(line, lineNoOpt, partsNoOpt);
       } else if (keyword.equals("router-sig-ed25519")) {
         this.parseRouterSigEd25519Line(line, lineNoOpt, partsNoOpt);
+      } else if (keyword.equals("onion-key-crosscert")) {
+        this.parseOnionKeyCrosscert(line, lineNoOpt, partsNoOpt);
+        nextCrypto = "onion-key-crosscert";
+      } else if (keyword.equals("ntor-onion-key-crosscert")) {
+        this.parseNtorOnionKeyCrosscert(line, lineNoOpt, partsNoOpt);
+        nextCrypto = "ntor-onion-key-crosscert";
       } else if (line.startsWith("-----BEGIN")) {
         cryptoLines = new ArrayList<String>();
         cryptoLines.add(line);
@@ -150,6 +156,10 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
         } else if ("identity-ed25519".equals(nextCrypto)) {
           this.identityEd25519 = cryptoString;
           this.parseIdentityEd25519CryptoBlock(cryptoString);
+        } else if ("onion-key-crosscert".equals(nextCrypto)) {
+          this.onionKeyCrosscert = cryptoString;
+        } else if ("ntor-onion-key-crosscert".equals(nextCrypto)) {
+          this.ntorOnionKeyCrosscert = cryptoString;
         } else if (this.failUnrecognizedDescriptorLines) {
           throw new DescriptorParseException("Unrecognized crypto "
               + "block '" + cryptoString + "' in server descriptor.");
@@ -534,6 +544,25 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
     }
   }
 
+  private void parseOnionKeyCrosscert(String line, String lineNoOpt,
+      String[] partsNoOpt) throws DescriptorParseException {
+    if (partsNoOpt.length != 1) {
+      throw new DescriptorParseException("Illegal line '" + line + "'.");
+    }
+  }
+
+  private void parseNtorOnionKeyCrosscert(String line, String lineNoOpt,
+      String[] partsNoOpt) throws DescriptorParseException {
+    if (partsNoOpt.length != 2) {
+      throw new DescriptorParseException("Illegal line '" + line + "'.");
+    }
+    try {
+      this.ntorOnionKeyCrosscertSign = Integer.parseInt(partsNoOpt[1]);
+    } catch (NumberFormatException e) {
+      throw new DescriptorParseException("Illegal line '" + line + "'.");
+    }
+  }
+
   private void parseIdentityEd25519CryptoBlock(String cryptoString)
       throws DescriptorParseException {
     String masterKeyEd25519FromIdentityEd25519 =
@@ -834,5 +863,20 @@ public abstract class ServerDescriptorImpl extends DescriptorImpl
   public String getRouterSignatureEd25519() {
     return this.routerSignatureEd25519;
   }
+
+  private String onionKeyCrosscert;
+  public String getOnionKeyCrosscert() {
+    return this.onionKeyCrosscert;
+  }
+
+  private String ntorOnionKeyCrosscert;
+  public String getNtorOnionKeyCrosscert() {
+    return this.ntorOnionKeyCrosscert;
+  }
+
+  private int ntorOnionKeyCrosscertSign = -1;
+  public int getNtorOnionKeyCrosscertSign() {
+    return ntorOnionKeyCrosscertSign;
+  }
 }
 
diff --git a/test/org/torproject/descriptor/impl/ServerDescriptorImplTest.java b/test/org/torproject/descriptor/impl/ServerDescriptorImplTest.java
index a98df9f..56f1419 100644
--- a/test/org/torproject/descriptor/impl/ServerDescriptorImplTest.java
+++ b/test/org/torproject/descriptor/impl/ServerDescriptorImplTest.java
@@ -104,6 +104,20 @@ public class ServerDescriptorImplTest {
       db.signingKeyLines = lines;
       return new RelayServerDescriptorImpl(db.buildDescriptor(), true);
     }
+    private String onionKeyCrosscertLines = null;
+    private static ServerDescriptor createWithOnionKeyCrosscertLines(
+        String lines) throws DescriptorParseException {
+      DescriptorBuilder db = new DescriptorBuilder();
+      db.onionKeyCrosscertLines = lines;
+      return new RelayServerDescriptorImpl(db.buildDescriptor(), true);
+    }
+    private String ntorOnionKeyCrosscertLines = null;
+    private static ServerDescriptor createWithNtorOnionKeyCrosscertLines(
+        String lines) throws DescriptorParseException {
+      DescriptorBuilder db = new DescriptorBuilder();
+      db.ntorOnionKeyCrosscertLines = lines;
+      return new RelayServerDescriptorImpl(db.buildDescriptor(), true);
+    }
     private String exitPolicyLines = "reject *:*";
     private static ServerDescriptor createWithExitPolicyLines(
         String lines) throws DescriptorParseException {
@@ -274,6 +288,12 @@ public class ServerDescriptorImplTest {
       if (this.signingKeyLines != null) {
         sb.append(this.signingKeyLines + "\n");
       }
+      if (this.onionKeyCrosscertLines != null) {
+        sb.append(this.onionKeyCrosscertLines + "\n");
+      }
+      if (this.ntorOnionKeyCrosscertLines != null) {
+        sb.append(this.ntorOnionKeyCrosscertLines + "\n");
+      }
       if (this.exitPolicyLines != null) {
         sb.append(this.exitPolicyLines + "\n");
       }
@@ -1481,5 +1501,58 @@ public class ServerDescriptorImplTest {
         MASTER_KEY_ED25519_LINE, ROUTER_SIG_ED25519_LINE + "\n"
         + ROUTER_SIG_ED25519_LINE);
   }
+
+  private static final String ONION_KEY_CROSSCERT_LINES =
+      "onion-key-crosscert\n"
+      + "-----BEGIN CROSSCERT-----\n"
+      + "gVWpiNgG2FekW1uonr4KKoqykjr4bqUBKGZfu6s9rvsV1TThnquZNP6ZhX2IPdQA"
+      + "\nlfKtzFggGu/4BiJ5oTSDj2sK2DMjY3rjrMQZ3I/wJ25yhc9gxjqYqUYO9MmJwA"
+      + "Lp\nfYkqp/t4WchJpyva/4hK8vITsI6eT2BfY/DWMy/suIE=\n"
+      + "-----END CROSSCERT-----";
+
+  private static final String NTOR_ONION_KEY_CROSSCERT_LINES =
+      "ntor-onion-key-crosscert 1\n"
+      + "-----BEGIN ED25519 CERT-----\n"
+      + "AQoABiUeAdauu1MxYGMmGLTCPaoes0RvW7udeLc1t8LZ4P3CDo5bAN4nrRfbCfOt"
+      + "\nz2Nwqn8tER1a+Ry6Vs+ilMZA55Rag4+f6Zdb1fmHWknCxbQlLHpqHACMtemPda"
+      + "Ka\nErPtMuiEqAc=\n"
+      + "-----END ED25519 CERT-----";
+
+  @Test()
+  public void testOnionKeyCrosscert() throws DescriptorParseException {
+    ServerDescriptor descriptor =
+        DescriptorBuilder.createWithOnionKeyCrosscertLines(
+        ONION_KEY_CROSSCERT_LINES);
+    assertEquals(ONION_KEY_CROSSCERT_LINES.substring(
+        ONION_KEY_CROSSCERT_LINES.indexOf("\n") + 1),
+        descriptor.getOnionKeyCrosscert());
+  }
+
+  @Test(expected = DescriptorParseException.class)
+  public void testOnionKeyCrosscertDuplicate()
+      throws DescriptorParseException {
+    DescriptorBuilder.createWithOnionKeyCrosscertLines(
+    ONION_KEY_CROSSCERT_LINES + "\n" + ONION_KEY_CROSSCERT_LINES);
+  }
+
+  @Test()
+  public void testNtorOnionKeyCrosscert()
+      throws DescriptorParseException {
+    ServerDescriptor descriptor =
+        DescriptorBuilder.createWithNtorOnionKeyCrosscertLines(
+        NTOR_ONION_KEY_CROSSCERT_LINES);
+    assertEquals(NTOR_ONION_KEY_CROSSCERT_LINES.substring(
+        NTOR_ONION_KEY_CROSSCERT_LINES.indexOf("\n") + 1),
+        descriptor.getNtorOnionKeyCrosscert());
+    assertEquals(1, descriptor.getNtorOnionKeyCrosscertSign());
+  }
+
+  @Test(expected = DescriptorParseException.class)
+  public void testNtorOnionKeyCrosscertDuplicate()
+      throws DescriptorParseException {
+    DescriptorBuilder.createWithOnionKeyCrosscertLines(
+        NTOR_ONION_KEY_CROSSCERT_LINES + "\n"
+        + NTOR_ONION_KEY_CROSSCERT_LINES);
+  }
 }
 



More information about the tor-commits mailing list