Commit 54e61094 authored by George Kadianakis's avatar George Kadianakis
Browse files

Merge remote-tracking branch 'tor-gitlab/mr/174' into master

parents df163760 62667b49
o Minor features (specification update):
- Several fields in microdescriptors, router descriptors, and consensus
documents that were formerly optional are now required. Implements
proposal 315; closes ticket 40132.
......@@ -70,19 +70,39 @@ i2d_RSAPublicKey.argtypes = [
i2d_RSAPublicKey.restype = ctypes.c_int
HEADER = """\
router fred 127.0.0.1 9001 0 9002
identity-ed25519
{d.ED_CERT}
signing-key
{d.RSA_IDENTITY}
master-key-ed25519 {d.ED_IDENTITY}
onion-key
{d.RSA_ONION_KEY}
ntor-onion-key {d.NTOR_ONION_KEY}
ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
{d.NTOR_CROSSCERT}
onion-key-crosscert
{d.RSA_CROSSCERT_ED}
"""
FOOTER="""
"""
def rsa_sign(msg, rsa):
buf = ctypes.create_string_buffer(1024)
buf = ctypes.create_string_buffer(2048)
n = RSA_private_encrypt(len(msg), msg, buf, rsa, 1)
if n <= 0:
raise Exception()
return buf.raw[:n]
def b64(x):
x = base64.b64encode(x)
def b64(x1):
x = binascii.b2a_base64(x1)
res = []
for i in xrange(0, len(x), 64):
res.append(x[i:i+64]+"\n")
return "".join(res)
res.append((x[i:i+64]).decode("ascii"))
return "\n".join(res)
def bio_extract(bio):
buf = ctypes.c_char_p()
......@@ -100,18 +120,19 @@ def make_rsa_key(e=65537):
n = crypt.i2d_RSAPublicKey(rsa, ctypes.byref(pBuf))
s = buf.raw[:n]
digest = hashlib.sha1(s).digest()
pem = pem.decode("ascii")
return (rsa,pem,digest)
def makeEdSigningKeyCert(sk_master, pk_master, pk_signing, date,
includeSigning=False, certType=1):
assert len(pk_signing) == len(pk_master) == 32
expiration = struct.pack("!L", date//3600)
expiration = struct.pack(b"!L", date//3600)
if includeSigning:
extensions = "\x01\x00\x20\x04\x00%s"%(pk_master)
extensions = b"\x01\x00\x20\x04\x00%s"%(pk_master)
else:
extensions = "\x00"
signed = "\x01%s%s\x01%s%s" % (
chr(certType), expiration, pk_signing, extensions)
extensions = b"\x00"
signed = b"\x01%s%s\x01%s%s" % (
bytes([certType]), expiration, pk_signing, extensions)
signature = ed25519_exts_ref.signatureWithESK(signed, sk_master, pk_master)
assert len(signature) == 64
return signed+signature
......@@ -127,7 +148,7 @@ MAGIC2 = "<<<<<!#!#!#XYZZY#!#!#!>>>>>"
class OnDemandKeys(object):
def __init__(self, certDate=None):
if certDate is None:
certDate = time.time() + 86400
certDate = int(time.time()) + 86400
self.certDate = certDate
self.rsa_id = None
self.rsa_onion_key = None
......@@ -151,7 +172,7 @@ class OnDemandKeys(object):
@property
def RSA_FINGERPRINT_NOSPACE(self):
return binascii.b2a_hex(self.RSA_ID_DIGEST).upper()
return binascii.b2a_hex(self.RSA_ID_DIGEST).upper().decode("ascii")
@property
def RSA_ONION_KEY(self):
......@@ -162,7 +183,7 @@ class OnDemandKeys(object):
@property
def RSA_FINGERPRINT(self):
hexdigest = self.RSA_FINGERPRINT_NOSPACEK
hexdigest = self.RSA_FINGERPRINT_NOSPACE
return " ".join(hexdigest[i:i+4] for i in range(0,len(hexdigest),4))
@property
......@@ -178,7 +199,7 @@ class OnDemandKeys(object):
if self.ntor_sk is None:
self.ntor_sk = slownacl_curve25519.Private()
self.ntor_pk = self.ntor_sk.get_public()
return base64.b64encode(self.ntor_pk.serialize())
return base64.b64encode(self.ntor_pk.serialize()).decode("ascii")
@property
def ED_CERT(self):
......@@ -191,6 +212,11 @@ class OnDemandKeys(object):
return objwrap('ED25519 CERT', b64(self.ed_cert))
@property
def ED_IDENTITY(self):
self.ED_CERT
return binascii.b2a_base64(self.ed_id_pk).strip().decode("ascii")
@property
def NTOR_CROSSCERT(self):
if self.ntor_crosscert is None:
......@@ -199,7 +225,7 @@ class OnDemandKeys(object):
ed_privkey = self.ntor_sk.serialize() + os.urandom(32)
ed_pub0 = ed25519_exts_ref.publickeyFromESK(ed_privkey)
sign = (ord(ed_pub0[31]) & 255) >> 7
sign = ((ed_pub0[31]) & 255) >> 7
self.ntor_crosscert = makeEdSigningKeyCert(self.ntor_sk.serialize() + os.urandom(32), ed_pub0, self.ed_id_pk, self.certDate, certType=10)
self.ntor_crosscert_sign = sign
......@@ -234,18 +260,19 @@ class OnDemandKeys(object):
self.ED_CERT
signed_part = body[:idx+len("\nrouter-sig-ed25519 ")]
signed_part = "Tor router descriptor signature v1" + signed_part
digest = hashlib.sha256(signed_part).digest()
digest = hashlib.sha256(signed_part.encode("utf-8")).digest()
ed_sig = ed25519_exts_ref.signatureWithESK(digest,
self.ed_signing_sk, self.ed_signing_pk)
body = body.replace(MAGIC2, base64.b64encode(ed_sig).replace("=",""))
body = body.replace(MAGIC2, base64.b64encode(ed_sig).decode("ascii").replace("=",""))
self.RSA_IDENTITY
idx = body.rindex("\nrouter-signature")
end_of_sig = body.index("\n", idx+1)
signed_part = body[:end_of_sig+1]
digest = hashlib.sha1(signed_part).digest()
digest = hashlib.sha1(signed_part.encode("utf-8")).digest()
assert len(digest) == 20
rsasig = rsa_sign(digest, self.rsa_id)
......@@ -318,29 +345,42 @@ def emit_ri(name, body):
body = info.sign_desc(body)
print_c_string("EX_RI_%s"%name.upper(), body)
def emit_ei(name, body):
def emit_ei(name, body, fields):
info = OnDemandKeys()
body = body.format(d=info)
body = info.sign_desc(body)
print_c_string("EX_EI_%s"%name.upper(), body)
print('const char EX_EI_{NAME}_FP[] = "{d.RSA_FINGERPRINT_NOSPACE}";'.format(
print('ATTR_UNUSED static const char EX_EI_{NAME}_FP[] = "{d.RSA_FINGERPRINT_NOSPACE}";'.format(
d=info, NAME=name.upper()))
print("ATTR_UNUSED")
print_c_string("EX_EI_%s_KEY"%name.upper(), info.RSA_IDENTITY)
def analyze(s):
fields = {}
while s.startswith(":::"):
first,s=s.split("\n", 1)
m = re.match(r'^:::(\w+)=(.*)',first)
if not m:
raise ValueError(first)
k,v = m.groups()
fields[k] = v
return fields, s
def process_file(s):
fields, s = analyze(s)
while s:
fields = {}
s_pre = s
while s.startswith(":::"):
first,s=s.split("\n", 1)
m = re.match(r'^:::(\w+)=(.*)',first)
if not m:
raise ValueError(first)
k,v = m.groups()
fields[k] = v
if "name" not in fields:
print(repr(s_pre))
idx = s.find(":::")
if idx != -1:
body = s[:idx].rstrip()
s = s[idx:]
else:
body = s.rstrip()
s = ""
yield (fields, body)
def emit_entry(fields, s):
try:
name = fields['name']
tp = fields['type']
......@@ -348,12 +388,21 @@ def process_file(s):
raise ValueError("missing required field")
if tp == 'ei':
emit_ei(name, s)
emit_ei(name, s, fields)
elif tp == 'ri':
emit_ri(name, s)
else:
raise ValueError("unrecognized type")
def process_file(s):
print("""\
/* These entries are automatically generated by makedesc.py to make sure
* that their keys and signatures are right except when otherwise
* specified. */
""")
for (fields, s) in analyze(s):
emit_entry(fields, s)
if __name__ == '__main__':
import sys
for fn in sys.argv[1:]:
......
......@@ -31,7 +31,7 @@
// clang-format off
static token_rule_t microdesc_token_table[] = {
T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
T1("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
T0N("id", K_ID, GE(2), NO_OBJ ),
T0N("a", K_A, GE(1), NO_OBJ ),
T01("family", K_FAMILY, CONCAT_ARGS, NO_OBJ ),
......
......@@ -54,7 +54,7 @@ static token_rule_t rtrstatus_token_table[] = {
T01("w", K_W, ARGS, NO_OBJ ),
T0N("m", K_M, CONCAT_ARGS, NO_OBJ ),
T0N("id", K_ID, GE(2), NO_OBJ ),
T01("pr", K_PROTO, CONCAT_ARGS, NO_OBJ ),
T1("pr", K_PROTO, CONCAT_ARGS, NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
END_OF_TABLE
};
......
......@@ -91,24 +91,24 @@ const token_rule_t routerdesc_token_table[] = {
T01("ipv6-policy", K_IPV6_POLICY, CONCAT_ARGS, NO_OBJ),
T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
T1("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T01("uptime", K_UPTIME, GE(1), NO_OBJ ),
T01("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ ),
T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ),
T01("proto", K_PROTO, CONCAT_ARGS, NO_OBJ ),
T1("proto", K_PROTO, CONCAT_ARGS, NO_OBJ ),
T01("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
T01("extra-info-digest", K_EXTRA_INFO_DIGEST, GE(1), NO_OBJ ),
T01("hidden-service-dir", K_HIDDEN_SERVICE_DIR, NO_ARGS, NO_OBJ ),
T01("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ),
T01("master-key-ed25519", K_MASTER_KEY_ED25519, GE(1), NO_OBJ ),
T01("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ),
T01("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),
T01("ntor-onion-key-crosscert", K_NTOR_ONION_KEY_CROSSCERT,
T1("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ),
T1("master-key-ed25519", K_MASTER_KEY_ED25519, GE(1), NO_OBJ ),
T1("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ),
T1("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),
T1("ntor-onion-key-crosscert", K_NTOR_ONION_KEY_CROSSCERT,
EQ(1), NEED_OBJ ),
T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS, NO_ARGS, NO_OBJ ),
......@@ -131,8 +131,8 @@ const token_rule_t routerdesc_token_table[] = {
static token_rule_t extrainfo_token_table[] = {
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T01("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ),
T01("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ),
T1("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ),
T1("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
......
......@@ -139,13 +139,13 @@ signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len))
* the document when generating log messages. Return 0 on success, negative
* on failure.
*/
int
check_signature_token(const char *digest,
MOCK_IMPL(int,
check_signature_token,(const char *digest,
ssize_t digest_len,
directory_token_t *tok,
crypto_pk_t *pkey,
int flags,
const char *doctype)
const char *doctype))
{
char *signed_digest;
size_t keysize;
......
......@@ -20,12 +20,12 @@ int router_get_hash_impl(const char *s, size_t s_len, char *digest,
#define CST_NO_CHECK_OBJTYPE (1<<0)
struct directory_token_t;
int check_signature_token(const char *digest,
ssize_t digest_len,
struct directory_token_t *tok,
crypto_pk_t *pkey,
int flags,
const char *doctype);
MOCK_DECL(int, check_signature_token,(const char *digest,
ssize_t digest_len,
struct directory_token_t *tok,
crypto_pk_t *pkey,
int flags,
const char *doctype));
int router_get_hash_impl_helper(const char *s, size_t s_len,
const char *start_str,
......
......@@ -53,7 +53,7 @@ def blindPK(pk, param):
def expandSK(sk):
h = H(sk)
a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
k = ''.join([h[i] for i in range(b/8,b/4)])
k = bytes(h[i] for i in range(b//8,b//4))
assert len(k) == 32
return encodeint(a)+k
......@@ -64,7 +64,7 @@ def publickeyFromESK(h):
def signatureWithESK(m,h,pk):
a = decodeint(h[:32])
r = Hint(''.join([h[i] for i in range(b/8,b/4)]) + m)
r = Hint(bytes([h[i] for i in range(b//8,b//4)]) + m)
R = scalarmult(B,r)
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
return encodepoint(R) + encodeint(S)
......@@ -263,5 +263,3 @@ if __name__ == '__main__':
unittest.main()
else:
makeTestVectors()
This diff is collapsed.
:::comment=this file is to be used with the makedescs.py utility
:::name=minimal
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
{d.ED_CERT}
published 2020-10-14 20:58:04
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=maximal
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
{d.ED_CERT}
published 2020-10-14 20:58:04
opt foobarbaz
read-history 900 1,2,3
write-history 900 1,2,3
dirreq-v2-ips 1
dirreq-v3-ips 100
dirreq-v3-reqs blahblah
dirreq-v2-share blahblah
dirreq-v3-share blahblah
dirreq-v2-resp djfkdj
dirreq-v3-resp djfkdj
dirreq-v2-direct-dl djfkdj
dirreq-v3-direct-dl djfkdj
dirreq-v2-tunneled-dl djfkdj
dirreq-v3-tunneled-dl djfkdj
dirreq-stats-end foobar
entry-ips jfsdfds
entry-stats-end ksdflkjfdkf
cell-stats-end FOO
cell-processed-cells FOO
cell-queued-cells FOO
cell-time-in-queue FOO
cell-circuits-per-decile FOO
exit-stats-end FOO
exit-kibibytes-written FOO
exit-kibibytes-read FOO
exit-streams-opened FOO
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=bad_sig1
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
{d.ED_CERT}
published 2020-10-14 20:58:04
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
-----BEGIN SIGNATURE-----
V3l9u1uUdGiUPOl8j+hXXw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi
zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2R3EA=
-----END SIGNATURE-----
:::name=bad_sig2
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
{d.ED_CERT}
published 2020-10-14 20:58:04
router-sig-ed25519 X{d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=bad_nickname
:::type=ei
extra-info bobhasaverylongnameandidontthinkweshouldlethim {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
{d.ED_CERT}
published 2020-10-14 20:58:04
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=bad_tokens
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
{d.ED_CERT}
published 2020-10-14 20:58:04
published 2020-10-14 20:58:04
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=bad_start
:::type=ei
identity-ed25519
{d.ED_CERT}
published 2020-10-14 20:58:04
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=bad_published
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
{d.ED_CERT}
published 2020-99-14 20:58:04
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=ed_missing_sig
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
{d.ED_CERT}
published 2020-10-14 20:58:04
router-signature
{d.RSA_SIGNATURE}
:::name=ed_missing_cert
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
published 2020-10-14 20:58:04
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=ed_bad_cert1
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
-----BEGIN PLAGICAL SPELL-----
aaaa
-----END PLAGICAL SPELL-----
published 2020-10-14 20:58:04
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=ed_bad_cert2
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
-----BEGIN ED25519 CERT-----
AQoABf55Acpw27GZBdwGCgawCj2F/DPadt8F/9DnEWywEew1Yi3qAOtLpCB8KXL7
4w5deFW2RBg8qTondNSUvAmwYLbLjNXMmgA3+nkoJOP3fcmQMHz1jm5xzgs2lCVP
t5txApaBIA4=
-----END ED25519 CERT-----
published 2020-10-14 20:58:04
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=ed_misplaced_cert
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
published 2020-10-14 20:58:04
identity-ed25519
{d.ED_CERT}
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=ed_misplaced_sig
:::type=ei
extra-info HomersRelay {d.RSA_FINGERPRINT_NOSPACE}
identity-ed25519
{d.ED_CERT}
router-sig-ed25519 {d.ED_SIGNATURE}
published 2020-10-14 20:58:04
router-signature
{d.RSA_SIGNATURE}
This diff is collapsed.
:::comment=this file is to be used with the makedescs.py utility
:::name=MINIMAL
:::type=ri
router fred 127.0.0.1 9001 0 9002
identity-ed25519
{d.ED_CERT}
signing-key
{d.RSA_IDENTITY}
master-key-ed25519 {d.ED_IDENTITY}
onion-key
{d.RSA_ONION_KEY}
ntor-onion-key {d.NTOR_ONION_KEY}
ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
{d.NTOR_CROSSCERT}
onion-key-crosscert
{d.RSA_CROSSCERT_ED}
published 2014-10-05 12:00:00
bandwidth 1000 1000 1000
proto Link=5
reject *:*
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::name=MAXIMAL
:::type=ri
router fred 127.0.0.1 9001 0 9002
identity-ed25519
{d.ED_CERT}
signing-key
{d.RSA_IDENTITY}
master-key-ed25519 {d.ED_IDENTITY}
onion-key
{d.RSA_ONION_KEY}
ntor-onion-key {d.NTOR_ONION_KEY}
ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
{d.NTOR_CROSSCERT}
onion-key-crosscert
{d.RSA_CROSSCERT_ED}
published 2014-10-05 12:00:00
bandwidth 1000 1000 1000
proto Link=5
reject 127.0.0.1:*
accept *:80
reject *:*
ipv6-policy accept 80,100,101
uptime 1000
hibernating 0
unrecognized-keywords are just dandy in this format
platform Tor 0.2.4.23 on a Banana PC Jr 6000 Series
contact O.W.Jones
fingerprint {d.RSA_FINGERPRINT}
read-history 900 1,2,3,4
write-history 900 1,2,3,4
extra-info-digest AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
hidden-service-dir
allow-single-hop-exits
family $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
caches-extra-info
or-address [::1:2:3:4]:9999
or-address 127.0.0.99:10000
opt fred is a fine router
router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
{d.RSA_SIGNATURE}
:::comment=this one has somebody else's signature.
:::name=BAD_SIG1
:::type=ri
router fred 127.0.0.1 9001 0 9002
identity-ed25519
{d.ED_CERT}