Commit f4fca351 authored by Karsten Loesing's avatar Karsten Loesing
Browse files

Support (ntor-)onion-key crosscerts.

parent f9762314
......@@ -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
......
......@@ -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();
}
......@@ -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;
}
}
......@@ -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);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment