mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
Merge branch '12498_ed25519_keys_v6'
Fixed numerous conflicts, and ported code to use new base64 api.
This commit is contained in:
commit
1b52e95028
@ -1857,6 +1857,13 @@ is non-zero):
|
||||
this. If this option is set to 0, Tor will try to pick a reasonable
|
||||
default based on your system's physical memory. (Default: 0)
|
||||
|
||||
[[SigningKeyLifetime]] **SigningKeyLifetime** __N__ **days**|**weeks**|**months**::
|
||||
For how long should each Ed25519 signing key be valid? Tor uses a
|
||||
permanent master identity key that can be kept offline, and periodically
|
||||
generates new "signing" keys that it uses online. This option
|
||||
configures their lifetime.
|
||||
(Default: 30 days)
|
||||
|
||||
DIRECTORY SERVER OPTIONS
|
||||
------------------------
|
||||
|
||||
@ -2349,6 +2356,23 @@ The following options are used for running a testing Tor network.
|
||||
authority on a testing network. Overrides the usual default lower bound
|
||||
of 4 KB. (Default: 0)
|
||||
|
||||
[[TestingLinkCertLifetime]] **TestingLinkCertifetime** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**|**months**::
|
||||
Overrides the default lifetime for the certificates used to authenticate
|
||||
our X509 link cert with our ed25519 signing key.
|
||||
(Default: 2 days)
|
||||
|
||||
[[TestingAuthKeyLifetime]] **TestingAuthKeyLifetime** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**|**months**::
|
||||
Overrides the default lifetime for a signing Ed25519 TLS Link authentication
|
||||
key.
|
||||
(Default: 2 days)
|
||||
|
||||
[[TestingLinkKeySlop]] **TestingLinkKeySlop** __N__ **seconds**|**minutes**|**hours**::
|
||||
[[TestingAuthKeySlop]] **TestingAuthKeySlop** __N__ **seconds**|**minutes**|**hours**::
|
||||
[[TestingSigningKeySlop]] **TestingSigningKeySlop** __N__ **seconds**|**minutes**|**hours**::
|
||||
How early before the official expiration of a an Ed25519 signing key do
|
||||
we replace it and issue a new key?
|
||||
(Default: 3 hours for link and auth; 1 day for signing.)
|
||||
|
||||
SIGNALS
|
||||
-------
|
||||
|
||||
|
@ -14,6 +14,18 @@ import binascii
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
import hashlib
|
||||
import optparse
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import time
|
||||
import UserDict
|
||||
|
||||
import slow_ed25519
|
||||
import slownacl_curve25519
|
||||
import ed25519_exts_ref
|
||||
|
||||
# Pull in the openssl stuff we need.
|
||||
|
||||
crypt = ctypes.CDLL(ctypes.util.find_library('crypto'))
|
||||
BIO_s_mem = crypt.BIO_s_mem
|
||||
@ -24,6 +36,15 @@ BIO_new = crypt.BIO_new
|
||||
BIO_new.argtypes = [ctypes.c_void_p]
|
||||
BIO_new.restype = ctypes.c_void_p
|
||||
|
||||
crypt.BIO_free.argtypes = [ctypes.c_void_p]
|
||||
crypt.BIO_free.restype = ctypes.c_int
|
||||
|
||||
crypt.BIO_ctrl.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_long, ctypes.c_void_p ]
|
||||
crypt.BIO_ctrl.restype = ctypes.c_long
|
||||
|
||||
crypt.PEM_write_bio_RSAPublicKey.argtypes = [ ctypes.c_void_p, ctypes.c_void_p ]
|
||||
crypt.PEM_write_bio_RSAPublicKey.restype = ctypes.c_int
|
||||
|
||||
RSA_generate_key = crypt.RSA_generate_key
|
||||
RSA_generate_key.argtypes = [ctypes.c_int, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_void_p]
|
||||
RSA_generate_key.restype = ctypes.c_void_p
|
||||
@ -39,6 +60,14 @@ i2d_RSAPublicKey.argtypes = [
|
||||
]
|
||||
i2d_RSAPublicKey.restype = ctypes.c_int
|
||||
|
||||
|
||||
def rsa_sign(msg, rsa):
|
||||
buf = ctypes.create_string_buffer(1024)
|
||||
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)
|
||||
res = []
|
||||
@ -51,29 +80,188 @@ def bio_extract(bio):
|
||||
length = crypt.BIO_ctrl(bio, 3, 0, ctypes.byref(buf))
|
||||
return ctypes.string_at(buf, length)
|
||||
|
||||
def make_key(e=65537):
|
||||
def make_rsa_key(e=65537):
|
||||
rsa = crypt.RSA_generate_key(1024, e, None, None)
|
||||
bio = BIO_new(BIO_s_mem())
|
||||
crypt.PEM_write_bio_RSAPublicKey(bio, rsa)
|
||||
pem = bio_extract(bio).rstrip()
|
||||
crypt.BIO_free(bio)
|
||||
|
||||
buf = ctypes.create_string_buffer(1024)
|
||||
pBuf = ctypes.c_char_p(ctypes.addressof(buf))
|
||||
n = crypt.i2d_RSAPublicKey(rsa, ctypes.byref(pBuf))
|
||||
s = buf.raw[:n]
|
||||
digest = hashlib.sha1(s).digest()
|
||||
|
||||
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)
|
||||
if includeSigning:
|
||||
extensions = "\x01\x00\x20\x04\x00%s"%(pk_master)
|
||||
else:
|
||||
extensions = "\x00"
|
||||
signed = "\x01%s%s\x01%s%s" % (
|
||||
chr(certType), expiration, pk_signing, extensions)
|
||||
signature = ed25519_exts_ref.signatureWithESK(signed, sk_master, pk_master)
|
||||
assert len(signature) == 64
|
||||
return signed+signature
|
||||
|
||||
def objwrap(identifier, body):
|
||||
return ("-----BEGIN {0}-----\n"
|
||||
"{1}"
|
||||
"-----END {0}-----").format(identifier, body)
|
||||
|
||||
MAGIC1 = "<<<<<<MAGIC>>>>>>"
|
||||
MAGIC2 = "<<<<<!#!#!#XYZZY#!#!#!>>>>>"
|
||||
|
||||
class OnDemandKeys(object):
|
||||
def __init__(self, certDate=None):
|
||||
if certDate is None:
|
||||
certDate = time.time() + 86400
|
||||
self.certDate = certDate
|
||||
self.rsa_id = None
|
||||
self.rsa_onion_key = None
|
||||
self.ed_id_sk = None
|
||||
self.ntor_sk = None
|
||||
self.ntor_crosscert = None
|
||||
self.rsa_crosscert_ed = None
|
||||
self.rsa_crosscert_noed = None
|
||||
|
||||
@property
|
||||
def RSA_IDENTITY(self):
|
||||
if self.rsa_id is None:
|
||||
self.rsa_id, self.rsa_ident_pem, self.rsa_id_digest = make_rsa_key()
|
||||
|
||||
return self.rsa_ident_pem
|
||||
|
||||
@property
|
||||
def RSA_ID_DIGEST(self):
|
||||
self.RSA_IDENTITY
|
||||
return self.rsa_id_digest
|
||||
|
||||
@property
|
||||
def RSA_FINGERPRINT_NOSPACE(self):
|
||||
return binascii.b2a_hex(self.RSA_ID_DIGEST).upper()
|
||||
|
||||
@property
|
||||
def RSA_ONION_KEY(self):
|
||||
if self.rsa_onion_key is None:
|
||||
self.rsa_onion_key, self.rsa_onion_pem, _ = make_rsa_key()
|
||||
|
||||
return self.rsa_onion_pem
|
||||
|
||||
@property
|
||||
def RSA_FINGERPRINT(self):
|
||||
hexdigest = self.RSA_FINGERPRINT_NOSPACEK
|
||||
return " ".join(hexdigest[i:i+4] for i in range(0,len(hexdigest),4))
|
||||
|
||||
@property
|
||||
def RSA_SIGNATURE(self):
|
||||
return MAGIC1
|
||||
|
||||
@property
|
||||
def ED_SIGNATURE(self):
|
||||
return MAGIC2
|
||||
|
||||
@property
|
||||
def NTOR_ONION_KEY(self):
|
||||
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())
|
||||
|
||||
@property
|
||||
def ED_CERT(self):
|
||||
if self.ed_id_sk is None:
|
||||
self.ed_id_sk = ed25519_exts_ref.expandSK(os.urandom(32))
|
||||
self.ed_signing_sk = ed25519_exts_ref.expandSK(os.urandom(32))
|
||||
self.ed_id_pk = ed25519_exts_ref.publickeyFromESK(self.ed_id_sk)
|
||||
self.ed_signing_pk = ed25519_exts_ref.publickeyFromESK(self.ed_signing_sk)
|
||||
self.ed_cert = makeEdSigningKeyCert(self.ed_id_sk, self.ed_id_pk, self.ed_signing_pk, self.certDate, includeSigning=True, certType=4)
|
||||
|
||||
return objwrap('ED25519 CERT', b64(self.ed_cert))
|
||||
|
||||
@property
|
||||
def NTOR_CROSSCERT(self):
|
||||
if self.ntor_crosscert is None:
|
||||
self.ED_CERT
|
||||
self.NTOR_ONION_KEY
|
||||
|
||||
ed_privkey = self.ntor_sk.serialize() + os.urandom(32)
|
||||
ed_pub0 = ed25519_exts_ref.publickeyFromESK(ed_privkey)
|
||||
sign = (ord(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
|
||||
|
||||
return objwrap('ED25519 CERT', b64(self.ntor_crosscert))
|
||||
|
||||
@property
|
||||
def NTOR_CROSSCERT_SIGN(self):
|
||||
self.NTOR_CROSSCERT
|
||||
return self.ntor_crosscert_sign
|
||||
|
||||
@property
|
||||
def RSA_CROSSCERT_NOED(self):
|
||||
if self.rsa_crosscert_noed is None:
|
||||
self.RSA_ONION_KEY
|
||||
signed = self.RSA_ID_DIGEST
|
||||
self.rsa_crosscert_noed = rsa_sign(signed, self.rsa_onion_key)
|
||||
return objwrap("CROSSCERT",b64(self.rsa_crosscert_noed))
|
||||
|
||||
@property
|
||||
def RSA_CROSSCERT_ED(self):
|
||||
if self.rsa_crosscert_ed is None:
|
||||
self.RSA_ONION_KEY
|
||||
self.ED_CERT
|
||||
signed = self.RSA_ID_DIGEST + self.ed_id_pk
|
||||
self.rsa_crosscert_ed = rsa_sign(signed, self.rsa_onion_key)
|
||||
return objwrap("CROSSCERT",b64(self.rsa_crosscert_ed))
|
||||
|
||||
def sign_desc(self, body):
|
||||
idx = body.rfind("\nrouter-sig-ed25519 ")
|
||||
if idx >= 0:
|
||||
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()
|
||||
ed_sig = ed25519_exts_ref.signatureWithESK(digest,
|
||||
self.ed_signing_sk, self.ed_signing_pk)
|
||||
|
||||
body = body.replace(MAGIC2, base64.b64encode(ed_sig).replace("=",""))
|
||||
|
||||
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()
|
||||
assert len(digest) == 20
|
||||
|
||||
rsasig = rsa_sign(digest, self.rsa_id)
|
||||
|
||||
body = body.replace(MAGIC1, objwrap("SIGNATURE", b64(rsasig)))
|
||||
|
||||
return body
|
||||
|
||||
|
||||
def signdesc(body, args_out=None):
|
||||
rsa, ident_pem, id_digest = make_key()
|
||||
_, onion_pem, _ = make_key()
|
||||
|
||||
need_ed = '{ED25519-CERT}' in body or '{ED25519-SIGNATURE}' in body
|
||||
if need_ed:
|
||||
sk_master = os.urandom(32)
|
||||
sk_signing = os.urandom(32)
|
||||
pk_master = slow_ed25519.pubkey(sk_master)
|
||||
pk_signing = slow_ed25519.pubkey(sk_signing)
|
||||
|
||||
hexdigest = binascii.b2a_hex(id_digest).upper()
|
||||
fingerprint = " ".join(hexdigest[i:i+4] for i in range(0,len(hexdigest),4))
|
||||
|
||||
MAGIC = "<<<<<<MAGIC>>>>>>"
|
||||
MORE_MAGIC = "<<<<<!#!#!#XYZZY#!#!#!>>>>>"
|
||||
args = {
|
||||
"RSA-IDENTITY" : ident_pem,
|
||||
"ONION-KEY" : onion_pem,
|
||||
@ -81,6 +269,11 @@ def signdesc(body, args_out=None):
|
||||
"FINGERPRINT-NOSPACE" : hexdigest,
|
||||
"RSA-SIGNATURE" : MAGIC
|
||||
}
|
||||
if need_ed:
|
||||
args['ED25519-CERT'] = makeEdSigningKeyCert(
|
||||
sk_master, pk_master, pk_signing)
|
||||
args['ED25519-SIGNATURE'] = MORE_MAGIC
|
||||
|
||||
if args_out:
|
||||
args_out.update(args)
|
||||
body = body.format(**args)
|
||||
@ -104,115 +297,55 @@ def signdesc(body, args_out=None):
|
||||
|
||||
return body.rstrip()
|
||||
|
||||
def emit_ri(name, body, args_out=None):
|
||||
print "const char %s[] ="%name
|
||||
body = "\n".join(line.rstrip() for line in body.split("\n"))+"\n"
|
||||
b = signdesc(body, args_out)
|
||||
for line in b.split("\n"):
|
||||
print ' "%s\\n"'%line
|
||||
def print_c_string(ident, body):
|
||||
print "static const char %s[] =" % ident
|
||||
for line in body.split("\n"):
|
||||
print ' "%s\\n"' %(line)
|
||||
print " ;"
|
||||
|
||||
def emit_ri(name, body):
|
||||
info = OnDemandKeys()
|
||||
body = body.format(d=info)
|
||||
body = info.sign_desc(body)
|
||||
print_c_string("EX_RI_%s"%name.upper(), body)
|
||||
|
||||
def emit_ei(name, body):
|
||||
args = { 'NAME' : name }
|
||||
emit_ri(name, body, args)
|
||||
args['key'] = "\n".join(
|
||||
' "%s\\n"'%line for line in args['RSA-IDENTITY'].split("\n"))
|
||||
print """
|
||||
const char {NAME}_fp[] = "{FINGERPRINT-NOSPACE}";
|
||||
const char {NAME}_key[] =
|
||||
{key};""".format(**args)
|
||||
info = OnDemandKeys()
|
||||
body = body.format(d=info)
|
||||
body = info.sign_desc(body)
|
||||
print_c_string("EX_EI_%s"%name.upper(), body)
|
||||
|
||||
if 0:
|
||||
emit_ri("minimal",
|
||||
"""\
|
||||
router fred 127.0.0.1 9001 0 9002
|
||||
signing-key
|
||||
{RSA-IDENTITY}
|
||||
onion-key
|
||||
{ONION-KEY}
|
||||
published 2014-10-05 12:00:00
|
||||
bandwidth 1000 1000 1000
|
||||
reject *:*
|
||||
router-signature
|
||||
{RSA-SIGNATURE}
|
||||
""")
|
||||
print 'const char EX_EI_{NAME}_FP[] = "{d.RSA_FINGERPRINT_NOSPACE}";'.format(
|
||||
d=info, NAME=name.upper())
|
||||
print_c_string("EX_EI_%s_KEY"%name.upper(), info.RSA_IDENTITY)
|
||||
|
||||
if 0:
|
||||
emit_ri("maximal",
|
||||
"""\
|
||||
router fred 127.0.0.1 9001 0 9002
|
||||
signing-key
|
||||
{RSA-IDENTITY}
|
||||
onion-key
|
||||
{ONION-KEY}
|
||||
published 2014-10-05 12:00:00
|
||||
bandwidth 1000 1000 1000
|
||||
reject 127.0.0.1:*
|
||||
accept *:80
|
||||
reject *:*
|
||||
ipv6-policy accept 80,100,101
|
||||
ntor-onion-key s7rSohmz9SXn8WWh1EefTHIsWePthsEntQi0WL+ScVw
|
||||
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 {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-signature
|
||||
{RSA-SIGNATURE}
|
||||
""")
|
||||
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
|
||||
|
||||
if 0:
|
||||
emit_ei("maximal",
|
||||
"""\
|
||||
extra-info bob {FINGERPRINT-NOSPACE}
|
||||
published 2014-10-05 20:07:00
|
||||
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-signature
|
||||
{RSA-SIGNATURE}
|
||||
""")
|
||||
def process_file(s):
|
||||
fields, s = analyze(s)
|
||||
try:
|
||||
name = fields['name']
|
||||
tp = fields['type']
|
||||
except KeyError:
|
||||
raise ValueError("missing required field")
|
||||
|
||||
if 0:
|
||||
emit_ei("minimal",
|
||||
"""\
|
||||
extra-info bob {FINGERPRINT-NOSPACE}
|
||||
published 2014-10-05 20:07:00
|
||||
router-signature
|
||||
{RSA-SIGNATURE}
|
||||
""")
|
||||
if tp == 'ei':
|
||||
emit_ei(name, s)
|
||||
elif tp == 'ri':
|
||||
emit_ri(name, s)
|
||||
else:
|
||||
raise ValueError("unrecognized type")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
for fn in sys.argv[1:]:
|
||||
process_file(open(fn).read())
|
||||
|
@ -5,7 +5,7 @@ if test "x$TRUNNEL_PATH" != "x"; then
|
||||
export PYTHONPATH
|
||||
fi
|
||||
|
||||
python -m trunnel --require-version=1.2 ./src/trunnel/*.trunnel
|
||||
python -m trunnel --require-version=1.4 ./src/trunnel/*.trunnel
|
||||
|
||||
python -m trunnel --require-version=1.2 --write-c-files --target-dir=./src/ext/trunnel/
|
||||
python -m trunnel --require-version=1.4 --write-c-files --target-dir=./src/ext/trunnel/
|
||||
|
||||
|
@ -208,6 +208,19 @@ smartlist_string_pos(const smartlist_t *sl, const char *element)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** If <b>element</b> is the same pointer as an element of <b>sl</b>, return
|
||||
* that element's index. Otherwise, return -1. */
|
||||
int
|
||||
smartlist_pos(const smartlist_t *sl, const void *element)
|
||||
{
|
||||
int i;
|
||||
if (!sl) return -1;
|
||||
for (i=0; i < sl->num_used; i++)
|
||||
if (element == sl->list[i])
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Return true iff <b>sl</b> has some element E such that
|
||||
* !strcasecmp(E,<b>element</b>)
|
||||
*/
|
||||
|
@ -38,6 +38,7 @@ void smartlist_reverse(smartlist_t *sl);
|
||||
void smartlist_string_remove(smartlist_t *sl, const char *element);
|
||||
int smartlist_contains(const smartlist_t *sl, const void *element);
|
||||
int smartlist_contains_string(const smartlist_t *sl, const char *element);
|
||||
int smartlist_pos(const smartlist_t *sl, const void *element);
|
||||
int smartlist_string_pos(const smartlist_t *, const char *elt);
|
||||
int smartlist_contains_string_case(const smartlist_t *sl, const char *element);
|
||||
int smartlist_contains_int_as_string(const smartlist_t *sl, int num);
|
||||
|
@ -829,7 +829,7 @@ crypto_pk_public_exponent_ok(crypto_pk_t *env)
|
||||
* Note that this may leak information about the keys through timing.
|
||||
*/
|
||||
int
|
||||
crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
|
||||
crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b)
|
||||
{
|
||||
int result;
|
||||
char a_is_non_null = (a != NULL) && (a->key != NULL);
|
||||
@ -855,19 +855,19 @@ crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
|
||||
* Note that this may leak information about the keys through timing.
|
||||
*/
|
||||
int
|
||||
crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b)
|
||||
crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b)
|
||||
{
|
||||
return (crypto_pk_cmp_keys(a, b) == 0);
|
||||
}
|
||||
|
||||
/** Return the size of the public key modulus in <b>env</b>, in bytes. */
|
||||
size_t
|
||||
crypto_pk_keysize(crypto_pk_t *env)
|
||||
crypto_pk_keysize(const crypto_pk_t *env)
|
||||
{
|
||||
tor_assert(env);
|
||||
tor_assert(env->key);
|
||||
|
||||
return (size_t) RSA_size(env->key);
|
||||
return (size_t) RSA_size((RSA*)env->key);
|
||||
}
|
||||
|
||||
/** Return the size of the public key modulus of <b>env</b>, in bits. */
|
||||
@ -996,7 +996,7 @@ crypto_pk_private_decrypt(crypto_pk_t *env, char *to,
|
||||
* at least the length of the modulus of <b>env</b>.
|
||||
*/
|
||||
int
|
||||
crypto_pk_public_checksig(crypto_pk_t *env, char *to,
|
||||
crypto_pk_public_checksig(const crypto_pk_t *env, char *to,
|
||||
size_t tolen,
|
||||
const char *from, size_t fromlen)
|
||||
{
|
||||
@ -1068,7 +1068,7 @@ crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data,
|
||||
* at least the length of the modulus of <b>env</b>.
|
||||
*/
|
||||
int
|
||||
crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen,
|
||||
crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen,
|
||||
const char *from, size_t fromlen)
|
||||
{
|
||||
int r;
|
||||
@ -1083,7 +1083,7 @@ crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen,
|
||||
|
||||
r = RSA_private_encrypt((int)fromlen,
|
||||
(unsigned char*)from, (unsigned char*)to,
|
||||
env->key, RSA_PKCS1_PADDING);
|
||||
(RSA*)env->key, RSA_PKCS1_PADDING);
|
||||
if (r<0) {
|
||||
crypto_log_errors(LOG_WARN, "generating RSA signature");
|
||||
return -1;
|
||||
@ -1297,7 +1297,7 @@ crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
|
||||
unsigned char *buf = NULL;
|
||||
int len;
|
||||
|
||||
len = i2d_RSAPublicKey(pk->key, &buf);
|
||||
len = i2d_RSAPublicKey((RSA*)pk->key, &buf);
|
||||
if (len < 0 || buf == NULL)
|
||||
return -1;
|
||||
if (crypto_digest(digest_out, (char*)buf, len) < 0) {
|
||||
@ -1795,7 +1795,24 @@ crypto_digest_assign(crypto_digest_t *into,
|
||||
* <b>out_len</b> must be \<= DIGEST256_LEN. */
|
||||
void
|
||||
crypto_digest_smartlist(char *digest_out, size_t len_out,
|
||||
const smartlist_t *lst, const char *append,
|
||||
const smartlist_t *lst,
|
||||
const char *append,
|
||||
digest_algorithm_t alg)
|
||||
{
|
||||
crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
|
||||
}
|
||||
|
||||
/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
|
||||
* at <b>digest_out</b> to the hash of the concatenation of: the
|
||||
* optional string <b>prepend</b>, those strings,
|
||||
* and the optional string <b>append</b>, computed with the algorithm
|
||||
* <b>alg</b>.
|
||||
* <b>out_len</b> must be \<= DIGEST256_LEN. */
|
||||
void
|
||||
crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
|
||||
const char *prepend,
|
||||
const smartlist_t *lst,
|
||||
const char *append,
|
||||
digest_algorithm_t alg)
|
||||
{
|
||||
crypto_digest_t *d;
|
||||
@ -1803,6 +1820,8 @@ crypto_digest_smartlist(char *digest_out, size_t len_out,
|
||||
d = crypto_digest_new();
|
||||
else
|
||||
d = crypto_digest256_new(alg);
|
||||
if (prepend)
|
||||
crypto_digest_add_bytes(d, prepend, strlen(prepend));
|
||||
SMARTLIST_FOREACH(lst, const char *, cp,
|
||||
crypto_digest_add_bytes(d, cp, strlen(cp)));
|
||||
if (append)
|
||||
@ -2673,6 +2692,65 @@ base64_encode(char *dest, size_t destlen, const char *src, size_t srclen,
|
||||
return (int) enclen;
|
||||
}
|
||||
|
||||
/** As base64_encode, but do not add any internal spaces or external padding
|
||||
* to the output stream. */
|
||||
int
|
||||
base64_encode_nopad(char *dest, size_t destlen,
|
||||
const uint8_t *src, size_t srclen)
|
||||
{
|
||||
int n = base64_encode(dest, destlen, (const char*) src, srclen, 0);
|
||||
if (n <= 0)
|
||||
return n;
|
||||
tor_assert((size_t)n < destlen && dest[n] == 0);
|
||||
char *in, *out;
|
||||
in = out = dest;
|
||||
while (*in) {
|
||||
if (*in == '=' || *in == '\n') {
|
||||
++in;
|
||||
} else {
|
||||
*out++ = *in++;
|
||||
}
|
||||
}
|
||||
*out = 0;
|
||||
|
||||
tor_assert(out - dest <= INT_MAX);
|
||||
|
||||
return (int)(out - dest);
|
||||
}
|
||||
|
||||
/** As base64_decode, but do not require any padding on the input */
|
||||
int
|
||||
base64_decode_nopad(uint8_t *dest, size_t destlen,
|
||||
const char *src, size_t srclen)
|
||||
{
|
||||
if (srclen > SIZE_T_CEILING - 4)
|
||||
return -1;
|
||||
char *buf = tor_malloc(srclen + 4);
|
||||
memcpy(buf, src, srclen+1);
|
||||
size_t buflen;
|
||||
switch (srclen % 4)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
buflen = srclen;
|
||||
break;
|
||||
case 1:
|
||||
tor_free(buf);
|
||||
return -1;
|
||||
case 2:
|
||||
memcpy(buf+srclen, "==", 3);
|
||||
buflen = srclen + 2;
|
||||
break;
|
||||
case 3:
|
||||
memcpy(buf+srclen, "=", 2);
|
||||
buflen = srclen + 1;
|
||||
break;
|
||||
}
|
||||
int n = base64_decode((char*)dest, destlen, buf, buflen);
|
||||
tor_free(buf);
|
||||
return n;
|
||||
}
|
||||
|
||||
#undef BASE64_OPENSSL_LINELEN
|
||||
|
||||
/** @{ */
|
||||
@ -2797,6 +2875,7 @@ base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
|
||||
/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
|
||||
* characters, and store the nul-terminated result in the first
|
||||
* BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */
|
||||
/* XXXX unify with crypto_format.c code */
|
||||
int
|
||||
digest_to_base64(char *d64, const char *digest)
|
||||
{
|
||||
@ -2810,6 +2889,7 @@ digest_to_base64(char *d64, const char *digest)
|
||||
/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
|
||||
* trailing newline or = characters), decode it and store the result in the
|
||||
* first DIGEST_LEN bytes at <b>digest</b>. */
|
||||
/* XXXX unify with crypto_format.c code */
|
||||
int
|
||||
digest_from_base64(char *digest, const char *d64)
|
||||
{
|
||||
@ -2821,7 +2901,8 @@ digest_from_base64(char *digest, const char *d64)
|
||||
|
||||
/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
|
||||
* trailing = characters, and store the nul-terminated result in the first
|
||||
* BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
|
||||
* BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
|
||||
/* XXXX unify with crypto_format.c code */
|
||||
int
|
||||
digest256_to_base64(char *d64, const char *digest)
|
||||
{
|
||||
@ -2835,6 +2916,7 @@ digest256_to_base64(char *d64, const char *digest)
|
||||
/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
|
||||
* trailing newline or = characters), decode it and store the result in the
|
||||
* first DIGEST256_LEN bytes at <b>digest</b>. */
|
||||
/* XXXX unify with crypto_format.c code */
|
||||
int
|
||||
digest256_from_base64(char *digest, const char *d64)
|
||||
{
|
||||
|
@ -146,9 +146,9 @@ int crypto_pk_write_private_key_to_filename(crypto_pk_t *env,
|
||||
const char *fname);
|
||||
|
||||
int crypto_pk_check_key(crypto_pk_t *env);
|
||||
int crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b);
|
||||
int crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b);
|
||||
size_t crypto_pk_keysize(crypto_pk_t *env);
|
||||
int crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b);
|
||||
int crypto_pk_eq_keys(const crypto_pk_t *a, const crypto_pk_t *b);
|
||||
size_t crypto_pk_keysize(const crypto_pk_t *env);
|
||||
int crypto_pk_num_bits(crypto_pk_t *env);
|
||||
crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig);
|
||||
crypto_pk_t *crypto_pk_copy_full(crypto_pk_t *orig);
|
||||
@ -160,11 +160,11 @@ int crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen,
|
||||
int crypto_pk_private_decrypt(crypto_pk_t *env, char *to, size_t tolen,
|
||||
const char *from, size_t fromlen,
|
||||
int padding, int warnOnFailure);
|
||||
int crypto_pk_public_checksig(crypto_pk_t *env, char *to, size_t tolen,
|
||||
int crypto_pk_public_checksig(const crypto_pk_t *env, char *to, size_t tolen,
|
||||
const char *from, size_t fromlen);
|
||||
int crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data,
|
||||
size_t datalen, const char *sig, size_t siglen);
|
||||
int crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen,
|
||||
int crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen,
|
||||
const char *from, size_t fromlen);
|
||||
int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,
|
||||
const char *from, size_t fromlen);
|
||||
@ -209,6 +209,11 @@ int crypto_digest256(char *digest, const char *m, size_t len,
|
||||
digest_algorithm_t algorithm);
|
||||
int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
|
||||
struct smartlist_t;
|
||||
void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
|
||||
const char *prepend,
|
||||
const struct smartlist_t *lst,
|
||||
const char *append,
|
||||
digest_algorithm_t alg);
|
||||
void crypto_digest_smartlist(char *digest_out, size_t len_out,
|
||||
const struct smartlist_t *lst, const char *append,
|
||||
digest_algorithm_t alg);
|
||||
@ -278,6 +283,11 @@ size_t base64_encode_size(size_t srclen, int flags);
|
||||
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen,
|
||||
int flags);
|
||||
int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||
int base64_encode_nopad(char *dest, size_t destlen,
|
||||
const uint8_t *src, size_t srclen);
|
||||
int base64_decode_nopad(uint8_t *dest, size_t destlen,
|
||||
const char *src, size_t srclen);
|
||||
|
||||
/** Characters that can appear (case-insensitively) in a base32 encoding. */
|
||||
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
|
||||
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||
|
@ -351,3 +351,24 @@ ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Release all storage held for <b>kp</b>. */
|
||||
void
|
||||
ed25519_keypair_free(ed25519_keypair_t *kp)
|
||||
{
|
||||
if (! kp)
|
||||
return;
|
||||
|
||||
memwipe(kp, 0, sizeof(*kp));
|
||||
tor_free(kp);
|
||||
}
|
||||
|
||||
/** Return true iff <b>key1</b> and <b>key2</b> are the same public key. */
|
||||
int
|
||||
ed25519_pubkey_eq(const ed25519_public_key_t *key1,
|
||||
const ed25519_public_key_t *key2)
|
||||
{
|
||||
tor_assert(key1);
|
||||
tor_assert(key2);
|
||||
return tor_memeq(key1->pubkey, key2->pubkey, ED25519_PUBKEY_LEN);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "testsupport.h"
|
||||
#include "torint.h"
|
||||
#include "crypto_curve25519.h"
|
||||
|
||||
#define ED25519_PUBKEY_LEN 32
|
||||
#define ED25519_SECKEY_LEN 64
|
||||
@ -60,7 +61,7 @@ int ed25519_checksig(const ed25519_signature_t *signature,
|
||||
*/
|
||||
typedef struct {
|
||||
/** The public key that supposedly generated the signature. */
|
||||
ed25519_public_key_t *pubkey;
|
||||
const ed25519_public_key_t *pubkey;
|
||||
/** The signature to check. */
|
||||
ed25519_signature_t signature;
|
||||
/** The message that the signature is supposed to have been applied to. */
|
||||
@ -87,13 +88,22 @@ int ed25519_public_blind(ed25519_public_key_t *out,
|
||||
const ed25519_public_key_t *inp,
|
||||
const uint8_t *param);
|
||||
|
||||
#define ED25519_BASE64_LEN 43
|
||||
|
||||
/* XXXX move these to crypto_format.h */
|
||||
#define ED25519_BASE64_LEN 43
|
||||
int ed25519_public_from_base64(ed25519_public_key_t *pkey,
|
||||
const char *input);
|
||||
int ed25519_public_to_base64(char *output,
|
||||
const ed25519_public_key_t *pkey);
|
||||
|
||||
/* XXXX move these to crypto_format.h */
|
||||
#define ED25519_SIG_BASE64_LEN 86
|
||||
|
||||
int ed25519_signature_from_base64(ed25519_signature_t *sig,
|
||||
const char *input);
|
||||
int ed25519_signature_to_base64(char *output,
|
||||
const ed25519_signature_t *sig);
|
||||
|
||||
/* XXXX read encrypted, write encrypted. */
|
||||
|
||||
int ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey,
|
||||
@ -109,5 +119,10 @@ int ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
|
||||
char **tag_out,
|
||||
const char *filename);
|
||||
|
||||
void ed25519_keypair_free(ed25519_keypair_t *kp);
|
||||
|
||||
int ed25519_pubkey_eq(const ed25519_public_key_t *key1,
|
||||
const ed25519_public_key_t *key2);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -65,3 +65,42 @@ ed25519_public_to_base64(char *output,
|
||||
return digest256_to_base64(output, (const char *)pkey->pubkey);
|
||||
}
|
||||
|
||||
/** Encode the signature <b>sig</b> into the buffer at <b>output</b>,
|
||||
* which must have space for ED25519_SIG_BASE64_LEN bytes of encoded signature,
|
||||
* plus one byte for a terminating NUL. Return 0 on success, -1 on failure.
|
||||
*/
|
||||
int
|
||||
ed25519_signature_to_base64(char *output,
|
||||
const ed25519_signature_t *sig)
|
||||
{
|
||||
char buf[256];
|
||||
int n = base64_encode_nopad(buf, sizeof(buf), sig->sig, ED25519_SIG_LEN);
|
||||
tor_assert(n == ED25519_SIG_BASE64_LEN);
|
||||
memcpy(output, buf, ED25519_SIG_BASE64_LEN+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Try to decode the string <b>input</b> into an ed25519 signature. On
|
||||
* success, store the value in <b>sig</b> and return 0. Otherwise return
|
||||
* -1. */
|
||||
int
|
||||
ed25519_signature_from_base64(ed25519_signature_t *sig,
|
||||
const char *input)
|
||||
{
|
||||
|
||||
if (strlen(input) != ED25519_SIG_BASE64_LEN)
|
||||
return -1;
|
||||
char buf[ED25519_SIG_BASE64_LEN+3];
|
||||
memcpy(buf, input, ED25519_SIG_BASE64_LEN);
|
||||
buf[ED25519_SIG_BASE64_LEN+0] = '=';
|
||||
buf[ED25519_SIG_BASE64_LEN+1] = '=';
|
||||
buf[ED25519_SIG_BASE64_LEN+2] = 0;
|
||||
char decoded[128];
|
||||
int n = base64_decode(decoded, sizeof(decoded), buf, strlen(buf));
|
||||
if (n < 0 || n != ED25519_SIG_LEN)
|
||||
return -1;
|
||||
memcpy(sig->sig, decoded, ED25519_SIG_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@
|
||||
#endif
|
||||
|
||||
/** Structure that we use for a single certificate. */
|
||||
struct tor_cert_t {
|
||||
struct tor_x509_cert_t {
|
||||
X509 *cert;
|
||||
uint8_t *encoded;
|
||||
size_t encoded_len;
|
||||
@ -132,9 +132,9 @@ struct tor_cert_t {
|
||||
typedef struct tor_tls_context_t {
|
||||
int refcnt;
|
||||
SSL_CTX *ctx;
|
||||
tor_cert_t *my_link_cert;
|
||||
tor_cert_t *my_id_cert;
|
||||
tor_cert_t *my_auth_cert;
|
||||
tor_x509_cert_t *my_link_cert;
|
||||
tor_x509_cert_t *my_id_cert;
|
||||
tor_x509_cert_t *my_auth_cert;
|
||||
crypto_pk_t *link_key;
|
||||
crypto_pk_t *auth_key;
|
||||
} tor_tls_context_t;
|
||||
@ -765,7 +765,7 @@ static const int N_CLIENT_CIPHERS = ARRAY_LENGTH(CLIENT_CIPHER_INFO_LIST);
|
||||
|
||||
/** Free all storage held in <b>cert</b> */
|
||||
void
|
||||
tor_cert_free(tor_cert_t *cert)
|
||||
tor_x509_cert_free(tor_x509_cert_t *cert)
|
||||
{
|
||||
if (! cert)
|
||||
return;
|
||||
@ -777,14 +777,14 @@ tor_cert_free(tor_cert_t *cert)
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new tor_cert_t to hold the certificate "x509_cert".
|
||||
* Allocate a new tor_x509_cert_t to hold the certificate "x509_cert".
|
||||
*
|
||||
* Steals a reference to x509_cert.
|
||||
*/
|
||||
static tor_cert_t *
|
||||
tor_cert_new(X509 *x509_cert)
|
||||
static tor_x509_cert_t *
|
||||
tor_x509_cert_new(X509 *x509_cert)
|
||||
{
|
||||
tor_cert_t *cert;
|
||||
tor_x509_cert_t *cert;
|
||||
EVP_PKEY *pkey;
|
||||
RSA *rsa;
|
||||
int length;
|
||||
@ -794,7 +794,7 @@ tor_cert_new(X509 *x509_cert)
|
||||
return NULL;
|
||||
|
||||
length = i2d_X509(x509_cert, &buf);
|
||||
cert = tor_malloc_zero(sizeof(tor_cert_t));
|
||||
cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
|
||||
if (length <= 0 || buf == NULL) {
|
||||
tor_free(cert);
|
||||
log_err(LD_CRYPTO, "Couldn't get length of encoded x509 certificate");
|
||||
@ -824,14 +824,14 @@ tor_cert_new(X509 *x509_cert)
|
||||
}
|
||||
|
||||
/** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>,
|
||||
* from a <b>certificate</b>. Return a newly allocated tor_cert_t on success
|
||||
* and NULL on failure. */
|
||||
tor_cert_t *
|
||||
tor_cert_decode(const uint8_t *certificate, size_t certificate_len)
|
||||
* from a <b>certificate</b>. Return a newly allocated tor_x509_cert_t on
|
||||
* success and NULL on failure. */
|
||||
tor_x509_cert_t *
|
||||
tor_x509_cert_decode(const uint8_t *certificate, size_t certificate_len)
|
||||
{
|
||||
X509 *x509;
|
||||
const unsigned char *cp = (const unsigned char *)certificate;
|
||||
tor_cert_t *newcert;
|
||||
tor_x509_cert_t *newcert;
|
||||
tor_assert(certificate);
|
||||
check_no_tls_errors();
|
||||
|
||||
@ -846,14 +846,14 @@ tor_cert_decode(const uint8_t *certificate, size_t certificate_len)
|
||||
X509_free(x509);
|
||||
goto err; /* Didn't use all the bytes */
|
||||
}
|
||||
newcert = tor_cert_new(x509);
|
||||
newcert = tor_x509_cert_new(x509);
|
||||
if (!newcert) {
|
||||
goto err;
|
||||
}
|
||||
if (newcert->encoded_len != certificate_len ||
|
||||
fast_memneq(newcert->encoded, certificate, certificate_len)) {
|
||||
/* Cert wasn't in DER */
|
||||
tor_cert_free(newcert);
|
||||
tor_x509_cert_free(newcert);
|
||||
goto err;
|
||||
}
|
||||
return newcert;
|
||||
@ -865,7 +865,7 @@ tor_cert_decode(const uint8_t *certificate, size_t certificate_len)
|
||||
/** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER
|
||||
* representation and length, respectively. */
|
||||
void
|
||||
tor_cert_get_der(const tor_cert_t *cert,
|
||||
tor_x509_cert_get_der(const tor_x509_cert_t *cert,
|
||||
const uint8_t **encoded_out, size_t *size_out)
|
||||
{
|
||||
tor_assert(cert);
|
||||
@ -878,7 +878,7 @@ tor_cert_get_der(const tor_cert_t *cert,
|
||||
/** Return a set of digests for the public key in <b>cert</b>, or NULL if this
|
||||
* cert's public key is not one we know how to take the digest of. */
|
||||
const digests_t *
|
||||
tor_cert_get_id_digests(const tor_cert_t *cert)
|
||||
tor_x509_cert_get_id_digests(const tor_x509_cert_t *cert)
|
||||
{
|
||||
if (cert->pkey_digests_set)
|
||||
return &cert->pkey_digests;
|
||||
@ -888,7 +888,7 @@ tor_cert_get_id_digests(const tor_cert_t *cert)
|
||||
|
||||
/** Return a set of digests for the public key in <b>cert</b>. */
|
||||
const digests_t *
|
||||
tor_cert_get_cert_digests(const tor_cert_t *cert)
|
||||
tor_x509_cert_get_cert_digests(const tor_x509_cert_t *cert)
|
||||
{
|
||||
return &cert->cert_digests;
|
||||
}
|
||||
@ -901,9 +901,9 @@ tor_tls_context_decref(tor_tls_context_t *ctx)
|
||||
tor_assert(ctx);
|
||||
if (--ctx->refcnt == 0) {
|
||||
SSL_CTX_free(ctx->ctx);
|
||||
tor_cert_free(ctx->my_link_cert);
|
||||
tor_cert_free(ctx->my_id_cert);
|
||||
tor_cert_free(ctx->my_auth_cert);
|
||||
tor_x509_cert_free(ctx->my_link_cert);
|
||||
tor_x509_cert_free(ctx->my_id_cert);
|
||||
tor_x509_cert_free(ctx->my_auth_cert);
|
||||
crypto_pk_free(ctx->link_key);
|
||||
crypto_pk_free(ctx->auth_key);
|
||||
tor_free(ctx);
|
||||
@ -917,8 +917,8 @@ tor_tls_context_decref(tor_tls_context_t *ctx)
|
||||
* client mode. */
|
||||
int
|
||||
tor_tls_get_my_certs(int server,
|
||||
const tor_cert_t **link_cert_out,
|
||||
const tor_cert_t **id_cert_out)
|
||||
const tor_x509_cert_t **link_cert_out,
|
||||
const tor_x509_cert_t **id_cert_out)
|
||||
{
|
||||
tor_tls_context_t *ctx = server ? server_tls_context : client_tls_context;
|
||||
if (! ctx)
|
||||
@ -947,7 +947,7 @@ tor_tls_get_my_client_auth_key(void)
|
||||
* certifies. Return NULL if the cert's key is not RSA.
|
||||
*/
|
||||
crypto_pk_t *
|
||||
tor_tls_cert_get_key(tor_cert_t *cert)
|
||||
tor_tls_cert_get_key(tor_x509_cert_t *cert)
|
||||
{
|
||||
crypto_pk_t *result = NULL;
|
||||
EVP_PKEY *pkey = X509_get_pubkey(cert->cert);
|
||||
@ -967,8 +967,8 @@ tor_tls_cert_get_key(tor_cert_t *cert)
|
||||
/** Return true iff the other side of <b>tls</b> has authenticated to us, and
|
||||
* the key certified in <b>cert</b> is the same as the key they used to do it.
|
||||
*/
|
||||
int
|
||||
tor_tls_cert_matches_key(const tor_tls_t *tls, const tor_cert_t *cert)
|
||||
MOCK_IMPL(int,
|
||||
tor_tls_cert_matches_key,(const tor_tls_t *tls, const tor_x509_cert_t *cert))
|
||||
{
|
||||
X509 *peercert = SSL_get_peer_certificate(tls->ssl);
|
||||
EVP_PKEY *link_key = NULL, *cert_key = NULL;
|
||||
@ -997,8 +997,8 @@ tor_tls_cert_matches_key(const tor_tls_t *tls, const tor_cert_t *cert)
|
||||
* we couldn't check it. */
|
||||
int
|
||||
tor_tls_cert_is_valid(int severity,
|
||||
const tor_cert_t *cert,
|
||||
const tor_cert_t *signing_cert,
|
||||
const tor_x509_cert_t *cert,
|
||||
const tor_x509_cert_t *signing_cert,
|
||||
int check_rsa_1024)
|
||||
{
|
||||
check_no_tls_errors();
|
||||
@ -1209,9 +1209,9 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
|
||||
result = tor_malloc_zero(sizeof(tor_tls_context_t));
|
||||
result->refcnt = 1;
|
||||
if (!is_client) {
|
||||
result->my_link_cert = tor_cert_new(X509_dup(cert));
|
||||
result->my_id_cert = tor_cert_new(X509_dup(idcert));
|
||||
result->my_auth_cert = tor_cert_new(X509_dup(authcert));
|
||||
result->my_link_cert = tor_x509_cert_new(X509_dup(cert));
|
||||
result->my_id_cert = tor_x509_cert_new(X509_dup(idcert));
|
||||
result->my_auth_cert = tor_x509_cert_new(X509_dup(authcert));
|
||||
if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert)
|
||||
goto error;
|
||||
result->link_key = crypto_pk_dup_key(rsa);
|
||||
@ -2346,15 +2346,15 @@ tor_tls_peer_has_cert(tor_tls_t *tls)
|
||||
}
|
||||
|
||||
/** Return the peer certificate, or NULL if there isn't one. */
|
||||
tor_cert_t *
|
||||
tor_tls_get_peer_cert(tor_tls_t *tls)
|
||||
MOCK_IMPL(tor_x509_cert_t *,
|
||||
tor_tls_get_peer_cert,(tor_tls_t *tls))
|
||||
{
|
||||
X509 *cert;
|
||||
cert = SSL_get_peer_certificate(tls->ssl);
|
||||
tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate");
|
||||
if (!cert)
|
||||
return NULL;
|
||||
return tor_cert_new(cert);
|
||||
return tor_x509_cert_new(cert);
|
||||
}
|
||||
|
||||
/** Warn that a certificate lifetime extends through a certain range. */
|
||||
@ -2772,8 +2772,8 @@ tor_tls_server_got_renegotiate(tor_tls_t *tls)
|
||||
* the v3 handshake to prove that the client knows the TLS secrets for the
|
||||
* connection <b>tls</b>. Return 0 on success, -1 on failure.
|
||||
*/
|
||||
int
|
||||
tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
|
||||
MOCK_IMPL(int,
|
||||
tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
|
||||
{
|
||||
#define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification"
|
||||
char buf[128];
|
||||
|
@ -19,7 +19,7 @@
|
||||
typedef struct tor_tls_t tor_tls_t;
|
||||
|
||||
/* Opaque structure to hold an X509 certificate. */
|
||||
typedef struct tor_cert_t tor_cert_t;
|
||||
typedef struct tor_x509_cert_t tor_x509_cert_t;
|
||||
|
||||
/* Possible return values for most tor_tls_* functions. */
|
||||
#define MIN_TOR_TLS_ERROR_VAL_ -9
|
||||
@ -72,7 +72,7 @@ void tor_tls_set_renegotiate_callback(tor_tls_t *tls,
|
||||
int tor_tls_is_server(tor_tls_t *tls);
|
||||
void tor_tls_free(tor_tls_t *tls);
|
||||
int tor_tls_peer_has_cert(tor_tls_t *tls);
|
||||
tor_cert_t *tor_tls_get_peer_cert(tor_tls_t *tls);
|
||||
MOCK_DECL(tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls));
|
||||
int tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity);
|
||||
int tor_tls_check_lifetime(int severity,
|
||||
tor_tls_t *tls, int past_tolerance,
|
||||
@ -102,7 +102,7 @@ int tor_tls_used_v1_handshake(tor_tls_t *tls);
|
||||
int tor_tls_received_v3_certificate(tor_tls_t *tls);
|
||||
int tor_tls_get_num_server_handshakes(tor_tls_t *tls);
|
||||
int tor_tls_server_got_renegotiate(tor_tls_t *tls);
|
||||
int tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out);
|
||||
MOCK_DECL(int,tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out));
|
||||
|
||||
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
|
||||
*/
|
||||
@ -120,22 +120,23 @@ struct bufferevent *tor_tls_init_bufferevent(tor_tls_t *tls,
|
||||
int filter);
|
||||
#endif
|
||||
|
||||
void tor_cert_free(tor_cert_t *cert);
|
||||
tor_cert_t *tor_cert_decode(const uint8_t *certificate,
|
||||
void tor_x509_cert_free(tor_x509_cert_t *cert);
|
||||
tor_x509_cert_t *tor_x509_cert_decode(const uint8_t *certificate,
|
||||
size_t certificate_len);
|
||||
void tor_cert_get_der(const tor_cert_t *cert,
|
||||
void tor_x509_cert_get_der(const tor_x509_cert_t *cert,
|
||||
const uint8_t **encoded_out, size_t *size_out);
|
||||
const digests_t *tor_cert_get_id_digests(const tor_cert_t *cert);
|
||||
const digests_t *tor_cert_get_cert_digests(const tor_cert_t *cert);
|
||||
const digests_t *tor_x509_cert_get_id_digests(const tor_x509_cert_t *cert);
|
||||
const digests_t *tor_x509_cert_get_cert_digests(const tor_x509_cert_t *cert);
|
||||
int tor_tls_get_my_certs(int server,
|
||||
const tor_cert_t **link_cert_out,
|
||||
const tor_cert_t **id_cert_out);
|
||||
const tor_x509_cert_t **link_cert_out,
|
||||
const tor_x509_cert_t **id_cert_out);
|
||||
crypto_pk_t *tor_tls_get_my_client_auth_key(void);
|
||||
crypto_pk_t *tor_tls_cert_get_key(tor_cert_t *cert);
|
||||
int tor_tls_cert_matches_key(const tor_tls_t *tls, const tor_cert_t *cert);
|
||||
crypto_pk_t *tor_tls_cert_get_key(tor_x509_cert_t *cert);
|
||||
MOCK_DECL(int,tor_tls_cert_matches_key,(const tor_tls_t *tls,
|
||||
const tor_x509_cert_t *cert));
|
||||
int tor_tls_cert_is_valid(int severity,
|
||||
const tor_cert_t *cert,
|
||||
const tor_cert_t *signing_cert,
|
||||
const tor_x509_cert_t *cert,
|
||||
const tor_x509_cert_t *signing_cert,
|
||||
int check_rsa_1024);
|
||||
const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls);
|
||||
|
||||
|
@ -4431,10 +4431,10 @@ channel_num_circuits(channel_t *chan)
|
||||
* This is called when setting up a channel and replaces the old
|
||||
* connection_or_set_circid_type()
|
||||
*/
|
||||
void
|
||||
channel_set_circid_type(channel_t *chan,
|
||||
crypto_pk_t *identity_rcvd,
|
||||
int consider_identity)
|
||||
MOCK_IMPL(void,
|
||||
channel_set_circid_type,(channel_t *chan,
|
||||
crypto_pk_t *identity_rcvd,
|
||||
int consider_identity))
|
||||
{
|
||||
int started_here;
|
||||
crypto_pk_t *our_identity;
|
||||
|
@ -562,8 +562,9 @@ int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info);
|
||||
int channel_matches_target_addr_for_extend(channel_t *chan,
|
||||
const tor_addr_t *target);
|
||||
unsigned int channel_num_circuits(channel_t *chan);
|
||||
void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd,
|
||||
int consider_identity);
|
||||
MOCK_DECL(void,channel_set_circid_type,(channel_t *chan,
|
||||
crypto_pk_t *identity_rcvd,
|
||||
int consider_identity));
|
||||
void channel_timestamp_client(channel_t *chan);
|
||||
void channel_update_xmit_queue_size(channel_t *chan);
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#define TOR_CHANNEL_INTERNAL_
|
||||
|
||||
#define CHANNELTLS_PRIVATE
|
||||
|
||||
#include "or.h"
|
||||
#include "channel.h"
|
||||
#include "channeltls.h"
|
||||
@ -22,6 +24,7 @@
|
||||
#include "connection.h"
|
||||
#include "connection_or.h"
|
||||
#include "control.h"
|
||||
#include "link_handshake.h"
|
||||
#include "relay.h"
|
||||
#include "rephist.h"
|
||||
#include "router.h"
|
||||
@ -48,9 +51,6 @@ uint64_t stats_n_authorize_cells_processed = 0;
|
||||
/** Active listener, if any */
|
||||
channel_listener_t *channel_tls_listener = NULL;
|
||||
|
||||
/* Utility function declarations */
|
||||
static void channel_tls_common_init(channel_tls_t *tlschan);
|
||||
|
||||
/* channel_tls_t method declarations */
|
||||
|
||||
static void channel_tls_close_method(channel_t *chan);
|
||||
@ -92,12 +92,6 @@ static void channel_tls_process_versions_cell(var_cell_t *cell,
|
||||
channel_tls_t *tlschan);
|
||||
static void channel_tls_process_netinfo_cell(cell_t *cell,
|
||||
channel_tls_t *tlschan);
|
||||
static void channel_tls_process_certs_cell(var_cell_t *cell,
|
||||
channel_tls_t *tlschan);
|
||||
static void channel_tls_process_auth_challenge_cell(var_cell_t *cell,
|
||||
channel_tls_t *tlschan);
|
||||
static void channel_tls_process_authenticate_cell(var_cell_t *cell,
|
||||
channel_tls_t *tlschan);
|
||||
static int command_allowed_before_handshake(uint8_t command);
|
||||
static int enter_v3_handshake_with_cell(var_cell_t *cell,
|
||||
channel_tls_t *tlschan);
|
||||
@ -107,7 +101,7 @@ static int enter_v3_handshake_with_cell(var_cell_t *cell,
|
||||
* and channel_tls_handle_incoming().
|
||||
*/
|
||||
|
||||
static void
|
||||
STATIC void
|
||||
channel_tls_common_init(channel_tls_t *tlschan)
|
||||
{
|
||||
channel_t *chan;
|
||||
@ -1747,16 +1741,17 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
|
||||
* If it's the server side, wait for an AUTHENTICATE cell.
|
||||
*/
|
||||
|
||||
static void
|
||||
STATIC void
|
||||
channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
{
|
||||
tor_cert_t *link_cert = NULL;
|
||||
tor_cert_t *id_cert = NULL;
|
||||
tor_cert_t *auth_cert = NULL;
|
||||
uint8_t *ptr;
|
||||
#define MAX_CERT_TYPE_WANTED OR_CERT_TYPE_AUTH_1024
|
||||
tor_x509_cert_t *certs[MAX_CERT_TYPE_WANTED + 1];
|
||||
int n_certs, i;
|
||||
certs_cell_t *cc = NULL;
|
||||
|
||||
int send_netinfo = 0;
|
||||
|
||||
memset(certs, 0, sizeof(certs));
|
||||
tor_assert(cell);
|
||||
tor_assert(chan);
|
||||
tor_assert(chan->conn);
|
||||
@ -1786,63 +1781,41 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
if (cell->circ_id)
|
||||
ERR("It had a nonzero circuit ID");
|
||||
|
||||
n_certs = cell->payload[0];
|
||||
ptr = cell->payload + 1;
|
||||
if (certs_cell_parse(&cc, cell->payload, cell->payload_len) < 0)
|
||||
ERR("It couldn't be parsed.");
|
||||
|
||||
n_certs = cc->n_certs;
|
||||
|
||||
for (i = 0; i < n_certs; ++i) {
|
||||
uint8_t cert_type;
|
||||
uint16_t cert_len;
|
||||
if (cell->payload_len < 3)
|
||||
goto truncated;
|
||||
if (ptr > cell->payload + cell->payload_len - 3) {
|
||||
goto truncated;
|
||||
}
|
||||
cert_type = *ptr;
|
||||
cert_len = ntohs(get_uint16(ptr+1));
|
||||
if (cell->payload_len < 3 + cert_len)
|
||||
goto truncated;
|
||||
if (ptr > cell->payload + cell->payload_len - cert_len - 3) {
|
||||
goto truncated;
|
||||
}
|
||||
if (cert_type == OR_CERT_TYPE_TLS_LINK ||
|
||||
cert_type == OR_CERT_TYPE_ID_1024 ||
|
||||
cert_type == OR_CERT_TYPE_AUTH_1024) {
|
||||
tor_cert_t *cert = tor_cert_decode(ptr + 3, cert_len);
|
||||
if (!cert) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Received undecodable certificate in CERTS cell from %s:%d",
|
||||
safe_str(chan->conn->base_.address),
|
||||
chan->conn->base_.port);
|
||||
certs_cell_cert_t *c = certs_cell_get_certs(cc, i);
|
||||
|
||||
uint16_t cert_type = c->cert_type;
|
||||
uint16_t cert_len = c->cert_len;
|
||||
uint8_t *cert_body = certs_cell_cert_getarray_body(c);
|
||||
|
||||
if (cert_type > MAX_CERT_TYPE_WANTED)
|
||||
continue;
|
||||
|
||||
tor_x509_cert_t *cert = tor_x509_cert_decode(cert_body, cert_len);
|
||||
if (!cert) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Received undecodable certificate in CERTS cell from %s:%d",
|
||||
safe_str(chan->conn->base_.address),
|
||||
chan->conn->base_.port);
|
||||
} else {
|
||||
if (certs[cert_type]) {
|
||||
tor_x509_cert_free(cert);
|
||||
ERR("Duplicate x509 certificate");
|
||||
} else {
|
||||
if (cert_type == OR_CERT_TYPE_TLS_LINK) {
|
||||
if (link_cert) {
|
||||
tor_cert_free(cert);
|
||||
ERR("Too many TLS_LINK certificates");
|
||||
}
|
||||
link_cert = cert;
|
||||
} else if (cert_type == OR_CERT_TYPE_ID_1024) {
|
||||
if (id_cert) {
|
||||
tor_cert_free(cert);
|
||||
ERR("Too many ID_1024 certificates");
|
||||
}
|
||||
id_cert = cert;
|
||||
} else if (cert_type == OR_CERT_TYPE_AUTH_1024) {
|
||||
if (auth_cert) {
|
||||
tor_cert_free(cert);
|
||||
ERR("Too many AUTH_1024 certificates");
|
||||
}
|
||||
auth_cert = cert;
|
||||
} else {
|
||||
tor_cert_free(cert);
|
||||
}
|
||||
certs[cert_type] = cert;
|
||||
}
|
||||
}
|
||||
ptr += 3 + cert_len;
|
||||
continue;
|
||||
|
||||
truncated:
|
||||
ERR("It ends in the middle of a certificate");
|
||||
}
|
||||
|
||||
tor_x509_cert_t *id_cert = certs[OR_CERT_TYPE_ID_1024];
|
||||
tor_x509_cert_t *auth_cert = certs[OR_CERT_TYPE_AUTH_1024];
|
||||
tor_x509_cert_t *link_cert = certs[OR_CERT_TYPE_TLS_LINK];
|
||||
|
||||
if (chan->conn->handshake_state->started_here) {
|
||||
int severity;
|
||||
if (! (id_cert && link_cert))
|
||||
@ -1867,7 +1840,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
|
||||
chan->conn->handshake_state->authenticated = 1;
|
||||
{
|
||||
const digests_t *id_digests = tor_cert_get_id_digests(id_cert);
|
||||
const digests_t *id_digests = tor_x509_cert_get_id_digests(id_cert);
|
||||
crypto_pk_t *identity_rcvd;
|
||||
if (!id_digests)
|
||||
ERR("Couldn't compute digests for key in ID cert");
|
||||
@ -1891,7 +1864,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
safe_str(chan->conn->base_.address), chan->conn->base_.port);
|
||||
|
||||
chan->conn->handshake_state->id_cert = id_cert;
|
||||
id_cert = NULL;
|
||||
certs[OR_CERT_TYPE_ID_1024] = NULL;
|
||||
|
||||
if (!public_server_mode(get_options())) {
|
||||
/* If we initiated the connection and we are not a public server, we
|
||||
@ -1918,7 +1891,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
|
||||
chan->conn->handshake_state->id_cert = id_cert;
|
||||
chan->conn->handshake_state->auth_cert = auth_cert;
|
||||
id_cert = auth_cert = NULL;
|
||||
certs[OR_CERT_TYPE_ID_1024] = certs[OR_CERT_TYPE_AUTH_1024] = NULL;
|
||||
}
|
||||
|
||||
chan->conn->handshake_state->received_certs_cell = 1;
|
||||
@ -1932,9 +1905,10 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
}
|
||||
|
||||
err:
|
||||
tor_cert_free(id_cert);
|
||||
tor_cert_free(link_cert);
|
||||
tor_cert_free(auth_cert);
|
||||
for (unsigned i = 0; i < ARRAY_LENGTH(certs); ++i) {
|
||||
tor_x509_cert_free(certs[i]);
|
||||
}
|
||||
certs_cell_free(cc);
|
||||
#undef ERR
|
||||
}
|
||||
|
||||
@ -1949,11 +1923,11 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
* want to authenticate, send an AUTHENTICATE cell and then a NETINFO cell.
|
||||
*/
|
||||
|
||||
static void
|
||||
STATIC void
|
||||
channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
{
|
||||
int n_types, i, use_type = -1;
|
||||
uint8_t *cp;
|
||||
auth_challenge_cell_t *ac = NULL;
|
||||
|
||||
tor_assert(cell);
|
||||
tor_assert(chan);
|
||||
@ -1966,7 +1940,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
safe_str(chan->conn->base_.address), \
|
||||
chan->conn->base_.port, (s)); \
|
||||
connection_or_close_for_error(chan->conn, 0); \
|
||||
return; \
|
||||
goto done; \
|
||||
} while (0)
|
||||
|
||||
if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
|
||||
@ -1979,19 +1953,17 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
ERR("We already received one");
|
||||
if (!(chan->conn->handshake_state->received_certs_cell))
|
||||
ERR("We haven't gotten a CERTS cell yet");
|
||||
if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2)
|
||||
ERR("It was too short");
|
||||
if (cell->circ_id)
|
||||
ERR("It had a nonzero circuit ID");
|
||||
|
||||
n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN));
|
||||
if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types)
|
||||
ERR("It looks truncated");
|
||||
if (auth_challenge_cell_parse(&ac, cell->payload, cell->payload_len) < 0)
|
||||
ERR("It was not well-formed.");
|
||||
|
||||
n_types = ac->n_methods;
|
||||
|
||||
/* Now see if there is an authentication type we can use */
|
||||
cp = cell->payload+OR_AUTH_CHALLENGE_LEN + 2;
|
||||
for (i = 0; i < n_types; ++i, cp += 2) {
|
||||
uint16_t authtype = ntohs(get_uint16(cp));
|
||||
for (i = 0; i < n_types; ++i) {
|
||||
uint16_t authtype = auth_challenge_cell_get_methods(ac, i);
|
||||
if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET)
|
||||
use_type = authtype;
|
||||
}
|
||||
@ -2002,7 +1974,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
/* If we're not a public server then we don't want to authenticate on a
|
||||
connection we originated, and we already sent a NETINFO cell when we
|
||||
got the CERTS cell. We have nothing more to do. */
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (use_type >= 0) {
|
||||
@ -2016,7 +1988,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
log_warn(LD_OR,
|
||||
"Couldn't send authenticate cell");
|
||||
connection_or_close_for_error(chan->conn, 0);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
log_info(LD_OR,
|
||||
@ -2029,9 +2001,12 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
if (connection_or_send_netinfo(chan->conn) < 0) {
|
||||
log_warn(LD_OR, "Couldn't send netinfo cell");
|
||||
connection_or_close_for_error(chan->conn, 0);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
auth_challenge_cell_free(ac);
|
||||
|
||||
#undef ERR
|
||||
}
|
||||
|
||||
@ -2045,10 +2020,10 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
* the identity of the router on the other side of the connection.
|
||||
*/
|
||||
|
||||
static void
|
||||
STATIC void
|
||||
channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
{
|
||||
uint8_t expected[V3_AUTH_FIXED_PART_LEN];
|
||||
uint8_t expected[V3_AUTH_FIXED_PART_LEN+256];
|
||||
const uint8_t *auth;
|
||||
int authlen;
|
||||
|
||||
@ -2104,11 +2079,13 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
if (authlen < V3_AUTH_BODY_LEN + 1)
|
||||
ERR("Authenticator was too short");
|
||||
|
||||
if (connection_or_compute_authenticate_cell_body(
|
||||
chan->conn, expected, sizeof(expected), NULL, 1) < 0)
|
||||
ssize_t bodylen =
|
||||
connection_or_compute_authenticate_cell_body(
|
||||
chan->conn, expected, sizeof(expected), NULL, 1);
|
||||
if (bodylen < 0 || bodylen != V3_AUTH_FIXED_PART_LEN)
|
||||
ERR("Couldn't compute expected AUTHENTICATE cell body");
|
||||
|
||||
if (tor_memneq(expected, auth, sizeof(expected)))
|
||||
if (tor_memneq(expected, auth, bodylen))
|
||||
ERR("Some field in the AUTHENTICATE cell body was not as expected");
|
||||
|
||||
{
|
||||
@ -2154,7 +2131,7 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
crypto_pk_t *identity_rcvd =
|
||||
tor_tls_cert_get_key(chan->conn->handshake_state->id_cert);
|
||||
const digests_t *id_digests =
|
||||
tor_cert_get_id_digests(chan->conn->handshake_state->id_cert);
|
||||
tor_x509_cert_get_id_digests(chan->conn->handshake_state->id_cert);
|
||||
|
||||
/* This must exist; we checked key type when reading the cert. */
|
||||
tor_assert(id_digests);
|
||||
|
@ -52,5 +52,15 @@ void channel_tls_update_marks(or_connection_t *conn);
|
||||
/* Cleanup at shutdown */
|
||||
void channel_tls_free_all(void);
|
||||
|
||||
#ifdef CHANNELTLS_PRIVATE
|
||||
STATIC void channel_tls_process_certs_cell(var_cell_t *cell,
|
||||
channel_tls_t *tlschan);
|
||||
STATIC void channel_tls_process_auth_challenge_cell(var_cell_t *cell,
|
||||
channel_tls_t *tlschan);
|
||||
STATIC void channel_tls_common_init(channel_tls_t *tlschan);
|
||||
STATIC void channel_tls_process_authenticate_cell(var_cell_t *cell,
|
||||
channel_tls_t *tlschan);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -300,6 +300,7 @@ static config_var_t option_vars_[] = {
|
||||
VAR("ServerTransportPlugin", LINELIST, ServerTransportPlugin, NULL),
|
||||
V(ServerTransportListenAddr, LINELIST, NULL),
|
||||
V(ServerTransportOptions, LINELIST, NULL),
|
||||
V(SigningKeyLifetime, INTERVAL, "30 days"),
|
||||
V(Socks4Proxy, STRING, NULL),
|
||||
V(Socks5Proxy, STRING, NULL),
|
||||
V(Socks5ProxyUsername, STRING, NULL),
|
||||
@ -358,6 +359,13 @@ static config_var_t option_vars_[] = {
|
||||
V(TestingTorNetwork, BOOL, "0"),
|
||||
V(TestingMinExitFlagThreshold, MEMUNIT, "0"),
|
||||
V(TestingMinFastFlagThreshold, MEMUNIT, "0"),
|
||||
|
||||
V(TestingLinkCertLifetime, INTERVAL, "2 days"),
|
||||
V(TestingAuthKeyLifetime, INTERVAL, "2 days"),
|
||||
V(TestingLinkKeySlop, INTERVAL, "3 hours"),
|
||||
V(TestingAuthKeySlop, INTERVAL, "3 hours"),
|
||||
V(TestingSigningKeySlop, INTERVAL, "1 day"),
|
||||
|
||||
V(OptimisticData, AUTOBOOL, "auto"),
|
||||
V(PortForwarding, BOOL, "0"),
|
||||
V(PortForwardingHelper, FILENAME, "tor-fw-helper"),
|
||||
@ -3688,8 +3696,20 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
CHECK_DEFAULT(TestingDescriptorMaxDownloadTries);
|
||||
CHECK_DEFAULT(TestingMicrodescMaxDownloadTries);
|
||||
CHECK_DEFAULT(TestingCertMaxDownloadTries);
|
||||
CHECK_DEFAULT(TestingAuthKeyLifetime);
|
||||
CHECK_DEFAULT(TestingLinkCertLifetime);
|
||||
CHECK_DEFAULT(TestingSigningKeySlop);
|
||||
CHECK_DEFAULT(TestingAuthKeySlop);
|
||||
CHECK_DEFAULT(TestingLinkKeySlop);
|
||||
#undef CHECK_DEFAULT
|
||||
|
||||
if (options->SigningKeyLifetime < options->TestingSigningKeySlop*2)
|
||||
REJECT("SigningKeyLifetime is too short.");
|
||||
if (options->TestingLinkCertLifetime < options->TestingAuthKeySlop*2)
|
||||
REJECT("LinkCertLifetime is too short.");
|
||||
if (options->TestingAuthKeyLifetime < options->TestingLinkKeySlop*2)
|
||||
REJECT("TestingAuthKeyLifetime is too short.");
|
||||
|
||||
if (options->TestingV3AuthInitialVotingInterval
|
||||
< MIN_VOTE_INTERVAL_TESTING_INITIAL) {
|
||||
REJECT("TestingV3AuthInitialVotingInterval is insanely low.");
|
||||
|
@ -61,6 +61,10 @@ char *options_get_datadir_fname2_suffix(const or_options_t *options,
|
||||
* get_datadir_fname2_suffix. */
|
||||
#define get_datadir_fname2(sub1,sub2) \
|
||||
get_datadir_fname2_suffix((sub1), (sub2), NULL)
|
||||
/** Return a newly allocated string containing datadir/sub1/sub2 relative to
|
||||
* opts. See get_datadir_fname2_suffix. */
|
||||
#define options_get_datadir_fname2(opts,sub1,sub2) \
|
||||
options_get_datadir_fname2_suffix((opts),(sub1), (sub2), NULL)
|
||||
/** Return a newly allocated string containing datadir/sub1suffix. See
|
||||
* get_datadir_fname2_suffix. */
|
||||
#define get_datadir_fname_suffix(sub1, suffix) \
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "entrynodes.h"
|
||||
#include "geoip.h"
|
||||
#include "main.h"
|
||||
#include "link_handshake.h"
|
||||
#include "networkstatus.h"
|
||||
#include "nodelist.h"
|
||||
#include "reasons.h"
|
||||
@ -1318,8 +1319,8 @@ connection_or_close_normally(or_connection_t *orconn, int flush)
|
||||
* the error state.
|
||||
*/
|
||||
|
||||
void
|
||||
connection_or_close_for_error(or_connection_t *orconn, int flush)
|
||||
MOCK_IMPL(void,
|
||||
connection_or_close_for_error,(or_connection_t *orconn, int flush))
|
||||
{
|
||||
channel_t *chan = NULL;
|
||||
|
||||
@ -1879,8 +1880,8 @@ or_handshake_state_free(or_handshake_state_t *state)
|
||||
return;
|
||||
crypto_digest_free(state->digest_sent);
|
||||
crypto_digest_free(state->digest_received);
|
||||
tor_cert_free(state->auth_cert);
|
||||
tor_cert_free(state->id_cert);
|
||||
tor_x509_cert_free(state->auth_cert);
|
||||
tor_x509_cert_free(state->id_cert);
|
||||
memwipe(state, 0xBE, sizeof(or_handshake_state_t));
|
||||
tor_free(state);
|
||||
}
|
||||
@ -2013,9 +2014,9 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn)
|
||||
* <b>conn</b>'s outbuf. Right now, this <em>DOES NOT</em> support cells that
|
||||
* affect a circuit.
|
||||
*/
|
||||
void
|
||||
connection_or_write_var_cell_to_buf(const var_cell_t *cell,
|
||||
or_connection_t *conn)
|
||||
MOCK_IMPL(void,
|
||||
connection_or_write_var_cell_to_buf,(const var_cell_t *cell,
|
||||
or_connection_t *conn))
|
||||
{
|
||||
int n;
|
||||
char hdr[VAR_CELL_MAX_HEADER_SIZE];
|
||||
@ -2158,8 +2159,8 @@ connection_or_send_versions(or_connection_t *conn, int v3_plus)
|
||||
|
||||
/** Send a NETINFO cell on <b>conn</b>, telling the other server what we know
|
||||
* about their address, our address, and the current time. */
|
||||
int
|
||||
connection_or_send_netinfo(or_connection_t *conn)
|
||||
MOCK_IMPL(int,
|
||||
connection_or_send_netinfo,(or_connection_t *conn))
|
||||
{
|
||||
cell_t cell;
|
||||
time_t now = time(NULL);
|
||||
@ -2228,7 +2229,7 @@ connection_or_send_netinfo(or_connection_t *conn)
|
||||
int
|
||||
connection_or_send_certs_cell(or_connection_t *conn)
|
||||
{
|
||||
const tor_cert_t *link_cert = NULL, *id_cert = NULL;
|
||||
const tor_x509_cert_t *link_cert = NULL, *id_cert = NULL;
|
||||
const uint8_t *link_encoded = NULL, *id_encoded = NULL;
|
||||
size_t link_len, id_len;
|
||||
var_cell_t *cell;
|
||||
@ -2243,8 +2244,8 @@ connection_or_send_certs_cell(or_connection_t *conn)
|
||||
server_mode = ! conn->handshake_state->started_here;
|
||||
if (tor_tls_get_my_certs(server_mode, &link_cert, &id_cert) < 0)
|
||||
return -1;
|
||||
tor_cert_get_der(link_cert, &link_encoded, &link_len);
|
||||
tor_cert_get_der(id_cert, &id_encoded, &id_len);
|
||||
tor_x509_cert_get_der(link_cert, &link_encoded, &link_len);
|
||||
tor_x509_cert_get_der(id_cert, &id_encoded, &id_len);
|
||||
|
||||
cell_len = 1 /* 1 byte: num certs in cell */ +
|
||||
2 * ( 1 + 2 ) /* For each cert: 1 byte for type, 2 for length */ +
|
||||
@ -2280,28 +2281,37 @@ connection_or_send_certs_cell(or_connection_t *conn)
|
||||
int
|
||||
connection_or_send_auth_challenge_cell(or_connection_t *conn)
|
||||
{
|
||||
var_cell_t *cell;
|
||||
uint8_t *cp;
|
||||
uint8_t challenge[OR_AUTH_CHALLENGE_LEN];
|
||||
var_cell_t *cell = NULL;
|
||||
int r = -1;
|
||||
tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
|
||||
|
||||
if (! conn->handshake_state)
|
||||
return -1;
|
||||
|
||||
if (crypto_rand((char*)challenge, OR_AUTH_CHALLENGE_LEN) < 0)
|
||||
return -1;
|
||||
cell = var_cell_new(OR_AUTH_CHALLENGE_LEN + 4);
|
||||
auth_challenge_cell_t *ac = auth_challenge_cell_new();
|
||||
|
||||
if (crypto_rand((char*)ac->challenge, sizeof(ac->challenge)) < 0)
|
||||
goto done;
|
||||
|
||||
auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET);
|
||||
auth_challenge_cell_set_n_methods(ac,
|
||||
auth_challenge_cell_getlen_methods(ac));
|
||||
|
||||
cell = var_cell_new(auth_challenge_cell_encoded_len(ac));
|
||||
ssize_t len = auth_challenge_cell_encode(cell->payload, cell->payload_len,
|
||||
ac);
|
||||
if (len != cell->payload_len)
|
||||
goto done;
|
||||
cell->command = CELL_AUTH_CHALLENGE;
|
||||
memcpy(cell->payload, challenge, OR_AUTH_CHALLENGE_LEN);
|
||||
cp = cell->payload + OR_AUTH_CHALLENGE_LEN;
|
||||
set_uint16(cp, htons(1)); /* We recognize one authentication type. */
|
||||
set_uint16(cp+2, htons(AUTHTYPE_RSA_SHA256_TLSSECRET));
|
||||
|
||||
connection_or_write_var_cell_to_buf(cell, conn);
|
||||
var_cell_free(cell);
|
||||
memwipe(challenge, 0, sizeof(challenge));
|
||||
r = 0;
|
||||
|
||||
return 0;
|
||||
done:
|
||||
var_cell_free(cell);
|
||||
auth_challenge_cell_free(ac);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Compute the main body of an AUTHENTICATE cell that a client can use
|
||||
@ -2328,28 +2338,28 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
|
||||
crypto_pk_t *signing_key,
|
||||
int server)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
auth1_t *auth = NULL;
|
||||
auth_ctx_t *ctx = auth_ctx_new();
|
||||
int result;
|
||||
|
||||
/* assert state is reasonable XXXX */
|
||||
|
||||
if (outlen < V3_AUTH_FIXED_PART_LEN ||
|
||||
(!server && outlen < V3_AUTH_BODY_LEN))
|
||||
return -1;
|
||||
ctx->is_ed = 0;
|
||||
|
||||
ptr = out;
|
||||
auth = auth1_new();
|
||||
|
||||
/* Type: 8 bytes. */
|
||||
memcpy(ptr, "AUTH0001", 8);
|
||||
ptr += 8;
|
||||
memcpy(auth1_getarray_type(auth), "AUTH0001", 8);
|
||||
|
||||
{
|
||||
const tor_cert_t *id_cert=NULL, *link_cert=NULL;
|
||||
const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL;
|
||||
const digests_t *my_digests, *their_digests;
|
||||
const uint8_t *my_id, *their_id, *client_id, *server_id;
|
||||
if (tor_tls_get_my_certs(server, &link_cert, &id_cert))
|
||||
return -1;
|
||||
my_digests = tor_cert_get_id_digests(id_cert);
|
||||
their_digests = tor_cert_get_id_digests(conn->handshake_state->id_cert);
|
||||
my_digests = tor_x509_cert_get_id_digests(id_cert);
|
||||
their_digests =
|
||||
tor_x509_cert_get_id_digests(conn->handshake_state->id_cert);
|
||||
tor_assert(my_digests);
|
||||
tor_assert(their_digests);
|
||||
my_id = (uint8_t*)my_digests->d[DIGEST_SHA256];
|
||||
@ -2359,12 +2369,10 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
|
||||
server_id = server ? my_id : their_id;
|
||||
|
||||
/* Client ID digest: 32 octets. */
|
||||
memcpy(ptr, client_id, 32);
|
||||
ptr += 32;
|
||||
memcpy(auth->cid, client_id, 32);
|
||||
|
||||
/* Server ID digest: 32 octets. */
|
||||
memcpy(ptr, server_id, 32);
|
||||
ptr += 32;
|
||||
memcpy(auth->sid, server_id, 32);
|
||||
}
|
||||
|
||||
{
|
||||
@ -2378,73 +2386,101 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
|
||||
}
|
||||
|
||||
/* Server log digest : 32 octets */
|
||||
crypto_digest_get_digest(server_d, (char*)ptr, 32);
|
||||
ptr += 32;
|
||||
crypto_digest_get_digest(server_d, (char*)auth->slog, 32);
|
||||
|
||||
/* Client log digest : 32 octets */
|
||||
crypto_digest_get_digest(client_d, (char*)ptr, 32);
|
||||
ptr += 32;
|
||||
crypto_digest_get_digest(client_d, (char*)auth->clog, 32);
|
||||
}
|
||||
|
||||
{
|
||||
/* Digest of cert used on TLS link : 32 octets. */
|
||||
const tor_cert_t *cert = NULL;
|
||||
tor_cert_t *freecert = NULL;
|
||||
const tor_x509_cert_t *cert = NULL;
|
||||
tor_x509_cert_t *freecert = NULL;
|
||||
if (server) {
|
||||
tor_tls_get_my_certs(1, &cert, NULL);
|
||||
} else {
|
||||
freecert = tor_tls_get_peer_cert(conn->tls);
|
||||
cert = freecert;
|
||||
}
|
||||
if (!cert)
|
||||
return -1;
|
||||
memcpy(ptr, tor_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
|
||||
if (!cert) {
|
||||
log_warn(LD_OR, "Unable to find cert when making AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(auth->scert,
|
||||
tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
|
||||
|
||||
if (freecert)
|
||||
tor_cert_free(freecert);
|
||||
ptr += 32;
|
||||
tor_x509_cert_free(freecert);
|
||||
}
|
||||
|
||||
/* HMAC of clientrandom and serverrandom using master key : 32 octets */
|
||||
tor_tls_get_tlssecrets(conn->tls, ptr);
|
||||
ptr += 32;
|
||||
|
||||
tor_assert(ptr - out == V3_AUTH_FIXED_PART_LEN);
|
||||
|
||||
if (server)
|
||||
return V3_AUTH_FIXED_PART_LEN; // ptr-out
|
||||
tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets);
|
||||
|
||||
/* 8 octets were reserved for the current time, but we're trying to get out
|
||||
* of the habit of sending time around willynilly. Fortunately, nothing
|
||||
* checks it. That's followed by 16 bytes of nonce. */
|
||||
crypto_rand((char*)ptr, 24);
|
||||
ptr += 24;
|
||||
crypto_rand((char*)auth->rand, 24);
|
||||
|
||||
tor_assert(ptr - out == V3_AUTH_BODY_LEN);
|
||||
|
||||
if (!signing_key)
|
||||
return V3_AUTH_BODY_LEN; // ptr - out
|
||||
|
||||
{
|
||||
int siglen;
|
||||
char d[32];
|
||||
crypto_digest256(d, (char*)out, ptr-out, DIGEST_SHA256);
|
||||
siglen = crypto_pk_private_sign(signing_key,
|
||||
(char*)ptr, outlen - (ptr-out),
|
||||
d, 32);
|
||||
if (siglen < 0)
|
||||
return -1;
|
||||
|
||||
ptr += siglen;
|
||||
tor_assert(ptr <= out+outlen);
|
||||
return (int)(ptr - out);
|
||||
ssize_t len;
|
||||
if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) {
|
||||
log_warn(LD_OR, "Unable to encode signed part of AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (server) {
|
||||
auth1_t *tmp = NULL;
|
||||
ssize_t len2 = auth1_parse(&tmp, out, len, ctx);
|
||||
if (!tmp) {
|
||||
log_warn(LD_OR, "Unable to parse signed part of AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
result = (int) (tmp->end_of_fixed_part - out);
|
||||
auth1_free(tmp);
|
||||
if (len2 != len) {
|
||||
log_warn(LD_OR, "Mismatched length when re-parsing AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (signing_key) {
|
||||
auth1_setlen_sig(auth, crypto_pk_keysize(signing_key));
|
||||
|
||||
char d[32];
|
||||
crypto_digest256(d, (char*)out, len, DIGEST_SHA256);
|
||||
int siglen = crypto_pk_private_sign(signing_key,
|
||||
(char*)auth1_getarray_sig(auth),
|
||||
auth1_getlen_sig(auth),
|
||||
d, 32);
|
||||
if (siglen < 0) {
|
||||
log_warn(LD_OR, "Unable to sign AUTH1 data.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auth1_setlen_sig(auth, siglen);
|
||||
|
||||
len = auth1_encode(out, outlen, auth, ctx);
|
||||
if (len < 0) {
|
||||
log_warn(LD_OR, "Unable to encode signed AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
result = (int) len;
|
||||
goto done;
|
||||
|
||||
err:
|
||||
result = -1;
|
||||
done:
|
||||
auth1_free(auth);
|
||||
auth_ctx_free(ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Send an AUTHENTICATE cell on the connection <b>conn</b>. Return 0 on
|
||||
* success, -1 on failure */
|
||||
int
|
||||
connection_or_send_authenticate_cell(or_connection_t *conn, int authtype)
|
||||
MOCK_IMPL(int,
|
||||
connection_or_send_authenticate_cell,(or_connection_t *conn, int authtype))
|
||||
{
|
||||
var_cell_t *cell;
|
||||
crypto_pk_t *pk = tor_tls_get_my_client_auth_key();
|
||||
|
@ -43,7 +43,8 @@ MOCK_DECL(or_connection_t *,
|
||||
const char *id_digest, channel_tls_t *chan));
|
||||
|
||||
void connection_or_close_normally(or_connection_t *orconn, int flush);
|
||||
void connection_or_close_for_error(or_connection_t *orconn, int flush);
|
||||
MOCK_DECL(void,connection_or_close_for_error,
|
||||
(or_connection_t *orconn, int flush));
|
||||
|
||||
void connection_or_report_broken_states(int severity, int domain);
|
||||
|
||||
@ -77,17 +78,18 @@ void or_handshake_state_record_var_cell(or_connection_t *conn,
|
||||
int connection_or_set_state_open(or_connection_t *conn);
|
||||
void connection_or_write_cell_to_buf(const cell_t *cell,
|
||||
or_connection_t *conn);
|
||||
void connection_or_write_var_cell_to_buf(const var_cell_t *cell,
|
||||
or_connection_t *conn);
|
||||
MOCK_DECL(void,connection_or_write_var_cell_to_buf,(const var_cell_t *cell,
|
||||
or_connection_t *conn));
|
||||
int connection_or_send_versions(or_connection_t *conn, int v3_plus);
|
||||
int connection_or_send_netinfo(or_connection_t *conn);
|
||||
MOCK_DECL(int,connection_or_send_netinfo,(or_connection_t *conn));
|
||||
int connection_or_send_certs_cell(or_connection_t *conn);
|
||||
int connection_or_send_auth_challenge_cell(or_connection_t *conn);
|
||||
int connection_or_compute_authenticate_cell_body(or_connection_t *conn,
|
||||
uint8_t *out, size_t outlen,
|
||||
crypto_pk_t *signing_key,
|
||||
int server);
|
||||
int connection_or_send_authenticate_cell(or_connection_t *conn, int type);
|
||||
MOCK_DECL(int,connection_or_send_authenticate_cell,
|
||||
(or_connection_t *conn, int type));
|
||||
|
||||
int is_or_protocol_version_known(uint16_t version);
|
||||
|
||||
|
257
src/or/dircollate.c
Normal file
257
src/or/dircollate.c
Normal file
@ -0,0 +1,257 @@
|
||||
/* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file dircollate.c
|
||||
*
|
||||
* \brief Collation code for figuring out which identities to vote for in
|
||||
* the directory voting process.
|
||||
*/
|
||||
|
||||
#define DIRCOLLATE_PRIVATE
|
||||
#include "dircollate.h"
|
||||
#include "dirvote.h"
|
||||
|
||||
static void dircollator_collate_by_rsa(dircollator_t *dc);
|
||||
static void dircollator_collate_by_ed25519(dircollator_t *dc);
|
||||
|
||||
typedef struct ddmap_entry_s {
|
||||
HT_ENTRY(ddmap_entry_s) node;
|
||||
uint8_t d[DIGEST_LEN + DIGEST256_LEN];
|
||||
vote_routerstatus_t *vrs_lst[FLEXIBLE_ARRAY_MEMBER];
|
||||
} ddmap_entry_t;
|
||||
|
||||
struct double_digest_map_s *by_both_ids;
|
||||
|
||||
static void
|
||||
ddmap_entry_free(ddmap_entry_t *e)
|
||||
{
|
||||
tor_free(e);
|
||||
}
|
||||
|
||||
static ddmap_entry_t *
|
||||
ddmap_entry_new(int n_votes)
|
||||
{
|
||||
return tor_malloc_zero(STRUCT_OFFSET(ddmap_entry_t, vrs_lst) +
|
||||
sizeof(vote_routerstatus_t *) * n_votes);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
ddmap_entry_hash(const ddmap_entry_t *ent)
|
||||
{
|
||||
return (unsigned) siphash24g(ent->d, sizeof(ent->d));
|
||||
}
|
||||
|
||||
static unsigned
|
||||
ddmap_entry_eq(const ddmap_entry_t *a, const ddmap_entry_t *b)
|
||||
{
|
||||
return fast_memeq(a->d, b->d, sizeof(a->d));
|
||||
}
|
||||
|
||||
static void
|
||||
ddmap_entry_set_digests(ddmap_entry_t *ent,
|
||||
const uint8_t *rsa_sha1,
|
||||
const uint8_t *ed25519)
|
||||
{
|
||||
memcpy(ent->d, rsa_sha1, DIGEST_LEN);
|
||||
memcpy(ent->d + DIGEST_LEN, ed25519, DIGEST256_LEN);
|
||||
}
|
||||
|
||||
HT_PROTOTYPE(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash, ddmap_entry_eq);
|
||||
HT_GENERATE2(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash, ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_);
|
||||
static void
|
||||
dircollator_add_routerstatus(dircollator_t *dc,
|
||||
int vote_num,
|
||||
networkstatus_t *vote,
|
||||
vote_routerstatus_t *vrs)
|
||||
{
|
||||
const char *id = vrs->status.identity_digest;
|
||||
|
||||
(void) vote;
|
||||
vote_routerstatus_t **vrs_lst = digestmap_get(dc->by_rsa_sha1, id);
|
||||
if (NULL == vrs_lst) {
|
||||
vrs_lst = tor_calloc(sizeof(vote_routerstatus_t *), dc->n_votes);
|
||||
digestmap_set(dc->by_rsa_sha1, id, vrs_lst);
|
||||
}
|
||||
tor_assert(vrs_lst[vote_num] == NULL);
|
||||
vrs_lst[vote_num] = vrs;
|
||||
|
||||
const uint8_t *ed = vrs->ed25519_id;
|
||||
|
||||
if (tor_mem_is_zero((char*)ed, DIGEST256_LEN))
|
||||
return;
|
||||
|
||||
ddmap_entry_t search, *found;
|
||||
memset(&search, 0, sizeof(search));
|
||||
ddmap_entry_set_digests(&search, (const uint8_t *)id, ed);
|
||||
found = HT_FIND(double_digest_map, &dc->by_both_ids, &search);
|
||||
if (NULL == found) {
|
||||
found = ddmap_entry_new(dc->n_votes);
|
||||
ddmap_entry_set_digests(found, (const uint8_t *)id, ed);
|
||||
HT_INSERT(double_digest_map, &dc->by_both_ids, found);
|
||||
}
|
||||
vrs_lst = found->vrs_lst;
|
||||
tor_assert(vrs_lst[vote_num] == NULL);
|
||||
vrs_lst[vote_num] = vrs;
|
||||
}
|
||||
|
||||
dircollator_t *
|
||||
dircollator_new(int n_votes, int n_authorities)
|
||||
{
|
||||
dircollator_t *dc = tor_malloc_zero(sizeof(dircollator_t));
|
||||
|
||||
tor_assert(n_votes <= n_authorities);
|
||||
|
||||
dc->n_votes = n_votes;
|
||||
dc->n_authorities = n_authorities;
|
||||
|
||||
dc->by_rsa_sha1 = digestmap_new();
|
||||
HT_INIT(double_digest_map, &dc->by_both_ids);
|
||||
|
||||
return dc;
|
||||
}
|
||||
|
||||
void
|
||||
dircollator_free(dircollator_t *dc)
|
||||
{
|
||||
if (!dc)
|
||||
return;
|
||||
|
||||
if (dc->by_collated_rsa_sha1 != dc->by_rsa_sha1)
|
||||
digestmap_free(dc->by_collated_rsa_sha1, NULL);
|
||||
|
||||
digestmap_free(dc->by_rsa_sha1, tor_free_);
|
||||
|
||||
ddmap_entry_t **e, **next, *this;
|
||||
for (e = HT_START(double_digest_map, &dc->by_both_ids);
|
||||
e != NULL; e = next) {
|
||||
this = *e;
|
||||
next = HT_NEXT_RMV(double_digest_map, &dc->by_both_ids, e);
|
||||
ddmap_entry_free(this);
|
||||
}
|
||||
HT_CLEAR(double_digest_map, &dc->by_both_ids);
|
||||
|
||||
tor_free(dc);
|
||||
}
|
||||
|
||||
void
|
||||
dircollator_add_vote(dircollator_t *dc, networkstatus_t *v)
|
||||
{
|
||||
tor_assert(v->type == NS_TYPE_VOTE);
|
||||
tor_assert(dc->next_vote_num < dc->n_votes);
|
||||
tor_assert(!dc->is_collated);
|
||||
|
||||
const int votenum = dc->next_vote_num++;
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(v->routerstatus_list, vote_routerstatus_t *, vrs) {
|
||||
dircollator_add_routerstatus(dc, votenum, v, vrs);
|
||||
} SMARTLIST_FOREACH_END(vrs);
|
||||
}
|
||||
|
||||
void
|
||||
dircollator_collate(dircollator_t *dc, int consensus_method)
|
||||
{
|
||||
tor_assert(!dc->is_collated);
|
||||
dc->all_rsa_sha1_lst = smartlist_new();
|
||||
|
||||
if (consensus_method < MIN_METHOD_FOR_ED25519_ID_VOTING + 10/*XXX*/)
|
||||
dircollator_collate_by_rsa(dc);
|
||||
else
|
||||
dircollator_collate_by_ed25519(dc);
|
||||
|
||||
smartlist_sort_digests(dc->all_rsa_sha1_lst);
|
||||
dc->is_collated = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
dircollator_collate_by_rsa(dircollator_t *dc)
|
||||
{
|
||||
const int total_authorities = dc->n_authorities;
|
||||
|
||||
DIGESTMAP_FOREACH(dc->by_rsa_sha1, k, vote_routerstatus_t **, vrs_lst) {
|
||||
int n = 0, i;
|
||||
for (i = 0; i < dc->n_votes; ++i) {
|
||||
if (vrs_lst[i] != NULL)
|
||||
++n;
|
||||
}
|
||||
|
||||
if (n <= total_authorities / 2)
|
||||
continue;
|
||||
|
||||
smartlist_add(dc->all_rsa_sha1_lst, (char *)k);
|
||||
} DIGESTMAP_FOREACH_END;
|
||||
|
||||
dc->by_collated_rsa_sha1 = dc->by_rsa_sha1;
|
||||
}
|
||||
|
||||
static void
|
||||
dircollator_collate_by_ed25519(dircollator_t *dc)
|
||||
{
|
||||
const int total_authorities = dc->n_authorities;
|
||||
digestmap_t *rsa_digests = digestmap_new();
|
||||
|
||||
ddmap_entry_t **iter;
|
||||
|
||||
HT_FOREACH(iter, double_digest_map, &dc->by_both_ids) {
|
||||
ddmap_entry_t *ent = *iter;
|
||||
int n = 0, i;
|
||||
for (i = 0; i < dc->n_votes; ++i) {
|
||||
if (ent->vrs_lst[i] != NULL)
|
||||
++n;
|
||||
}
|
||||
|
||||
if (n <= total_authorities / 2)
|
||||
continue;
|
||||
|
||||
vote_routerstatus_t **vrs_lst2 = digestmap_get(dc->by_rsa_sha1,
|
||||
(char*)ent->d);
|
||||
tor_assert(vrs_lst2);
|
||||
|
||||
for (i = 0; i < dc->n_votes; ++i) {
|
||||
if (ent->vrs_lst[i] != NULL) {
|
||||
ent->vrs_lst[i]->ed25519_reflects_consensus = 1;
|
||||
} else if (vrs_lst2[i] && ! vrs_lst2[i]->has_ed25519_listing) {
|
||||
ent->vrs_lst[i] = vrs_lst2[i];
|
||||
}
|
||||
}
|
||||
|
||||
digestmap_set(rsa_digests, (char*)ent->d, ent->vrs_lst);
|
||||
smartlist_add(dc->all_rsa_sha1_lst, ent->d);
|
||||
}
|
||||
|
||||
DIGESTMAP_FOREACH(dc->by_rsa_sha1, k, vote_routerstatus_t **, vrs_lst) {
|
||||
if (digestmap_get(rsa_digests, k) != NULL)
|
||||
continue;
|
||||
|
||||
int n = 0, i;
|
||||
for (i = 0; i < dc->n_votes; ++i) {
|
||||
if (vrs_lst[i] != NULL)
|
||||
++n;
|
||||
}
|
||||
|
||||
if (n <= total_authorities / 2)
|
||||
continue;
|
||||
|
||||
digestmap_set(rsa_digests, k, vrs_lst);
|
||||
smartlist_add(dc->all_rsa_sha1_lst, (char *)k);
|
||||
} DIGESTMAP_FOREACH_END;
|
||||
|
||||
dc->by_collated_rsa_sha1 = rsa_digests;
|
||||
}
|
||||
|
||||
int
|
||||
dircollator_n_routers(dircollator_t *dc)
|
||||
{
|
||||
return smartlist_len(dc->all_rsa_sha1_lst);
|
||||
}
|
||||
|
||||
vote_routerstatus_t **
|
||||
dircollator_get_votes_for_router(dircollator_t *dc, int idx)
|
||||
{
|
||||
tor_assert(idx < smartlist_len(dc->all_rsa_sha1_lst));
|
||||
return digestmap_get(dc->by_collated_rsa_sha1,
|
||||
smartlist_get(dc->all_rsa_sha1_lst, idx));
|
||||
}
|
||||
|
49
src/or/dircollate.h
Normal file
49
src/or/dircollate.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file dirvote.h
|
||||
* \brief Header file for dirvote.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_DIRCOLLATE_H
|
||||
#define TOR_DIRCOLLATE_H
|
||||
|
||||
#include "testsupport.h"
|
||||
#include "or.h"
|
||||
|
||||
typedef struct dircollator_s dircollator_t;
|
||||
|
||||
dircollator_t *dircollator_new(int n_votes, int n_authorities);
|
||||
void dircollator_free(dircollator_t *obj);
|
||||
void dircollator_add_vote(dircollator_t *dc, networkstatus_t *v);
|
||||
|
||||
void dircollator_collate(dircollator_t *dc, int consensus_method);
|
||||
|
||||
int dircollator_n_routers(dircollator_t *dc);
|
||||
vote_routerstatus_t **dircollator_get_votes_for_router(dircollator_t *dc,
|
||||
int idx);
|
||||
|
||||
#ifdef DIRCOLLATE_PRIVATE
|
||||
struct ddmap_entry_s;
|
||||
typedef HT_HEAD(double_digest_map, ddmap_entry_s) double_digest_map_t;
|
||||
struct dircollator_s {
|
||||
/**DOCDOC */
|
||||
int is_collated;
|
||||
int n_votes;
|
||||
int n_authorities;
|
||||
|
||||
int next_vote_num;
|
||||
digestmap_t *by_rsa_sha1;
|
||||
struct double_digest_map by_both_ids;
|
||||
|
||||
digestmap_t *by_collated_rsa_sha1;
|
||||
|
||||
smartlist_t *all_rsa_sha1_lst;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
@ -18,6 +18,7 @@
|
||||
#include "dirserv.h"
|
||||
#include "dirvote.h"
|
||||
#include "hibernate.h"
|
||||
#include "keypin.h"
|
||||
#include "microdesc.h"
|
||||
#include "networkstatus.h"
|
||||
#include "nodelist.h"
|
||||
@ -27,6 +28,7 @@
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "routerset.h"
|
||||
#include "torcert.h"
|
||||
|
||||
/**
|
||||
* \file dirserv.c
|
||||
@ -225,6 +227,16 @@ dirserv_load_fingerprint_file(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this is set, then we don't allow routers that have advertised an Ed25519
|
||||
* identity to stop doing so. This is going to be essential for good identity
|
||||
* security: otherwise anybody who can attack RSA-1024 but not Ed25519 could
|
||||
* just sign fake descriptors missing the Ed25519 key. But we won't actually
|
||||
* be able to prevent that kind of thing until we're confident that there
|
||||
* isn't actually a legit reason to downgrade to 0.2.5. So for now, we have
|
||||
* to leave this #undef.
|
||||
*/
|
||||
#undef DISABLE_DISABLING_ED25519
|
||||
|
||||
/** Check whether <b>router</b> has a nickname/identity key combination that
|
||||
* we recognize from the fingerprint list, or an IP we automatically act on
|
||||
* according to our configuration. Return the appropriate router status.
|
||||
@ -243,6 +255,36 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg)
|
||||
return FP_REJECT;
|
||||
}
|
||||
|
||||
if (router->signing_key_cert) {
|
||||
/* This has an ed25519 identity key. */
|
||||
if (KEYPIN_MISMATCH ==
|
||||
keypin_check((const uint8_t*)router->cache_info.identity_digest,
|
||||
router->signing_key_cert->signing_key.pubkey)) {
|
||||
if (msg) {
|
||||
*msg = "Ed25519 identity key or RSA identity key has changed.";
|
||||
}
|
||||
log_warn(LD_DIR, "Router %s uploaded a descriptor with a Ed25519 key "
|
||||
"but the <rsa,ed25519> keys don't match what they were before.",
|
||||
router_describe(router));
|
||||
return FP_REJECT;
|
||||
}
|
||||
} else {
|
||||
/* No ed25519 key */
|
||||
if (KEYPIN_MISMATCH == keypin_check_lone_rsa(
|
||||
(const uint8_t*)router->cache_info.identity_digest)) {
|
||||
log_warn(LD_DIR, "Router %s uploaded a descriptor with no Ed25519 key, "
|
||||
"when we previously knew an Ed25519 for it. Ignoring for now, "
|
||||
"since Tor 0.2.6 is under development.",
|
||||
router_describe(router));
|
||||
#ifdef DISABLE_DISABLING_ED25519
|
||||
if (msg) {
|
||||
*msg = "Ed25519 identity key has disappeared.";
|
||||
}
|
||||
return FP_REJECT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return dirserv_get_status_impl(d, router->nickname,
|
||||
router->addr, router->or_port,
|
||||
router->platform, msg, 1);
|
||||
@ -578,6 +620,28 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
|
||||
return ROUTER_IS_ALREADY_KNOWN;
|
||||
}
|
||||
|
||||
/* Do keypinning again ... this time, to add the pin if appropriate */
|
||||
int keypin_status;
|
||||
if (ri->signing_key_cert) {
|
||||
keypin_status = keypin_check_and_add(
|
||||
(const uint8_t*)ri->cache_info.identity_digest,
|
||||
ri->signing_key_cert->signing_key.pubkey);
|
||||
} else {
|
||||
keypin_status = keypin_check_lone_rsa(
|
||||
(const uint8_t*)ri->cache_info.identity_digest);
|
||||
#ifndef DISABLE_DISABLING_ED25519
|
||||
if (keypin_status == KEYPIN_MISMATCH)
|
||||
keypin_status = KEYPIN_NOT_FOUND;
|
||||
#endif
|
||||
}
|
||||
if (keypin_status == KEYPIN_MISMATCH) {
|
||||
log_info(LD_DIRSERV, "Dropping descriptor from %s (source: %s) because "
|
||||
"its key did not match an older RSA/Ed25519 keypair",
|
||||
router_describe(ri), source);
|
||||
*msg = "Looks like your keypair does not match its older value.";
|
||||
return ROUTER_AUTHDIR_REJECTS;
|
||||
}
|
||||
|
||||
/* Make a copy of desc, since router_add_to_routerlist might free
|
||||
* ri and its associated signed_descriptor_t. */
|
||||
desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen);
|
||||
@ -1929,6 +1993,16 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
|
||||
smartlist_add_asprintf(chunks, "p %s\n", summary);
|
||||
tor_free(summary);
|
||||
}
|
||||
|
||||
if (format == NS_V3_VOTE && vrs) {
|
||||
if (tor_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
|
||||
smartlist_add(chunks, tor_strdup("id ed25519 none\n"));
|
||||
} else {
|
||||
char ed_b64[BASE64_DIGEST256_LEN+1];
|
||||
digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id);
|
||||
smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
@ -2751,6 +2825,11 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
|
||||
listbadexits,
|
||||
vote_on_hsdirs);
|
||||
|
||||
if (ri->signing_key_cert) {
|
||||
memcpy(vrs->ed25519_id, ri->signing_key_cert->signing_key.pubkey,
|
||||
ED25519_PUBKEY_LEN);
|
||||
}
|
||||
|
||||
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
|
||||
clear_status_flags_on_sybil(rs);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define DIRVOTE_PRIVATE
|
||||
#include "or.h"
|
||||
#include "config.h"
|
||||
#include "dircollate.h"
|
||||
#include "directory.h"
|
||||
#include "dirserv.h"
|
||||
#include "dirvote.h"
|
||||
@ -17,6 +18,7 @@
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "entrynodes.h" /* needed for guardfraction methods */
|
||||
#include "torcert.h"
|
||||
|
||||
/**
|
||||
* \file dirvote.c
|
||||
@ -1138,6 +1140,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
char *params = NULL;
|
||||
char *packages = NULL;
|
||||
int added_weights = 0;
|
||||
dircollator_t *collator = NULL;
|
||||
tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC);
|
||||
tor_assert(total_authorities >= smartlist_len(votes));
|
||||
|
||||
@ -1493,12 +1496,24 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
}
|
||||
);
|
||||
|
||||
/* Populate the collator */
|
||||
collator = dircollator_new(smartlist_len(votes), total_authorities);
|
||||
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
|
||||
dircollator_add_vote(collator, v);
|
||||
} SMARTLIST_FOREACH_END(v);
|
||||
|
||||
dircollator_collate(collator, consensus_method);
|
||||
|
||||
/* Now go through all the votes */
|
||||
flag_counts = tor_calloc(smartlist_len(flags), sizeof(int));
|
||||
while (1) {
|
||||
const int num_routers = dircollator_n_routers(collator);
|
||||
for (i = 0; i < num_routers; ++i) {
|
||||
vote_routerstatus_t **vrs_lst =
|
||||
dircollator_get_votes_for_router(collator, i);
|
||||
|
||||
vote_routerstatus_t *rs;
|
||||
routerstatus_t rs_out;
|
||||
const char *lowest_id = NULL;
|
||||
const char *current_rsa_id = NULL;
|
||||
const char *chosen_version;
|
||||
const char *chosen_name = NULL;
|
||||
int exitsummary_disagreement = 0;
|
||||
@ -1506,23 +1521,9 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
int is_guard = 0, is_exit = 0, is_bad_exit = 0;
|
||||
int naming_conflict = 0;
|
||||
int n_listing = 0;
|
||||
int i;
|
||||
char microdesc_digest[DIGEST256_LEN];
|
||||
tor_addr_port_t alt_orport = {TOR_ADDR_NULL, 0};
|
||||
|
||||
/* Of the next-to-be-considered digest in each voter, which is first? */
|
||||
SMARTLIST_FOREACH(votes, networkstatus_t *, v, {
|
||||
if (index[v_sl_idx] < size[v_sl_idx]) {
|
||||
rs = smartlist_get(v->routerstatus_list, index[v_sl_idx]);
|
||||
if (!lowest_id ||
|
||||
fast_memcmp(rs->status.identity_digest,
|
||||
lowest_id, DIGEST_LEN) < 0)
|
||||
lowest_id = rs->status.identity_digest;
|
||||
}
|
||||
});
|
||||
if (!lowest_id) /* we're out of routers. */
|
||||
break;
|
||||
|
||||
memset(flag_counts, 0, sizeof(int)*smartlist_len(flags));
|
||||
smartlist_clear(matching_descs);
|
||||
smartlist_clear(chosen_flags);
|
||||
@ -1532,29 +1533,25 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
num_guardfraction_inputs = 0;
|
||||
|
||||
/* Okay, go through all the entries for this digest. */
|
||||
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
|
||||
if (index[v_sl_idx] >= size[v_sl_idx])
|
||||
continue; /* out of entries. */
|
||||
rs = smartlist_get(v->routerstatus_list, index[v_sl_idx]);
|
||||
if (fast_memcmp(rs->status.identity_digest, lowest_id, DIGEST_LEN))
|
||||
continue; /* doesn't include this router. */
|
||||
/* At this point, we know that we're looking at a routerstatus with
|
||||
* identity "lowest".
|
||||
*/
|
||||
++index[v_sl_idx];
|
||||
for (int voter_idx = 0; voter_idx < smartlist_len(votes); ++voter_idx) {
|
||||
if (vrs_lst[voter_idx] == NULL)
|
||||
continue; /* This voter had nothig to say about this entry. */
|
||||
rs = vrs_lst[voter_idx];
|
||||
++n_listing;
|
||||
|
||||
current_rsa_id = rs->status.identity_digest;
|
||||
|
||||
smartlist_add(matching_descs, rs);
|
||||
if (rs->version && rs->version[0])
|
||||
smartlist_add(versions, rs->version);
|
||||
|
||||
/* Tally up all the flags. */
|
||||
for (i = 0; i < n_voter_flags[v_sl_idx]; ++i) {
|
||||
if (rs->flags & (U64_LITERAL(1) << i))
|
||||
++flag_counts[flag_map[v_sl_idx][i]];
|
||||
for (int flag = 0; flag < n_voter_flags[voter_idx]; ++flag) {
|
||||
if (rs->flags & (U64_LITERAL(1) << flag))
|
||||
++flag_counts[flag_map[voter_idx][flag]];
|
||||
}
|
||||
if (named_flag[v_sl_idx] >= 0 &&
|
||||
(rs->flags & (U64_LITERAL(1) << named_flag[v_sl_idx]))) {
|
||||
if (named_flag[voter_idx] >= 0 &&
|
||||
(rs->flags & (U64_LITERAL(1) << named_flag[voter_idx]))) {
|
||||
if (chosen_name && strcmp(chosen_name, rs->status.nickname)) {
|
||||
log_notice(LD_DIR, "Conflict on naming for router: %s vs %s",
|
||||
chosen_name, rs->status.nickname);
|
||||
@ -1575,7 +1572,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
|
||||
if (rs->status.has_bandwidth)
|
||||
bandwidths_kb[num_bandwidths++] = rs->status.bandwidth_kb;
|
||||
} SMARTLIST_FOREACH_END(v);
|
||||
}
|
||||
|
||||
/* We don't include this router at all unless more than half of
|
||||
* the authorities we believe in list it. */
|
||||
@ -1589,8 +1586,9 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
microdesc_digest, &alt_orport);
|
||||
/* Copy bits of that into rs_out. */
|
||||
memset(&rs_out, 0, sizeof(rs_out));
|
||||
tor_assert(fast_memeq(lowest_id, rs->status.identity_digest,DIGEST_LEN));
|
||||
memcpy(rs_out.identity_digest, lowest_id, DIGEST_LEN);
|
||||
tor_assert(fast_memeq(current_rsa_id,
|
||||
rs->status.identity_digest,DIGEST_LEN));
|
||||
memcpy(rs_out.identity_digest, current_rsa_id, DIGEST_LEN);
|
||||
memcpy(rs_out.descriptor_digest, rs->status.descriptor_digest,
|
||||
DIGEST_LEN);
|
||||
rs_out.addr = rs->status.addr;
|
||||
@ -1614,7 +1612,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
const char *d = strmap_get_lc(name_to_id_map, rs_out.nickname);
|
||||
if (!d) {
|
||||
is_named = is_unnamed = 0;
|
||||
} else if (fast_memeq(d, lowest_id, DIGEST_LEN)) {
|
||||
} else if (fast_memeq(d, current_rsa_id, DIGEST_LEN)) {
|
||||
is_named = 1; is_unnamed = 0;
|
||||
} else {
|
||||
is_named = 0; is_unnamed = 1;
|
||||
@ -1980,6 +1978,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
|
||||
done:
|
||||
|
||||
dircollator_free(collator);
|
||||
tor_free(client_versions);
|
||||
tor_free(server_versions);
|
||||
tor_free(packages);
|
||||
@ -3487,9 +3486,18 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
|
||||
}
|
||||
|
||||
if (consensus_method >= MIN_METHOD_FOR_ID_HASH_IN_MD) {
|
||||
char idbuf[BASE64_DIGEST_LEN+1];
|
||||
digest_to_base64(idbuf, ri->cache_info.identity_digest);
|
||||
smartlist_add_asprintf(chunks, "id rsa1024 %s\n", idbuf);
|
||||
char idbuf[ED25519_BASE64_LEN+1];
|
||||
const char *keytype;
|
||||
if (consensus_method >= MIN_METHOD_FOR_ED25519_ID_IN_MD &&
|
||||
ri->signing_key_cert &&
|
||||
ri->signing_key_cert->signing_key_included) {
|
||||
keytype = "ed25519";
|
||||
ed25519_public_to_base64(idbuf, &ri->signing_key_cert->signing_key);
|
||||
} else {
|
||||
keytype = "rsa1024";
|
||||
digest_to_base64(idbuf, ri->cache_info.identity_digest);
|
||||
}
|
||||
smartlist_add_asprintf(chunks, "id %s %s\n", keytype, idbuf);
|
||||
}
|
||||
|
||||
output = smartlist_join_strings(chunks, "", 0, NULL);
|
||||
@ -3562,7 +3570,8 @@ static const struct consensus_method_range_t {
|
||||
{MIN_METHOD_FOR_A_LINES, MIN_METHOD_FOR_P6_LINES - 1},
|
||||
{MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1},
|
||||
{MIN_METHOD_FOR_NTOR_KEY, MIN_METHOD_FOR_ID_HASH_IN_MD - 1},
|
||||
{MIN_METHOD_FOR_ID_HASH_IN_MD, MAX_SUPPORTED_CONSENSUS_METHOD},
|
||||
{MIN_METHOD_FOR_ID_HASH_IN_MD, MIN_METHOD_FOR_ED25519_ID_IN_MD - 1},
|
||||
{MIN_METHOD_FOR_ED25519_ID_IN_MD, MAX_SUPPORTED_CONSENSUS_METHOD},
|
||||
{-1, -1}
|
||||
};
|
||||
|
||||
|
@ -55,7 +55,7 @@
|
||||
#define MIN_SUPPORTED_CONSENSUS_METHOD 13
|
||||
|
||||
/** The highest consensus method that we currently support. */
|
||||
#define MAX_SUPPORTED_CONSENSUS_METHOD 20
|
||||
#define MAX_SUPPORTED_CONSENSUS_METHOD 21
|
||||
|
||||
/** Lowest consensus method where microdesc consensuses omit any entry
|
||||
* with no microdesc. */
|
||||
@ -86,6 +86,13 @@
|
||||
* GuardFraction information in microdescriptors. */
|
||||
#define MIN_METHOD_FOR_GUARDFRACTION 20
|
||||
|
||||
/** Lowest consensus method where authorities may include an "id" line for
|
||||
* ed25519 identities in microdescriptors. */
|
||||
#define MIN_METHOD_FOR_ED25519_ID_IN_MD 21
|
||||
/** Lowest consensus method where authorities vote on ed25519 ids and ensure
|
||||
* ed25519 id consistency. */
|
||||
#define MIN_METHOD_FOR_ED25519_ID_VOTING MIN_METHOD_FOR_ED25519_ID_IN_MD
|
||||
|
||||
/** Default bandwidth to clip unmeasured bandwidths to using method >=
|
||||
* MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
|
||||
* get confused with the above macros.) */
|
||||
|
@ -43,6 +43,7 @@ LIBTOR_A_SOURCES = \
|
||||
src/or/connection_or.c \
|
||||
src/or/control.c \
|
||||
src/or/cpuworker.c \
|
||||
src/or/dircollate.c \
|
||||
src/or/directory.c \
|
||||
src/or/dirserv.c \
|
||||
src/or/dirvote.c \
|
||||
@ -53,6 +54,7 @@ LIBTOR_A_SOURCES = \
|
||||
src/or/entrynodes.c \
|
||||
src/or/ext_orport.c \
|
||||
src/or/hibernate.c \
|
||||
src/or/keypin.c \
|
||||
src/or/main.c \
|
||||
src/or/microdesc.c \
|
||||
src/or/networkstatus.c \
|
||||
@ -71,12 +73,14 @@ LIBTOR_A_SOURCES = \
|
||||
src/or/rephist.c \
|
||||
src/or/replaycache.c \
|
||||
src/or/router.c \
|
||||
src/or/routerkeys.c \
|
||||
src/or/routerlist.c \
|
||||
src/or/routerparse.c \
|
||||
src/or/routerset.c \
|
||||
src/or/scheduler.c \
|
||||
src/or/statefile.c \
|
||||
src/or/status.c \
|
||||
src/or/torcert.c \
|
||||
src/or/onion_ntor.c \
|
||||
$(evdns_source) \
|
||||
$(tor_platform_source)
|
||||
@ -84,11 +88,6 @@ LIBTOR_A_SOURCES = \
|
||||
src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES)
|
||||
src_or_libtor_testing_a_SOURCES = $(LIBTOR_A_SOURCES)
|
||||
|
||||
#libtor_a_LIBADD = $(top_builddir)/common/libor.a \
|
||||
# $(top_builddir)/common/libor-crypto.a \
|
||||
# $(top_builddir)/common/libor-event.a
|
||||
|
||||
|
||||
src_or_tor_SOURCES = src/or/tor_main.c
|
||||
AM_CPPFLAGS += -I$(srcdir)/src/or -Isrc/or
|
||||
|
||||
@ -109,7 +108,7 @@ src_or_libtor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||
src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
|
||||
src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \
|
||||
src/common/libor-crypto.a $(LIBDONNA) \
|
||||
src/common/libor-event.a \
|
||||
src/common/libor-event.a src/trunnel/libor-trunnel.a \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@
|
||||
|
||||
@ -120,7 +119,7 @@ src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||
src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
|
||||
src_or_tor_cov_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
|
||||
src/common/libor-crypto-testing.a $(LIBDONNA) \
|
||||
src/common/libor-event-testing.a \
|
||||
src/common/libor-event-testing.a src/trunnel/libor-trunnel-testing.a \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
|
||||
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@
|
||||
TESTING_TOR_BINARY = $(top_builddir)/src/or/tor-cov
|
||||
@ -148,6 +147,7 @@ ORHEADERS = \
|
||||
src/or/connection_or.h \
|
||||
src/or/control.h \
|
||||
src/or/cpuworker.h \
|
||||
src/or/dircollate.h \
|
||||
src/or/directory.h \
|
||||
src/or/dirserv.h \
|
||||
src/or/dirvote.h \
|
||||
@ -159,6 +159,7 @@ ORHEADERS = \
|
||||
src/or/geoip.h \
|
||||
src/or/entrynodes.h \
|
||||
src/or/hibernate.h \
|
||||
src/or/keypin.h \
|
||||
src/or/main.h \
|
||||
src/or/microdesc.h \
|
||||
src/or/networkstatus.h \
|
||||
@ -180,12 +181,15 @@ ORHEADERS = \
|
||||
src/or/rephist.h \
|
||||
src/or/replaycache.h \
|
||||
src/or/router.h \
|
||||
src/or/routerkeys.h \
|
||||
src/or/routerlist.h \
|
||||
src/or/routerkeys.h \
|
||||
src/or/routerset.h \
|
||||
src/or/routerparse.h \
|
||||
src/or/scheduler.h \
|
||||
src/or/statefile.h \
|
||||
src/or/status.h
|
||||
src/or/status.h \
|
||||
src/or/torcert.h
|
||||
|
||||
noinst_HEADERS+= $(ORHEADERS) micro-revision.i
|
||||
|
||||
|
419
src/or/keypin.c
Normal file
419
src/or/keypin.c
Normal file
@ -0,0 +1,419 @@
|
||||
/* Copyright (c) 2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#define KEYPIN_PRIVATE
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "compat.h"
|
||||
#include "crypto.h"
|
||||
#include "di_ops.h"
|
||||
#include "ht.h"
|
||||
#include "keypin.h"
|
||||
#include "siphash.h"
|
||||
#include "torint.h"
|
||||
#include "torlog.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file keypin.c
|
||||
* @brief Key-pinning for RSA and Ed25519 identity keys at directory
|
||||
* authorities.
|
||||
*
|
||||
* This module implements a key-pinning mechanism to ensure that it's safe
|
||||
* to use RSA keys as identitifers even as we migrate to Ed25519 keys. It
|
||||
* remembers, for every Ed25519 key we've seen, what the associated Ed25519
|
||||
* key is. This way, if we see a different Ed25519 key with that RSA key,
|
||||
* we'll know that there's a mismatch.
|
||||
*
|
||||
* We persist these entries to disk using a simple format, where each line
|
||||
* has a base64-encoded RSA SHA1 hash, then a base64-endoded Ed25519 key.
|
||||
* Empty lines, misformed lines, and lines beginning with # are
|
||||
* ignored. Lines beginning with @ are reserved for future extensions.
|
||||
*/
|
||||
|
||||
static int keypin_journal_append_entry(const uint8_t *rsa_id_digest,
|
||||
const uint8_t *ed25519_id_key);
|
||||
static int keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
|
||||
const uint8_t *ed25519_id_key,
|
||||
int do_not_add);
|
||||
|
||||
static HT_HEAD(rsamap, keypin_ent_st) the_rsa_map = HT_INITIALIZER();
|
||||
static HT_HEAD(edmap, keypin_ent_st) the_ed_map = HT_INITIALIZER();
|
||||
|
||||
/** Hashtable helper: compare two keypin table entries and return true iff
|
||||
* they have the same RSA key IDs. */
|
||||
static INLINE int
|
||||
keypin_ents_eq_rsa(const keypin_ent_t *a, const keypin_ent_t *b)
|
||||
{
|
||||
return tor_memeq(a->rsa_id, b->rsa_id, sizeof(a->rsa_id));
|
||||
}
|
||||
|
||||
/** Hashtable helper: hash a keypin table entries based on its RSA key ID */
|
||||
static INLINE unsigned
|
||||
keypin_ent_hash_rsa(const keypin_ent_t *a)
|
||||
{
|
||||
return (unsigned) siphash24g(a->rsa_id, sizeof(a->rsa_id));
|
||||
}
|
||||
|
||||
/** Hashtable helper: compare two keypin table entries and return true iff
|
||||
* they have the same ed25519 keys */
|
||||
static INLINE int
|
||||
keypin_ents_eq_ed(const keypin_ent_t *a, const keypin_ent_t *b)
|
||||
{
|
||||
return tor_memeq(a->ed25519_key, b->ed25519_key, sizeof(a->ed25519_key));
|
||||
}
|
||||
|
||||
/** Hashtable helper: hash a keypin table entries based on its ed25519 key */
|
||||
static INLINE unsigned
|
||||
keypin_ent_hash_ed(const keypin_ent_t *a)
|
||||
{
|
||||
return (unsigned) siphash24g(a->ed25519_key, sizeof(a->ed25519_key));
|
||||
}
|
||||
|
||||
HT_PROTOTYPE(rsamap, keypin_ent_st, rsamap_node, keypin_ent_hash_rsa,
|
||||
keypin_ents_eq_rsa);
|
||||
HT_GENERATE2(rsamap, keypin_ent_st, rsamap_node, keypin_ent_hash_rsa,
|
||||
keypin_ents_eq_rsa, 0.6, tor_reallocarray, tor_free_);
|
||||
|
||||
HT_PROTOTYPE(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed,
|
||||
keypin_ents_eq_ed);
|
||||
HT_GENERATE2(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed,
|
||||
keypin_ents_eq_ed, 0.6, tor_reallocarray, tor_free_);
|
||||
|
||||
/**
|
||||
* Check whether we already have an entry in the key pinning table for a
|
||||
* router with RSA ID digest <b>rsa_id_digest</b> or for ed25519 key
|
||||
* <b>ed25519_id_key</b>. If we have an entry that matches both keys,
|
||||
* return KEYPIN_FOUND. If we find an entry that matches one key but
|
||||
* not the other, return KEYPIN_MISMATCH. If we have no entry for either
|
||||
* key, add such an entry to the table and return KEYPIN_ADDED.
|
||||
*/
|
||||
int
|
||||
keypin_check_and_add(const uint8_t *rsa_id_digest,
|
||||
const uint8_t *ed25519_id_key)
|
||||
{
|
||||
return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* As keypin_check_and_add, but do not add. Return KEYPIN_NOT_FOUND if
|
||||
* we would add.
|
||||
*/
|
||||
int
|
||||
keypin_check(const uint8_t *rsa_id_digest,
|
||||
const uint8_t *ed25519_id_key)
|
||||
{
|
||||
return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: implements keypin_check and keypin_check_and_add.
|
||||
*/
|
||||
static int
|
||||
keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
|
||||
const uint8_t *ed25519_id_key,
|
||||
int do_not_add)
|
||||
{
|
||||
keypin_ent_t search, *ent;
|
||||
memset(&search, 0, sizeof(search));
|
||||
memcpy(search.rsa_id, rsa_id_digest, sizeof(search.rsa_id));
|
||||
memcpy(search.ed25519_key, ed25519_id_key, sizeof(search.ed25519_key));
|
||||
|
||||
/* Search by RSA key digest first */
|
||||
ent = HT_FIND(rsamap, &the_rsa_map, &search);
|
||||
if (ent) {
|
||||
tor_assert(fast_memeq(ent->rsa_id, rsa_id_digest, sizeof(ent->rsa_id)));
|
||||
if (tor_memeq(ent->ed25519_key, ed25519_id_key,sizeof(ent->ed25519_key))) {
|
||||
return KEYPIN_FOUND; /* Match on both keys. Great. */
|
||||
} else {
|
||||
return KEYPIN_MISMATCH; /* Found RSA with different Ed key */
|
||||
}
|
||||
}
|
||||
|
||||
/* See if we know a different RSA key for this ed key */
|
||||
ent = HT_FIND(edmap, &the_ed_map, &search);
|
||||
if (ent) {
|
||||
/* If we got here, then the ed key matches and the RSA doesn't */
|
||||
tor_assert(fast_memeq(ent->ed25519_key, ed25519_id_key,
|
||||
sizeof(ent->ed25519_key)));
|
||||
tor_assert(fast_memneq(ent->rsa_id, rsa_id_digest, sizeof(ent->rsa_id)));
|
||||
return KEYPIN_MISMATCH;
|
||||
}
|
||||
|
||||
/* Okay, this one is new to us. */
|
||||
if (do_not_add)
|
||||
return KEYPIN_NOT_FOUND;
|
||||
|
||||
ent = tor_memdup(&search, sizeof(search));
|
||||
keypin_add_entry_to_map(ent);
|
||||
keypin_journal_append_entry(rsa_id_digest, ed25519_id_key);
|
||||
return KEYPIN_ADDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: add <b>ent</b> to the hash tables.
|
||||
*/
|
||||
MOCK_IMPL(STATIC void,
|
||||
keypin_add_entry_to_map, (keypin_ent_t *ent))
|
||||
{
|
||||
HT_INSERT(rsamap, &the_rsa_map, ent);
|
||||
HT_INSERT(edmap, &the_ed_map, ent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we already have an entry in the key pinning table for a
|
||||
* router with RSA ID digest <b>rsa_id_digest</b>. If we have no such entry,
|
||||
* return KEYPIN_NOT_FOUND. If we find an entry that matches the RSA key but
|
||||
* which has an ed25519 key, return KEYPIN_MISMATCH.
|
||||
*/
|
||||
int
|
||||
keypin_check_lone_rsa(const uint8_t *rsa_id_digest)
|
||||
{
|
||||
keypin_ent_t search, *ent;
|
||||
memset(&search, 0, sizeof(search));
|
||||
memcpy(search.rsa_id, rsa_id_digest, sizeof(search.rsa_id));
|
||||
|
||||
/* Search by RSA key digest first */
|
||||
ent = HT_FIND(rsamap, &the_rsa_map, &search);
|
||||
if (ent) {
|
||||
return KEYPIN_MISMATCH;
|
||||
} else {
|
||||
return KEYPIN_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
/** Open fd to the keypinning journal file. */
|
||||
static int keypin_journal_fd = -1;
|
||||
|
||||
/** Open the key-pinning journal to append to <b>fname</b>. Return 0 on
|
||||
* success, -1 on failure. */
|
||||
int
|
||||
keypin_open_journal(const char *fname)
|
||||
{
|
||||
/* O_SYNC ??*/
|
||||
int fd = tor_open_cloexec(fname, O_WRONLY|O_CREAT, 0600);
|
||||
if (fd < 0)
|
||||
goto err;
|
||||
|
||||
if (tor_fd_seekend(fd) < 0)
|
||||
goto err;
|
||||
|
||||
/* Add a newline in case the last line was only partially written */
|
||||
if (write(fd, "\n", 1) < 1)
|
||||
goto err;
|
||||
|
||||
/* Add something about when we opened this file. */
|
||||
char buf[80];
|
||||
char tbuf[ISO_TIME_LEN+1];
|
||||
format_iso_time(tbuf, approx_time());
|
||||
tor_snprintf(buf, sizeof(buf), "@opened-at %s\n", tbuf);
|
||||
if (write_all(fd, buf, strlen(buf), 0) < 0)
|
||||
goto err;
|
||||
|
||||
keypin_journal_fd = fd;
|
||||
return 0;
|
||||
err:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Close the keypinning journal file. */
|
||||
int
|
||||
keypin_close_journal(void)
|
||||
{
|
||||
if (keypin_journal_fd >= 0)
|
||||
close(keypin_journal_fd);
|
||||
keypin_journal_fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Length of a keypinning journal line, including terminating newline. */
|
||||
#define JOURNAL_LINE_LEN (BASE64_DIGEST_LEN + BASE64_DIGEST256_LEN + 2)
|
||||
|
||||
/** Add an entry to the keypinning journal to map <b>rsa_id_digest</b> and
|
||||
* <b>ed25519_id_key</b>. */
|
||||
static int
|
||||
keypin_journal_append_entry(const uint8_t *rsa_id_digest,
|
||||
const uint8_t *ed25519_id_key)
|
||||
{
|
||||
if (keypin_journal_fd == -1)
|
||||
return -1;
|
||||
char line[JOURNAL_LINE_LEN];
|
||||
digest_to_base64(line, (const char*)rsa_id_digest);
|
||||
line[BASE64_DIGEST_LEN] = ' ';
|
||||
digest256_to_base64(line + BASE64_DIGEST_LEN + 1,
|
||||
(const char*)ed25519_id_key);
|
||||
line[BASE64_DIGEST_LEN+1+BASE64_DIGEST256_LEN] = '\n';
|
||||
|
||||
if (write_all(keypin_journal_fd, line, JOURNAL_LINE_LEN, 0)<0) {
|
||||
log_warn(LD_DIRSERV, "Error while adding a line to the key-pinning "
|
||||
"journal: %s", strerror(errno));
|
||||
keypin_close_journal();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Load a journal from the <b>size</b>-byte region at <b>data</b>. Return 0
|
||||
* on success, -1 on failure. */
|
||||
STATIC int
|
||||
keypin_load_journal_impl(const char *data, size_t size)
|
||||
{
|
||||
const char *start = data, *end = data + size, *next;
|
||||
|
||||
int n_corrupt_lines = 0;
|
||||
int n_entries = 0;
|
||||
int n_duplicates = 0;
|
||||
int n_conflicts = 0;
|
||||
|
||||
for (const char *cp = start; cp < end; cp = next) {
|
||||
const char *eol = memchr(cp, '\n', end-cp);
|
||||
const char *eos = eol ? eol : end;
|
||||
const size_t len = eos - cp;
|
||||
|
||||
next = eol ? eol + 1 : end;
|
||||
|
||||
if (len == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*cp == '@') {
|
||||
/* Lines that start with @ are reserved. Ignore for now. */
|
||||
continue;
|
||||
}
|
||||
if (*cp == '#') {
|
||||
/* Lines that start with # are comments. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Is it the right length? (The -1 here is for the newline.) */
|
||||
if (len != JOURNAL_LINE_LEN - 1) {
|
||||
/* Lines with a bad length are corrupt unless they are empty.
|
||||
* Ignore them either way */
|
||||
for (const char *s = cp; s < eos; ++s) {
|
||||
if (! TOR_ISSPACE(*s)) {
|
||||
++n_corrupt_lines;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
keypin_ent_t *ent = keypin_parse_journal_line(cp);
|
||||
|
||||
if (ent == NULL) {
|
||||
++n_corrupt_lines;
|
||||
continue;
|
||||
}
|
||||
|
||||
const keypin_ent_t *ent2;
|
||||
if ((ent2 = HT_FIND(rsamap, &the_rsa_map, ent))) {
|
||||
if (fast_memeq(ent2->ed25519_key, ent->ed25519_key, DIGEST256_LEN)) {
|
||||
++n_duplicates;
|
||||
} else {
|
||||
++n_conflicts;
|
||||
}
|
||||
tor_free(ent);
|
||||
continue;
|
||||
} else if (HT_FIND(edmap, &the_ed_map, ent)) {
|
||||
tor_free(ent);
|
||||
++n_conflicts;
|
||||
continue;
|
||||
}
|
||||
|
||||
keypin_add_entry_to_map(ent);
|
||||
++n_entries;
|
||||
}
|
||||
|
||||
int severity = (n_corrupt_lines || n_duplicates) ? LOG_WARN : LOG_INFO;
|
||||
tor_log(severity, LD_DIRSERV,
|
||||
"Loaded %d entries from keypin journal. "
|
||||
"Found %d corrupt lines, %d duplicates, and %d conflicts.",
|
||||
n_entries, n_corrupt_lines, n_duplicates, n_conflicts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a journal from the file called <b>fname</b>. Return 0 on success,
|
||||
* -1 on failure.
|
||||
*/
|
||||
int
|
||||
keypin_load_journal(const char *fname)
|
||||
{
|
||||
tor_mmap_t *map = tor_mmap_file(fname);
|
||||
if (!map) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
int r = keypin_load_journal_impl(map->data, map->size);
|
||||
tor_munmap_file(map);
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Parse a single keypinning journal line entry from <b>cp</b>. The input
|
||||
* does not need to be NUL-terminated, but it <em>does</em> need to have
|
||||
* KEYPIN_JOURNAL_LINE_LEN -1 bytes available to read. Return a new entry
|
||||
* on success, and NULL on failure.
|
||||
*/
|
||||
STATIC keypin_ent_t *
|
||||
keypin_parse_journal_line(const char *cp)
|
||||
{
|
||||
/* XXXX assumes !USE_OPENSSL_BASE64 */
|
||||
keypin_ent_t *ent = tor_malloc_zero(sizeof(keypin_ent_t));
|
||||
|
||||
if (base64_decode((char*)ent->rsa_id, sizeof(ent->rsa_id),
|
||||
cp, BASE64_DIGEST_LEN) != DIGEST_LEN ||
|
||||
cp[BASE64_DIGEST_LEN] != ' ' ||
|
||||
base64_decode((char*)ent->ed25519_key, sizeof(ent->ed25519_key),
|
||||
cp+BASE64_DIGEST_LEN+1, BASE64_DIGEST256_LEN) != DIGEST256_LEN) {
|
||||
tor_free(ent);
|
||||
return NULL;
|
||||
} else {
|
||||
return ent;
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove all entries from the keypinning table.*/
|
||||
void
|
||||
keypin_clear(void)
|
||||
{
|
||||
int bad_entries = 0;
|
||||
{
|
||||
keypin_ent_t **ent, **next, *this;
|
||||
for (ent = HT_START(rsamap, &the_rsa_map); ent != NULL; ent = next) {
|
||||
this = *ent;
|
||||
next = HT_NEXT_RMV(rsamap, &the_rsa_map, ent);
|
||||
|
||||
keypin_ent_t *other_ent = HT_REMOVE(edmap, &the_ed_map, this);
|
||||
bad_entries += (other_ent != this);
|
||||
|
||||
tor_free(this);
|
||||
}
|
||||
}
|
||||
bad_entries += HT_SIZE(&the_ed_map);
|
||||
|
||||
HT_CLEAR(edmap,&the_ed_map);
|
||||
HT_CLEAR(rsamap,&the_rsa_map);
|
||||
|
||||
if (bad_entries) {
|
||||
log_warn(LD_BUG, "Found %d discrepencies in the the keypin database.",
|
||||
bad_entries);
|
||||
}
|
||||
}
|
||||
|
46
src/or/keypin.h
Normal file
46
src/or/keypin.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* Copyright (c) 2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_KEYPIN_H
|
||||
#define TOR_KEYPIN_H
|
||||
|
||||
#include "testsupport.h"
|
||||
|
||||
int keypin_check_and_add(const uint8_t *rsa_id_digest,
|
||||
const uint8_t *ed25519_id_key);
|
||||
int keypin_check(const uint8_t *rsa_id_digest,
|
||||
const uint8_t *ed25519_id_key);
|
||||
|
||||
int keypin_open_journal(const char *fname);
|
||||
int keypin_close_journal(void);
|
||||
int keypin_load_journal(const char *fname);
|
||||
void keypin_clear(void);
|
||||
int keypin_check_lone_rsa(const uint8_t *rsa_id_digest);
|
||||
|
||||
#define KEYPIN_FOUND 0
|
||||
#define KEYPIN_ADDED 1
|
||||
#define KEYPIN_MISMATCH -1
|
||||
#define KEYPIN_NOT_FOUND -2
|
||||
|
||||
#ifdef KEYPIN_PRIVATE
|
||||
|
||||
/**
|
||||
* In-memory representation of a key-pinning table entry.
|
||||
*/
|
||||
typedef struct keypin_ent_st {
|
||||
HT_ENTRY(keypin_ent_st) rsamap_node;
|
||||
HT_ENTRY(keypin_ent_st) edmap_node;
|
||||
/** SHA1 hash of the RSA key */
|
||||
uint8_t rsa_id[DIGEST_LEN];
|
||||
/** Ed2219 key. */
|
||||
uint8_t ed25519_key[DIGEST256_LEN];
|
||||
} keypin_ent_t;
|
||||
|
||||
STATIC keypin_ent_t * keypin_parse_journal_line(const char *cp);
|
||||
STATIC int keypin_load_journal_impl(const char *data, size_t size);
|
||||
|
||||
MOCK_DECL(STATIC void, keypin_add_entry_to_map, (keypin_ent_t *ent));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "entrynodes.h"
|
||||
#include "geoip.h"
|
||||
#include "hibernate.h"
|
||||
#include "keypin.h"
|
||||
#include "main.h"
|
||||
#include "microdesc.h"
|
||||
#include "networkstatus.h"
|
||||
@ -51,6 +52,7 @@
|
||||
#include "rendservice.h"
|
||||
#include "rephist.h"
|
||||
#include "router.h"
|
||||
#include "routerkeys.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "scheduler.h"
|
||||
@ -1223,10 +1225,13 @@ typedef struct {
|
||||
time_t check_descriptor;
|
||||
/** When do we next launch DNS wildcarding checks? */
|
||||
time_t check_for_correct_dns;
|
||||
/** When do we next make sure our Ed25519 keys aren't about to expire? */
|
||||
time_t check_ed_keys;
|
||||
|
||||
} time_to_t;
|
||||
|
||||
static time_to_t time_to = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/** Reset all the time_to's so we'll do all our actions again as if we
|
||||
@ -1297,6 +1302,18 @@ run_scheduled_events(time_t now)
|
||||
router_upload_dir_desc_to_dirservers(0);
|
||||
}
|
||||
|
||||
if (is_server && time_to.check_ed_keys < now) {
|
||||
if (should_make_new_ed_keys(options, now)) {
|
||||
if (load_ed_keys(options, now) < 0 ||
|
||||
generate_ed_link_cert(options, now)) {
|
||||
log_err(LD_OR, "Unable to update Ed25519 keys! Exiting.");
|
||||
tor_cleanup();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
time_to.check_ed_keys = now + 30;
|
||||
}
|
||||
|
||||
if (!should_delay_dir_fetches(options, NULL) &&
|
||||
time_to.try_getting_descriptors < now) {
|
||||
update_all_descriptor_downloads(now);
|
||||
@ -2015,6 +2032,23 @@ do_main_loop(void)
|
||||
/* initialize the bootstrap status events to know we're starting up */
|
||||
control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0);
|
||||
|
||||
/* Initialize the keypinning log. */
|
||||
if (authdir_mode_v3(get_options())) {
|
||||
char *fname = get_datadir_fname("key-pinning-entries");
|
||||
int r = 0;
|
||||
if (keypin_load_journal(fname)<0) {
|
||||
log_err(LD_DIR, "Error loading key-pinning journal: %s",strerror(errno));
|
||||
r = -1;
|
||||
}
|
||||
if (keypin_open_journal(fname)<0) {
|
||||
log_err(LD_DIR, "Error opening key-pinning journal: %s",strerror(errno));
|
||||
r = -1;
|
||||
}
|
||||
tor_free(fname);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (trusted_dirs_reload_certs()) {
|
||||
log_warn(LD_DIR,
|
||||
"Couldn't load all cached v3 certificates. Starting anyway.");
|
||||
@ -2695,6 +2729,7 @@ tor_free_all(int postfork)
|
||||
config_free_all();
|
||||
or_state_free_all();
|
||||
router_free_all();
|
||||
routerkeys_free_all();
|
||||
policies_free_all();
|
||||
}
|
||||
if (!postfork) {
|
||||
@ -2752,6 +2787,7 @@ tor_cleanup(void)
|
||||
or_state_save(now);
|
||||
if (authdir_mode_tests_reachability(options))
|
||||
rep_hist_record_mtbf_data(now, 0);
|
||||
keypin_close_journal();
|
||||
}
|
||||
#ifdef USE_DMALLOC
|
||||
dmalloc_log_stats();
|
||||
|
@ -738,6 +738,7 @@ microdesc_free_(microdesc_t *md, const char *fname, int lineno)
|
||||
if (md->onion_pkey)
|
||||
crypto_pk_free(md->onion_pkey);
|
||||
tor_free(md->onion_curve25519_pkey);
|
||||
tor_free(md->ed25519_identity_pkey);
|
||||
if (md->body && md->saved_location != SAVED_IN_CACHE)
|
||||
tor_free(md->body);
|
||||
|
||||
|
41
src/or/or.h
41
src/or/or.h
@ -96,6 +96,7 @@
|
||||
#include "ht.h"
|
||||
#include "replaycache.h"
|
||||
#include "crypto_curve25519.h"
|
||||
#include "crypto_ed25519.h"
|
||||
#include "tor_queue.h"
|
||||
|
||||
/* These signals are defined to help handle_control_signal work.
|
||||
@ -1353,6 +1354,8 @@ typedef struct listener_connection_t {
|
||||
* in the v3 handshake. The subject key must be a 1024-bit RSA key; it
|
||||
* must be signed by the identity key */
|
||||
#define OR_CERT_TYPE_AUTH_1024 3
|
||||
/** DOCDOC */
|
||||
#define OR_CERT_TYPE_RSA_ED_CROSSCERT 7
|
||||
/**@}*/
|
||||
|
||||
/** The one currently supported type of AUTHENTICATE cell. It contains
|
||||
@ -1428,9 +1431,9 @@ typedef struct or_handshake_state_t {
|
||||
* @{
|
||||
*/
|
||||
/** The cert for the key that's supposed to sign the AUTHENTICATE cell */
|
||||
tor_cert_t *auth_cert;
|
||||
tor_x509_cert_t *auth_cert;
|
||||
/** A self-signed identity certificate */
|
||||
tor_cert_t *id_cert;
|
||||
tor_x509_cert_t *id_cert;
|
||||
/**@}*/
|
||||
} or_handshake_state_t;
|
||||
|
||||
@ -2023,6 +2026,8 @@ typedef int16_t country_t;
|
||||
/** Information about another onion router in the network. */
|
||||
typedef struct {
|
||||
signed_descriptor_t cache_info;
|
||||
/** A SHA256-digest of the extrainfo (if any) */
|
||||
char extra_info_digest256[DIGEST256_LEN];
|
||||
char *nickname; /**< Human-readable OR name. */
|
||||
|
||||
uint32_t addr; /**< IPv4 address of OR, in host order. */
|
||||
@ -2040,6 +2045,11 @@ typedef struct {
|
||||
crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */
|
||||
/** Public curve25519 key for onions */
|
||||
curve25519_public_key_t *onion_curve25519_pkey;
|
||||
/** Certificate for ed25519 signing key */
|
||||
struct tor_cert_st *signing_key_cert;
|
||||
/** What's the earliest expiration time on all the certs in this
|
||||
* routerinfo? */
|
||||
time_t cert_expiration_time;
|
||||
|
||||
char *platform; /**< What software/operating system is this OR using? */
|
||||
|
||||
@ -2099,8 +2109,12 @@ typedef struct {
|
||||
/** Information needed to keep and cache a signed extra-info document. */
|
||||
typedef struct extrainfo_t {
|
||||
signed_descriptor_t cache_info;
|
||||
/** SHA256 digest of this document */
|
||||
uint8_t digest256[DIGEST256_LEN];
|
||||
/** The router's nickname. */
|
||||
char nickname[MAX_NICKNAME_LEN+1];
|
||||
/** Certificate for ed25519 signing key */
|
||||
struct tor_cert_st *signing_key_cert;
|
||||
/** True iff we found the right key for this extra-info, verified the
|
||||
* signature, and found it to be bad. */
|
||||
unsigned int bad_sig : 1;
|
||||
@ -2245,6 +2259,8 @@ typedef struct microdesc_t {
|
||||
crypto_pk_t *onion_pkey;
|
||||
/** As routerinfo_t.onion_curve25519_pkey */
|
||||
curve25519_public_key_t *onion_curve25519_pkey;
|
||||
/** Ed25519 identity key, if included. */
|
||||
ed25519_public_key_t *ed25519_identity_pkey;
|
||||
/** As routerinfo_t.ipv6_add */
|
||||
tor_addr_t ipv6_addr;
|
||||
/** As routerinfo_t.ipv6_orport */
|
||||
@ -2359,9 +2375,13 @@ typedef struct vote_routerstatus_t {
|
||||
char *version; /**< The version that the authority says this router is
|
||||
* running. */
|
||||
unsigned int has_measured_bw:1; /**< The vote had a measured bw */
|
||||
unsigned int has_ed25519_listing:1; /** DOCDOC */
|
||||
unsigned int ed25519_reflects_consensus:1; /** DOCDOC */
|
||||
uint32_t measured_bw_kb; /**< Measured bandwidth (capacity) of the router */
|
||||
/** The hash or hashes that the authority claims this microdesc has. */
|
||||
vote_microdesc_hash_t *microdesc;
|
||||
/** Ed25519 identity for this router, or zero if it has none. */
|
||||
uint8_t ed25519_id[ED25519_PUBKEY_LEN];
|
||||
} vote_routerstatus_t;
|
||||
|
||||
/** A signature of some document by an authority. */
|
||||
@ -4261,6 +4281,21 @@ typedef struct {
|
||||
* XXXX Eventually, the default will be 0. */
|
||||
int ExitRelay;
|
||||
|
||||
|
||||
/** For how long (seconds) do we declare our singning keys to be valid? */
|
||||
int SigningKeyLifetime;
|
||||
/** For how long (seconds) do we declare our link keys to be valid? */
|
||||
int TestingLinkCertLifetime;
|
||||
/** For how long (seconds) do we declare our auth keys to be valid? */
|
||||
int TestingAuthKeyLifetime;
|
||||
|
||||
/** How long before signing keys expire will we try to make a new one? */
|
||||
int TestingSigningKeySlop;
|
||||
/** How long before link keys expire will we try to make a new one? */
|
||||
int TestingLinkKeySlop;
|
||||
/** How long before auth keys expire will we try to make a new one? */
|
||||
int TestingAuthKeySlop;
|
||||
|
||||
} or_options_t;
|
||||
|
||||
/** Persistent state for an onion router, as saved to disk. */
|
||||
@ -5065,6 +5100,8 @@ typedef enum was_router_added_t {
|
||||
/* Router descriptor was rejected because it was older than
|
||||
* OLD_ROUTER_DESC_MAX_AGE. */
|
||||
ROUTER_WAS_TOO_OLD = -7, /* note contrast with 'NOT_NEW' */
|
||||
/* DOCDOC */
|
||||
ROUTER_CERTS_EXPIRED = -8
|
||||
} was_router_added_t;
|
||||
|
||||
/********************************* routerparse.c ************************/
|
||||
|
242
src/or/router.c
242
src/or/router.c
@ -26,9 +26,11 @@
|
||||
#include "relay.h"
|
||||
#include "rephist.h"
|
||||
#include "router.h"
|
||||
#include "routerkeys.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "statefile.h"
|
||||
#include "torcert.h"
|
||||
#include "transports.h"
|
||||
#include "routerset.h"
|
||||
|
||||
@ -204,6 +206,8 @@ set_server_identity_key(crypto_pk_t *k)
|
||||
static void
|
||||
assert_identity_keys_ok(void)
|
||||
{
|
||||
if (1)
|
||||
return;
|
||||
tor_assert(client_identitykey);
|
||||
if (public_server_mode(get_options())) {
|
||||
/* assert that we have set the client and server keys to be equal */
|
||||
@ -863,6 +867,10 @@ init_keys(void)
|
||||
set_client_identity_key(prkey);
|
||||
}
|
||||
|
||||
/* 1d. Load all ed25519 keys */
|
||||
if (load_ed_keys(options,now) < 0)
|
||||
return -1;
|
||||
|
||||
/* 2. Read onion key. Make it if none is found. */
|
||||
keydir = get_datadir_fname2("keys", "secret_onion_key");
|
||||
log_info(LD_GENERAL,"Reading/making onion key \"%s\"...",keydir);
|
||||
@ -928,6 +936,13 @@ init_keys(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 3b. Get an ed25519 link certificate. Note that we need to do this
|
||||
* after we set up the TLS context */
|
||||
if (generate_ed_link_cert(options, now) < 0) {
|
||||
log_err(LD_GENERAL,"Couldn't make link cert");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 4. Build our router descriptor. */
|
||||
/* Must be called after keys are initialized. */
|
||||
mydesc = router_get_my_descriptor();
|
||||
@ -1872,6 +1887,8 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
|
||||
routerinfo_free(ri);
|
||||
return -1;
|
||||
}
|
||||
ri->signing_key_cert = tor_cert_dup(get_master_signing_key_cert());
|
||||
|
||||
get_platform_str(platform, sizeof(platform));
|
||||
ri->platform = tor_strdup(platform);
|
||||
|
||||
@ -1962,10 +1979,12 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
|
||||
ei->cache_info.is_extrainfo = 1;
|
||||
strlcpy(ei->nickname, get_options()->Nickname, sizeof(ei->nickname));
|
||||
ei->cache_info.published_on = ri->cache_info.published_on;
|
||||
ei->signing_key_cert = tor_cert_dup(get_master_signing_key_cert());
|
||||
memcpy(ei->cache_info.identity_digest, ri->cache_info.identity_digest,
|
||||
DIGEST_LEN);
|
||||
if (extrainfo_dump_to_string(&ei->cache_info.signed_descriptor_body,
|
||||
ei, get_server_identity_key()) < 0) {
|
||||
ei, get_server_identity_key(),
|
||||
get_master_signing_keypair()) < 0) {
|
||||
log_warn(LD_BUG, "Couldn't generate extra-info descriptor.");
|
||||
extrainfo_free(ei);
|
||||
ei = NULL;
|
||||
@ -1975,6 +1994,10 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
|
||||
router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body,
|
||||
ei->cache_info.signed_descriptor_len,
|
||||
ei->cache_info.signed_descriptor_digest);
|
||||
crypto_digest256((char*) ei->digest256,
|
||||
ei->cache_info.signed_descriptor_body,
|
||||
ei->cache_info.signed_descriptor_len,
|
||||
DIGEST_SHA256);
|
||||
}
|
||||
|
||||
/* Now finish the router descriptor. */
|
||||
@ -1982,12 +2005,18 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
|
||||
memcpy(ri->cache_info.extra_info_digest,
|
||||
ei->cache_info.signed_descriptor_digest,
|
||||
DIGEST_LEN);
|
||||
memcpy(ri->extra_info_digest256,
|
||||
ei->digest256,
|
||||
DIGEST256_LEN);
|
||||
} else {
|
||||
/* ri was allocated with tor_malloc_zero, so there is no need to
|
||||
* zero ri->cache_info.extra_info_digest here. */
|
||||
}
|
||||
if (! (ri->cache_info.signed_descriptor_body = router_dump_router_to_string(
|
||||
ri, get_server_identity_key()))) {
|
||||
if (! (ri->cache_info.signed_descriptor_body =
|
||||
router_dump_router_to_string(ri, get_server_identity_key(),
|
||||
get_onion_key(),
|
||||
get_current_curve25519_keypair(),
|
||||
get_master_signing_keypair())) ) {
|
||||
log_warn(LD_BUG, "Couldn't generate router descriptor.");
|
||||
routerinfo_free(ri);
|
||||
extrainfo_free(ei);
|
||||
@ -2328,22 +2357,28 @@ get_platform_str(char *platform, size_t len)
|
||||
*/
|
||||
char *
|
||||
router_dump_router_to_string(routerinfo_t *router,
|
||||
crypto_pk_t *ident_key)
|
||||
const crypto_pk_t *ident_key,
|
||||
const crypto_pk_t *tap_key,
|
||||
const curve25519_keypair_t *ntor_keypair,
|
||||
const ed25519_keypair_t *signing_keypair)
|
||||
{
|
||||
char *address = NULL;
|
||||
char *onion_pkey = NULL; /* Onion key, PEM-encoded. */
|
||||
char *identity_pkey = NULL; /* Identity key, PEM-encoded. */
|
||||
char digest[DIGEST_LEN];
|
||||
char digest[DIGEST256_LEN];
|
||||
char published[ISO_TIME_LEN+1];
|
||||
char fingerprint[FINGERPRINT_LEN+1];
|
||||
int has_extra_info_digest;
|
||||
char extra_info_digest[HEX_DIGEST_LEN+1];
|
||||
char *extra_info_line = NULL;
|
||||
size_t onion_pkeylen, identity_pkeylen;
|
||||
char *family_line = NULL;
|
||||
char *extra_or_address = NULL;
|
||||
const or_options_t *options = get_options();
|
||||
smartlist_t *chunks = NULL;
|
||||
char *output = NULL;
|
||||
const int emit_ed_sigs = signing_keypair && router->signing_key_cert;
|
||||
char *ed_cert_line = NULL;
|
||||
char *rsa_tap_cc_line = NULL;
|
||||
char *ntor_cc_line = NULL;
|
||||
|
||||
/* Make sure the identity key matches the one in the routerinfo. */
|
||||
if (!crypto_pk_eq_keys(ident_key, router->identity_pkey)) {
|
||||
@ -2351,6 +2386,16 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
"match router's public key!");
|
||||
goto err;
|
||||
}
|
||||
if (emit_ed_sigs) {
|
||||
if (!router->signing_key_cert->signing_key_included ||
|
||||
!ed25519_pubkey_eq(&router->signing_key_cert->signed_key,
|
||||
&signing_keypair->pubkey)) {
|
||||
log_warn(LD_BUG, "Tried to sign a router descriptor with a mismatched "
|
||||
"ed25519 key chain %d",
|
||||
router->signing_key_cert->signing_key_included);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* record our fingerprint, so we can include it in the descriptor */
|
||||
if (crypto_pk_get_fingerprint(router->identity_pkey, fingerprint, 1)<0) {
|
||||
@ -2358,6 +2403,22 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (emit_ed_sigs) {
|
||||
/* Encode ed25519 signing cert */
|
||||
char ed_cert_base64[256];
|
||||
if (base64_encode(ed_cert_base64, sizeof(ed_cert_base64),
|
||||
(const char*)router->signing_key_cert->encoded,
|
||||
router->signing_key_cert->encoded_len,
|
||||
BASE64_ENCODE_MULTILINE) < 0) {
|
||||
log_err(LD_BUG,"Couldn't base64-encode signing key certificate!");
|
||||
goto err;
|
||||
}
|
||||
tor_asprintf(&ed_cert_line, "identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"%s"
|
||||
"-----END ED25519 CERT-----\n", ed_cert_base64);
|
||||
}
|
||||
|
||||
/* PEM-encode the onion key */
|
||||
if (crypto_pk_write_public_key_to_string(router->onion_pkey,
|
||||
&onion_pkey,&onion_pkeylen)<0) {
|
||||
@ -2372,6 +2433,69 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Cross-certify with RSA key */
|
||||
if (tap_key && router->signing_key_cert &&
|
||||
router->signing_key_cert->signing_key_included) {
|
||||
char buf[256];
|
||||
int tap_cc_len = 0;
|
||||
uint8_t *tap_cc =
|
||||
make_tap_onion_key_crosscert(tap_key,
|
||||
&router->signing_key_cert->signing_key,
|
||||
router->identity_pkey,
|
||||
&tap_cc_len);
|
||||
if (!tap_cc) {
|
||||
log_warn(LD_BUG,"make_tap_onion_key_crosscert failed!");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (base64_encode(buf, sizeof(buf), (const char*)tap_cc, tap_cc_len,
|
||||
BASE64_ENCODE_MULTILINE) < 0) {
|
||||
log_warn(LD_BUG,"base64_encode(rsa_crosscert) failed!");
|
||||
tor_free(tap_cc);
|
||||
goto err;
|
||||
}
|
||||
tor_free(tap_cc);
|
||||
|
||||
tor_asprintf(&rsa_tap_cc_line,
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"%s"
|
||||
"-----END CROSSCERT-----\n", buf);
|
||||
}
|
||||
|
||||
/* Cross-certify with onion keys */
|
||||
if (ntor_keypair && router->signing_key_cert &&
|
||||
router->signing_key_cert->signing_key_included) {
|
||||
int sign = 0;
|
||||
char buf[256];
|
||||
/* XXXX Base the expiration date on the actual onion key expiration time?*/
|
||||
tor_cert_t *cert =
|
||||
make_ntor_onion_key_crosscert(ntor_keypair,
|
||||
&router->signing_key_cert->signing_key,
|
||||
router->cache_info.published_on,
|
||||
MIN_ONION_KEY_LIFETIME, &sign);
|
||||
if (!cert) {
|
||||
log_warn(LD_BUG,"make_ntor_onion_key_crosscert failed!");
|
||||
goto err;
|
||||
}
|
||||
tor_assert(sign == 0 || sign == 1);
|
||||
|
||||
if (base64_encode(buf, sizeof(buf),
|
||||
(const char*)cert->encoded, cert->encoded_len,
|
||||
BASE64_ENCODE_MULTILINE)<0) {
|
||||
log_warn(LD_BUG,"base64_encode(ntor_crosscert) failed!");
|
||||
tor_cert_free(cert);
|
||||
goto err;
|
||||
}
|
||||
tor_cert_free(cert);
|
||||
|
||||
tor_asprintf(&ntor_cc_line,
|
||||
"ntor-onion-key-crosscert %d\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"%s"
|
||||
"-----END ED25519 CERT-----\n", sign, buf);
|
||||
}
|
||||
|
||||
/* Encode the publication time. */
|
||||
format_iso_time(published, router->cache_info.published_on);
|
||||
|
||||
@ -2384,12 +2508,19 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
family_line = tor_strdup("");
|
||||
}
|
||||
|
||||
has_extra_info_digest =
|
||||
! tor_digest_is_zero(router->cache_info.extra_info_digest);
|
||||
|
||||
if (has_extra_info_digest) {
|
||||
if (!tor_digest_is_zero(router->cache_info.extra_info_digest)) {
|
||||
char extra_info_digest[HEX_DIGEST_LEN+1];
|
||||
base16_encode(extra_info_digest, sizeof(extra_info_digest),
|
||||
router->cache_info.extra_info_digest, DIGEST_LEN);
|
||||
if (!tor_digest256_is_zero(router->extra_info_digest256)) {
|
||||
char d256_64[BASE64_DIGEST256_LEN+1];
|
||||
digest256_to_base64(d256_64, router->extra_info_digest256);
|
||||
tor_asprintf(&extra_info_line, "extra-info-digest %s %s\n",
|
||||
extra_info_digest, d256_64);
|
||||
} else {
|
||||
tor_asprintf(&extra_info_line, "extra-info-digest %s\n",
|
||||
extra_info_digest);
|
||||
}
|
||||
}
|
||||
|
||||
if (router->ipv6_orport &&
|
||||
@ -2411,20 +2542,23 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
smartlist_add_asprintf(chunks,
|
||||
"router %s %s %d 0 %d\n"
|
||||
"%s"
|
||||
"%s"
|
||||
"platform %s\n"
|
||||
"protocols Link 1 2 Circuit 1\n"
|
||||
"published %s\n"
|
||||
"fingerprint %s\n"
|
||||
"uptime %ld\n"
|
||||
"bandwidth %d %d %d\n"
|
||||
"%s%s%s%s"
|
||||
"%s%s"
|
||||
"onion-key\n%s"
|
||||
"signing-key\n%s"
|
||||
"%s%s"
|
||||
"%s%s%s%s",
|
||||
router->nickname,
|
||||
address,
|
||||
router->or_port,
|
||||
decide_to_advertise_dirport(options, router->dir_port),
|
||||
ed_cert_line ? ed_cert_line : "",
|
||||
extra_or_address ? extra_or_address : "",
|
||||
router->platform,
|
||||
published,
|
||||
@ -2433,12 +2567,12 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
(int) router->bandwidthrate,
|
||||
(int) router->bandwidthburst,
|
||||
(int) router->bandwidthcapacity,
|
||||
has_extra_info_digest ? "extra-info-digest " : "",
|
||||
has_extra_info_digest ? extra_info_digest : "",
|
||||
has_extra_info_digest ? "\n" : "",
|
||||
extra_info_line ? extra_info_line : "",
|
||||
(options->DownloadExtraInfo || options->V3AuthoritativeDir) ?
|
||||
"caches-extra-info\n" : "",
|
||||
onion_pkey, identity_pkey,
|
||||
rsa_tap_cc_line ? rsa_tap_cc_line : "",
|
||||
ntor_cc_line ? ntor_cc_line : "",
|
||||
family_line,
|
||||
we_are_hibernating() ? "hibernating 1\n" : "",
|
||||
options->HidServDirectoryV2 ? "hidden-service-dir\n" : "",
|
||||
@ -2481,7 +2615,24 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
tor_free(p6);
|
||||
}
|
||||
|
||||
/* Sign the descriptor */
|
||||
/* Sign the descriptor with Ed25519 */
|
||||
if (emit_ed_sigs) {
|
||||
smartlist_add(chunks, tor_strdup("router-sig-ed25519 "));
|
||||
crypto_digest_smartlist_prefix(digest, DIGEST256_LEN,
|
||||
ED_DESC_SIGNATURE_PREFIX,
|
||||
chunks, "", DIGEST_SHA256);
|
||||
ed25519_signature_t sig;
|
||||
char buf[ED25519_SIG_BASE64_LEN+1];
|
||||
if (ed25519_sign(&sig, (const uint8_t*)digest, DIGEST256_LEN,
|
||||
signing_keypair) < 0)
|
||||
goto err;
|
||||
if (ed25519_signature_to_base64(buf, &sig) < 0)
|
||||
goto err;
|
||||
|
||||
smartlist_add_asprintf(chunks, "%s\n", buf);
|
||||
}
|
||||
|
||||
/* Sign the descriptor with RSA */
|
||||
smartlist_add(chunks, tor_strdup("router-signature\n"));
|
||||
|
||||
crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1);
|
||||
@ -2533,6 +2684,10 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
tor_free(onion_pkey);
|
||||
tor_free(identity_pkey);
|
||||
tor_free(extra_or_address);
|
||||
tor_free(ed_cert_line);
|
||||
tor_free(rsa_tap_cc_line);
|
||||
tor_free(ntor_cc_line);
|
||||
tor_free(extra_info_line);
|
||||
|
||||
return output;
|
||||
}
|
||||
@ -2676,7 +2831,8 @@ load_stats_file(const char *filename, const char *end_line, time_t now,
|
||||
* success, negative on failure. */
|
||||
int
|
||||
extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
|
||||
crypto_pk_t *ident_key)
|
||||
crypto_pk_t *ident_key,
|
||||
const ed25519_keypair_t *signing_keypair)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
char identity[HEX_DIGEST_LEN+1];
|
||||
@ -2686,18 +2842,45 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
|
||||
int result;
|
||||
static int write_stats_to_extrainfo = 1;
|
||||
char sig[DIROBJ_MAX_SIG_LEN+1];
|
||||
char *s, *pre, *contents, *cp, *s_dup = NULL;
|
||||
char *s = NULL, *pre, *contents, *cp, *s_dup = NULL;
|
||||
time_t now = time(NULL);
|
||||
smartlist_t *chunks = smartlist_new();
|
||||
extrainfo_t *ei_tmp = NULL;
|
||||
const int emit_ed_sigs = signing_keypair && extrainfo->signing_key_cert;
|
||||
char *ed_cert_line = NULL;
|
||||
|
||||
base16_encode(identity, sizeof(identity),
|
||||
extrainfo->cache_info.identity_digest, DIGEST_LEN);
|
||||
format_iso_time(published, extrainfo->cache_info.published_on);
|
||||
bandwidth_usage = rep_hist_get_bandwidth_lines();
|
||||
if (emit_ed_sigs) {
|
||||
if (!extrainfo->signing_key_cert->signing_key_included ||
|
||||
!ed25519_pubkey_eq(&extrainfo->signing_key_cert->signed_key,
|
||||
&signing_keypair->pubkey)) {
|
||||
log_warn(LD_BUG, "Tried to sign a extrainfo descriptor with a "
|
||||
"mismatched ed25519 key chain %d",
|
||||
extrainfo->signing_key_cert->signing_key_included);
|
||||
goto err;
|
||||
}
|
||||
char ed_cert_base64[256];
|
||||
if (base64_encode(ed_cert_base64, sizeof(ed_cert_base64),
|
||||
(const char*)extrainfo->signing_key_cert->encoded,
|
||||
extrainfo->signing_key_cert->encoded_len,
|
||||
BASE64_ENCODE_MULTILINE) < 0) {
|
||||
log_err(LD_BUG,"Couldn't base64-encode signing key certificate!");
|
||||
goto err;
|
||||
}
|
||||
tor_asprintf(&ed_cert_line, "identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"%s"
|
||||
"-----END ED25519 CERT-----\n", ed_cert_base64);
|
||||
} else {
|
||||
ed_cert_line = tor_strdup("");
|
||||
}
|
||||
|
||||
tor_asprintf(&pre, "extra-info %s %s\npublished %s\n%s",
|
||||
tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n%s",
|
||||
extrainfo->nickname, identity,
|
||||
ed_cert_line,
|
||||
published, bandwidth_usage);
|
||||
tor_free(bandwidth_usage);
|
||||
smartlist_add(chunks, pre);
|
||||
@ -2757,6 +2940,23 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
|
||||
}
|
||||
}
|
||||
|
||||
if (emit_ed_sigs) {
|
||||
char digest[DIGEST256_LEN];
|
||||
smartlist_add(chunks, tor_strdup("router-sig-ed25519 "));
|
||||
crypto_digest_smartlist_prefix(digest, DIGEST256_LEN,
|
||||
ED_DESC_SIGNATURE_PREFIX,
|
||||
chunks, "", DIGEST_SHA256);
|
||||
ed25519_signature_t sig;
|
||||
char buf[ED25519_SIG_BASE64_LEN+1];
|
||||
if (ed25519_sign(&sig, (const uint8_t*)digest, DIGEST256_LEN,
|
||||
signing_keypair) < 0)
|
||||
goto err;
|
||||
if (ed25519_signature_to_base64(buf, &sig) < 0)
|
||||
goto err;
|
||||
|
||||
smartlist_add_asprintf(chunks, "%s\n", buf);
|
||||
}
|
||||
|
||||
smartlist_add(chunks, tor_strdup("router-signature\n"));
|
||||
s = smartlist_join_strings(chunks, "", 0, NULL);
|
||||
|
||||
@ -2805,7 +3005,8 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
|
||||
"adding statistics to this or any future "
|
||||
"extra-info descriptors.");
|
||||
write_stats_to_extrainfo = 0;
|
||||
result = extrainfo_dump_to_string(s_out, extrainfo, ident_key);
|
||||
result = extrainfo_dump_to_string(s_out, extrainfo, ident_key,
|
||||
signing_keypair);
|
||||
goto done;
|
||||
} else {
|
||||
log_warn(LD_BUG, "We just generated an extrainfo descriptor we "
|
||||
@ -2827,6 +3028,7 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
|
||||
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
|
||||
smartlist_free(chunks);
|
||||
tor_free(s_dup);
|
||||
tor_free(ed_cert_line);
|
||||
extrainfo_free(ei_tmp);
|
||||
|
||||
return result;
|
||||
|
@ -92,7 +92,10 @@ int router_pick_published_address(const or_options_t *options, uint32_t *addr);
|
||||
int router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e);
|
||||
int router_rebuild_descriptor(int force);
|
||||
char *router_dump_router_to_string(routerinfo_t *router,
|
||||
crypto_pk_t *ident_key);
|
||||
const crypto_pk_t *ident_key,
|
||||
const crypto_pk_t *tap_key,
|
||||
const curve25519_keypair_t *ntor_keypair,
|
||||
const ed25519_keypair_t *signing_keypair);
|
||||
char *router_dump_exit_policy_to_string(const routerinfo_t *router,
|
||||
int include_ipv4,
|
||||
int include_ipv6);
|
||||
@ -107,7 +110,8 @@ int router_has_addr(const routerinfo_t *router, const tor_addr_t *addr);
|
||||
int router_has_orport(const routerinfo_t *router,
|
||||
const tor_addr_port_t *orport);
|
||||
int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo,
|
||||
crypto_pk_t *ident_key);
|
||||
crypto_pk_t *ident_key,
|
||||
const ed25519_keypair_t *signing_keypair);
|
||||
int is_legal_nickname(const char *s);
|
||||
int is_legal_nickname_or_hexdigest(const char *s);
|
||||
int is_legal_hexdigest(const char *s);
|
||||
|
648
src/or/routerkeys.c
Normal file
648
src/or/routerkeys.c
Normal file
@ -0,0 +1,648 @@
|
||||
/* Copyright (c) 2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "or.h"
|
||||
#include "config.h"
|
||||
#include "router.h"
|
||||
#include "routerkeys.h"
|
||||
#include "torcert.h"
|
||||
|
||||
/**
|
||||
* Read an ed25519 key and associated certificates from files beginning with
|
||||
* <b>fname</b>, with certificate type <b>cert_type</b>. On failure, return
|
||||
* NULL; on success return the keypair.
|
||||
*
|
||||
* If INIT_ED_KEY_CREATE is set in <b>flags</b>, then create the key (and
|
||||
* certificate if requested) if it doesn't exist, and save it to disk.
|
||||
*
|
||||
* If INIT_ED_KEY_NEEDCERT is set in <b>flags</b>, load/create a certificate
|
||||
* too and store it in *<b>cert_out</b>. Fail if the cert can't be
|
||||
* found/created. To create a certificate, <b>signing_key</b> must be set to
|
||||
* the key that should sign it; <b>now</b> to the current time, and
|
||||
* <b>lifetime</b> to the lifetime of the key.
|
||||
*
|
||||
* If INIT_ED_KEY_REPLACE is set in <b>flags</b>, then create and save new key
|
||||
* whether we can read the old one or not.
|
||||
*
|
||||
* If INIT_ED_KEY_EXTRA_STRONG is set in <b>flags</b>, set the extra_strong
|
||||
* flag when creating the secret key.
|
||||
*
|
||||
* If INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT is set in <b>flags</b>, and
|
||||
* we create a new certificate, create it with the signing key embedded.
|
||||
*
|
||||
* If INIT_ED_KEY_SPLIT is set in <b>flags</b>, and we create a new key,
|
||||
* store the public key in a separate file from the secret key.
|
||||
*
|
||||
* If INIT_ED_KEY_MISSING_SECRET_OK is set in <b>flags</b>, and we find a
|
||||
* public key file but no secret key file, return successfully anyway.
|
||||
*
|
||||
* If INIT_ED_KEY_OMIT_SECRET is set in <b>flags</b>, do not even try to
|
||||
* load or return a secret key (but create and save on if needed).
|
||||
*/
|
||||
ed25519_keypair_t *
|
||||
ed_key_init_from_file(const char *fname, uint32_t flags,
|
||||
int severity,
|
||||
const ed25519_keypair_t *signing_key,
|
||||
time_t now,
|
||||
time_t lifetime,
|
||||
uint8_t cert_type,
|
||||
struct tor_cert_st **cert_out)
|
||||
{
|
||||
char *secret_fname = NULL;
|
||||
char *public_fname = NULL;
|
||||
char *cert_fname = NULL;
|
||||
int created_pk = 0, created_sk = 0, created_cert = 0;
|
||||
const int try_to_load = ! (flags & INIT_ED_KEY_REPLACE);
|
||||
|
||||
char tag[8];
|
||||
tor_snprintf(tag, sizeof(tag), "type%d", (int)cert_type);
|
||||
|
||||
tor_cert_t *cert = NULL;
|
||||
char *got_tag = NULL;
|
||||
ed25519_keypair_t *keypair = tor_malloc_zero(sizeof(ed25519_keypair_t));
|
||||
|
||||
tor_asprintf(&secret_fname, "%s_secret_key", fname);
|
||||
tor_asprintf(&public_fname, "%s_public_key", fname);
|
||||
tor_asprintf(&cert_fname, "%s_cert", fname);
|
||||
|
||||
/* Try to read the secret key. */
|
||||
const int have_secret = try_to_load &&
|
||||
!(flags & INIT_ED_KEY_OMIT_SECRET) &&
|
||||
ed25519_seckey_read_from_file(&keypair->seckey,
|
||||
&got_tag, secret_fname) == 0;
|
||||
|
||||
if (have_secret) {
|
||||
if (strcmp(got_tag, tag)) {
|
||||
tor_log(severity, LD_OR, "%s has wrong tag", secret_fname);
|
||||
goto err;
|
||||
}
|
||||
/* Derive the public key */
|
||||
if (ed25519_public_key_generate(&keypair->pubkey, &keypair->seckey)<0) {
|
||||
tor_log(severity, LD_OR, "%s can't produce a public key", secret_fname);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's absent and that's okay, try to read the pubkey. */
|
||||
int found_public = 0;
|
||||
if (!have_secret && try_to_load) {
|
||||
tor_free(got_tag);
|
||||
found_public = ed25519_pubkey_read_from_file(&keypair->pubkey,
|
||||
&got_tag, public_fname) == 0;
|
||||
if (found_public && strcmp(got_tag, tag)) {
|
||||
tor_log(severity, LD_OR, "%s has wrong tag", public_fname);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the secret key is absent and it's not allowed to be, fail. */
|
||||
if (!have_secret && found_public && !(flags & INIT_ED_KEY_MISSING_SECRET_OK))
|
||||
goto err;
|
||||
|
||||
/* If it's absent, and we're not supposed to make a new keypair, fail. */
|
||||
if (!have_secret && !found_public && !(flags & INIT_ED_KEY_CREATE))
|
||||
goto err;
|
||||
|
||||
/* if it's absent, make a new keypair and save it. */
|
||||
if (!have_secret && !found_public) {
|
||||
const int split = !! (flags & INIT_ED_KEY_SPLIT);
|
||||
tor_free(keypair);
|
||||
keypair = ed_key_new(signing_key, flags, now, lifetime,
|
||||
cert_type, &cert);
|
||||
if (!keypair) {
|
||||
tor_log(severity, LD_OR, "Couldn't create keypair");
|
||||
goto err;
|
||||
}
|
||||
|
||||
created_pk = created_sk = created_cert = 1;
|
||||
if (ed25519_seckey_write_to_file(&keypair->seckey, secret_fname, tag) < 0
|
||||
||
|
||||
(split &&
|
||||
ed25519_pubkey_write_to_file(&keypair->pubkey, public_fname, tag) < 0)
|
||||
||
|
||||
(cert &&
|
||||
crypto_write_tagged_contents_to_file(cert_fname, "ed25519v1-cert",
|
||||
tag, cert->encoded, cert->encoded_len) < 0)) {
|
||||
tor_log(severity, LD_OR, "Couldn't write keys or cert to file.");
|
||||
goto err;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* If we're not supposed to get a cert, we're done. */
|
||||
if (! (flags & INIT_ED_KEY_NEEDCERT))
|
||||
goto done;
|
||||
|
||||
/* Read a cert. */
|
||||
uint8_t certbuf[256];
|
||||
ssize_t cert_body_len = crypto_read_tagged_contents_from_file(
|
||||
cert_fname, "ed25519v1-cert",
|
||||
&got_tag, certbuf, sizeof(certbuf));
|
||||
if (cert_body_len >= 0 && !strcmp(got_tag, tag))
|
||||
cert = tor_cert_parse(certbuf, cert_body_len);
|
||||
|
||||
/* If we got it, check it to the extent we can. */
|
||||
if (cert) {
|
||||
int bad_cert = 0;
|
||||
|
||||
if (! cert) {
|
||||
tor_log(severity, LD_OR, "Cert was unparseable");
|
||||
bad_cert = 1;
|
||||
} else if (!tor_memeq(cert->signed_key.pubkey, keypair->pubkey.pubkey,
|
||||
ED25519_PUBKEY_LEN)) {
|
||||
tor_log(severity, LD_OR, "Cert was for wrong key");
|
||||
bad_cert = 1;
|
||||
} else if (tor_cert_checksig(cert, &signing_key->pubkey, now) < 0 &&
|
||||
(signing_key || cert->cert_expired)) {
|
||||
tor_log(severity, LD_OR, "Can't check certificate");
|
||||
bad_cert = 1;
|
||||
}
|
||||
|
||||
if (bad_cert) {
|
||||
tor_cert_free(cert);
|
||||
cert = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we got a cert, we're done. */
|
||||
if (cert)
|
||||
goto done;
|
||||
|
||||
/* If we didn't get a cert, and we're not supposed to make one, fail. */
|
||||
if (!signing_key || !(flags & INIT_ED_KEY_CREATE))
|
||||
goto err;
|
||||
|
||||
/* We have keys but not a certificate, so make one. */
|
||||
uint32_t cert_flags = 0;
|
||||
if (flags & INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT)
|
||||
cert_flags |= CERT_FLAG_INCLUDE_SIGNING_KEY;
|
||||
cert = tor_cert_create(signing_key, cert_type,
|
||||
&keypair->pubkey,
|
||||
now, lifetime,
|
||||
cert_flags);
|
||||
|
||||
if (! cert)
|
||||
goto err;
|
||||
|
||||
/* Write it to disk. */
|
||||
created_cert = 1;
|
||||
if (crypto_write_tagged_contents_to_file(cert_fname, "ed25519v1-cert",
|
||||
tag, cert->encoded, cert->encoded_len) < 0) {
|
||||
tor_log(severity, LD_OR, "Couldn't write cert to disk.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
done:
|
||||
if (cert_out)
|
||||
*cert_out = cert;
|
||||
else
|
||||
tor_cert_free(cert);
|
||||
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
memwipe(keypair, 0, sizeof(*keypair));
|
||||
tor_free(keypair);
|
||||
tor_cert_free(cert);
|
||||
if (cert_out)
|
||||
*cert_out = NULL;
|
||||
if (created_sk)
|
||||
unlink(secret_fname);
|
||||
if (created_pk)
|
||||
unlink(public_fname);
|
||||
if (created_cert)
|
||||
unlink(cert_fname);
|
||||
|
||||
cleanup:
|
||||
tor_free(secret_fname);
|
||||
tor_free(public_fname);
|
||||
tor_free(cert_fname);
|
||||
|
||||
return keypair;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new signing key and (optionally) certficiate; do not read or write
|
||||
* from disk. See ed_key_init_from_file() for more information.
|
||||
*/
|
||||
ed25519_keypair_t *
|
||||
ed_key_new(const ed25519_keypair_t *signing_key,
|
||||
uint32_t flags,
|
||||
time_t now,
|
||||
time_t lifetime,
|
||||
uint8_t cert_type,
|
||||
struct tor_cert_st **cert_out)
|
||||
{
|
||||
if (cert_out)
|
||||
*cert_out = NULL;
|
||||
|
||||
const int extra_strong = !! (flags & INIT_ED_KEY_EXTRA_STRONG);
|
||||
ed25519_keypair_t *keypair = tor_malloc_zero(sizeof(ed25519_keypair_t));
|
||||
if (ed25519_keypair_generate(keypair, extra_strong) < 0)
|
||||
goto err;
|
||||
|
||||
if (! (flags & INIT_ED_KEY_NEEDCERT))
|
||||
return keypair;
|
||||
|
||||
tor_assert(signing_key);
|
||||
tor_assert(cert_out);
|
||||
uint32_t cert_flags = 0;
|
||||
if (flags & INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT)
|
||||
cert_flags |= CERT_FLAG_INCLUDE_SIGNING_KEY;
|
||||
tor_cert_t *cert = tor_cert_create(signing_key, cert_type,
|
||||
&keypair->pubkey,
|
||||
now, lifetime,
|
||||
cert_flags);
|
||||
if (! cert)
|
||||
goto err;
|
||||
|
||||
*cert_out = cert;
|
||||
return keypair;
|
||||
|
||||
err:
|
||||
tor_free(keypair);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ed25519_keypair_t *master_identity_key = NULL;
|
||||
static ed25519_keypair_t *master_signing_key = NULL;
|
||||
static ed25519_keypair_t *current_auth_key = NULL;
|
||||
static tor_cert_t *signing_key_cert = NULL;
|
||||
static tor_cert_t *link_cert_cert = NULL;
|
||||
static tor_cert_t *auth_key_cert = NULL;
|
||||
|
||||
static uint8_t *rsa_ed_crosscert = NULL;
|
||||
static size_t rsa_ed_crosscert_len = 0;
|
||||
|
||||
/**
|
||||
* Running as a server: load, reload, or refresh our ed25519 keys and
|
||||
* certificates, creating and saving new ones as needed.
|
||||
*/
|
||||
int
|
||||
load_ed_keys(const or_options_t *options, time_t now)
|
||||
{
|
||||
ed25519_keypair_t *id = NULL;
|
||||
ed25519_keypair_t *sign = NULL;
|
||||
ed25519_keypair_t *auth = NULL;
|
||||
const ed25519_keypair_t *sign_signing_key_with_id = NULL;
|
||||
const ed25519_keypair_t *use_signing = NULL;
|
||||
const tor_cert_t *check_signing_cert = NULL;
|
||||
tor_cert_t *sign_cert = NULL;
|
||||
tor_cert_t *auth_cert = NULL;
|
||||
|
||||
#define FAIL(msg) do { \
|
||||
log_warn(LD_OR, (msg)); \
|
||||
goto err; \
|
||||
} while (0)
|
||||
#define SET_KEY(key, newval) do { \
|
||||
ed25519_keypair_free(key); \
|
||||
key = (newval); \
|
||||
} while (0)
|
||||
#define SET_CERT(cert, newval) do { \
|
||||
tor_cert_free(cert); \
|
||||
cert = (newval); \
|
||||
} while (0)
|
||||
#define EXPIRES_SOON(cert, interval) \
|
||||
(!(cert) || (cert)->valid_until < now + (interval))
|
||||
|
||||
/* XXXX support encrypted identity keys fully */
|
||||
|
||||
/* First try to get the signing key to see how it is. */
|
||||
if (master_signing_key) {
|
||||
check_signing_cert = signing_key_cert;
|
||||
use_signing = master_signing_key;
|
||||
} else {
|
||||
sign = ed_key_init_from_file(
|
||||
options_get_datadir_fname2(options, "keys", "ed25519_signing"),
|
||||
INIT_ED_KEY_NEEDCERT|
|
||||
INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT,
|
||||
LOG_INFO,
|
||||
NULL, 0, 0, CERT_TYPE_ID_SIGNING, &sign_cert);
|
||||
check_signing_cert = sign_cert;
|
||||
use_signing = sign;
|
||||
}
|
||||
|
||||
const int need_new_signing_key =
|
||||
NULL == use_signing ||
|
||||
EXPIRES_SOON(check_signing_cert, 0);
|
||||
const int want_new_signing_key =
|
||||
need_new_signing_key ||
|
||||
EXPIRES_SOON(check_signing_cert, options->TestingSigningKeySlop);
|
||||
|
||||
{
|
||||
uint32_t flags =
|
||||
(INIT_ED_KEY_CREATE|INIT_ED_KEY_SPLIT|
|
||||
INIT_ED_KEY_EXTRA_STRONG);
|
||||
if (! need_new_signing_key)
|
||||
flags |= INIT_ED_KEY_MISSING_SECRET_OK;
|
||||
if (! want_new_signing_key)
|
||||
flags |= INIT_ED_KEY_OMIT_SECRET;
|
||||
|
||||
id = ed_key_init_from_file(
|
||||
options_get_datadir_fname2(options, "keys", "ed25519_master_id"),
|
||||
flags,
|
||||
LOG_WARN, NULL, 0, 0, 0, NULL);
|
||||
if (!id)
|
||||
FAIL("Missing identity key");
|
||||
if (tor_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey)))
|
||||
sign_signing_key_with_id = NULL;
|
||||
else
|
||||
sign_signing_key_with_id = id;
|
||||
}
|
||||
|
||||
if (need_new_signing_key && NULL == sign_signing_key_with_id)
|
||||
FAIL("Can't load master key make a new signing key.");
|
||||
|
||||
if (want_new_signing_key && sign_signing_key_with_id) {
|
||||
uint32_t flags = (INIT_ED_KEY_CREATE|
|
||||
INIT_ED_KEY_REPLACE|
|
||||
INIT_ED_KEY_EXTRA_STRONG|
|
||||
INIT_ED_KEY_NEEDCERT|
|
||||
INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT);
|
||||
sign = ed_key_init_from_file(
|
||||
options_get_datadir_fname2(options, "keys", "ed25519_signing"),
|
||||
flags, LOG_WARN,
|
||||
sign_signing_key_with_id, now,
|
||||
options->SigningKeyLifetime,
|
||||
CERT_TYPE_ID_SIGNING, &sign_cert);
|
||||
if (!sign)
|
||||
FAIL("Missing signing key");
|
||||
use_signing = sign;
|
||||
} else if (want_new_signing_key) {
|
||||
static ratelim_t missing_master = RATELIM_INIT(3600);
|
||||
log_fn_ratelim(&missing_master, LOG_WARN, LD_OR,
|
||||
"Signing key will expire soon, but I can't load the "
|
||||
"master key to sign a new one!");
|
||||
}
|
||||
|
||||
tor_assert(use_signing);
|
||||
|
||||
/* At this point we no longer need our secret identity key. So wipe
|
||||
* it, if we loaded it in the first place. */
|
||||
memwipe(id->seckey.seckey, 0, sizeof(id->seckey));
|
||||
|
||||
if (!rsa_ed_crosscert && server_mode(options)) {
|
||||
uint8_t *crosscert;
|
||||
ssize_t crosscert_len = tor_make_rsa_ed25519_crosscert(&id->pubkey,
|
||||
get_server_identity_key(),
|
||||
now+10*365*86400,/*XXXX*/
|
||||
&crosscert);
|
||||
rsa_ed_crosscert_len = crosscert_len;
|
||||
rsa_ed_crosscert = crosscert;
|
||||
}
|
||||
|
||||
if (!current_auth_key ||
|
||||
EXPIRES_SOON(auth_key_cert, options->TestingAuthKeySlop)) {
|
||||
auth = ed_key_new(use_signing, INIT_ED_KEY_NEEDCERT,
|
||||
now,
|
||||
options->TestingAuthKeyLifetime,
|
||||
CERT_TYPE_SIGNING_AUTH, &auth_cert);
|
||||
|
||||
if (!auth)
|
||||
FAIL("Can't create auth key");
|
||||
}
|
||||
|
||||
/* We've generated or loaded everything. Put them in memory. */
|
||||
|
||||
if (! master_identity_key) {
|
||||
SET_KEY(master_identity_key, id);
|
||||
} else {
|
||||
tor_free(id);
|
||||
}
|
||||
if (sign) {
|
||||
SET_KEY(master_signing_key, sign);
|
||||
SET_CERT(signing_key_cert, sign_cert);
|
||||
}
|
||||
if (auth) {
|
||||
SET_KEY(current_auth_key, auth);
|
||||
SET_CERT(auth_key_cert, auth_cert);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
ed25519_keypair_free(id);
|
||||
ed25519_keypair_free(sign);
|
||||
ed25519_keypair_free(auth);
|
||||
tor_cert_free(sign_cert);
|
||||
tor_cert_free(auth_cert);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**DOCDOC*/
|
||||
int
|
||||
generate_ed_link_cert(const or_options_t *options, time_t now)
|
||||
{
|
||||
const tor_x509_cert_t *link = NULL, *id = NULL;
|
||||
tor_cert_t *link_cert = NULL;
|
||||
|
||||
if (tor_tls_get_my_certs(1, &link, &id) < 0 || link == NULL) {
|
||||
log_warn(LD_OR, "Can't get my x509 link cert.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const digests_t *digests = tor_x509_cert_get_cert_digests(link);
|
||||
|
||||
if (link_cert_cert &&
|
||||
! EXPIRES_SOON(link_cert_cert, options->TestingLinkKeySlop) &&
|
||||
fast_memeq(digests->d[DIGEST_SHA256], link_cert_cert->signed_key.pubkey,
|
||||
DIGEST256_LEN)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ed25519_public_key_t dummy_key;
|
||||
memcpy(dummy_key.pubkey, digests->d[DIGEST_SHA256], DIGEST256_LEN);
|
||||
|
||||
link_cert = tor_cert_create(get_master_signing_keypair(),
|
||||
CERT_TYPE_SIGNING_LINK,
|
||||
&dummy_key,
|
||||
now,
|
||||
options->TestingLinkCertLifetime, 0);
|
||||
|
||||
if (link_cert) {
|
||||
SET_CERT(link_cert_cert, link_cert);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef FAIL
|
||||
#undef SET_KEY
|
||||
#undef SET_CERT
|
||||
|
||||
int
|
||||
should_make_new_ed_keys(const or_options_t *options, const time_t now)
|
||||
{
|
||||
if (!master_identity_key ||
|
||||
!master_signing_key ||
|
||||
!current_auth_key ||
|
||||
!link_cert_cert ||
|
||||
EXPIRES_SOON(signing_key_cert, options->TestingSigningKeySlop) ||
|
||||
EXPIRES_SOON(auth_key_cert, options->TestingAuthKeySlop) ||
|
||||
EXPIRES_SOON(link_cert_cert, options->TestingLinkKeySlop))
|
||||
return 1;
|
||||
|
||||
const tor_x509_cert_t *link = NULL, *id = NULL;
|
||||
|
||||
if (tor_tls_get_my_certs(1, &link, &id) < 0 || link == NULL)
|
||||
return 1;
|
||||
|
||||
const digests_t *digests = tor_x509_cert_get_cert_digests(link);
|
||||
|
||||
if (!fast_memeq(digests->d[DIGEST_SHA256],
|
||||
link_cert_cert->signed_key.pubkey,
|
||||
DIGEST256_LEN)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef EXPIRES_SOON
|
||||
|
||||
const ed25519_public_key_t *
|
||||
get_master_identity_key(void)
|
||||
{
|
||||
if (!master_identity_key)
|
||||
return NULL;
|
||||
return &master_identity_key->pubkey;
|
||||
}
|
||||
|
||||
const ed25519_keypair_t *
|
||||
get_master_signing_keypair(void)
|
||||
{
|
||||
return master_signing_key;
|
||||
}
|
||||
|
||||
const struct tor_cert_st *
|
||||
get_master_signing_key_cert(void)
|
||||
{
|
||||
return signing_key_cert;
|
||||
}
|
||||
|
||||
const ed25519_keypair_t *
|
||||
get_current_auth_keypair(void)
|
||||
{
|
||||
return current_auth_key;
|
||||
}
|
||||
|
||||
const tor_cert_t *
|
||||
get_current_link_cert_cert(void)
|
||||
{
|
||||
return link_cert_cert;
|
||||
}
|
||||
|
||||
const tor_cert_t *
|
||||
get_current_auth_key_cert(void)
|
||||
{
|
||||
return auth_key_cert;
|
||||
}
|
||||
|
||||
void
|
||||
get_master_rsa_crosscert(const uint8_t **cert_out,
|
||||
size_t *size_out)
|
||||
{
|
||||
*cert_out = rsa_ed_crosscert;
|
||||
*size_out = rsa_ed_crosscert_len;
|
||||
}
|
||||
|
||||
/** Construct cross-certification for the master identity key with
|
||||
* the ntor onion key. Store the sign of the corresponding ed25519 public key
|
||||
* in *<b>sign_out</b>. */
|
||||
tor_cert_t *
|
||||
make_ntor_onion_key_crosscert(const curve25519_keypair_t *onion_key,
|
||||
const ed25519_public_key_t *master_id_key, time_t now, time_t lifetime,
|
||||
int *sign_out)
|
||||
{
|
||||
tor_cert_t *cert = NULL;
|
||||
ed25519_keypair_t ed_onion_key;
|
||||
|
||||
if (ed25519_keypair_from_curve25519_keypair(&ed_onion_key, sign_out,
|
||||
onion_key) < 0)
|
||||
goto end;
|
||||
|
||||
cert = tor_cert_create(&ed_onion_key, CERT_TYPE_ONION_ID, master_id_key,
|
||||
now, lifetime, 0);
|
||||
|
||||
end:
|
||||
memwipe(&ed_onion_key, 0, sizeof(ed_onion_key));
|
||||
return cert;
|
||||
}
|
||||
|
||||
/** Construct and return an RSA signature for the TAP onion key to
|
||||
* cross-certify the RSA and Ed25519 identity keys. Set <b>len_out</b> to its
|
||||
* length. */
|
||||
uint8_t *
|
||||
make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
|
||||
const ed25519_public_key_t *master_id_key,
|
||||
const crypto_pk_t *rsa_id_key,
|
||||
int *len_out)
|
||||
{
|
||||
uint8_t signature[PK_BYTES];
|
||||
uint8_t signed_data[DIGEST_LEN + ED25519_PUBKEY_LEN];
|
||||
|
||||
*len_out = 0;
|
||||
crypto_pk_get_digest(rsa_id_key, (char*)signed_data);
|
||||
memcpy(signed_data + DIGEST_LEN, master_id_key->pubkey, ED25519_PUBKEY_LEN);
|
||||
|
||||
int r = crypto_pk_private_sign(onion_key,
|
||||
(char*)signature, sizeof(signature),
|
||||
(const char*)signed_data, sizeof(signed_data));
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
*len_out = r;
|
||||
|
||||
return tor_memdup(signature, r);
|
||||
}
|
||||
|
||||
/** Check whether an RSA-TAP cross-certification is correct. Return 0 if it
|
||||
* is, -1 if it isn't. */
|
||||
int
|
||||
check_tap_onion_key_crosscert(const uint8_t *crosscert,
|
||||
int crosscert_len,
|
||||
const crypto_pk_t *onion_pkey,
|
||||
const ed25519_public_key_t *master_id_pkey,
|
||||
const uint8_t *rsa_id_digest)
|
||||
{
|
||||
uint8_t *cc = tor_malloc(crypto_pk_keysize(onion_pkey));
|
||||
int cc_len =
|
||||
crypto_pk_public_checksig(onion_pkey,
|
||||
(char*)cc,
|
||||
crypto_pk_keysize(onion_pkey),
|
||||
(const char*)crosscert,
|
||||
crosscert_len);
|
||||
if (cc_len < 0) {
|
||||
goto err;
|
||||
}
|
||||
if (cc_len < DIGEST_LEN + ED25519_PUBKEY_LEN) {
|
||||
log_warn(LD_DIR, "Short signature on cross-certification with TAP key");
|
||||
goto err;
|
||||
}
|
||||
if (tor_memneq(cc, rsa_id_digest, DIGEST_LEN) ||
|
||||
tor_memneq(cc + DIGEST_LEN, master_id_pkey->pubkey,
|
||||
ED25519_PUBKEY_LEN)) {
|
||||
log_warn(LD_DIR, "Incorrect cross-certification with TAP key");
|
||||
goto err;
|
||||
}
|
||||
|
||||
tor_free(cc);
|
||||
return 0;
|
||||
err:
|
||||
tor_free(cc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
routerkeys_free_all(void)
|
||||
{
|
||||
ed25519_keypair_free(master_identity_key);
|
||||
ed25519_keypair_free(master_signing_key);
|
||||
ed25519_keypair_free(current_auth_key);
|
||||
tor_cert_free(signing_key_cert);
|
||||
tor_cert_free(link_cert_cert);
|
||||
tor_cert_free(auth_key_cert);
|
||||
|
||||
master_identity_key = master_signing_key = NULL;
|
||||
current_auth_key = NULL;
|
||||
signing_key_cert = link_cert_cert = auth_key_cert = NULL;
|
||||
}
|
||||
|
67
src/or/routerkeys.h
Normal file
67
src/or/routerkeys.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* Copyright (c) 2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_ROUTERKEYS_H
|
||||
#define TOR_ROUTERKEYS_H
|
||||
|
||||
#include "crypto_ed25519.h"
|
||||
|
||||
#define INIT_ED_KEY_CREATE (1u<<0)
|
||||
#define INIT_ED_KEY_REPLACE (1u<<1)
|
||||
#define INIT_ED_KEY_SPLIT (1u<<2)
|
||||
#define INIT_ED_KEY_MISSING_SECRET_OK (1u<<3)
|
||||
#define INIT_ED_KEY_NEEDCERT (1u<<4)
|
||||
#define INIT_ED_KEY_EXTRA_STRONG (1u<<5)
|
||||
#define INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT (1u<<6)
|
||||
#define INIT_ED_KEY_OMIT_SECRET (1u<<7)
|
||||
|
||||
struct tor_cert_st;
|
||||
ed25519_keypair_t *ed_key_init_from_file(const char *fname, uint32_t flags,
|
||||
int severity,
|
||||
const ed25519_keypair_t *signing_key,
|
||||
time_t now,
|
||||
time_t lifetime,
|
||||
uint8_t cert_type,
|
||||
struct tor_cert_st **cert_out);
|
||||
ed25519_keypair_t *ed_key_new(const ed25519_keypair_t *signing_key,
|
||||
uint32_t flags,
|
||||
time_t now,
|
||||
time_t lifetime,
|
||||
uint8_t cert_type,
|
||||
struct tor_cert_st **cert_out);
|
||||
const ed25519_public_key_t *get_master_identity_key(void);
|
||||
const ed25519_keypair_t *get_master_signing_keypair(void);
|
||||
const struct tor_cert_st *get_master_signing_key_cert(void);
|
||||
|
||||
const ed25519_keypair_t *get_current_auth_keypair(void);
|
||||
const struct tor_cert_st *get_current_link_cert_cert(void);
|
||||
const struct tor_cert_st *get_current_auth_key_cert(void);
|
||||
|
||||
void get_master_rsa_crosscert(const uint8_t **cert_out,
|
||||
size_t *size_out);
|
||||
|
||||
struct tor_cert_st *make_ntor_onion_key_crosscert(
|
||||
const curve25519_keypair_t *onion_key,
|
||||
const ed25519_public_key_t *master_id_key,
|
||||
time_t now, time_t lifetime,
|
||||
int *sign_out);
|
||||
uint8_t *make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
|
||||
const ed25519_public_key_t *master_id_key,
|
||||
const crypto_pk_t *rsa_id_key,
|
||||
int *len_out);
|
||||
|
||||
int check_tap_onion_key_crosscert(const uint8_t *crosscert,
|
||||
int crosscert_len,
|
||||
const crypto_pk_t *onion_pkey,
|
||||
const ed25519_public_key_t *master_id_pkey,
|
||||
const uint8_t *rsa_id_digest);
|
||||
|
||||
int load_ed_keys(const or_options_t *options, time_t now);
|
||||
int should_make_new_ed_keys(const or_options_t *options, const time_t now);
|
||||
|
||||
int generate_ed_link_cert(const or_options_t *options, time_t now);
|
||||
|
||||
void routerkeys_free_all(void);
|
||||
|
||||
#endif
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#define ROUTERLIST_PRIVATE
|
||||
#include "or.h"
|
||||
#include "crypto_ed25519.h"
|
||||
#include "circuitstats.h"
|
||||
#include "config.h"
|
||||
#include "connection.h"
|
||||
@ -38,6 +39,8 @@
|
||||
#include "routerparse.h"
|
||||
#include "routerset.h"
|
||||
#include "sandbox.h"
|
||||
#include "torcert.h"
|
||||
|
||||
// #define DEBUG_ROUTERLIST
|
||||
|
||||
/****************************************************************************/
|
||||
@ -2660,6 +2663,7 @@ routerinfo_free(routerinfo_t *router)
|
||||
tor_free(router->onion_curve25519_pkey);
|
||||
if (router->identity_pkey)
|
||||
crypto_pk_free(router->identity_pkey);
|
||||
tor_cert_free(router->signing_key_cert);
|
||||
if (router->declared_family) {
|
||||
SMARTLIST_FOREACH(router->declared_family, char *, s, tor_free(s));
|
||||
smartlist_free(router->declared_family);
|
||||
@ -2678,6 +2682,7 @@ extrainfo_free(extrainfo_t *extrainfo)
|
||||
{
|
||||
if (!extrainfo)
|
||||
return;
|
||||
tor_cert_free(extrainfo->signing_key_cert);
|
||||
tor_free(extrainfo->cache_info.signed_descriptor_body);
|
||||
tor_free(extrainfo->pending_sig);
|
||||
|
||||
@ -3288,6 +3293,11 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
|
||||
|
||||
old_router = router_get_mutable_by_digest(id_digest);
|
||||
|
||||
/* Make sure that it isn't expired. */
|
||||
if (router->cert_expiration_time < approx_time()) {
|
||||
return ROUTER_CERTS_EXPIRED;
|
||||
}
|
||||
|
||||
/* Make sure that we haven't already got this exact descriptor. */
|
||||
if (sdmap_get(routerlist->desc_digest_map,
|
||||
router->cache_info.signed_descriptor_digest)) {
|
||||
@ -4894,7 +4904,7 @@ routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri,
|
||||
signed_descriptor_t *sd,
|
||||
const char **msg)
|
||||
{
|
||||
int digest_matches, r=1;
|
||||
int digest_matches, digest256_matches, r=1;
|
||||
tor_assert(ri);
|
||||
tor_assert(ei);
|
||||
if (!sd)
|
||||
@ -4907,6 +4917,11 @@ routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri,
|
||||
|
||||
digest_matches = tor_memeq(ei->cache_info.signed_descriptor_digest,
|
||||
sd->extra_info_digest, DIGEST_LEN);
|
||||
/* Set digest256_matches to 1 if the digest is correct, or if no
|
||||
* digest256 was in the ri. */
|
||||
digest256_matches = tor_memeq(ei->digest256,
|
||||
ri->extra_info_digest256, DIGEST256_LEN);
|
||||
digest256_matches |= tor_mem_is_zero(ri->extra_info_digest256, DIGEST256_LEN);
|
||||
|
||||
/* The identity must match exactly to have been generated at the same time
|
||||
* by the same router. */
|
||||
@ -4917,6 +4932,11 @@ routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri,
|
||||
goto err; /* different servers */
|
||||
}
|
||||
|
||||
if (! tor_cert_opt_eq(ri->signing_key_cert, ei->signing_key_cert)) {
|
||||
if (msg) *msg = "Extrainfo signing key cert didn't match routerinfo";
|
||||
goto err; /* different servers */
|
||||
}
|
||||
|
||||
if (ei->pending_sig) {
|
||||
char signed_digest[128];
|
||||
if (crypto_pk_public_checksig(ri->identity_pkey,
|
||||
@ -4943,6 +4963,11 @@ routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!digest256_matches) {
|
||||
if (msg) *msg = "Extrainfo digest did not match digest256 from routerdesc";
|
||||
goto err; /* Digest doesn't match declared value. */
|
||||
}
|
||||
|
||||
if (!digest_matches) {
|
||||
if (msg) *msg = "Extrainfo digest did not match value from routerdesc";
|
||||
goto err; /* Digest doesn't match declared value. */
|
||||
|
@ -118,13 +118,15 @@ WRA_WAS_ADDED(was_router_added_t s) {
|
||||
* - not in the consensus
|
||||
* - neither in the consensus nor in any networkstatus document
|
||||
* - it was outdated.
|
||||
* - its certificates were expired.
|
||||
*/
|
||||
static INLINE int WRA_WAS_OUTDATED(was_router_added_t s)
|
||||
{
|
||||
return (s == ROUTER_WAS_TOO_OLD ||
|
||||
s == ROUTER_IS_ALREADY_KNOWN ||
|
||||
s == ROUTER_NOT_IN_CONSENSUS ||
|
||||
s == ROUTER_NOT_IN_CONSENSUS_OR_NETWORKSTATUS);
|
||||
s == ROUTER_NOT_IN_CONSENSUS_OR_NETWORKSTATUS ||
|
||||
s == ROUTER_CERTS_EXPIRED);
|
||||
}
|
||||
/** Return true iff the outcome code in <b>s</b> indicates that the descriptor
|
||||
* was flat-out rejected. */
|
||||
@ -138,7 +140,8 @@ static INLINE int WRA_NEVER_DOWNLOADABLE(was_router_added_t s)
|
||||
{
|
||||
return (s == ROUTER_AUTHDIR_REJECTS ||
|
||||
s == ROUTER_BAD_EI ||
|
||||
s == ROUTER_WAS_TOO_OLD);
|
||||
s == ROUTER_WAS_TOO_OLD ||
|
||||
s == ROUTER_CERTS_EXPIRED);
|
||||
}
|
||||
was_router_added_t router_add_to_routerlist(routerinfo_t *router,
|
||||
const char **msg,
|
||||
|
@ -24,8 +24,11 @@
|
||||
#include "microdesc.h"
|
||||
#include "networkstatus.h"
|
||||
#include "rephist.h"
|
||||
#include "routerkeys.h"
|
||||
#include "routerparse.h"
|
||||
#include "entrynodes.h"
|
||||
#include "torcert.h"
|
||||
|
||||
#undef log
|
||||
#include <math.h>
|
||||
|
||||
@ -69,6 +72,7 @@ typedef enum {
|
||||
K_CLIENT_VERSIONS,
|
||||
K_SERVER_VERSIONS,
|
||||
K_OR_ADDRESS,
|
||||
K_ID,
|
||||
K_P,
|
||||
K_P6,
|
||||
K_R,
|
||||
@ -83,6 +87,10 @@ typedef enum {
|
||||
K_HIDDEN_SERVICE_DIR,
|
||||
K_ALLOW_SINGLE_HOP_EXITS,
|
||||
K_IPV6_POLICY,
|
||||
K_ROUTER_SIG_ED25519,
|
||||
K_IDENTITY_ED25519,
|
||||
K_ONION_KEY_CROSSCERT,
|
||||
K_NTOR_ONION_KEY_CROSSCERT,
|
||||
|
||||
K_DIRREQ_END,
|
||||
K_DIRREQ_V2_IPS,
|
||||
@ -293,6 +301,12 @@ static token_rule_t routerdesc_token_table[] = {
|
||||
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("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,
|
||||
EQ(1), NEED_OBJ ),
|
||||
|
||||
T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS, NO_ARGS, NO_OBJ ),
|
||||
|
||||
T01("family", K_FAMILY, ARGS, NO_OBJ ),
|
||||
@ -310,6 +324,8 @@ static 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 ),
|
||||
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 ),
|
||||
@ -353,6 +369,7 @@ static token_rule_t rtrstatus_token_table[] = {
|
||||
T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
|
||||
T01("w", K_W, ARGS, NO_OBJ ),
|
||||
T0N("m", K_M, CONCAT_ARGS, NO_OBJ ),
|
||||
T0N("id", K_ID, GE(2), NO_OBJ ),
|
||||
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
|
||||
END_OF_TABLE
|
||||
};
|
||||
@ -490,6 +507,7 @@ static token_rule_t networkstatus_detached_signature_token_table[] = {
|
||||
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 ),
|
||||
T0N("id", K_ID, GE(2), NO_OBJ ),
|
||||
T0N("a", K_A, GE(1), NO_OBJ ),
|
||||
T01("family", K_FAMILY, ARGS, NO_OBJ ),
|
||||
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
|
||||
@ -506,6 +524,10 @@ static addr_policy_t *router_parse_addr_policy(directory_token_t *tok,
|
||||
unsigned fmt_flags);
|
||||
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
|
||||
|
||||
static int router_get_hash_impl_helper(const char *s, size_t s_len,
|
||||
const char *start_str,
|
||||
const char *end_str, char end_c,
|
||||
const char **start_out, const char **end_out);
|
||||
static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
|
||||
const char *start_str, const char *end_str,
|
||||
char end_char,
|
||||
@ -637,7 +659,7 @@ router_get_extrainfo_hash(const char *s, size_t s_len, char *digest)
|
||||
char *
|
||||
router_get_dirobj_signature(const char *digest,
|
||||
size_t digest_len,
|
||||
crypto_pk_t *private_key)
|
||||
const crypto_pk_t *private_key)
|
||||
{
|
||||
char *signature;
|
||||
size_t i, keysize;
|
||||
@ -858,8 +880,8 @@ check_signature_token(const char *digest,
|
||||
tor_free(signed_digest);
|
||||
return -1;
|
||||
}
|
||||
// log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
|
||||
// hex_str(signed_digest,4));
|
||||
// log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
|
||||
// hex_str(signed_digest,4));
|
||||
if (tor_memneq(digest, signed_digest, digest_len)) {
|
||||
log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
|
||||
tor_free(signed_digest);
|
||||
@ -1106,6 +1128,7 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
size_t prepend_len = prepend_annotations ? strlen(prepend_annotations) : 0;
|
||||
int ok = 1;
|
||||
memarea_t *area = NULL;
|
||||
tor_cert_t *ntor_cc_cert = NULL;
|
||||
/* Do not set this to '1' until we have parsed everything that we intend to
|
||||
* parse that's covered by the hash. */
|
||||
int can_dl_again = 0;
|
||||
@ -1178,9 +1201,11 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
}
|
||||
|
||||
tok = find_by_keyword(tokens, K_ROUTER);
|
||||
const int router_token_pos = smartlist_pos(tokens, tok);
|
||||
tor_assert(tok->n_args >= 5);
|
||||
|
||||
router = tor_malloc_zero(sizeof(routerinfo_t));
|
||||
router->cert_expiration_time = TIME_MAX;
|
||||
router->cache_info.routerlist_index = -1;
|
||||
router->cache_info.annotations_len = s-start_of_annotations + prepend_len;
|
||||
router->cache_info.signed_descriptor_len = end-s;
|
||||
@ -1311,6 +1336,147 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
log_warn(LD_DIR, "Couldn't calculate key digest"); goto err;
|
||||
}
|
||||
|
||||
{
|
||||
directory_token_t *ed_sig_tok, *ed_cert_tok, *cc_tap_tok, *cc_ntor_tok;
|
||||
ed_sig_tok = find_opt_by_keyword(tokens, K_ROUTER_SIG_ED25519);
|
||||
ed_cert_tok = find_opt_by_keyword(tokens, K_IDENTITY_ED25519);
|
||||
cc_tap_tok = find_opt_by_keyword(tokens, K_ONION_KEY_CROSSCERT);
|
||||
cc_ntor_tok = find_opt_by_keyword(tokens, K_NTOR_ONION_KEY_CROSSCERT);
|
||||
int n_ed_toks = !!ed_sig_tok + !!ed_cert_tok +
|
||||
!!cc_tap_tok + !!cc_ntor_tok;
|
||||
if ((n_ed_toks != 0 && n_ed_toks != 4) ||
|
||||
(n_ed_toks == 4 && !router->onion_curve25519_pkey)) {
|
||||
log_warn(LD_DIR, "Router descriptor with only partial ed25519/"
|
||||
"cross-certification support");
|
||||
goto err;
|
||||
}
|
||||
if (ed_sig_tok) {
|
||||
tor_assert(ed_cert_tok && cc_tap_tok && cc_ntor_tok);
|
||||
const int ed_cert_token_pos = smartlist_pos(tokens, ed_cert_tok);
|
||||
if (ed_cert_token_pos == -1 || router_token_pos == -1 ||
|
||||
(ed_cert_token_pos != router_token_pos + 1 &&
|
||||
ed_cert_token_pos != router_token_pos - 1)) {
|
||||
log_warn(LD_DIR, "Ed25519 certificate in wrong position");
|
||||
goto err;
|
||||
}
|
||||
if (ed_sig_tok != smartlist_get(tokens, smartlist_len(tokens)-2)) {
|
||||
log_warn(LD_DIR, "Ed25519 signature in wrong position");
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(ed_cert_tok->object_type, "ED25519 CERT")) {
|
||||
log_warn(LD_DIR, "Wrong object type on identity-ed25519 in decriptor");
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(cc_ntor_tok->object_type, "ED25519 CERT")) {
|
||||
log_warn(LD_DIR, "Wrong object type on ntor-onion-key-crosscert "
|
||||
"in decriptor");
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(cc_tap_tok->object_type, "CROSSCERT")) {
|
||||
log_warn(LD_DIR, "Wrong object type on onion-key-crosscert "
|
||||
"in decriptor");
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(cc_ntor_tok->args[0], "0") &&
|
||||
strcmp(cc_ntor_tok->args[0], "1")) {
|
||||
log_warn(LD_DIR, "Bad sign bit on ntor-onion-key-crosscert");
|
||||
goto err;
|
||||
}
|
||||
int ntor_cc_sign_bit = !strcmp(cc_ntor_tok->args[0], "1");
|
||||
|
||||
uint8_t d256[DIGEST256_LEN];
|
||||
const char *signed_start, *signed_end;
|
||||
tor_cert_t *cert = tor_cert_parse(
|
||||
(const uint8_t*)ed_cert_tok->object_body,
|
||||
ed_cert_tok->object_size);
|
||||
if (! cert) {
|
||||
log_warn(LD_DIR, "Couldn't parse ed25519 cert");
|
||||
goto err;
|
||||
}
|
||||
router->signing_key_cert = cert; /* makes sure it gets freed. */
|
||||
if (cert->cert_type != CERT_TYPE_ID_SIGNING ||
|
||||
! cert->signing_key_included) {
|
||||
log_warn(LD_DIR, "Invalid form for ed25519 cert");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ntor_cc_cert = tor_cert_parse((const uint8_t*)cc_ntor_tok->object_body,
|
||||
cc_ntor_tok->object_size);
|
||||
if (!ntor_cc_cert) {
|
||||
log_warn(LD_DIR, "Couldn't parse ntor-onion-key-crosscert cert");
|
||||
goto err;
|
||||
}
|
||||
if (ntor_cc_cert->cert_type != CERT_TYPE_ONION_ID ||
|
||||
! ed25519_pubkey_eq(&ntor_cc_cert->signed_key, &cert->signing_key)) {
|
||||
log_warn(LD_DIR, "Invalid contents for ntor-onion-key-crosscert cert");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ed25519_public_key_t ntor_cc_pk;
|
||||
if (ed25519_public_key_from_curve25519_public_key(&ntor_cc_pk,
|
||||
router->onion_curve25519_pkey,
|
||||
ntor_cc_sign_bit)<0) {
|
||||
log_warn(LD_DIR, "Error converting onion key to ed25519");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (router_get_hash_impl_helper(s, end-s, "router ",
|
||||
"\nrouter-sig-ed25519",
|
||||
' ', &signed_start, &signed_end) < 0) {
|
||||
log_warn(LD_DIR, "Can't find ed25519-signed portion of descriptor");
|
||||
goto err;
|
||||
}
|
||||
crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA256);
|
||||
crypto_digest_add_bytes(d, ED_DESC_SIGNATURE_PREFIX,
|
||||
strlen(ED_DESC_SIGNATURE_PREFIX));
|
||||
crypto_digest_add_bytes(d, signed_start, signed_end-signed_start);
|
||||
crypto_digest_get_digest(d, (char*)d256, sizeof(d256));
|
||||
crypto_digest_free(d);
|
||||
|
||||
ed25519_checkable_t check[3];
|
||||
int check_ok[3];
|
||||
if (tor_cert_get_checkable_sig(&check[0], cert, NULL) < 0) {
|
||||
log_err(LD_BUG, "Couldn't create 'checkable' for cert.");
|
||||
goto err;
|
||||
}
|
||||
if (tor_cert_get_checkable_sig(&check[1],
|
||||
ntor_cc_cert, &ntor_cc_pk) < 0) {
|
||||
log_err(LD_BUG, "Couldn't create 'checkable' for ntor_cc_cert.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ed25519_signature_from_base64(&check[2].signature,
|
||||
ed_sig_tok->args[0])<0) {
|
||||
log_warn(LD_DIR, "Couldn't decode ed25519 signature");
|
||||
goto err;
|
||||
}
|
||||
check[2].pubkey = &cert->signed_key;
|
||||
check[2].msg = d256;
|
||||
check[2].len = DIGEST256_LEN;
|
||||
|
||||
if (ed25519_checksig_batch(check_ok, check, 3) < 0) {
|
||||
log_warn(LD_DIR, "Incorrect ed25519 signature(s)");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (check_tap_onion_key_crosscert(
|
||||
(const uint8_t*)cc_tap_tok->object_body,
|
||||
(int)cc_tap_tok->object_size,
|
||||
router->onion_pkey,
|
||||
&cert->signing_key,
|
||||
(const uint8_t*)router->cache_info.identity_digest)<0) {
|
||||
log_warn(LD_DIR, "Incorrect TAP cross-verification");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* We check this before adding it to the routerlist. */
|
||||
if (cert->valid_until < ntor_cc_cert->valid_until)
|
||||
router->cert_expiration_time = cert->valid_until;
|
||||
else
|
||||
router->cert_expiration_time = ntor_cc_cert->valid_until;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tok = find_opt_by_keyword(tokens, K_FINGERPRINT))) {
|
||||
/* If there's a fingerprint line, it must match the identity digest. */
|
||||
char d[DIGEST_LEN];
|
||||
@ -1402,6 +1568,14 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
} else {
|
||||
log_warn(LD_DIR, "Invalid extra info digest %s", escaped(tok->args[0]));
|
||||
}
|
||||
|
||||
if (tok->n_args >= 2) {
|
||||
if (digest256_from_base64(router->extra_info_digest256, tok->args[1])
|
||||
< 0) {
|
||||
log_warn(LD_DIR, "Invalid extra info digest256 %s",
|
||||
escaped(tok->args[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (find_opt_by_keyword(tokens, K_HIDDEN_SERVICE_DIR)) {
|
||||
@ -1437,6 +1611,7 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
routerinfo_free(router);
|
||||
router = NULL;
|
||||
done:
|
||||
tor_cert_free(ntor_cc_cert);
|
||||
if (tokens) {
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
|
||||
smartlist_free(tokens);
|
||||
@ -1503,6 +1678,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* XXXX Accept this in position 1 too, and ed identity in position 0. */
|
||||
tok = smartlist_get(tokens,0);
|
||||
if (tok->tp != K_EXTRA_INFO) {
|
||||
log_warn(LD_DIR,"Entry does not start with \"extra-info\"");
|
||||
@ -1515,6 +1691,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
|
||||
extrainfo->cache_info.signed_descriptor_body = tor_memdup_nulterm(s,end-s);
|
||||
extrainfo->cache_info.signed_descriptor_len = end-s;
|
||||
memcpy(extrainfo->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
|
||||
crypto_digest256((char*)extrainfo->digest256, s, end-s, DIGEST_SHA256);
|
||||
|
||||
tor_assert(tok->n_args >= 2);
|
||||
if (!is_legal_nickname(tok->args[0])) {
|
||||
@ -1537,6 +1714,87 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
|
||||
goto err;
|
||||
}
|
||||
|
||||
{
|
||||
directory_token_t *ed_sig_tok, *ed_cert_tok;
|
||||
ed_sig_tok = find_opt_by_keyword(tokens, K_ROUTER_SIG_ED25519);
|
||||
ed_cert_tok = find_opt_by_keyword(tokens, K_IDENTITY_ED25519);
|
||||
int n_ed_toks = !!ed_sig_tok + !!ed_cert_tok;
|
||||
if (n_ed_toks != 0 && n_ed_toks != 2) {
|
||||
log_warn(LD_DIR, "Router descriptor with only partial ed25519/"
|
||||
"cross-certification support");
|
||||
goto err;
|
||||
}
|
||||
if (ed_sig_tok) {
|
||||
tor_assert(ed_cert_tok);
|
||||
const int ed_cert_token_pos = smartlist_pos(tokens, ed_cert_tok);
|
||||
if (ed_cert_token_pos != 1) {
|
||||
/* Accept this in position 0 XXXX */
|
||||
log_warn(LD_DIR, "Ed25519 certificate in wrong position");
|
||||
goto err;
|
||||
}
|
||||
if (ed_sig_tok != smartlist_get(tokens, smartlist_len(tokens)-2)) {
|
||||
log_warn(LD_DIR, "Ed25519 signature in wrong position");
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(ed_cert_tok->object_type, "ED25519 CERT")) {
|
||||
log_warn(LD_DIR, "Wrong object type on identity-ed25519 in decriptor");
|
||||
goto err;
|
||||
}
|
||||
|
||||
uint8_t d256[DIGEST256_LEN];
|
||||
const char *signed_start, *signed_end;
|
||||
tor_cert_t *cert = tor_cert_parse(
|
||||
(const uint8_t*)ed_cert_tok->object_body,
|
||||
ed_cert_tok->object_size);
|
||||
if (! cert) {
|
||||
log_warn(LD_DIR, "Couldn't parse ed25519 cert");
|
||||
goto err;
|
||||
}
|
||||
extrainfo->signing_key_cert = cert; /* makes sure it gets freed. */
|
||||
if (cert->cert_type != CERT_TYPE_ID_SIGNING ||
|
||||
! cert->signing_key_included) {
|
||||
log_warn(LD_DIR, "Invalid form for ed25519 cert");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (router_get_hash_impl_helper(s, end-s, "extra-info ",
|
||||
"\nrouter-sig-ed25519",
|
||||
' ', &signed_start, &signed_end) < 0) {
|
||||
log_warn(LD_DIR, "Can't find ed25519-signed portion of extrainfo");
|
||||
goto err;
|
||||
}
|
||||
crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA256);
|
||||
crypto_digest_add_bytes(d, ED_DESC_SIGNATURE_PREFIX,
|
||||
strlen(ED_DESC_SIGNATURE_PREFIX));
|
||||
crypto_digest_add_bytes(d, signed_start, signed_end-signed_start);
|
||||
crypto_digest_get_digest(d, (char*)d256, sizeof(d256));
|
||||
crypto_digest_free(d);
|
||||
|
||||
ed25519_checkable_t check[2];
|
||||
int check_ok[2];
|
||||
if (tor_cert_get_checkable_sig(&check[0], cert, NULL) < 0) {
|
||||
log_err(LD_BUG, "Couldn't create 'checkable' for cert.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ed25519_signature_from_base64(&check[1].signature,
|
||||
ed_sig_tok->args[0])<0) {
|
||||
log_warn(LD_DIR, "Couldn't decode ed25519 signature");
|
||||
goto err;
|
||||
}
|
||||
check[1].pubkey = &cert->signed_key;
|
||||
check[1].msg = d256;
|
||||
check[1].len = DIGEST256_LEN;
|
||||
|
||||
if (ed25519_checksig_batch(check_ok, check, 2) < 0) {
|
||||
log_warn(LD_DIR, "Incorrect ed25519 signature(s)");
|
||||
goto err;
|
||||
}
|
||||
/* We don't check the certificate expiration time: checking that it
|
||||
* matches the cert in the router descriptor is adequate. */
|
||||
}
|
||||
}
|
||||
|
||||
/* We've checked everything that's covered by the hash. */
|
||||
can_dl_again = 1;
|
||||
|
||||
@ -2089,6 +2347,17 @@ routerstatus_parse_entry_from_string(memarea_t *area,
|
||||
line->microdesc_hash_line = tor_strdup(t->args[0]);
|
||||
vote_rs->microdesc = line;
|
||||
}
|
||||
if (t->tp == K_ID) {
|
||||
tor_assert(t->n_args >= 2);
|
||||
if (!strcmp(t->args[0], "ed25519")) {
|
||||
vote_rs->has_ed25519_listing = 1;
|
||||
if (strcmp(t->args[1], "none") &&
|
||||
digest256_from_base64((char*)vote_rs->ed25519_id, t->args[1])<0) {
|
||||
log_warn(LD_DIR, "Bogus ed25519 key in networkstatus vote");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(t);
|
||||
} else if (flav == FLAV_MICRODESC) {
|
||||
tok = find_opt_by_keyword(tokens, K_M);
|
||||
@ -2913,6 +3182,21 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (ns_type != NS_TYPE_CONSENSUS) {
|
||||
digest256map_t *ed_id_map = digest256map_new();
|
||||
SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, vote_routerstatus_t *, vrs) {
|
||||
if (! vrs->has_ed25519_listing ||
|
||||
tor_mem_is_zero((const char *)vrs->ed25519_id, DIGEST256_LEN))
|
||||
continue;
|
||||
if (digest256map_get(ed_id_map, vrs->ed25519_id) != NULL) {
|
||||
log_warn(LD_DIR, "Vote networkstatus ed25519 identities were not "
|
||||
"unique");
|
||||
goto err;
|
||||
}
|
||||
digest256map_set(ed_id_map, vrs->ed25519_id, (void*)1);
|
||||
} SMARTLIST_FOREACH_END(vrs);
|
||||
digest256map_free(ed_id_map, NULL);
|
||||
}
|
||||
|
||||
/* Parse footer; check signature. */
|
||||
footer_tokens = smartlist_new();
|
||||
@ -4210,6 +4494,26 @@ microdescs_parse_from_string(const char *s, const char *eos,
|
||||
tor_memdup(&k, sizeof(curve25519_public_key_t));
|
||||
}
|
||||
|
||||
smartlist_t *id_lines = find_all_by_keyword(tokens, K_ID);
|
||||
if (id_lines) {
|
||||
SMARTLIST_FOREACH_BEGIN(id_lines, directory_token_t *, t) {
|
||||
tor_assert(t->n_args >= 2);
|
||||
if (!strcmp(t->args[0], "ed25519")) {
|
||||
if (md->ed25519_identity_pkey) {
|
||||
log_warn(LD_DIR, "Extra ed25519 key in microdesc");
|
||||
goto next;
|
||||
}
|
||||
ed25519_public_key_t k;
|
||||
if (ed25519_public_from_base64(&k, t->args[1])<0) {
|
||||
log_warn(LD_DIR, "Bogus ed25519 key in microdesc");
|
||||
goto next;
|
||||
}
|
||||
md->ed25519_identity_pkey = tor_memdup(&k, sizeof(k));
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(t);
|
||||
smartlist_free(id_lines);
|
||||
}
|
||||
|
||||
{
|
||||
smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
|
||||
if (a_lines) {
|
||||
|
@ -19,7 +19,7 @@ int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest);
|
||||
#define DIROBJ_MAX_SIG_LEN 256
|
||||
char *router_get_dirobj_signature(const char *digest,
|
||||
size_t digest_len,
|
||||
crypto_pk_t *private_key);
|
||||
const crypto_pk_t *private_key);
|
||||
int router_append_dirobj_signature(char *buf, size_t buf_len,
|
||||
const char *digest,
|
||||
size_t digest_len,
|
||||
@ -91,5 +91,7 @@ STATIC int routerstatus_parse_guardfraction(const char *guardfraction_str,
|
||||
routerstatus_t *rs);
|
||||
#endif
|
||||
|
||||
#define ED_DESC_SIGNATURE_PREFIX "Tor router descriptor signature v1"
|
||||
|
||||
#endif
|
||||
|
||||
|
280
src/or/torcert.c
Normal file
280
src/or/torcert.c
Normal file
@ -0,0 +1,280 @@
|
||||
/* Copyright (c) 2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "crypto.h"
|
||||
#include "torcert.h"
|
||||
#include "ed25519_cert.h"
|
||||
#include "torlog.h"
|
||||
#include "util.h"
|
||||
#include "compat.h"
|
||||
#include "link_handshake.h"
|
||||
|
||||
/** Helper for tor_cert_create(): signs any 32 bytes, not just an ed25519
|
||||
* key.
|
||||
*/
|
||||
static tor_cert_t *
|
||||
tor_cert_sign_impl(const ed25519_keypair_t *signing_key,
|
||||
uint8_t cert_type,
|
||||
uint8_t signed_key_type,
|
||||
const uint8_t signed_key_info[32],
|
||||
time_t now, time_t lifetime,
|
||||
uint32_t flags)
|
||||
{
|
||||
tor_cert_t *torcert = NULL;
|
||||
|
||||
ed25519_cert_t *cert = ed25519_cert_new();
|
||||
cert->cert_type = cert_type;
|
||||
cert->exp_field = (uint32_t) CEIL_DIV(now + lifetime, 3600);
|
||||
cert->cert_key_type = signed_key_type;
|
||||
memcpy(cert->certified_key, signed_key_info, 32);
|
||||
|
||||
if (flags & CERT_FLAG_INCLUDE_SIGNING_KEY) {
|
||||
ed25519_cert_extension_t *ext = ed25519_cert_extension_new();
|
||||
ext->ext_type = CERTEXT_SIGNED_WITH_KEY;
|
||||
memcpy(ext->un_signing_key, signing_key->pubkey.pubkey, 32);
|
||||
ed25519_cert_add_ext(cert, ext);
|
||||
++cert->n_extensions;
|
||||
}
|
||||
|
||||
const ssize_t alloc_len = ed25519_cert_encoded_len(cert);
|
||||
tor_assert(alloc_len > 0);
|
||||
uint8_t *encoded = tor_malloc(alloc_len);
|
||||
const ssize_t real_len = ed25519_cert_encode(encoded, alloc_len, cert);
|
||||
if (real_len < 0)
|
||||
goto err;
|
||||
tor_assert(real_len == alloc_len);
|
||||
tor_assert(real_len > ED25519_SIG_LEN);
|
||||
uint8_t *sig = encoded + (real_len - ED25519_SIG_LEN);
|
||||
tor_assert(tor_mem_is_zero((char*)sig, ED25519_SIG_LEN));
|
||||
|
||||
ed25519_signature_t signature;
|
||||
if (ed25519_sign(&signature, encoded,
|
||||
real_len-ED25519_SIG_LEN, signing_key)<0) {
|
||||
log_warn(LD_BUG, "Can't sign certificate");
|
||||
goto err;
|
||||
}
|
||||
memcpy(sig, signature.sig, ED25519_SIG_LEN);
|
||||
|
||||
torcert = tor_cert_parse(encoded, real_len);
|
||||
if (! torcert) {
|
||||
log_warn(LD_BUG, "Generated a certificate we cannot parse");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (tor_cert_checksig(torcert, &signing_key->pubkey, now) < 0) {
|
||||
log_warn(LD_BUG, "Generated a certificate whose signature we can't check");
|
||||
goto err;
|
||||
}
|
||||
|
||||
tor_free(encoded);
|
||||
|
||||
return torcert;
|
||||
|
||||
err:
|
||||
tor_cert_free(torcert);
|
||||
ed25519_cert_free(cert);
|
||||
tor_free(encoded);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new new certificate of type <b>cert_type</b> to
|
||||
* authenticate <b>signed_key</b> using the key <b>signing_key</b>. The
|
||||
* certificate should remain valid for at least <b>lifetime</b> seconds after
|
||||
* <b>now</b>.
|
||||
*
|
||||
* If CERT_FLAG_INCLUDE_SIGNING_KEY is set in <b>flags</b>, embed
|
||||
* the public part of <b>signing_key</b> in the certificate.
|
||||
*/
|
||||
tor_cert_t *
|
||||
tor_cert_create(const ed25519_keypair_t *signing_key,
|
||||
uint8_t cert_type,
|
||||
const ed25519_public_key_t *signed_key,
|
||||
time_t now, time_t lifetime,
|
||||
uint32_t flags)
|
||||
{
|
||||
return tor_cert_sign_impl(signing_key, cert_type,
|
||||
SIGNED_KEY_TYPE_ED25519, signed_key->pubkey,
|
||||
now, lifetime, flags);
|
||||
}
|
||||
|
||||
/** Release all storage held for <b>cert</>. */
|
||||
void
|
||||
tor_cert_free(tor_cert_t *cert)
|
||||
{
|
||||
if (! cert)
|
||||
return;
|
||||
|
||||
if (cert->encoded)
|
||||
memwipe(cert->encoded, 0, cert->encoded_len);
|
||||
tor_free(cert->encoded);
|
||||
|
||||
memwipe(cert, 0, sizeof(tor_cert_t));
|
||||
tor_free(cert);
|
||||
}
|
||||
|
||||
/** Parse a certificate encoded with <b>len</b> bytes in <b>encoded</b>. */
|
||||
tor_cert_t *
|
||||
tor_cert_parse(const uint8_t *encoded, const size_t len)
|
||||
{
|
||||
tor_cert_t *cert = NULL;
|
||||
ed25519_cert_t *parsed = NULL;
|
||||
ssize_t got_len = ed25519_cert_parse(&parsed, encoded, len);
|
||||
if (got_len < 0 || (size_t) got_len != len)
|
||||
goto err;
|
||||
|
||||
cert = tor_malloc_zero(sizeof(tor_cert_t));
|
||||
cert->encoded = tor_memdup(encoded, len);
|
||||
cert->encoded_len = len;
|
||||
|
||||
memcpy(cert->signed_key.pubkey, parsed->certified_key, 32);
|
||||
cert->valid_until = parsed->exp_field * 3600;
|
||||
cert->cert_type = parsed->cert_type;
|
||||
|
||||
for (unsigned i = 0; i < ed25519_cert_getlen_ext(parsed); ++i) {
|
||||
ed25519_cert_extension_t *ext = ed25519_cert_get_ext(parsed, i);
|
||||
if (ext->ext_type == CERTEXT_SIGNED_WITH_KEY) {
|
||||
if (cert->signing_key_included)
|
||||
goto err;
|
||||
|
||||
cert->signing_key_included = 1;
|
||||
memcpy(cert->signing_key.pubkey, ext->un_signing_key, 32);
|
||||
} else if (ext->ext_flags & CERTEXT_FLAG_AFFECTS_VALIDATION) {
|
||||
/* Unrecognized extension with affects_validation set */
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return cert;
|
||||
err:
|
||||
ed25519_cert_free(parsed);
|
||||
tor_cert_free(cert);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Fill in <b>checkable_out</b> with the information needed to check
|
||||
* the signature on <b>cert</b> with <b>pubkey</b>. */
|
||||
int
|
||||
tor_cert_get_checkable_sig(ed25519_checkable_t *checkable_out,
|
||||
const tor_cert_t *cert,
|
||||
const ed25519_public_key_t *pubkey)
|
||||
{
|
||||
if (! pubkey) {
|
||||
if (cert->signing_key_included)
|
||||
pubkey = &cert->signing_key;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
checkable_out->msg = cert->encoded;
|
||||
checkable_out->pubkey = pubkey;
|
||||
tor_assert(cert->encoded_len > ED25519_SIG_LEN);
|
||||
const size_t signed_len = cert->encoded_len - ED25519_SIG_LEN;
|
||||
checkable_out->len = signed_len;
|
||||
memcpy(checkable_out->signature.sig,
|
||||
cert->encoded + signed_len, ED25519_SIG_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Validates the signature on <b>cert</b> with <b>pubkey</b> relative to
|
||||
* the current time <b>now</b>. Return 0 on success, -1 on failure.
|
||||
* Sets flags in <b>cert</b> as appropriate.
|
||||
*/
|
||||
int
|
||||
tor_cert_checksig(tor_cert_t *cert,
|
||||
const ed25519_public_key_t *pubkey, time_t now)
|
||||
{
|
||||
ed25519_checkable_t checkable;
|
||||
int okay;
|
||||
|
||||
if (now > cert->valid_until) {
|
||||
cert->cert_expired = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tor_cert_get_checkable_sig(&checkable, cert, pubkey) < 0)
|
||||
return -1;
|
||||
|
||||
if (ed25519_checksig_batch(&okay, &checkable, 1) < 0) {
|
||||
cert->sig_bad = 1;
|
||||
return -1;
|
||||
} else {
|
||||
cert->sig_ok = 1;
|
||||
memcpy(cert->signing_key.pubkey, checkable.pubkey->pubkey, 32);
|
||||
cert->cert_valid = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return a new copy of <b>cert</b> */
|
||||
tor_cert_t *
|
||||
tor_cert_dup(const tor_cert_t *cert)
|
||||
{
|
||||
tor_cert_t *newcert = tor_memdup(cert, sizeof(tor_cert_t));
|
||||
if (cert->encoded)
|
||||
newcert->encoded = tor_memdup(cert->encoded, cert->encoded_len);
|
||||
return newcert;
|
||||
}
|
||||
|
||||
/** Return true iff cert1 and cert2 are the same cert. */
|
||||
int
|
||||
tor_cert_eq(const tor_cert_t *cert1, const tor_cert_t *cert2)
|
||||
{
|
||||
tor_assert(cert1);
|
||||
tor_assert(cert2);
|
||||
return cert1->encoded_len == cert2->encoded_len &&
|
||||
tor_memeq(cert1->encoded, cert2->encoded, cert1->encoded_len);
|
||||
}
|
||||
|
||||
/** Return true iff cert1 and cert2 are the same cert, or if they are both
|
||||
* NULL. */
|
||||
int
|
||||
tor_cert_opt_eq(const tor_cert_t *cert1, const tor_cert_t *cert2)
|
||||
{
|
||||
if (cert1 == NULL && cert2 == NULL)
|
||||
return 1;
|
||||
if (!cert1 || !cert2)
|
||||
return 0;
|
||||
return tor_cert_eq(cert1, cert2);
|
||||
}
|
||||
|
||||
/** Create new cross-certification object to certify <b>ed_key</b> as the
|
||||
* master ed25519 identity key for the RSA identity key <b>rsa_key</b>.
|
||||
* Allocates and stores the encoded certificate in *<b>cert</b>, and returns
|
||||
* the number of bytes stored. Returns negative on error.*/
|
||||
ssize_t
|
||||
tor_make_rsa_ed25519_crosscert(const ed25519_public_key_t *ed_key,
|
||||
const crypto_pk_t *rsa_key,
|
||||
time_t expires,
|
||||
uint8_t **cert)
|
||||
{
|
||||
uint8_t *res;
|
||||
|
||||
rsa_ed_crosscert_t *cc = rsa_ed_crosscert_new();
|
||||
memcpy(cc->ed_key, ed_key->pubkey, ED25519_PUBKEY_LEN);
|
||||
cc->expiration = (uint32_t) CEIL_DIV(expires, 3600);
|
||||
cc->sig_len = crypto_pk_keysize(rsa_key);
|
||||
rsa_ed_crosscert_setlen_sig(cc, crypto_pk_keysize(rsa_key));
|
||||
|
||||
ssize_t alloc_sz = rsa_ed_crosscert_encoded_len(cc);
|
||||
tor_assert(alloc_sz > 0);
|
||||
res = tor_malloc_zero(alloc_sz);
|
||||
ssize_t sz = rsa_ed_crosscert_encode(res, alloc_sz, cc);
|
||||
tor_assert(sz > 0 && sz <= alloc_sz);
|
||||
|
||||
const int signed_part_len = 32 + 4;
|
||||
int siglen = crypto_pk_private_sign(rsa_key,
|
||||
(char*)rsa_ed_crosscert_getarray_sig(cc),
|
||||
rsa_ed_crosscert_getlen_sig(cc),
|
||||
(char*)res, signed_part_len);
|
||||
tor_assert(siglen > 0 && siglen <= (int)crypto_pk_keysize(rsa_key));
|
||||
tor_assert(siglen <= UINT8_MAX);
|
||||
cc->sig_len = siglen;
|
||||
rsa_ed_crosscert_setlen_sig(cc, siglen);
|
||||
|
||||
sz = rsa_ed_crosscert_encode(res, alloc_sz, cc);
|
||||
rsa_ed_crosscert_free(cc);
|
||||
*cert = res;
|
||||
return sz;
|
||||
}
|
76
src/or/torcert.h
Normal file
76
src/or/torcert.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* Copyright (c) 2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TORCERT_H_INCLUDED
|
||||
#define TORCERT_H_INCLUDED
|
||||
|
||||
#include "crypto_ed25519.h"
|
||||
|
||||
#define SIGNED_KEY_TYPE_ED25519 0x01
|
||||
|
||||
#define CERT_TYPE_ID_SIGNING 0x04
|
||||
#define CERT_TYPE_SIGNING_LINK 0x05
|
||||
#define CERT_TYPE_SIGNING_AUTH 0x06
|
||||
#define CERT_TYPE_ONION_ID 0x0A
|
||||
|
||||
#define CERT_FLAG_INCLUDE_SIGNING_KEY 0x1
|
||||
|
||||
/** An ed25519-signed certificate as used throughout the Tor protocol.
|
||||
**/
|
||||
typedef struct tor_cert_st {
|
||||
/** The key authenticated by this certificate */
|
||||
ed25519_public_key_t signed_key;
|
||||
/** The key that signed this certificate. This value may be unset if the
|
||||
* certificate has never been checked, and didn't include its own key. */
|
||||
ed25519_public_key_t signing_key;
|
||||
/** A time after which this certificate will no longer be valid. */
|
||||
time_t valid_until;
|
||||
|
||||
/** The encoded representation of this certificate */
|
||||
uint8_t *encoded;
|
||||
/** The length of <b>encoded</b> */
|
||||
size_t encoded_len;
|
||||
|
||||
/** One of CERT_TYPE_... */
|
||||
uint8_t cert_type;
|
||||
/** True iff we received a signing key embedded in this certificate */
|
||||
unsigned signing_key_included : 1;
|
||||
/** True iff we checked the signature and found it bad */
|
||||
unsigned sig_bad : 1;
|
||||
/** True iff we checked the signature and found it correct */
|
||||
unsigned sig_ok : 1;
|
||||
/** True iff we checked the signature and first found that the cert
|
||||
* had expired */
|
||||
unsigned cert_expired : 1;
|
||||
/** True iff we checked the signature and found the whole cert valid */
|
||||
unsigned cert_valid : 1;
|
||||
} tor_cert_t;
|
||||
|
||||
tor_cert_t *tor_cert_create(const ed25519_keypair_t *signing_key,
|
||||
uint8_t cert_type,
|
||||
const ed25519_public_key_t *signed_key,
|
||||
time_t now, time_t lifetime,
|
||||
uint32_t flags);
|
||||
|
||||
tor_cert_t *tor_cert_parse(const uint8_t *cert, size_t certlen);
|
||||
|
||||
void tor_cert_free(tor_cert_t *cert);
|
||||
|
||||
int tor_cert_get_checkable_sig(ed25519_checkable_t *checkable_out,
|
||||
const tor_cert_t *out,
|
||||
const ed25519_public_key_t *pubkey);
|
||||
|
||||
int tor_cert_checksig(tor_cert_t *cert,
|
||||
const ed25519_public_key_t *pubkey, time_t now);
|
||||
|
||||
tor_cert_t *tor_cert_dup(const tor_cert_t *cert);
|
||||
int tor_cert_eq(const tor_cert_t *cert1, const tor_cert_t *cert2);
|
||||
int tor_cert_opt_eq(const tor_cert_t *cert1, const tor_cert_t *cert2);
|
||||
|
||||
ssize_t tor_make_rsa_ed25519_crosscert(const ed25519_public_key_t *ed_key,
|
||||
const crypto_pk_t *rsa_key,
|
||||
time_t expires,
|
||||
uint8_t **cert);
|
||||
|
||||
#endif
|
||||
|
@ -190,3 +190,236 @@ static const char EX_EI_BAD_PUBLISHED_KEY[] =
|
||||
"BvG6303md3INygg+KP49RvWEJR/cU4RZ9QfHpORxH2OocMyRedw2rLex2E7jNNSi\n"
|
||||
"52yd1sHFYI8ZQ4aff+ZHUjJUGKRyqpbc8okVbq/Rl7vug0dd12eHAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n";
|
||||
|
||||
static const char EX_EI_GOOD_ED_EI[] =
|
||||
"extra-info emma A692FE045C32B5E3A54B52882EF678A9DAC46A73\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AYgHn/OKR8GHBlscN5VkO73wA9jSci8QgTM30615ZT44AQAgBAC08woT\n"
|
||||
"MBZpKzRcaoEJhEG7+RmuYtnB2+nODk9IRIs8ZoyYPTZ6dLzI+MLMmtzUuo/Wmvw0\n"
|
||||
"PflTyCb2RlWitOEhAErWH3Z9UmYGnzM/COId0Fe3ScSriyvRoFnJY1+GVAQ=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"published 2014-10-05 20:07:00\n"
|
||||
"router-sig-ed25519 a7K8nwfg+HrdlSGQwr9rnLBq0qozkyZZs6d6aiLEiXGdhV1r9KJncmlQ5SNoY/zMQlyQm8EV5rCyBiVliKQ1Bw\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"GvmCmIGgbC1DeawRyRuChy62VmBOG0EviryG/a2qSZiFy0iPPwqSp5ZyZDQEIEId\n"
|
||||
"kkk1zPzK1+S3fmgOAXyXGH0r4YFkoLGnhMk07BoEwi6HEXzjJsabmcNkOHfaOWgs\n"
|
||||
"/5nvnLfcmxL4c6FstZ7t9VQpE06y3GU0zwBeIy1qjp0=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"\n"
|
||||
;
|
||||
const char EX_EI_GOOD_ED_EI_FP[] = "A692FE045C32B5E3A54B52882EF678A9DAC46A73";
|
||||
static const char EX_EI_GOOD_ED_EI_KEY[] =
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAM3jdYwjwGxDWYj/vyFkQT7RgeCNIn89Ei6D2+L/fdtFnqrMXOreFFHL\n"
|
||||
"C7CK2v2uN3v+uXxfb5lADz3NcalxJrCfGTGtaBk7PwMZraTSh2luFKOvSRBQCmB1\n"
|
||||
"yD5N0QqnIhBJoGr6NITpbWyiTKWvYLjl9PZd9af8e8jQCAa5P1j1AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
;
|
||||
|
||||
static const char EX_EI_ED_MISSING_SIG[] =
|
||||
"extra-info rachel 2A7521497B91A8437021515308A47491164EDBA1\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AT2/T71LFYHiI1ppwNiuaewIu2Hq+GWWQ85O8gpWcUxeAQAgBAC2dgYu\n"
|
||||
"moxhtuip7GVlthT9iomZKba1IllVa7uE1u2uO9BUYZQWXciFt7OnNzMH5mlffwxB\n"
|
||||
"1dWCl+G5nbOsV5jYLbfhrF5afZotf+EQTfob4cCH79AV223LPcySbTHTtQ4=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"published 2014-10-05 20:07:00\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"oypRD2IZQ5EttOE8dvofrW80nnBfijSkvYzBrM6H4KVeayRYvWfmi96dYO6ybMqm\n"
|
||||
"Yp7Gs3ngqeeNdfHtkRPuQVUXUGYZgBTvYItuagnFlFgRqaHy0knwUIVOL35eqWYx\n"
|
||||
"xSbQKA7fglxEDMFs/RK7FRP4dWc731ZMt5wzzfJHZ8E=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"\n"
|
||||
;
|
||||
const char EX_EI_ED_MISSING_SIG_FP[] = "2A7521497B91A8437021515308A47491164EDBA1";
|
||||
static const char EX_EI_ED_MISSING_SIG_KEY[] =
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAOOB8ccxbtk2dB5FuKFhGndDcO6STNjB6KiG0b9X2QwKrOZMfmXSigto\n"
|
||||
"mtC1JfPTxECayRjLSiP/9UD8iTVvlcnc8mMWBGM12Pa/KoCZRn7McHI3JJ7n9lfn\n"
|
||||
"qw9+iZ9b/rBimzOb3W6k3uxzg9r8secdq4jJwTnwSjTObgxZtC8/AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
;
|
||||
|
||||
static const char EX_EI_ED_MISSING_CERT[] =
|
||||
"extra-info lynne E88E43E86015345A323D93D825C33E4AD1028F65\n"
|
||||
"published 2014-10-05 20:07:00\n"
|
||||
"router-sig-ed25519 H4gKIKm5K9Pfkriy7SlMUD6BdYVp6B5mXKzR/rTyYlpH0tEZ4Fx2hlHNfNNdWXJieXzKZQZo8e7SOVzvrAC3CQ\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"dIrbQjK5T9t5KM8CpsMF85hh2i060oPIxzYQMgE1q4j99dtb/n7SE8nhj1Sjij4D\n"
|
||||
"7JvTjGdLHi3bFSxXaSmla0wxD9PUYFN7VsBQmwSaDrqrzJFb1SGwZuzW1IEZ7BBi\n"
|
||||
"H0czsxEteg5hcNRwISj5WVthuWmau9v13MijtZGSK40=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
;
|
||||
const char EX_EI_ED_MISSING_CERT_FP[] = "E88E43E86015345A323D93D825C33E4AD1028F65";
|
||||
static const char EX_EI_ED_MISSING_CERT_KEY[] =
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBALjA/geb0TR9rp/UPvLhABQpB0XUDYuZAnLkrv+i7AAV7FemTDveEGnc\n"
|
||||
"XdXNSusO1mHOquvr0YYKPhwauInxD56S8QOzLYiWWajGq8XHARQ33b4/9K2TUrAx\n"
|
||||
"W9HTHV1U1zrPlCJtrkbjxsYoHpUg5ljzM7FGYGY5xuvyHu18SQvzAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
;
|
||||
static const char EX_EI_ED_BAD_CERT1[] =
|
||||
"extra-info marcie F78D8A655607D32281D02144817A4F1D26AE520F\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN PLAGICAL SPELL-----\n"
|
||||
"aaaa\n"
|
||||
"-----END PLAGICAL SPELL\n"
|
||||
"published 2014-10-05 20:07:00\n"
|
||||
"router-sig-ed25519 KQJ+2AH7EkkjrD0RtDtUAIr+Vc7wndwILYnoUxFLSJiTP+5fMi54eFF/f1OgkG8gYyTh8phMij9WOxK/dsOpBg\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"XWD+P25AH6moi79j20Si3hqKGcJDws+FORL1MTu+GeJLV1mp5CR9N83UH4ffulcL\n"
|
||||
"CpSSBDL/j74HqapzW7QvBx3FilaNT55GvcobZDFK4TKkCEyEmcuWKpEceBS7JTTV\n"
|
||||
"SvwZeOObTjWPafELbsc/gI9Rh5Idwu7mZt3ZVntCGaQ=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
const char EX_EI_ED_BAD_CERT1_FP[] = "F78D8A655607D32281D02144817A4F1D26AE520F";
|
||||
static const char EX_EI_ED_BAD_CERT1_KEY[] =
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMlR46JhxsCmWYtmIB/JjTV2TUYIhJLmHy+X7FfkK3ZVQvvl9/3GSXFL\n"
|
||||
"3USfyf3j34XLh8An7pJBi9LAHkIXgnRbglCud7dXoexabmC+c2mSbw5RnuxDGEwz\n"
|
||||
"krXUph/r2b+2UY1CgEt28nFigaHrIQbCmF4szFX/2GPYCLi5SrRNAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
;
|
||||
static const char EX_EI_ED_BAD_CERT2[] =
|
||||
"extra-info jaeger 7C2B42E783C4E0EB0CC3BDB37385D16737BACFBD\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55Acpw27GZBdwGCgawCj2F/DPadt8F/9DnEWywEew1Yi3qAOtLpCB8KXL7\n"
|
||||
"4w5deFW2RBg8qTondNSUvAmwYLbLjNXMmgA3+nkoJOP3fcmQMHz1jm5xzgs2lCVP\n"
|
||||
"t5txApaBIA4=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"published 2014-10-05 20:07:00\n"
|
||||
"router-sig-ed25519 DRQ4MLOGosBbW8M+17klNu8uWVkPxErmmEYoSo6OuH2Tzrcs6sUY+8Xi2qLoV1SbOugJ214Htl0I+6ceag+vBA\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"DfdA+DbuN9nVJNujuSY5wNCDLk7Hfzkrde/sK0hVmZRvivtpF/Fy/dVQHHGNFY5i\n"
|
||||
"L1cESAgq9HLdbHU+hcc08XXxTIaGwvoklcJClcG3ENVBWkTXbJNT+ifr7chEagIi\n"
|
||||
"cVrtU6RVmzldSbyir8V/Z4S/Cm67gYAgjM5gfoFUqDs=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
;
|
||||
const char EX_EI_ED_BAD_CERT2_FP[] = "7C2B42E783C4E0EB0CC3BDB37385D16737BACFBD";
|
||||
static const char EX_EI_ED_BAD_CERT2_KEY[] =
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBALAM1F/0XJEsbxIQqb3+ObX/yGVnq9of8Q9sLsmxffD6hwVpCqnV3lTg\n"
|
||||
"iC6+xZ/bSlTGLPi0k8QLCaTmYxgKwmlMPpbQZ4kpZUrsb9flKdChMN7w8hd48pY9\n"
|
||||
"lu8QiAEgErsl5rCCJIHHjrxxM/Cnd0TnedRnj/Z2YqpNx/ggsmsRAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
;
|
||||
static const char EX_EI_ED_BAD_SIG1[] =
|
||||
"extra-info vary 5AC3A538FEEFC6F9FCC5FA0CE64704396C30D62A\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AbPp++GrRb6WphSu+PkMaYsqY/beiLBmtiV3YP5i2JkKAQAgBABKXjg1\n"
|
||||
"aiz2JfQpNOG308i2EojnUAZEk0C0x9g2BAAXGL63sv3eO/qrlytsG1x2hkcamxFn\n"
|
||||
"LmfZBb/prqe1Vy4wABuhqWHAUtM29vXR6lpiCJeddt9Pa8XVy/tgWLX6TAw=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"published 2014-10-05 20:07:00\n"
|
||||
"router-sig-ed25519 a7K8nwfg+HrdlSGQwr9rnLBq0qozkyZZs6d6aiLEiXGdhV1r9KJncmlQ5SNoY/zMQlyQm8EV5rCyBiVliKQ1Bw\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"xhZX8Qmgft51NJ7eMd4vrESzf/VdxDrBz7hgn8K+5bLtZUksG0s6s7IyGRYWQtp4\n"
|
||||
"/7oc9sYe3lcQiUN2K7DkeBDlL8Pcsl8aIlKuujWomCE3j0TIu+8XK6oJeo7eYic+\n"
|
||||
"IA7EwVbdZsKsW5/eJVzbX2eO0a5zyJ5RIYotFNYNCSE=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
const char EX_EI_ED_BAD_SIG1_FP[] = "5AC3A538FEEFC6F9FCC5FA0CE64704396C30D62A";
|
||||
static const char EX_EI_ED_BAD_SIG1_KEY[] =
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMvb6SuoIkPfBkJgQuo5aQDepAs1kEETZ9VXotMlhB0JJikrqBrAAz+7\n"
|
||||
"rjIJ4JsBaeQuN0Z5ksXk2ebxtef7oMIUs37NfekLQHbNR0VsXkFXPEGmOAqpZjW0\n"
|
||||
"P524eHqybWYZTckvZtUvKI3xYGD6kEEkz4qmV6dcExU1OiAYO9jrAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
;
|
||||
static const char EX_EI_ED_BAD_SIG2[] =
|
||||
"extra-info coward 7F1D4DD477E340C6D6B389FAC26EDC746113082F\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf56AZkSDiFZ1QaiLJhcKdFDE5Kei/sPaPEIEoPMGP4BvOVXAQAgBAAlRLzx\n"
|
||||
"U029tgIL9BRe47MVgcPJGy48db6ntzhjil7iOnWKT70z2LorUD5CZoLJs72TjB6r\n"
|
||||
"8+HYNyFLEM6dvytWZf9NA5gLdhogbFcUk/R3gbNepmCF7XoZjbhPIp8zOwg=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"published 2014-10-05 20:07:00\n"
|
||||
"router-sig-ed25519 yfV+GySMIP1fw1oVa1C1de4XOWBqT4pUtEmSHq1h+WrLBNCh3/HZWvNC/denf2YVntuQrMLCJEv5ZaFKU+AIDQ\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"g+BWq69i9CP19va2cYMAXCQ6jK3IG0VmNYspjjUFgmFpJKGG6bHeOkuy1GXp47fG\n"
|
||||
"LzZ3OPfJLptxU5AOQDUUYf25hu9uSl6gyknCzsszFs5n6ticuNejvcpzw6UfO1LP\n"
|
||||
"5u+mGJlgpcMtmSraImDZrRipmZ3oRWvEULltlvzGQcQ=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
const char EX_EI_ED_BAD_SIG2_FP[] = "7F1D4DD477E340C6D6B389FAC26EDC746113082F";
|
||||
static const char EX_EI_ED_BAD_SIG2_KEY[] =
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBALzOyfCEUZnvCyhlyMctPkdXg/XRE3Cr6QgyzdKf5kQbUiu2n0FgSHOX\n"
|
||||
"iP5gfq8sO9eVeTPZtjE7/+KiR8aQJECy+eoye+lpsfm3tXpLxnpOIgL4DlURxlo/\n"
|
||||
"rfCyv30SYBN9j62qgU9m6U2ydI0tH7/9Ep8yIY/QL8me8VAjLbf/AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
;
|
||||
|
||||
static const char EX_EI_ED_MISPLACED_CERT[] =
|
||||
"extra-info msselene 3B788BD0CE348BC5CED48313307C78175EB6D0F3\n"
|
||||
"published 2014-10-05 20:07:00\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AWBcqjzLESDuLNGsqQ/tHn32XueXwj2fDlgEy/kQNVf/AQAgBAAFOegg\n"
|
||||
"XY1LR82xE9ohAYJxYpwJJw0YfXsBhGHqfakEoBtSgFJ3cQAUXZQX4lX6G8IxAlQB\n"
|
||||
"7Rj7dPQuQRUmqD1yyKb/ScBgCa8esxlhNlATz47kRNR38A3TcoJ4c1Zv6AE=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"router-sig-ed25519 Q52JKH9/iMsr1jIPlWHHxakSBvyqjT1gzL944vad4OhzCZuNuAYGWyWSGzTb1DVmBqqbAUq73TiZKAz77YLNCQ\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"YplvAIwExGf5/L8AoroVQXtGm+26EffrxKBArMKn0zS1NOOie1p0oF/+qJg+rNWU\n"
|
||||
"6cv3Anf188EXGlkUOddavgVH8CQbvve2nHSfIAPxjgEX9QNXbM5CiaMwgpCewXnF\n"
|
||||
"UoNBVo5tydeLHVns15MBg/JNIxUQMd6svMoPp2WqmaE=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
const char EX_EI_ED_MISPLACED_CERT_FP[] = "3B788BD0CE348BC5CED48313307C78175EB6D0F3";
|
||||
static const char EX_EI_ED_MISPLACED_CERT_KEY[] =
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBALTwNqhTprg1oC6bEbDqwIYBoER6prqUXQFbwbFDn+ekXhZj8vltgGwp\n"
|
||||
"aDGl9ceZWDKfi+reR6rZXjAJGctmv0VHkfe7maUX4FC/d2T8N8DvS+3IvJzFMpbT\n"
|
||||
"O0fFrDTrCSnPikqFfQWnlP8yoF5vO7wo0jRRY432fLRXg9WqVzdrAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
;
|
||||
static const char EX_EI_ED_MISPLACED_SIG[] =
|
||||
"extra-info grazie 384E40A5DEED4AB1D8A74F1FCBDB18B7C24A8284\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AcGuIBoa6TBqD8Gg5atcwp/+r9ThxIBkULmPv9OSGhv+AQAgBACXH13y\n"
|
||||
"mUvdpcN6oRN1nX6mnH40LyfYR5um8xogJZk3oINse5cRNrfMgVWiBpDlJZAwlDDa\n"
|
||||
"lx99hzuZBong+CiOcnEvLMsBaVJmNTm5mpdetYclZpl0g8QEXznXXeRBMgM=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"router-sig-ed25519 TxuO86dQ3pUaIY2raQ3hoDBmh4TTPC0OVgY98T5cf6Y+sHyiELCkkKQ3lqqXCjqnbTLr1/4riH980JoWPpR+Dw\n"
|
||||
"published 2014-10-05 20:07:00\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"kV2CtArl1VF1nUSyHL00mO3nEdNxlQU5N7/hZNTd+45lej5Veb+6vb4ujelsFERJ\n"
|
||||
"YoxwIs6SuKAR4orQytCL0e+GgZsrg8zGTveEtMX/+u//OcCwQBYEevR5duBZjVw/\n"
|
||||
"yzpEHwdIdB2PPyDBLkf1VKnP7uDj059tXiQRWl7LXgE=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
const char EX_EI_ED_MISPLACED_SIG_FP[] = "384E40A5DEED4AB1D8A74F1FCBDB18B7C24A8284";
|
||||
static const char EX_EI_ED_MISPLACED_SIG_KEY[] =
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAK0HgOCG/6433VCrwz/vhk3cKmyOfenCp0GZ4DIUwPWt4DeyP4nTbN6T\n"
|
||||
"1HJ1H8+hXC9bMuI4m43IWrzgLycQ9UaskUn372ZjHP9InPqHMJU6GQ7vZUe9Tgza\n"
|
||||
"qnBdRPoxnrZzUOzlvatGrePt0hDiOZaMtDAkeEojFp9Wp2ZN7+tZAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
;
|
||||
|
||||
|
@ -666,3 +666,904 @@ static const char EX_RI_ZERO_ORPORT[] =
|
||||
"wgFKhHI/49NHyWHX5IMQpeicg0T7Qa6qwnUvspH62p8=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
;
|
||||
|
||||
static const char EX_RI_MINIMAL_ED[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf5iAa+2yD5ryD5kXaWbpmzaTyuTjRfjMTFleDuFGkHe26wrAQAgBABFTAHm\n"
|
||||
"hdZriC+6BRCCMYu48cYc9tUN1adfEROqSHZN3HHP4k/fYgncoxrS3OYDX1x8Ysm/\n"
|
||||
"sqxAXBY4NhCMswWvuDYgtQpro9YaFohiorJkHjyLQXjUeZikCfDrlxyR8AM=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAOsjlHgM/lPQgjJyfrq0y+cR+iipcAeS2HAU8CK9SATETOTZYrxoL5vH\n"
|
||||
"1BNteT+JxAxpjva+j7r7XZV41xPDx7alVr8G3zQsjqkAt5NnleTfUREUbg0+OSMV\n"
|
||||
"10gU+DgcZJTMehfGYJnuJsF4eQHio/ZTdJLaZML7qwq0iWg3sZfBAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAK9NjRY7GtAZnlxrAZlImChXmGzml0uk2KlCugvju+eIsjSA/zW3LuqW\n"
|
||||
"wqp7Kh488Ak5nUFSlCaV9GjAexT134pynst8P0m/ofrejwlzl5DHd6sFbR33Fkzl\n"
|
||||
"H48zic0QDY+8tKXI732dA4GveEwZDlxxy8sPcvUDaVyTsuZLHR4zAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key 71DgscFrk4i58O5GuTerI9g3JL0kz+6QaCstAllz9xw=\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf5iAUVMAeaF1muIL7oFEIIxi7jxxhz21Q3Vp18RE6pIdk3cAH5ijeKqa+LM\n"
|
||||
"T5Nb0I42Io4Z7BVjXG7sYVSxrospCOI4dqkl2ln3BKNuEFFT42xJwt+XGz3aMyK2\n"
|
||||
"Cpp8w8I8nwU=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"lAZwD6YVic61NvJ0Iy62cSPuzJl5hJOFYNh9iSG/vn4/lVfnnCik+Gqi2v9pwItC\n"
|
||||
"acwmutCSrMprmmFAW1dgzoU7GzUtdbxaGaOJdg8WwtO4JjFSzScTDB8R6sp0SCAI\n"
|
||||
"PdbzAzJyiMqYcynyyCTiL77iwhUOBPzs2fXlivMtW2E=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 Oyo/eES+/wsgse1f+YSiJDGatBDaiB4fASf7vJ7GxFeD4OfLbB7OYa4hYNEo5NBssNt/PA55AQVSL8hvzBE3Cg\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"wdk26ZtS1H81IxcUThyirANLoszrnYYhOMP57YRAUDEzUr88X6yNDZ5S0tLl+FoT\n"
|
||||
"9XlEVrpN7Z3k4N9WloWb0o/zVVidPMRVwt8YQakSgR8axzMQg6QhQ6zXTiYhiXa4\n"
|
||||
"mawlwYFXsaVDSIIqYA2CudIyF3UBRZuTbw0CFZElMWc=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
|
||||
static const char EX_RI_ED_MISSING_CROSSCERT[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf54AfsyyHhGluzfESzL4LP8AhFEm83+GkFoHbe1KnssVngHAQAgBABNzJRw\n"
|
||||
"BLXT3QMlic0QZ4eG612wkfSRS4yzONIbATKLHIgyzgGiGl4gaSX0JTeHeGfIlu7P\n"
|
||||
"5SKocZVNxm1mp55PG+tgBqHObDRJRSgbOyUbUgfOtcbQGUeVgUlFKWZ9FAY=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMqT7K8cEzWIaPNXbNgvoZ5ejavoszI2OjW9XXetPD/S2f+N7TfQXHBW\n"
|
||||
"bnjpgj87gmk59w0OXTMCv+XofZ0xOy2YR/jG5l1VJIvqgJhhFJ8oSEGVzy+97Ekn\n"
|
||||
"Lb1FEYuVfVxSxnU2jhHW6KPtee/gvuyRI/TvZuwmYWxLRpikVn4pAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAM4nITNe8UykgsIuo5czSSSl3Okr1K+UVWTzDGLznDg77MkLy7mydmk9\n"
|
||||
"vf51OB+ogQhozYKIh9uHvecOzY4EhSIuKhui4hNyQklD9juGoW7RVTSpGdYT1ymp\n"
|
||||
"dDYS30JBPwCZ7KjdMtXiU8ch2WgbzYBuI+JfjwOhfcsuNC9QPfbfAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key lx8o212IYw5Ly2KbH2ua1+fr4YvDq5nKd7LHMdPzTGo=\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
|
||||
"Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
|
||||
"mjQFK4AtRwg=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"cv1yL8HhQzQfjzkSosziu2kMecNUQGle4d103h6tVMoZS1ua1xiDpVKeuWPl9Z0+\n"
|
||||
"wpFwRkOmK0HpNeOXCNHJwfJaWBGQXunB3WQ6Oi1BLilwLtWQixGTYG0hZ6xYLTnX\n"
|
||||
"PdSQIbsohSgCzo9HLTAgTnkyBgklIO1PHJBJsaNOwfI=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
|
||||
static const char EX_RI_ED_MISSING_CROSSCERT2[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf54AXXgm0CUWQr+rxvgdIslqaFdBiwosT+9PaC8zOxYGIsZAQAgBAA6yeH7\n"
|
||||
"3AfGIGuDpVihVUUo0QwguWDPwk2dBJan7B0qgPWF5Y4YL5XDh2nMatskUrtUGCr1\n"
|
||||
"abLYlJPozmYd6QBSv6eyBfITS/oNOMyZpjDiIjcLQD08tVQ2Jho+WmN64wc=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMdyTK/VPZloLUaLsvj1+NOFs33/E9HmA0VgvZ1nNUrR+PxSR71QF7Tw\n"
|
||||
"DKz+/p2rJE+MPfQ/Na3dH0vH4CDZ+FH2m4A8SB9emF8aKxdc/7KCjQNDQCNlEQYn\n"
|
||||
"O9WvZJhbNPHUmX0z4OotI+Sk3qBzVHu0BGDsPYC9gwszIumDUILxAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAL8o6CJiLfW4vdRFvJ2nFt/H/ei0ov83rilOuwSmNORmL9lvnHY++HrD\n"
|
||||
"dmEEvBv74xqWJxGbJ6OQ3VOwRpf2X/cb4gAvsQDqDmNwpJsrPYRQVXp/KY/8z7bJ\n"
|
||||
"dM4CjcsuJHHmj3yc3iCzgqt/Xr6vR24X4bee12/bP7R8IETvWoiHAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key qpNEGrLMVn28Odonk/nDtZq1ljy0fBshwgoAm4X1yzQ=\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"i4RKGIeaUrO6nzfdtb6j+ijYJh1Vgc9bsHMpW9cVCOjoJKFW9xljgl9xp6LytviN\n"
|
||||
"ppKYCt9/JflbZUZjny34ESltPGrdquvHe8TtdQazjiZBWQok/kKnx2i+PioRF/xI\n"
|
||||
"P8D0512kbJjXSuuq9tGl94RKPM/ySGjkTJPevN4TaJE=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 pMAOpepn5Q9MxcV9+Yiftu50oBzBsItQcBV9qdZCIt3lvSFqFY9+wJjaShvW3N9ICHkunrC0h/w5VEfx4SQdDA\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"Du5fJYDzvEeGqKTJwgaQsJJgz39K/J4qEM2TZ3Mh0XuDM1ZWDtjyzP03PaPQqbJ1\n"
|
||||
"FsN5IStjOqN3O1IWuLzGaZGpGVuqcyYOxjs7REkGQn2LfqCjpzjaAdcsL0fI4ain\n"
|
||||
"o/in8GQ6S/qhsx8enKlN0tffTmWmH9bmmVz0+yYmBSo=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_MISSING_CROSSCERT_SIGN[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf54AfoVFYuJnDNBWbjbTqfXACUtXWPipmqEYC++Ok/+4VoFAQAgBADH7JzI\n"
|
||||
"fjSMV158AMiftgNY+KyHYIECuL9SnV3CSO+8+I7+r9n+A3DQQmGLULo/uZnkbteJ\n"
|
||||
"+uy6uRG4kW0fnuBlKhseJQm9hjNGWzC8hmebp1M+bxwG41EGI7BZvnTrRgM=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBALEqlijoFIDX1y1i5zfei8DuDIsFtSw56PGgnMRGcybwD1PRQCheCUZM\n"
|
||||
"erQgFCWjgLgvGJERBK/oILW1dFXp4MAR5RgnrPGTfWTinCj32obMLN1gIczpq6a9\n"
|
||||
"P9uv6Cz0ApSxpA/AuvjyAZwQKbUXuMvIY4aTprAKSqqVohk6E+E1AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMZbbBjGV7xPri4XNmejq4add93p+XsWlsfbM930bcC2JZiwg4g4cq6W\n"
|
||||
"idl8VDmCXeaWg5y3kb82Ch/Q9vPG0QYQbXxUA3JxQKKbcEK3QsEvqQh8Nb7krILK\n"
|
||||
"YnSGAnLG2Nc3PnKb7Wpb8M3rAysC5O99Gq1mSfm8ntj3zlIM7NSHAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key CYcpfIF4T9PJcfROfVJTUYl0zNd4Ia5u0L9eng/EBSo=\n"
|
||||
"ntor-onion-key-crosscert\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf54AcfsnMh+NIxXXnwAyJ+2A1j4rIdggQK4v1KdXcJI77z4AMRc2LxiKbyr\n"
|
||||
"fqRVynHuB031C4TN/HAlNPBjVoRvQRgzpiyyoyCqMDxLZdM8KtzdLLeqZJOXtWod\n"
|
||||
"UXbYG3L70go=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"BRwRAK2lWxWGS49k8gXFHLEQ/h4k8gOQxM0WgCaN4LjAOilLHFjsjXkmKgttVpHl\n"
|
||||
"f0V9ebSf+HgkpQnDSD8ittnr/0QaohUbD4lzslW4e/tQYEiM46soSoFft85J6U3G\n"
|
||||
"D3D63+GmaOfIaa4nv7CD0Rw/Jz0zTuyEuARsdJIr1IY=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 7XfV5r7FXbXPEvrxlecWmAJxat/6VT+/4tE5cHrQnvLM4zslysstWH6/AfIfcmUuDlQ0watmfg1MvVnjavcfDA\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"eigLL3S/oMGL2tJULt9bl3S0iY+YIxdKeGFCcKZci59zD786m+n+BpGM3yPpvrXr\n"
|
||||
"bGvl4IBqCa1I+TqPP1rM9lIEcUWaBT7Zo5uMcL1o+zZl1ZWPWVVKP5hC5ehDueu8\n"
|
||||
"/blzNhTEFAp23ftDK9PnFf+bXxqbgKkEoZsxnd3e9Ns=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
|
||||
static const char EX_RI_ED_BAD_SIG1[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf54AR8QC+SNBpPOTVY198IQBANNwZjy+SBqQNxfzjEmo204AQAgBABjz4FP\n"
|
||||
"zW/G+fu7YirvANvvqJeb7S1YYJnf6IrPaPsPRzDqJcO3/sTzFC5OSb9iJmzQAWnn\n"
|
||||
"ADPOl+nOJC58XJnJ7CUJdPtyoVdMvUiUT/Jtg4RuCN1iDaDYaTh2VavImAY=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAKuLC0kzCBTV6+WPZcAOQPKjqbjvMIyaehIQS1o90dYM+Tosrhtk3bw8\n"
|
||||
"QBLMaiWL3kfIWPZuWi2ai40dmqAXMrXH3yBgKRNZ6zZSbUUuJ1IknqmrQ2PKjC/p\n"
|
||||
"sIW2awC6Tq+zrZ7vntDb02zY857vP59j8eolTDg1Vvn6l2ieL+WhAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMnBQPOJBQLZ3NAa70n6lGZGvS3DYZFNOZ2QnHVeVvOSFIFsuvHtnUdX\n"
|
||||
"svDafznYAuRFRVqJS2xtKKGu0cmy6ulEbBF+4uAEMwQY7dGRPMgVF1Z33U0CSd08\n"
|
||||
"ChCJGPTE7tGGuoeSIGN3mfC4z2v9SP3McBdAiLHisPzaUjfRTcwRAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key W8fUvBpKBoePmqb70rdJUcRT0NhELDWH7/BSXJtkXS0=\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf54AWPPgU/Nb8b5+7tiKu8A2++ol5vtLVhgmd/ois9o+w9HAAPwWqmL0HXa\n"
|
||||
"bYKrKPWQYnpQHQ3Ty0MmCgj3ABF940JURnV161RlN8CRAOJaeQ0Z8wBRLFC1NqLT\n"
|
||||
"+GVdtewGeQA=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"x0vT5Wv7Guc0/Vu2BqomWwenh8oda9+8K/7ILi5GQL/WC29Tj51i0EE7PVSnSMJ7\n"
|
||||
"33I/V+N5neauqWnbg7TxYaLsPfr6SpPTpBL1Xt0OiwT1//PvPYZ1gCcF3ig3KcfI\n"
|
||||
"mreQd5C5Vri6ukWkMtz/zNDaDpDanzaNXTdaUXmFHF4=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"Hci/Br1+NNymDZBmQy1QWMlCeLe8Z1vtZ2ZTj42jDhWg1OC/v72ptI072x4x5cmi\n"
|
||||
"X3EONy8wQUvTNowkfG6/V/B768C7FYJYBId1GAFZZymXnON9zUYnE3z1J20eu6l6\n"
|
||||
"QepmmdvRmteIHMQ7HLSrBuDuXZUDJD0yXm6g8bMT+Ek=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_SIG2[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf54AW8fyx54c7vQQA/AmShAitFP7XI1CLdifEVPSrFKwYq6AQAgBAChqjVA\n"
|
||||
"/wKKJZ30BIQoXe5+QMiPR6meNxF1lBttQ2t5AhauZbH5XzRhZkdGo114wuyPNEM9\n"
|
||||
"PrBwp5akTtari9doVy6gs3McqdoIbRdWevpaGj5g5oOEOtA9b5UNWQSwUAs=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBALp0Croi9zhpGxi9sUj54jr/flZdzxVVS+8VNldJG2c1soSx8kwlwotu\n"
|
||||
"7mGGudJDAzDHGo5F5CCPEfQov2OmDehpefYUz/AaMLly6PrLRJlcUcpLogGf1+KU\n"
|
||||
"1lLwE8kanXUkgvDhVQiFvNjy2Dxxuv3AHH4WdZZfbMbm8FJRGoHzAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMoI9vQT4g2sV2dViGOWOzxckk367T9sMjVwcYfJCmnixGxjWeKScQFB\n"
|
||||
"K9v1uK73cfZR8AxiUGK4/iOX/9en14mJOGF7fftAqypFLAt1TBvb07IgXljOBoHc\n"
|
||||
"Paw4oZoJQzEoazt0Oa181LyNnNIoaZpHVZd1+a1Gs1gKoM4xDBv1AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key KjyvXYkMcpke5ZsUYf2gZAUNeEoz8NAwYoQvvbcDGiw=\n"
|
||||
"ntor-onion-key-crosscert 0\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf54AaGqNUD/AoolnfQEhChd7n5AyI9HqZ43EXWUG21Da3kCAI6MRHm7GpCF\n"
|
||||
"/3zDGR/6jKe625uFZX9HpLt6FgAdGSJeMQ9W4Np9VkrFXAB3gvh7xxRzSgZ1rXgR\n"
|
||||
"lUomgi7N1gc=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"xJXvCCpP4ExBuT3OTsdn2HJB0HidupmQq5zBh8fx/ox6+047ZBOM7+hVxxWapcMg\n"
|
||||
"PMXbcLD4L/FCBpA/rjnFUE/9kztdq7FH/rOdi0nB6FZWhwDcsZuyfvbnDTxz5iHJ\n"
|
||||
"87gd5nXA5PE649SRCxW5LX0OtSiPFPazu4KyyBgnTIM=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"tk4kBNYqB8utOmX30HrV8YfnwBXYODIiL3M/juRS6nPn0uvbW7pjoZ3ck/ahgW+6\n"
|
||||
"FNQsgTJnEADCWS1r6v7PcvzQjtrOUUpNxGJxYw1r8yZkvmIxSQD6GMzuTxq7o1VA\n"
|
||||
"/wZYDLonLhCWRdPjxnrl12+z92NdyISJCHMLRVqs2QY=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_SIG3[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf54AYYiKZrFWZ/Cj5mZbfK11MZHYbwchllsUl4qPqY9gfi6AQAgBAB4irxT\n"
|
||||
"86FYA0NbZssSTmfyG6Edcf0ge61OwB4QD35kHCrvuZk2HnmL+63Tj4QoFqIVnwVC\n"
|
||||
"3wRGJGcmS7y+vS64GUXbuyTgqgpl/KuoHo5Aqe6IxJlVWYtU6W0M6FV9tAM=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMUEvXTVTl5xkQ2MTEsB4sXQ3MQkz8sQrU63rlqglpi1yUv24fotjzvE\n"
|
||||
"oJpeKJBwwg5WBW/fW0bUDJF2cOHRHkj/R4Is3m+2PR1Kn3UbYfxNkFkTE11l099V\n"
|
||||
"H6xlsi0TJOJKlgrcbSuB7se2QctZVhwsdsJvFRptC9Qd+klAPb7tAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMooTeSUX7GPoyklSd1/6cF1u8e2LbjOLIpZrMon0Xt7c/aNwlrG9rVo\n"
|
||||
"TSokHs3AQ2H2XIceySVRRWR4AdX9KApO4CX0gGTuVUmq6hFJWMnHdAs2mKL0kt1w\n"
|
||||
"I+YWzjUqn4jIVa2nMbyHVQWzIysWwWiO4yduIjAYpBbWd9Biew4BAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key BN0I+pLmFkDQD5iRsdkcped4eZwGIuXnLiX2K0Zoi2I=\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf54AXiKvFPzoVgDQ1tmyxJOZ/IboR1x/SB7rU7AHhAPfmQcAOrIvaG/xJqe\n"
|
||||
"adM6mai+FlV8Dbt6QrXTcNHJU1m+CUDthA9TPTAYz9D8W0mTEQ6KEAKGfQrNLy2r\n"
|
||||
"G1B+9wWSpA4=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
|
||||
"JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
|
||||
"M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 abcdvEzGFYMcJ/Ea7sbessW1qRJmnNNo2Khkkl0rEEgtLX0b4L4MMhK/ktS52Y6jX3PRQWK5PZc6gjV7Jaldh+g0Aw\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"Vyj7g3eQ3K4+tm49fJkAtsAYnYHcEiMnlucYCEPeKojzYStNfZwQO2SG5gsoBIif\n"
|
||||
"urgQZ/heaF4uiGFg64UFw08doXqQkd5SHO3B4astslITvmq0jyaqzSXhdB5uUzvp\n"
|
||||
"QCR0fqGLVS1acUiqGbRr4PiZ9G7OJkm230N3rGdet+0=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_SIG4[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AaEnncX/t0cbLm1xrtlUpkXghaA8fVuV7g1VF3YNfCaIAQAgBAC7Ki3S\n"
|
||||
"zzH9Aezz5X4fbwHeF+BQEDfVasfyTxTI4fhRi7t3RxHzBJd60uEMXy2FchD8VO5d\n"
|
||||
"j4Dl7R4btrohPVSVBQZuemBQSW6g3ufNl0txpFWu0R7vBPTFH6oyXYfY9gQ=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBALGKwzhOui2/jJPjU1ngW5IZRPcoDk7RAfGDO4xaef4VfAFHCV9CQO1c\n"
|
||||
"/wQ09CcRdggTvUcv9hJTGJhSObUUooCkxw4/35f/A6/NoW1Gi0JqF9EsQWHpuAfr\n"
|
||||
"n/ATlJQ9oGdTCNDq/BXSPWXhoI6UhUe0wiD4P4x4QwaYHcZh+lE5AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAOKrizVm2h5/jE/HqqLCBLWJZVVoGspasCtDDqHhSqsPzyjpqa52iMKi\n"
|
||||
"q/deJ92le3J2NJRGKxPmPQqWxwhIjnMS5kUMoW182iLpO/G9qyPZ0dh6jXB0NBLF\n"
|
||||
"ySfW6V2s3h4G4D2P+fqnsnzQnAX7YufkvgDau/qTWi2CqD0CjavDAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key A9h8jY9dPbhHTDbIc/NYWXmRP65wwSMrkY1MN8dV3BM=\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AbsqLdLPMf0B7PPlfh9vAd4X4FAQN9Vqx/JPFMjh+FGLAN8xr/w3KFVi\n"
|
||||
"yXoP/az6hIbJh0HYCwH8D1rPoQLcdpe8XVwFSrHGarZesdslIwc9dZa/D1dx3OGO\n"
|
||||
"UhJOrdv51QY=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"bLmdO7ME5vq+c9y/Hd8EyBviMBTeo85sHZF/z6Pehc3Wg3i1BJ8DHSd1cK24Pg48\n"
|
||||
"4WUrGTfonewuzJBDd3MLkKe6epXmvUgvuQN5wQszq1+u9ap/mRf6b3nEG0MHxMlO\n"
|
||||
"FLx5MBsScuo+Q+pwXZa8vPuKTtEjqbVZivdKExJuIX0=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
" router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"LqNGEa10zwSPeomBXTfgvBnnWAdWyiR7KYZq9T++jK4ctR6hUaWngH8qSteUrkMx\n"
|
||||
"gyWb6UMmlxdfOG0sdcU463HsqV7zObaKya8/WwQ9elj3FfsToswUCeOaLR/Rg7wC\n"
|
||||
"zcUjI5VsneQoXT2WVZbZBLsLB3+7QfezVHRMB377GAY=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
;
|
||||
|
||||
static const char EX_RI_ED_BAD_CROSSCERT1[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AV1AfOvQWKlWsbzoBdJc5m72ShIJuA8eNV15basjhXYdAQAgBABy+KQK\n"
|
||||
"3oLDGtqL5kwRmjAsls/+C6SAoAALll7U7wNSH7en5RVBal4RUzCf57ea/KG0c9V8\n"
|
||||
"2DmZ3PdOt2aY/M2bWGmmH/tyyapOoV98dhDwFU7zcx/pMfRnJTDRSDwl8QE=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMP6xbqbj+x1mq5XImjeT0rUzqKZTgBd5zvK4Xcy9IifJuFC9+mMzrY4\n"
|
||||
"WhYbdClxKUkDMkit9MVhek+P/w5TSHKl6AuqGaO09ID+hZpoUSdoBUYktynxfGsx\n"
|
||||
"kIDu0XvgtAeSyJaVvoV1SKVChY0IBbzUqbHt4O2Q1BhzFCKEJTEzAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBANwWlBh7e/eSLlhto5YUdj1iGYOq+yAmlosDItVfYrSPJuUfM2ocMBAn\n"
|
||||
"udbRbWiADoqsbKn/gwwHCC/f1HX2FkRXxxnOlJKLo+NEi8tGmOlcQXSQol1pCpvK\n"
|
||||
"sA9TxtYr+Ft4LRpxNrexF+pIBxqzwetqQrZbKYr0CFJi8q1qlMynAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key cs1AP+xF5cXTLuKeOeItdoDAzfALTJkwk9lB4mtC4QI=\n"
|
||||
"ntor-onion-key-crosscert 3\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AXL4pAregsMa2ovmTBGaMCyWz/4LpICgAAuWXtTvA1IfAKo6ANUq+hi+\n"
|
||||
"xb3J4aYafnszlj87oi/DR+SDf29wzwNw8gmaqGzJ5GbfISfABuTUCzlilZyVnLxi\n"
|
||||
"BHcCH6PWiAQ=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"qC9Kph/kGtONR2DxZDoIFFgnDFC+/7H07EgCiYQdIFIROc+gGK9qBOgeFEptrkXF\n"
|
||||
"XdE35xxox5xSASQvp7hjFwxUtJRGOtf2O98regqeeaz6O9VPXHkLf51uqX3bVgq8\n"
|
||||
"KvFAsFFS66GxhtbrVjpyRgIwHAYvse1WVESfLuZZTn0=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 3uW8Q1aetIQLOsqSco128ZUaHlhqdYiBvrxV7x75BGNS5RzIMTEwYDNtEX1LNPFJ5N0YOV0HEEOLhrJUV9QCBA\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"WuD7S/saTYBxKvItITbHRi8n+e6g/oVbosicfbRbafYPzPp4Prb+RK03UTafzXrV\n"
|
||||
"QEQIzDNhfePcIMH8qX+qrogLMXFqiXx6TVQ0GqNvqirokk8ar3AgtRtewhChAuAj\n"
|
||||
"8pmQTj2JpZn/iB3PCE2l/93O9LHZfp44hc8QOWKs6BE=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_CROSSCERT4[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AW5TTGF9jCMl7aALZzqypD9Bj8WYnAPIrKCoIJdgMbY0AQAgBAB7eCn8\n"
|
||||
"rukx7t/egZUdqU7+FYqsnO4wdmOkLZkp0+gpF3jjk6N1Q0037NNVNZBjONB0Nm2F\n"
|
||||
"CpB3nWSJliSSKr5tOYsuBPFy5VVGYeKPakpOoxanQ1UcqevMBAQy0zf9hwA=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBALeS5YbeDuKQ5iiuUvh3REoyJ47/YU9lslWmTrVBf9b66pMnYJv/awPu\n"
|
||||
"m2HredUAJ3VzwQ38VJA39w3fQXUhQDnQ0OPpKzeAmIiuG+6WdW/mBSK7uKcezC23\n"
|
||||
"LA1d6Afyl79LjZz/n+ENXqNMlJk4QPcPHuRnAvwBl3t8YVRPJmxhAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAPprokY7utWuO/0252dBB5MCxmVD/dROaIBDyFtpdH+YVv04rkOlDzYD\n"
|
||||
"W4mgHVBMxEm/cspTgQmJ4exRHJPpcSe1RYHt1ONZdLYr6D7OOWf0y1IUrVSzF6K4\n"
|
||||
"lqlmNuH1H4+TKGbkvixYc5GU/2ZmAy6gFEuphYnBbsN2Ywc38mnfAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key Cgo6xniGfEiuYoLSPUdE4Vb2D4zj2NQzC1lRjysRRXs=\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
|
||||
"Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
|
||||
"mjQFK4AtRwg=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"bi4M/AJLZF7/vSNmOj4uhrgKBQA/KfcZy5e58mhGL4owxd9vaWfl3aelvb9jf9zN\n"
|
||||
"Q7FMv8f9aXzeVIoXIpRJxSKIJgBtG2wnMumIc80pqBvTyGInharszb6njfm0bg1u\n"
|
||||
"PfJkbQYyf/dA5l5UwCrjFs06ImDmjFTAdsSWf6DfZ/k=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"io16v+e0pK3sbFzPGnkQrAjrRgIOJHrVZ1RXcxZ1+UNXagWM/MOLhQpkU/cw49Wd\n"
|
||||
"4rQeZD3JQh16330eXbxc97AyDgp0b30He846SI0MfW/DnmGI8ZNeYfLbMv2bmbs9\n"
|
||||
"QULzyIH8C+5mnMI1arcuiAua+Dpa34F79vgqPuvw5fU=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_CROSSCERT3[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AVB+j+B2yPgGywvp7nvejyhMh9ejKmw7LCwufV83Zl9eAQAgBAConA3B\n"
|
||||
"jJ3X2tES40jd94rRUFS2/s/Yv7E4LEQ9z0+jz8horNivzK3O/t7IGxJggi+b41/9\n"
|
||||
"Uaqt+wqtVuKj0xJ9jwBlCXFt28G2P9s4ZyXYgGZqo7MlJlboybnOMvmoTQA=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAPWuEWckT4aYAVNrZzLA8xVwfXp0wzfXeTWBztLS8VzssN6w/+cwXdeY\n"
|
||||
"N1YNc2DiD3u8f+7kmuZIqL1EFQUwTvRwEzQXm2dqGM7qkm5ZGNMb5FKu+QwO2ImI\n"
|
||||
"FLNiO5zO/LqP3cf/2L8/DuvruLenUrhRtecGFaHmhDYl+2brHIiPAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMtHTfk0gDvp9+PtIG8Ks7rgCiJZ2aihSvr6WaKHYuIprgspFuga98cg\n"
|
||||
"D//J80CrgH5Dw68YnkG+gU40IxP7YzhQ4glFlJGu3s2y7Qazcv5ww1XtHur+GDoA\n"
|
||||
"cY0zCLhltNQFxIsoVUepY97XA6Y2ejYJjyqNXQcAmoPNoVhnTdkhAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key ibZf57LptdOK3WpVFXkYMatEEqPhuVWxsnkwF6638V4=\n"
|
||||
"ntor-onion-key-crosscert 0\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AaicDcGMndfa0RLjSN33itFQVLb+z9i/sTgsRD3PT6PPAEbkxCdI/bH/\n"
|
||||
"B06DAjRuoDiv1HKsGuW+UN1iGEiWu2ieFzf3m0Z7BL9p2u2zIbHYkP50b3T3sebD\n"
|
||||
"1AksemmMdA0=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
|
||||
"JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
|
||||
"M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 XS4zVi46Xl3xKhuozPCDlW0QRFD4qUhJmkefonQNsRlMVsrPkALnP2tfnfdfTc69hbNa22pOjJNf6Gm505EnAw\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"Q+R3OpO8VhfvFbXuE5qolhVbgosBHy2A5QS91TMzCbsxa8pBA6Li4QdPR37wvdLq\n"
|
||||
"KayfmmNCMKU5qiZMyXqJZm4fdpxiSi50Z0tYlXM3b2OVfza3+pSOEBl89fN6G4Qc\n"
|
||||
"pAmM14eEo1UzXrqZw76tMS2CwOYF5vR2xFGCYC0b5hM=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_CROSSCERT5[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AaCfOaispi7dJhK0c8HXJHIwoBkMgRpmmHu+3Zce/soMAQAgBAB5bAIo\n"
|
||||
"5i4TSY/bV2KQAyziRwvgJm+nEiECClflPbP9Um+zOzOgxtDmNnR5UFQj+VWNG4uf\n"
|
||||
"5lnaryN+PfUXZMTcs8AARof3fFz9tVPINHDrsGvKt8gpzgZEHkVioAXOFwg=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAL3Fr/ovZ9SMGYrAM24taKBm/NpemZaXdD/JeBXFYm5Zs3szLwJC4Etm\n"
|
||||
"zjNL6tVy+I21O1g3cs16TkflcidsjPXNx//PHAn7bqWMekjrt3SQdkHW2gDPgT2c\n"
|
||||
"zYJ/hBR96JYG796jP3pkfJz6Iz5uT/ci3A/cdaVbzM1uZbMUgYGzAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMHB+1dWa8BBrKE94vTqfbkSEuysG5LyyZF/WrqHq/3W+ocDLz795k8O\n"
|
||||
"2Zvgr9im/Ib4hD7IyrtRexcuBdwujdG7cBALdCcWiUTGAMkl96HNETSX+lUVIpJ9\n"
|
||||
"pMsc9O7+yz+/0Cl2RpILZCdE/7I96qHpZl3tzlRKSu15WeIm5U77AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key GXi0a2VLcRHQMMYys85zu3IPqOn5ZTsOixYyQvTGnQs=\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN BUTTERED CRUMPET-----\n"
|
||||
"AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
|
||||
"Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
|
||||
"mjQFK4AtRwg=\n"
|
||||
"-----END BUTTERED CRUMPET-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"T9NHMBhuJo+TlfU3TztNgCc9fK1naNRwPOyoqr5R6lJvJ40jkHnIVOFuvuzvZ35O\n"
|
||||
"QgPbyFcMjv6leV5xcW+/I9tWaBUFXiRGI27qjCFth4Gxq2B6B2dIcQliLXSvW9b+\n"
|
||||
"CMTgDwVa4h2R2PMh18TRx1596ywE09YhCgBF3CwYsiM=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 sRpiP9kyW/DGOphp4V2VCtcKNA8i7zGuv2tnljNIPTB7r7KsTvdUk/Ha9ArRQEivO4nC2HHENtknDl3GtWIPCA\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"DtORw3+gO/yUUIp70xDaWSOgQZrJAAoZTNCB7q5WCoZOngeaCiC1Gtc+Fmdn7tER\n"
|
||||
"uPqQC5H/Kh3Mi82PCj0JxvNivnNTNY1AZVaIX5YoioXVOkWF0B2pqMvFuDSdm2oJ\n"
|
||||
"29PqSVcklquu19EjJRTopIHvYn3sFhQL4LarMsYY11c=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_CROSSCERT6[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55ARMMCtQ8pObC5bq02AUE9Lx2bqsZBBkeOsDZVaEq6JavAQAgBABtV0xF\n"
|
||||
"CsWXL/uFIBnoEsnXBeU1MvYRFrj1vR7QHdWXnxywXvBYUAC8lu/uyc8qqLp+aQSJ\n"
|
||||
"5JzpDYlg3hp1fl5k97iv5F9WrR6s554YpmgYy9agFaxZ4LmRgz7n0UJ8mwM=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAO5qd1TndKD2pEs1ZLWsHlvfO/E7cA0H7NKGLSioGpBf4P0rtkueX4ci\n"
|
||||
"kJNa/4Fn/QsLECqEF2lUjkIc8YL+HMS6qteKvN8+nn16DfvnIhPDNZWTJjLl1bOI\n"
|
||||
"sWSSiduhanoWQnhRtl3Rxg3opdNd9ApO0DLUNy4Qy18Ai6SgksfHAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAJkMYNpK7eJJyGwD/xG/iNg6gzzbIwrOSvmtoP7Rot42qtBiQ9A9kdsy\n"
|
||||
"sazwkWkM93U1+1OaAADPYxeHoyHnuia95Cnc5y2lFSH3I7gnGGSPKSTwXtdyvDWZ\n"
|
||||
"P1LbmQ4Bnh5leTCNZ/eFC4/GjNVzqHxjbb8a11dQhA8dOk8PrUq9AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key HdSQOqvLr4YnJE1XzzVIddgKgnjaHKJqnq0GqF4wXDg=\n"
|
||||
"ntor-onion-key-crosscert 0\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AW1XTEUKxZcv+4UgGegSydcF5TUy9hEWuPW9HtAd1ZefACVwif1deQry\n"
|
||||
"K5GeemRa32sGzujVDDe75WRiPKFT3l/EtjTq3oeVq2xwbVJklnG3ASejKTr3YcHt\n"
|
||||
"ov0jOl0jywc=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN NAUGHTY MARMOSET-----\n"
|
||||
"BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
|
||||
"JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
|
||||
"M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
|
||||
"-----END NAUGHTY MARMOSET-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 lNY8TRX/FZdH5eFbsBkFHuRi8bPDsE5P+v7zExyD/IXnKS/ffYlP8qw1XIPdEDOIzGQ14+kyPX0SotaAqHRtBA\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"BHamS+epF77iozo5cBt+tbs22m9GhwY55DRXpEWAtvn67jsMnmn7qCOLONigK1RT\n"
|
||||
"adZNezIydcCxXltgHTdKaZw4lcqv3s0KL8kI8frbBmm7PjXtWnrdXBYY+YK54MN/\n"
|
||||
"t4N3162o9hzzKSwye0gPjgzpQ1xtEIkzWhBcmE9Vw5s=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_CROSSCERT7[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AfVmH2ReTyatl4VnS5YREtCM2dwikWuAPffq6M5bysZxAQAgBAAXoqE7\n"
|
||||
"taqwLDXLZrZukpF1eBkCwYQK9uzctHTuMdqOHChguvkfX7V4H3O76Ayqvz+Z1ut1\n"
|
||||
"KYRdgiArn3viRaBv3ZKT4Z75suMI3bjqGOSGLAKfOa0uLkOmKblHHhSUkwQ=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAOLNugzUezzzw+N1SuQWzILJYkUJyQDoVXSZjT0dzBplHCjlrv0WZCUP\n"
|
||||
"/pbonE7SlCChIovHcdiASaLj7MVaGgYDq3M1Vtgt5vhgGl10/+evBAD1QEt8AVfr\n"
|
||||
"5+PH/sbZvOWucAhNUhOlqFKAn4vdRY39VEEXC5/Jz5fsk1E/DBu5AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAKxzg1hsYMS+0zAIrgYxSGO0GbKRrL/VhdlMEGu7ACaoqlGnmGQS3B4B\n"
|
||||
"gLk8xDdx9N//8+YTx0hUIxP38w08lubPl1WXMq8s7wAiFd06Nklf65mHs0sXVtS1\n"
|
||||
"EG3f97PQqmBpEJOwYBATNcA9e6F62P8SXNkpSjOzNaE0h9wHNKk7AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key msdr3O4W4bm/xdmZLzj35363ZSFex8yQxLWsV3wRCAQ=\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"VQoABx54AU3MlHAEtgPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
|
||||
"Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
|
||||
"mjQFK4AtRwg=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"RJJRiU0vjVtRi3bVZru3aTvV5l56X/WOOp/ii316yPAS3aAMpOm1+piFVR5MNqcB\n"
|
||||
"ZGyrA2Kx0hawdL2buU47iZ12GOCi4f1Es4V4N0TQgJICsKX38DsRdct9c1qMcqpp\n"
|
||||
"1aENSRuaw0szTIr9OgR7/8stqR5c3iF1H5fOhmTi6xM=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"F3ZqvsyL6RRhPEnNFFIZY4WJM7LK082rseWzRkGNXjwoEwOWUK8enQ4Wjit+wozW\n"
|
||||
"4HVIY1F+vP7gm6IiOEAFgEpB4C8FGuyoFw2q0ONA2tqTcvBJDDnqbx08FO7v2Dij\n"
|
||||
"d3ucfc5gf7YNaoFCMMuyAzC56eyNk4U+6cSKy6wnJds=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
;
|
||||
|
||||
static const char EX_RI_ED_MISPLACED1[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAKT6OIN6TsDB+xcp1uLeE0K3aiHGqa7hdxMBGpvcD0UFSyzpVv1A/fJa\n"
|
||||
"tClDCwTpfTGbyK2L7AO75Ci0c7jf6Pq+V7L6R7o12g6WBTMrgsceC4YqXSKpXNhi\n"
|
||||
"oudJyPfVzBfKcJUSynv89FUQOyul/WRRqWTfv0xUsJ3yjuOESfCNAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AbBV9NVz0Hdl0Uiv87LiXaTAoeSXE+bheNG4Dju1GzQHAQAgBAD16h+T\n"
|
||||
"ygzSgPN4Qat5ITthvm+lvMwMVGbVNWMxNy9i33NGhgp8kqMp2iPAY+LhX8It2b+X\n"
|
||||
"8H9cBmYLO5G7AlMPj7GsuWdCdP/M/ldMvFfznlqeE3pCpRas6W48CFJ+9Ao=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBANMO/MepK3uCkKTLRCwIWc/8URVza2gEmDx6mDTJIB/Mw8U8VRDuu4iJ\n"
|
||||
"v+LL3D8/HGLvT9a8OXbl5525Zszt8XueF3uePBF0Qp0fjGBL8GFqmrmFe6plurPJ\n"
|
||||
"TfrS/m3q+KhXAUowmghciVGDY0kMiDG9X/t/zKLMKWVDYRZk+fupAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key I8yDO62Flx5O/QsFvgb2ArIRqwJLWetHMeZdxngRl2A=\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AfXqH5PKDNKA83hBq3khO2G+b6W8zAxUZtU1YzE3L2LfAGC1uXxN2KwW\n"
|
||||
"w4PqRidM1UPZ5jVOHceZYNQcTzzzArfBpr9OraOO2up4TGte8GVqjJNxrZc1gfjn\n"
|
||||
"CwPW5WxpFg0=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"jLg3D3VO4i0sN8p2qtB6+5C3tai/K4M89mP7z2abQnUTbynOacPoNXIk4o64DjBJ\n"
|
||||
"kaR42yfA7yQZ8Rj8abwgz0Zz6zbd+JjE+s/EklrEEtOl+jZAl3i+92FaHROJojXq\n"
|
||||
"hw+ZEPOb9zgb1UQ7S1Fo+GoqA5bdGm/Wg1kSQielkNE=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 TRKvIl/wIIRD4Xcmd6HYmy7tD0KhVGgoStpWPtX0zmXGZ7+jugItrY0frDu9n82syiruuA45ZOs1Rfi4CbOSCg\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"NYpRfurB1YhFmDAdRc2Sd77S7By2V/0kgEHpJhtySb7efiQsyOA4ZBr1zEFPAXdp\n"
|
||||
"TviKzyS9kN2fnz3hORoqFul33BDZbiLMNLtt5tzp62TYtmIg9IZdjjczbJUgbVLt\n"
|
||||
"KCJL0vM7fdbXkZX61GIBbMYwzwIiHvVxG7F/AS5RbtE=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_MISPLACED2[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55AfJo9FIePrxeDNnWT6SWkoz0/L27018XjUNWEHfaR06MAQAgBAAMgolK\n"
|
||||
"nLg3ZnVv0skzHCfmX+ZR9Ttwj7FNXfhXCsyr860S79OW5LD0/m1GcS9JflWhP+FO\n"
|
||||
"ng5cRb+aqNc8Ul+/4sQudZRx8w4U3d5rOuMGCqhQXnktH9AFzQHFq0jpAAU=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAPeK/znKLRvSUmCIUiZOgfhiRFt7XGN//C2GFuey4xkKiIr9LWMuVe9m\n"
|
||||
"Wx39Ea2UGEtNGCEVvZdJMDVRl7heFTfJTN4L1YeyWx6iNRWlpAmgQOKII7slHwlq\n"
|
||||
"seEULOLOXc9AsU/v9ba9G54DFbHfe2k44ZOwEmaQZW5VF/I0YMMdAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAKFRzlrqPPxEW0nboAJ1qzKFb/vFtvRW0xNVb8RtbOY/NY5FV1hS8yfH\n"
|
||||
"igtugkrOBmWah7cmJhiON2j+TKeBxEoXwJMZeyV+HLbr7nY/mFhad4BQ3Frkl8d6\n"
|
||||
"1kQMhOJswMdwnnVHPNGUob4YAX0SpFA6MpBVj92zmMBeaihqUS9VAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key br8svioLcJCAQxoo3KvlT288p8rb4lQIZNLlplkIKkw=\n"
|
||||
"ntor-onion-key-crosscert 0\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AQyCiUqcuDdmdW/SyTMcJ+Zf5lH1O3CPsU1d+FcKzKvzAG9XqwmRm0uJ\n"
|
||||
"E49NoHcWr9IzdIwSGo+PJSkVpk95a5p2s065BetCWxEEBJQniajQf2hZ36zmV9rq\n"
|
||||
"a6puqkEAKAM=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"d6QGIVAJL5JjHUyV+aicLIdBYyxHwviKpPcp7uldRF8vfDGFpu0qFgJ5KT+3t36w\n"
|
||||
"QY1r75bvUMG/ZzGKDg95dcK0X2AK6GFlcrYyCoQEVOsuPc1QEUeK9P2s7viNQE4V\n"
|
||||
"tRwG/CvJhPfcnxErzVGfXIeYRL1r/hPNFDZSeSxPPM0=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"router-sig-ed25519 ts9pFk8PnDWtXgQad09XC/ZCbruSx1U1pNOMWF9fyoNG0CodxdDH9Vglg+BOS7Nd9fmsINfPWKCVdVuSSM7zCA\n"
|
||||
"reject *:*\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"YMl6mpQm7UCsPQhZKMm0aZ7fzGevWzRbQO+de20HTn7fVqMWQf2hBDJe9QTN/uDK\n"
|
||||
"/VKYT8SnIBexbrSMy1N5q8kNFKxxUtwA9GRtz620Vvc4m+lz/tnT9qucIKCDL5iJ\n"
|
||||
"eRpnls0JoAMIHKl99zdUioYubmOZuqUaRAdT8ulWy+Y=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_CERT1[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn\n"
|
||||
"Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8\n"
|
||||
"dZToQTFSzAQ=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAM4o2DrTwn3wrvUMm41S/hFL5ZtRHGRDh26o8htn14AKMC65vpygKFY7\n"
|
||||
"fUQVClAiJthAs5fD/8sE5XDtQrLnFv5OegQx8kSPuwyS/+5pI1bdxRJvKMOUl2Tc\n"
|
||||
"fAUhzeNBmPvW3lMi9Fksw5sCSAKQ5VH/+DlYvBGZIO49pTnOAty1AgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAMzIsJeEWWjN3Lp6qrzaJGn8uhJPJyjy2Wt3sp7z7iD/yBWW6Q7Jku3e\n"
|
||||
"C5QfKmSmNi2pNjS0SqPjqZZNsbcxpq/bEOcZdysZG1lqi/QgxUevk57RWjh3EFsG\n"
|
||||
"TwK3ougKWB5Q6/3m32dNsnnnDqzVapgZo7Zd3V/aCo0BVtL5VXZbAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key W28nwT/5FJ818M78y/5sNOkxhQ7ENBhjVhGG2j6KvFY=\n"
|
||||
"ntor-onion-key-crosscert 0\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn\n"
|
||||
"Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8\n"
|
||||
"dZToQTFSzAQ=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"FWnEjvFob0ObgqohMT7miwGsAuioCT7Urz6tyWaGWph/TP9hbFWj4MPK5mt998mn\n"
|
||||
"xA8zHSF5n/edu7wVX+rtnPrYPBmg+qN8+Pq6XMg64CwtWu+sqigsi6vtz/TfAIDL\n"
|
||||
"mypENmSY32sWPvy/CA8dAZ2ASh57EH9a+WcFModpXkM=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 88YqJdGJS4O6XiUCNrc9xbOHxujvcN/TkCoRuQQeKfZGHM+4IhI6AcXFlPIfDYq0SAavMhVmzsDDw0ROl7vyCQ\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"cU4WDO3w9ZfVRbNUgxOQMbwS2xWXvaL+cZmIV6AAjAZVWkLEpif4g6uYu+jJUZOS\n"
|
||||
"NUT7lNOMwTu4tE4b1YJpnD9T8iW0DlOXxlvRBMQYmKwhQuYk898BDGTSk+0AY0HJ\n"
|
||||
"vv8wRVewDajNhW7tFY907IdHvPXG0u83GANxkYrRyUg=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_CERT2[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN WOBBLY RUTABAGA-----\n"
|
||||
"helo\n"
|
||||
"-----END WOBBLY RUTABAGA-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBANZvqyqFeiekh8ApqIGK4ZtOqjaX87EzDestvAWwamVOXiPoUrzXgM3O\n"
|
||||
"l8uuTnMA4TfnjLyyA2TnaMzJylOI1OMHuW/D9B/liWDstSxWNNIlKgLQ/Dh9xBS7\n"
|
||||
"uQb2PYlI+iMkPKPyJQSTDdGHE7cdFPewUfhRtJU3F5ztm/3FLBFvAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBANZl8U/Z8KCPS7EBDzt8i9kNETXS7vnp9gnw3BQNXfjiDtDg9eO7ChxY\n"
|
||||
"NBwuOTXmRxfX3W9kvZ0op9Hno6hixIhHzDql+vZ+hN7yPanVVDglSUXcr31yBm5K\n"
|
||||
"kA+ZnRvH3oVQ97E4rRzpi09dtI13Pzu7JS5jRMtH+JF1kQBoNC0dAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key lUrEL+TVXpjjHQ2BIKk34vblyDmoyMro1a6/9hJ4VRc=\n"
|
||||
"ntor-onion-key-crosscert 0\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55Abm5E7FBdd3F8N1xuz/vdv03zh2lABrmGjzPQ3AFJtntALNeQTgjv0JL\n"
|
||||
"jON4+SPNi0B2Bva3yKaSsdxiHQ1rIwQqIUVkzXmmX4jmsvJK/9gERAdD7GafTKZQ\n"
|
||||
"BaZbNXBvmQw=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"OxkqFsw1vHUQ9iPYcKC/MHUBtbLPK6JY2i81ccAai2eW118UXcTbeCRccrXyqSkl\n"
|
||||
"RLcooZyli1D6wg9x7O8+2+HXIbUa6WcTOD1Qi7Z9wKZfk4sDUy7QHKENMRfAXwX3\n"
|
||||
"U/gqd4BflMPp4+XrYfPzz+6yQPWp0t9wXbFv5hZ9F3k=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 fW6Bt4R3xVk5KMDyOcYg8n5ANP0OrQq2PQFK2cW0lTAdi+eX+oT/BeWnkrn0uSWOC/t4omCmH4Rdl8M9xtpfBA\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"DHxiQXuLxZR0ylqwUGGePgN4KF4ItlOV/DuGmmszCO/Ut0p+5s4FP2v6Mm9M92Wj\n"
|
||||
"75rS9xF/Ts0Kf49dvgc+c5VTvhX5I5SwGQkRk0RNJtNoP0t+qXBHaFV8BlAeaWF6\n"
|
||||
"Lg3O+GUK325fQv9uDPCe37mFQV9jafAzsZUrO/ggb1U=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_ED_BAD_CERT3[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"BVVVnf55AW5TTGF9jCMl7aALZzqypD9Bj8WYnAPIrKCoIJdgMbY0AQAgBAB7eCn8\n"
|
||||
"rukx7t/egZUdqU7+FYqsnO4wdmOkLZkp0+gpF3jjk6N1Q0037NNVNZBjONB0Nm2F\n"
|
||||
"CpB3nWSJliSSKr5tOYsuBPFy5VVGYeKPakpOoxanQ1UcqevMBAQy0zf9hwA=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAPgeQNbKwpnTU+qW/2djh66hptS9rcy1B4vdyWkDTdREao2ECuCv691Y\n"
|
||||
"oIw3MpTWvpC1qHIKorunusR0FKgwXw3xQTikXbDq/1ptsekzoIA1R/hltQV3UuGH\n"
|
||||
"zdzHuQXAMX7Fdll2gyya03c3Yq5s+xSDvGdkEeaIoctKjwxp4SdNAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAOzWuH4cPW9rIrfi8MrruMUg4IUVHz4BxfY4/szMIUvzeEAdHn4FYkWy\n"
|
||||
"Vt7MDtUELZsmZeFNmkn72kLxnrdZ5XhxZBriq1Fzq11cSWRBF+SyE1MdcouY4GyG\n"
|
||||
"drw6T8xb8ty19q0eO6C/gw27iqXPAp1clvkroLg6Nv9lGZvsedVDAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key /vYZ+9yLqG7yUnutoI57s96JBl36GTz0IDWE244rbzE=\n"
|
||||
"ntor-onion-key-crosscert 0\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AZ4zVBWP/fIYEgWmyj0WpO6CkXRJjtrWXtiT02k3IddiAMpYgMemGIpN\n"
|
||||
"xj7TQRULsHHYvo4fLcKrSgndQbUUhfLTUuVhIzbnE2TBLMVOEkpxKU6mTuvTT/3h\n"
|
||||
"MJugrwTWVg4=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"c/Vqu3wtsTsYMdnhTS9Tn1Pq6jDmH4uRD5WmbaCKKrkin2DjuYSMVpypndkdlZDE\n"
|
||||
"He7uF7SUO3QG/UcRIXYOsg9MSLUmvn2kIwef8ykyqlRh95Csjo5DyattUhL2w4QF\n"
|
||||
"tJkJBQAnXWaAVW1O8XimGCAvJ84cxbmZEcpN6WKjrXI=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 Ue7bkPpOoc8ca7cyQj/Vq3BP5X4vwLA5QmpLGw/WfRNVRPojJRxU3RVqWMi3JbsJFRTe6pH6ZHyXER33G5aAAA\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"ifKUtbxmqHVs8A0oT5n7Te0c6D/XqWQTc0RxX9OKGspzh6wNX26h0Xa2vpK1Q9Zu\n"
|
||||
"sj61I7vbHuZN6rxiWs9IzJgb//XaNJasX1pd9tbGSXW+yYzc9G9kaa7vp3HcnhIP\n"
|
||||
"XVWzzS8WmOiVNGcF65j6f7yGloTgN7cHMptgJG7pWes=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
static const char EX_RI_BAD_EI_DIGEST2[] =
|
||||
"router fred 127.0.0.1 9001 0 9002\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf55ATrK8IVBWLO2yXKCqXLXJOTu89W2b+hREPO+tCrxjVqWAQAgBACG/vVx\n"
|
||||
"NK8wKVZvf34d75ZObSR0ge1N2RrAIKNslNXBq/tcllIrNE4S0ZNcMpA+hxXoVFeo\n"
|
||||
"jbxifYX7nTs5N3GrGPmkiuo82v2X6ZwoIXJGFnvWMxCjsYsUVDDxoT6h/w8=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"extra-info-digest E5FAC29E766D63F96AD175069640E803F2723765 99oo\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAK9wHSdRalxkuAybrSCA3dlEC1ZGc7oHOzXRGLg+z6batuiCdQtus1Rk\n"
|
||||
"LP821eZJtEMAE56aewCIHDcTiCxVa6DMqmxRjm5pfW4G5H5QCPYT6Fu0RoYck3Ef\n"
|
||||
"vkgits5/fNYGPPVC7k8AdGax5dKj5oFVGq+JWolYFRv6tyR9AThvAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAKxjxTQ/T/MHpFbk7/zwA7l5b3IW3yVcyVe6eIGFoYun8FI0fbYRmR4M\n"
|
||||
"G5Asu07gP9Bbgt3AFPuEqrjg4u+lIkgqTcCgKWJbAgm7fslwaDTXQ36A7I1M95PD\n"
|
||||
"GJ10Dk5v4dVbrqwoF7MSrQPFtMO91RP11nGPSvDqXZJ4XpwqwdxpAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key LuVmHxpj4F5mPXGNi4MtxbIbLMav6frJRBsRgAvpdzo=\n"
|
||||
"ntor-onion-key-crosscert 0\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf55AYb+9XE0rzApVm9/fh3vlk5tJHSB7U3ZGsAgo2yU1cGrAKBcSzwi4lY/\n"
|
||||
"salCELOLdeZzOjDNnBd6cKp2WJg7Yz5zFlbVbyNk0iwfGmucHk8vQZe5BS0Oq/Pz\n"
|
||||
"B1u/BcJv8gk=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"QsAQVdDVHtasDbhrZG4ZxImdTTMY7fz3vouAiGyZx6/jCCB5v0gHwTn4xo6pgLEW\n"
|
||||
"LQfMhQZIr76Ky67c0hAN2hihuDlfvhfVe9c2c5UOH1BOhq3llE3Hc3xGyEy3rw7r\n"
|
||||
"5y38YGi759CvsP2/L8JfXMuBg89OcgJYFa27Q6e6MdQ=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"published 2014-10-05 12:00:00\n"
|
||||
"bandwidth 1000 1000 1000\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 5zoQ0dufeeOJ/tE/BgcWgM8JpfW1ELSXLz4dI+K8YRH/gUtaPmYJgU2QfeUHD0oy1iwv4Qvl8Ferga7aBk1+DA\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"D6KRMwkb6JmVEnpZ825SD3LMB84UmVy0i94xk44OwhoWNKLXhaSTWJgf6AqnPG5o\n"
|
||||
"QrCypSb44bYLn+VaDN5LVUl36jeZqCT4xd+4ZwIRdPOUj7vcVmyUDg3lXcAIk97Q\n"
|
||||
"E5PrQY1mQuLSIjjKInAR2NRBumNJtRw31Y/DTB7tODU=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
"\n"
|
||||
;
|
||||
|
@ -35,6 +35,8 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
|
||||
-DLOCALSTATEDIR="\"$(localstatedir)\"" \
|
||||
-DBINDIR="\"$(bindir)\"" \
|
||||
-I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext" \
|
||||
-I"$(top_srcdir)/src/trunnel" \
|
||||
-I"$(top_srcdir)/src/ext/trunnel" \
|
||||
-DTOR_UNIT_TESTS
|
||||
|
||||
# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
|
||||
@ -67,6 +69,8 @@ src_test_test_SOURCES = \
|
||||
src/test/test_extorport.c \
|
||||
src/test/test_hs.c \
|
||||
src/test/test_introduce.c \
|
||||
src/test/test_keypin.c \
|
||||
src/test/test_link_handshake.c \
|
||||
src/test/test_logging.c \
|
||||
src/test/test_microdesc.c \
|
||||
src/test/test_nodelist.c \
|
||||
@ -135,7 +139,7 @@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
|
||||
@TOR_LDFLAGS_libevent@
|
||||
src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
|
||||
src/common/libor-crypto.a $(LIBDONNA) \
|
||||
src/common/libor-event.a \
|
||||
src/common/libor-event.a src/trunnel/libor-trunnel.a \
|
||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
|
||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
|
||||
@TOR_SYSTEMD_LIBS@
|
||||
|
@ -1137,6 +1137,8 @@ extern struct testcase_t guardfraction_tests[];
|
||||
extern struct testcase_t extorport_tests[];
|
||||
extern struct testcase_t hs_tests[];
|
||||
extern struct testcase_t introduce_tests[];
|
||||
extern struct testcase_t keypin_tests[];
|
||||
extern struct testcase_t link_handshake_tests[];
|
||||
extern struct testcase_t logging_tests[];
|
||||
extern struct testcase_t microdesc_tests[];
|
||||
extern struct testcase_t nodelist_tests[];
|
||||
@ -1183,6 +1185,8 @@ struct testgroup_t testgroups[] = {
|
||||
{ "extorport/", extorport_tests },
|
||||
{ "hs/", hs_tests },
|
||||
{ "introduce/", introduce_tests },
|
||||
{ "keypin/", keypin_tests },
|
||||
{ "link-handshake/", link_handshake_tests },
|
||||
{ "nodelist/", nodelist_tests },
|
||||
{ "oom/", oom_tests },
|
||||
{ "options/", options_tests },
|
||||
|
@ -495,6 +495,43 @@ test_container_smartlist_join(void *arg)
|
||||
tor_free(joined);
|
||||
}
|
||||
|
||||
static void
|
||||
test_container_smartlist_pos(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
smartlist_t *sl = smartlist_new();
|
||||
|
||||
smartlist_add(sl, tor_strdup("This"));
|
||||
smartlist_add(sl, tor_strdup("is"));
|
||||
smartlist_add(sl, tor_strdup("a"));
|
||||
smartlist_add(sl, tor_strdup("test"));
|
||||
smartlist_add(sl, tor_strdup("for"));
|
||||
smartlist_add(sl, tor_strdup("a"));
|
||||
smartlist_add(sl, tor_strdup("function"));
|
||||
|
||||
/* Test string_pos */
|
||||
tt_int_op(smartlist_string_pos(NULL, "Fred"), ==, -1);
|
||||
tt_int_op(smartlist_string_pos(sl, "Fred"), ==, -1);
|
||||
tt_int_op(smartlist_string_pos(sl, "This"), ==, 0);
|
||||
tt_int_op(smartlist_string_pos(sl, "a"), ==, 2);
|
||||
tt_int_op(smartlist_string_pos(sl, "function"), ==, 6);
|
||||
|
||||
/* Test pos */
|
||||
tt_int_op(smartlist_pos(NULL, "Fred"), ==, -1);
|
||||
tt_int_op(smartlist_pos(sl, "Fred"), ==, -1);
|
||||
tt_int_op(smartlist_pos(sl, "This"), ==, -1);
|
||||
tt_int_op(smartlist_pos(sl, "a"), ==, -1);
|
||||
tt_int_op(smartlist_pos(sl, "function"), ==, -1);
|
||||
tt_int_op(smartlist_pos(sl, smartlist_get(sl,0)), ==, 0);
|
||||
tt_int_op(smartlist_pos(sl, smartlist_get(sl,2)), ==, 2);
|
||||
tt_int_op(smartlist_pos(sl, smartlist_get(sl,5)), ==, 5);
|
||||
tt_int_op(smartlist_pos(sl, smartlist_get(sl,6)), ==, 6);
|
||||
|
||||
done:
|
||||
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
|
||||
smartlist_free(sl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_container_smartlist_ints_eq(void *arg)
|
||||
{
|
||||
@ -1053,6 +1090,7 @@ struct testcase_t container_tests[] = {
|
||||
CONTAINER_LEGACY(smartlist_overlap),
|
||||
CONTAINER_LEGACY(smartlist_digests),
|
||||
CONTAINER_LEGACY(smartlist_join),
|
||||
CONTAINER_LEGACY(smartlist_pos),
|
||||
CONTAINER(smartlist_ints_eq, 0),
|
||||
CONTAINER_LEGACY(bitarray),
|
||||
CONTAINER_LEGACY(digestset),
|
||||
|
@ -698,9 +698,18 @@ test_crypto_formats(void *arg)
|
||||
for (idx = 0; idx < 10; ++idx) {
|
||||
i = base64_encode(data2, 1024, data1, idx, 0);
|
||||
tt_int_op(i, OP_GE, 0);
|
||||
tt_int_op(i, OP_EQ, strlen(data2));
|
||||
j = base64_decode(data3, 1024, data2, i);
|
||||
tt_int_op(j,OP_EQ, idx);
|
||||
tt_mem_op(data3,OP_EQ, data1, idx);
|
||||
|
||||
i = base64_encode_nopad(data2, 1024, (uint8_t*)data1, idx);
|
||||
tt_int_op(i, OP_GE, 0);
|
||||
tt_int_op(i, OP_EQ, strlen(data2));
|
||||
tt_assert(! strchr(data2, '='));
|
||||
j = base64_decode_nopad((uint8_t*)data3, 1024, data2, i);
|
||||
tt_int_op(j, OP_EQ, idx);
|
||||
tt_mem_op(data3,OP_EQ, data1, idx);
|
||||
}
|
||||
|
||||
strlcpy(data1, "Test string that contains 35 chars.", 1024);
|
||||
@ -1264,6 +1273,8 @@ test_crypto_ed25519_simple(void *arg)
|
||||
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec1));
|
||||
|
||||
tt_mem_op(pub1.pubkey, OP_EQ, pub2.pubkey, sizeof(pub1.pubkey));
|
||||
tt_assert(ed25519_pubkey_eq(&pub1, &pub2));
|
||||
tt_assert(ed25519_pubkey_eq(&pub1, &pub1));
|
||||
|
||||
memcpy(&kp1.pubkey, &pub1, sizeof(pub1));
|
||||
memcpy(&kp1.seckey, &sec1, sizeof(sec1));
|
||||
@ -1283,6 +1294,7 @@ test_crypto_ed25519_simple(void *arg)
|
||||
/* Wrong public key doesn't work. */
|
||||
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec2));
|
||||
tt_int_op(-1, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub2));
|
||||
tt_assert(! ed25519_pubkey_eq(&pub1, &pub2));
|
||||
|
||||
/* Wrong message doesn't work. */
|
||||
tt_int_op(0, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub1));
|
||||
@ -1421,9 +1433,10 @@ test_crypto_ed25519_test_vectors(void *arg)
|
||||
static void
|
||||
test_crypto_ed25519_encode(void *arg)
|
||||
{
|
||||
char buf[ED25519_BASE64_LEN+1];
|
||||
char buf[ED25519_SIG_BASE64_LEN+1];
|
||||
ed25519_keypair_t kp;
|
||||
ed25519_public_key_t pk;
|
||||
ed25519_signature_t sig1, sig2;
|
||||
char *mem_op_hex_tmp = NULL;
|
||||
(void) arg;
|
||||
|
||||
@ -1434,6 +1447,11 @@ test_crypto_ed25519_encode(void *arg)
|
||||
tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk, buf));
|
||||
tt_mem_op(kp.pubkey.pubkey, OP_EQ, pk.pubkey, ED25519_PUBKEY_LEN);
|
||||
|
||||
tt_int_op(0, OP_EQ, ed25519_sign(&sig1, (const uint8_t*)"ABC", 3, &kp));
|
||||
tt_int_op(0, OP_EQ, ed25519_signature_to_base64(buf, &sig1));
|
||||
tt_int_op(0, OP_EQ, ed25519_signature_from_base64(&sig2, buf));
|
||||
tt_mem_op(sig1.sig, OP_EQ, sig2.sig, ED25519_SIG_LEN);
|
||||
|
||||
/* Test known value. */
|
||||
tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk,
|
||||
"lVIuIctLjbGZGU5wKMNXxXlSE3cW4kaqkqm04u6pxvM"));
|
||||
|
@ -14,15 +14,18 @@
|
||||
#define NETWORKSTATUS_PRIVATE
|
||||
#include "or.h"
|
||||
#include "config.h"
|
||||
#include "crypto_ed25519.h"
|
||||
#include "directory.h"
|
||||
#include "dirserv.h"
|
||||
#include "dirvote.h"
|
||||
#include "hibernate.h"
|
||||
#include "networkstatus.h"
|
||||
#include "router.h"
|
||||
#include "routerkeys.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "test.h"
|
||||
#include "torcert.h"
|
||||
|
||||
static void
|
||||
test_dir_nicknames(void *arg)
|
||||
@ -87,8 +90,11 @@ test_dir_formats(void *arg)
|
||||
routerinfo_t *rp1 = NULL, *rp2 = NULL;
|
||||
addr_policy_t *ex1, *ex2;
|
||||
routerlist_t *dir1 = NULL, *dir2 = NULL;
|
||||
uint8_t *rsa_cc = NULL;
|
||||
tor_cert_t *ntor_cc = NULL;
|
||||
or_options_t *options = get_options_mutable();
|
||||
const addr_policy_t *p;
|
||||
time_t now = time(NULL);
|
||||
|
||||
(void)arg;
|
||||
pk1 = pk_generate(0);
|
||||
@ -127,14 +133,33 @@ test_dir_formats(void *arg)
|
||||
ex2->prt_min = ex2->prt_max = 24;
|
||||
r2 = tor_malloc_zero(sizeof(routerinfo_t));
|
||||
r2->addr = 0x0a030201u; /* 10.3.2.1 */
|
||||
ed25519_keypair_t kp1, kp2;
|
||||
ed25519_secret_key_from_seed(&kp1.seckey,
|
||||
(const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
|
||||
ed25519_public_key_generate(&kp1.pubkey, &kp1.seckey);
|
||||
ed25519_secret_key_from_seed(&kp2.seckey,
|
||||
(const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
|
||||
ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey);
|
||||
r2->signing_key_cert = tor_cert_create(&kp1,
|
||||
CERT_TYPE_ID_SIGNING,
|
||||
&kp2.pubkey,
|
||||
now, 86400,
|
||||
CERT_FLAG_INCLUDE_SIGNING_KEY);
|
||||
char cert_buf[256];
|
||||
base64_encode(cert_buf, sizeof(cert_buf),
|
||||
(const char*)r2->signing_key_cert->encoded,
|
||||
r2->signing_key_cert->encoded_len,
|
||||
BASE64_ENCODE_MULTILINE);
|
||||
r2->platform = tor_strdup(platform);
|
||||
r2->cache_info.published_on = 5;
|
||||
r2->or_port = 9005;
|
||||
r2->dir_port = 0;
|
||||
r2->onion_pkey = crypto_pk_dup_key(pk2);
|
||||
r2->onion_curve25519_pkey = tor_malloc_zero(sizeof(curve25519_public_key_t));
|
||||
curve25519_public_from_base64(r2->onion_curve25519_pkey,
|
||||
"skyinAnvardNostarsNomoonNowindormistsorsnow");
|
||||
curve25519_keypair_t r2_onion_keypair;
|
||||
curve25519_keypair_generate(&r2_onion_keypair, 0);
|
||||
r2->onion_curve25519_pkey = tor_memdup(&r2_onion_keypair.pubkey,
|
||||
sizeof(curve25519_public_key_t));
|
||||
r2->identity_pkey = crypto_pk_dup_key(pk1);
|
||||
r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000;
|
||||
r2->exit_policy = smartlist_new();
|
||||
@ -150,7 +175,7 @@ test_dir_formats(void *arg)
|
||||
/* XXXX025 router_dump_to_string should really take this from ri.*/
|
||||
options->ContactInfo = tor_strdup("Magri White "
|
||||
"<magri@elsewhere.example.com>");
|
||||
buf = router_dump_router_to_string(r1, pk2);
|
||||
buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL);
|
||||
tor_free(options->ContactInfo);
|
||||
tt_assert(buf);
|
||||
|
||||
@ -183,7 +208,7 @@ test_dir_formats(void *arg)
|
||||
tt_str_op(buf,OP_EQ, buf2);
|
||||
tor_free(buf);
|
||||
|
||||
buf = router_dump_router_to_string(r1, pk2);
|
||||
buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL);
|
||||
tt_assert(buf);
|
||||
cp = buf;
|
||||
rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
|
||||
@ -201,6 +226,10 @@ test_dir_formats(void *arg)
|
||||
|
||||
strlcpy(buf2,
|
||||
"router Fred 10.3.2.1 9005 0 0\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n", sizeof(buf2));
|
||||
strlcat(buf2, cert_buf, sizeof(buf2));
|
||||
strlcat(buf2, "-----END ED25519 CERT-----\n"
|
||||
"platform Tor "VERSION" on ", sizeof(buf2));
|
||||
strlcat(buf2, get_uname(), sizeof(buf2));
|
||||
strlcat(buf2, "\n"
|
||||
@ -215,19 +244,52 @@ test_dir_formats(void *arg)
|
||||
strlcat(buf2, pk2_str, sizeof(buf2));
|
||||
strlcat(buf2, "signing-key\n", sizeof(buf2));
|
||||
strlcat(buf2, pk1_str, sizeof(buf2));
|
||||
strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
|
||||
strlcat(buf2, "ntor-onion-key "
|
||||
"skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2));
|
||||
strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
|
||||
strlcat(buf2, "router-signature\n", sizeof(buf2));
|
||||
int rsa_cc_len;
|
||||
rsa_cc = make_tap_onion_key_crosscert(pk2,
|
||||
&kp1.pubkey,
|
||||
pk1,
|
||||
&rsa_cc_len);
|
||||
tt_assert(rsa_cc);
|
||||
base64_encode(cert_buf, sizeof(cert_buf), (char*)rsa_cc, rsa_cc_len,
|
||||
BASE64_ENCODE_MULTILINE);
|
||||
strlcat(buf2, "onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n", sizeof(buf2));
|
||||
strlcat(buf2, cert_buf, sizeof(buf2));
|
||||
strlcat(buf2, "-----END CROSSCERT-----\n", sizeof(buf2));
|
||||
int ntor_cc_sign;
|
||||
ntor_cc = make_ntor_onion_key_crosscert(&r2_onion_keypair,
|
||||
&kp1.pubkey,
|
||||
r2->cache_info.published_on,
|
||||
MIN_ONION_KEY_LIFETIME,
|
||||
&ntor_cc_sign);
|
||||
tt_assert(ntor_cc);
|
||||
base64_encode(cert_buf, sizeof(cert_buf),
|
||||
(char*)ntor_cc->encoded, ntor_cc->encoded_len,
|
||||
BASE64_ENCODE_MULTILINE);
|
||||
tor_snprintf(buf2+strlen(buf2), sizeof(buf2)-strlen(buf2),
|
||||
"ntor-onion-key-crosscert %d\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"%s"
|
||||
"-----END ED25519 CERT-----\n", ntor_cc_sign, cert_buf);
|
||||
|
||||
buf = router_dump_router_to_string(r2, pk1);
|
||||
strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
|
||||
strlcat(buf2, "ntor-onion-key ", sizeof(buf2));
|
||||
base64_encode(cert_buf, sizeof(cert_buf),
|
||||
(const char*)r2_onion_keypair.pubkey.public_key, 32,
|
||||
BASE64_ENCODE_MULTILINE);
|
||||
strlcat(buf2, cert_buf, sizeof(buf2));
|
||||
strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
|
||||
strlcat(buf2, "router-sig-ed25519 ", sizeof(buf2));
|
||||
|
||||
buf = router_dump_router_to_string(r2, pk1, pk2, &r2_onion_keypair, &kp2);
|
||||
tt_assert(buf);
|
||||
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
|
||||
* twice */
|
||||
tt_str_op(buf,OP_EQ, buf2);
|
||||
|
||||
tt_str_op(buf, OP_EQ, buf2);
|
||||
tor_free(buf);
|
||||
|
||||
buf = router_dump_router_to_string(r2, pk1);
|
||||
buf = router_dump_router_to_string(r2, pk1, NULL, NULL, NULL);
|
||||
cp = buf;
|
||||
rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
|
||||
tt_assert(rp2);
|
||||
@ -280,6 +342,7 @@ test_dir_formats(void *arg)
|
||||
if (rp2)
|
||||
routerinfo_free(rp2);
|
||||
|
||||
tor_free(rsa_cc);
|
||||
tor_free(buf);
|
||||
tor_free(pk1_str);
|
||||
tor_free(pk2_str);
|
||||
@ -293,7 +356,7 @@ test_dir_formats(void *arg)
|
||||
#include "failing_routerdescs.inc"
|
||||
|
||||
static void
|
||||
test_dir_routerparse_bad(void *arg)
|
||||
test_dir_routerinfo_parsing(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
@ -318,6 +381,8 @@ test_dir_routerparse_bad(void *arg)
|
||||
CHECK_OK(EX_RI_MINIMAL);
|
||||
CHECK_OK(EX_RI_MAXIMAL);
|
||||
|
||||
CHECK_OK(EX_RI_MINIMAL_ED);
|
||||
|
||||
/* good annotations prepended */
|
||||
routerinfo_free(ri);
|
||||
ri = router_parse_entry_from_string(EX_RI_MINIMAL, NULL, 0, 0,
|
||||
@ -376,8 +441,28 @@ test_dir_routerparse_bad(void *arg)
|
||||
CHECK_FAIL(EX_RI_BAD_FAMILY, 0);
|
||||
CHECK_FAIL(EX_RI_ZERO_ORPORT, 0);
|
||||
|
||||
CHECK_FAIL(EX_RI_ED_MISSING_CROSSCERT, 0);
|
||||
CHECK_FAIL(EX_RI_ED_MISSING_CROSSCERT2, 0);
|
||||
CHECK_FAIL(EX_RI_ED_MISSING_CROSSCERT_SIGN, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_SIG1, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_SIG2, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_SIG3, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_SIG4, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT1, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT3, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT4, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT5, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT6, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT7, 0);
|
||||
CHECK_FAIL(EX_RI_ED_MISPLACED1, 0);
|
||||
CHECK_FAIL(EX_RI_ED_MISPLACED2, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_CERT1, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_CERT2, 0);
|
||||
CHECK_FAIL(EX_RI_ED_BAD_CERT3, 0);
|
||||
|
||||
/* This is allowed; we just ignore it. */
|
||||
CHECK_OK(EX_RI_BAD_EI_DIGEST);
|
||||
CHECK_OK(EX_RI_BAD_EI_DIGEST2);
|
||||
|
||||
#undef CHECK_FAIL
|
||||
#undef CHECK_OK
|
||||
@ -433,20 +518,34 @@ test_dir_extrainfo_parsing(void *arg)
|
||||
tt_assert(ei->pending_sig);
|
||||
CHECK_OK(EX_EI_MAXIMAL);
|
||||
tt_assert(ei->pending_sig);
|
||||
CHECK_OK(EX_EI_GOOD_ED_EI);
|
||||
tt_assert(ei->pending_sig);
|
||||
|
||||
map = (struct digest_ri_map_t *)digestmap_new();
|
||||
ADD(EX_EI_MINIMAL);
|
||||
ADD(EX_EI_MAXIMAL);
|
||||
ADD(EX_EI_GOOD_ED_EI);
|
||||
ADD(EX_EI_BAD_FP);
|
||||
ADD(EX_EI_BAD_NICKNAME);
|
||||
ADD(EX_EI_BAD_TOKENS);
|
||||
ADD(EX_EI_BAD_START);
|
||||
ADD(EX_EI_BAD_PUBLISHED);
|
||||
|
||||
ADD(EX_EI_ED_MISSING_SIG);
|
||||
ADD(EX_EI_ED_MISSING_CERT);
|
||||
ADD(EX_EI_ED_BAD_CERT1);
|
||||
ADD(EX_EI_ED_BAD_CERT2);
|
||||
ADD(EX_EI_ED_BAD_SIG1);
|
||||
ADD(EX_EI_ED_BAD_SIG2);
|
||||
ADD(EX_EI_ED_MISPLACED_CERT);
|
||||
ADD(EX_EI_ED_MISPLACED_SIG);
|
||||
|
||||
CHECK_OK(EX_EI_MINIMAL);
|
||||
tt_assert(!ei->pending_sig);
|
||||
CHECK_OK(EX_EI_MAXIMAL);
|
||||
tt_assert(!ei->pending_sig);
|
||||
CHECK_OK(EX_EI_GOOD_ED_EI);
|
||||
tt_assert(!ei->pending_sig);
|
||||
|
||||
CHECK_FAIL(EX_EI_BAD_SIG1,1);
|
||||
CHECK_FAIL(EX_EI_BAD_SIG2,1);
|
||||
@ -457,6 +556,15 @@ test_dir_extrainfo_parsing(void *arg)
|
||||
CHECK_FAIL(EX_EI_BAD_START,0);
|
||||
CHECK_FAIL(EX_EI_BAD_PUBLISHED,0);
|
||||
|
||||
CHECK_FAIL(EX_EI_ED_MISSING_SIG,0);
|
||||
CHECK_FAIL(EX_EI_ED_MISSING_CERT,0);
|
||||
CHECK_FAIL(EX_EI_ED_BAD_CERT1,0);
|
||||
CHECK_FAIL(EX_EI_ED_BAD_CERT2,0);
|
||||
CHECK_FAIL(EX_EI_ED_BAD_SIG1,0);
|
||||
CHECK_FAIL(EX_EI_ED_BAD_SIG2,0);
|
||||
CHECK_FAIL(EX_EI_ED_MISPLACED_CERT,0);
|
||||
CHECK_FAIL(EX_EI_ED_MISPLACED_SIG,0);
|
||||
|
||||
#undef CHECK_OK
|
||||
#undef CHECK_FAIL
|
||||
|
||||
@ -1394,6 +1502,7 @@ generate_ri_from_rs(const vote_routerstatus_t *vrs)
|
||||
static time_t published = 0;
|
||||
|
||||
r = tor_malloc_zero(sizeof(routerinfo_t));
|
||||
r->cert_expiration_time = TIME_MAX;
|
||||
memcpy(r->cache_info.identity_digest, rs->identity_digest, DIGEST_LEN);
|
||||
memcpy(r->cache_info.signed_descriptor_digest, rs->descriptor_digest,
|
||||
DIGEST_LEN);
|
||||
@ -3108,7 +3217,7 @@ test_dir_packages(void *arg)
|
||||
struct testcase_t dir_tests[] = {
|
||||
DIR_LEGACY(nicknames),
|
||||
DIR_LEGACY(formats),
|
||||
DIR(routerparse_bad, 0),
|
||||
DIR(routerinfo_parsing, 0),
|
||||
DIR(extrainfo_parsing, 0),
|
||||
DIR(parse_router_list, TT_FORK),
|
||||
DIR(load_routers, TT_FORK),
|
||||
|
255
src/test/test_keypin.c
Normal file
255
src/test/test_keypin.c
Normal file
@ -0,0 +1,255 @@
|
||||
/* Copyright (c) 2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "orconfig.h"
|
||||
#define KEYPIN_PRIVATE
|
||||
#include "or.h"
|
||||
#include "keypin.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static void
|
||||
test_keypin_parse_line(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
keypin_ent_t *ent = NULL;
|
||||
|
||||
/* Good line */
|
||||
ent = keypin_parse_journal_line(
|
||||
"aGVyZSBpcyBhIGdvb2Qgc2hhMSE "
|
||||
"VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4");
|
||||
tt_assert(ent);
|
||||
tt_mem_op(ent->rsa_id, ==, "here is a good sha1!", 20);
|
||||
tt_mem_op(ent->ed25519_key, ==, "This ed25519 scoffs at the sha1.", 32);
|
||||
tor_free(ent); ent = NULL;
|
||||
|
||||
/* Good line with extra stuff we will ignore. */
|
||||
ent = keypin_parse_journal_line(
|
||||
"aGVyZSBpcyBhIGdvb2Qgc2hhMSE "
|
||||
"VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4helloworld");
|
||||
tt_assert(ent);
|
||||
tt_mem_op(ent->rsa_id, ==, "here is a good sha1!", 20);
|
||||
tt_mem_op(ent->ed25519_key, ==, "This ed25519 scoffs at the sha1.", 32);
|
||||
tor_free(ent); ent = NULL;
|
||||
|
||||
/* Bad line: no space in the middle. */
|
||||
ent = keypin_parse_journal_line(
|
||||
"aGVyZSBpcyBhIGdvb2Qgc2hhMSE?"
|
||||
"VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4");
|
||||
tt_assert(! ent);
|
||||
|
||||
/* Bad line: bad base64 in RSA ID */
|
||||
ent = keypin_parse_journal_line(
|
||||
"aGVyZSBpcyBhIGdv!2Qgc2hhMSE "
|
||||
"VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4");
|
||||
tt_assert(! ent);
|
||||
|
||||
/* Bad line: bad base64 in Ed25519 */
|
||||
ent = keypin_parse_journal_line(
|
||||
"aGVyZSBpcyBhIGdvb2Qgc2hhMSE "
|
||||
"VGhpcyBlZDI1NTE5IHNjb2ZmcyB!dCB0aGUgc2hhMS4");
|
||||
tt_assert(! ent);
|
||||
|
||||
done:
|
||||
tor_free(ent);
|
||||
}
|
||||
|
||||
static smartlist_t *mock_addent_got = NULL;
|
||||
static void
|
||||
mock_addent(keypin_ent_t *ent)
|
||||
{
|
||||
smartlist_add(mock_addent_got, ent);
|
||||
keypin_add_entry_to_map__real(ent);
|
||||
}
|
||||
|
||||
static void
|
||||
test_keypin_parse_file(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
mock_addent_got = smartlist_new();
|
||||
MOCK(keypin_add_entry_to_map, mock_addent);
|
||||
|
||||
/* Simple, minimal, correct example. */
|
||||
const char data1[] =
|
||||
"PT09PT09PT09PT09PT09PT09PT0 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0\n"
|
||||
"TG9yYXggaXBzdW0gZ3J1dnZ1bHU cyB0aG5lZWQgYW1ldCwgc25lcmdlbGx5IG9uY2UtbGU\n"
|
||||
"ciBsZXJraW0sIHNlZCBkbyBiYXI YmFsb290IHRlbXBvciBnbHVwcGl0dXMgdXQgbGFib3I\n"
|
||||
"ZSBldCB0cnVmZnVsYSBtYWduYSA YWxpcXVhLiBVdCBlbmltIGFkIGdyaWNrbGUtZ3Jhc3M\n"
|
||||
"dmVuaWFtLCBxdWlzIG1pZmYtbXU ZmZlcmVkIGdhLXp1bXBjbyBsYWJvcmlzIG5pc2kgdXQ\n"
|
||||
"Y3J1ZmZ1bHVzIGV4IGVhIHNjaGw b3BwaXR5IGNvbnNlcXVhdC4gRHVpcyBhdXRlIHNuYXI\n"
|
||||
"Z2dsZSBpbiBzd29tZWVzd2FucyA aW4gdm9sdXB0YXRlIGF4ZS1oYWNrZXIgZXNzZSByaXA\n"
|
||||
"cHVsdXMgY3J1bW1paSBldSBtb28 ZiBudWxsYSBzbnV2di5QTFVHSFBMT1ZFUlhZWlpZLi4\n";
|
||||
|
||||
tt_int_op(0, ==, keypin_load_journal_impl(data1, strlen(data1)));
|
||||
tt_int_op(8, ==, smartlist_len(mock_addent_got));
|
||||
keypin_ent_t *ent = smartlist_get(mock_addent_got, 2);
|
||||
tt_mem_op(ent->rsa_id, ==, "r lerkim, sed do bar", 20);
|
||||
tt_mem_op(ent->ed25519_key, ==, "baloot tempor gluppitus ut labor", 32);
|
||||
|
||||
/* More complex example: weird lines, bogus lines,
|
||||
duplicate/conflicting lines */
|
||||
const char data2[] =
|
||||
"PT09PT09PT09PT09PT09PT09PT0 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0\n"
|
||||
"# This is a comment.\n"
|
||||
" \n"
|
||||
"QXQgdGhlIGVuZCBvZiB0aGUgeWU YXIgS3VycmVta2FybWVycnVrIHNhaWQgdG8gaGltLCA\n"
|
||||
"IllvdSBoYXZlIG1hZGUgYSBnb28 ZCBiZWdpbm5pbmcuIiBCdXQgbm8gbW9yZS4gV2l6YXI\n"
|
||||
"\n"
|
||||
"ZHMgc3BlYWsgdHJ1dGgsIGFuZCA aXQgd2FzIHRydWUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n"
|
||||
"@reserved for a future extension \n"
|
||||
"eSBvZiBOYW1lcyB0aGF0IEdlZCA aGFkIHRvaWxlZCbyB3aW4gdGhhdCB5ZWFyIHdhcyA\n"
|
||||
"eSBvZiBOYW1lcyB0aGF0IEdlZCA aGFkIHRvaWxlZCbyB3aW4gdGhhdCB5ZWFyIHdhcy"
|
||||
"A line too long\n"
|
||||
"dGhlIG1lcmUgc3RhcnQgb2Ygd2g YXQgaGUgbXVzdCBnbyBvb!BsZWFybmluZy4uLi4uLi4\n"
|
||||
"ZHMgc3BlYWsgdaJ1dGgsIGFuZCA aXQgd2FzIHRydWUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n"
|
||||
"ZHMgc3BlYWsgdHJ1dGgsIGFuZCA aXQgd2FzIHRydaUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n"
|
||||
;
|
||||
|
||||
tt_int_op(0, ==, keypin_load_journal_impl(data2, strlen(data2)));
|
||||
tt_int_op(11, ==, smartlist_len(mock_addent_got));
|
||||
ent = smartlist_get(mock_addent_got, 9);
|
||||
tt_mem_op(ent->rsa_id, ==, "\"You have made a goo", 20);
|
||||
tt_mem_op(ent->ed25519_key, ==, "d beginning.\" But no more. Wizar", 32);
|
||||
|
||||
ent = smartlist_get(mock_addent_got, 10);
|
||||
tt_mem_op(ent->rsa_id, ==, "ds speak truth, and ", 20);
|
||||
tt_mem_op(ent->ed25519_key, ==, "it was true that all the master\n", 32);
|
||||
|
||||
/* File truncated before NL */
|
||||
const char data3[] =
|
||||
"Tm8gZHJhZ29uIGNhbiByZXNpc3Q IHRoZSBmYXNjaW5hdGlvbiBvZiByaWRkbGluZyB0YWw";
|
||||
tt_int_op(0, ==, keypin_load_journal_impl(data3, strlen(data3)));
|
||||
tt_int_op(12, ==, smartlist_len(mock_addent_got));
|
||||
ent = smartlist_get(mock_addent_got, 11);
|
||||
tt_mem_op(ent->rsa_id, ==, "No dragon can resist", 20);
|
||||
tt_mem_op(ent->ed25519_key, ==, " the fascination of riddling tal", 32);
|
||||
|
||||
done:
|
||||
keypin_clear();
|
||||
smartlist_free(mock_addent_got);
|
||||
}
|
||||
|
||||
#define ADD(a,b) keypin_check_and_add((const uint8_t*)(a),(const uint8_t*)(b))
|
||||
#define LONE_RSA(a) keypin_check_lone_rsa((const uint8_t*)(a))
|
||||
|
||||
static void
|
||||
test_keypin_add_entry(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
keypin_clear();
|
||||
|
||||
tt_int_op(KEYPIN_ADDED, ==, ADD("ambassadors-at-large",
|
||||
"bread-and-butter thing-in-itself"));
|
||||
tt_int_op(KEYPIN_ADDED, ==, ADD("gentleman-adventurer",
|
||||
"cloak-and-dagger what's-his-face"));
|
||||
|
||||
tt_int_op(KEYPIN_FOUND, ==, ADD("ambassadors-at-large",
|
||||
"bread-and-butter thing-in-itself"));
|
||||
tt_int_op(KEYPIN_FOUND, ==, ADD("ambassadors-at-large",
|
||||
"bread-and-butter thing-in-itself"));
|
||||
tt_int_op(KEYPIN_FOUND, ==, ADD("gentleman-adventurer",
|
||||
"cloak-and-dagger what's-his-face"));
|
||||
|
||||
tt_int_op(KEYPIN_ADDED, ==, ADD("Johnnies-come-lately",
|
||||
"run-of-the-mill root-mean-square"));
|
||||
|
||||
tt_int_op(KEYPIN_MISMATCH, ==, ADD("gentleman-adventurer",
|
||||
"hypersentimental closefistedness"));
|
||||
|
||||
tt_int_op(KEYPIN_MISMATCH, ==, ADD("disestablismentarian",
|
||||
"cloak-and-dagger what's-his-face"));
|
||||
|
||||
tt_int_op(KEYPIN_FOUND, ==, ADD("gentleman-adventurer",
|
||||
"cloak-and-dagger what's-his-face"));
|
||||
|
||||
tt_int_op(KEYPIN_NOT_FOUND, ==, LONE_RSA("Llanfairpwllgwyngyll"));
|
||||
tt_int_op(KEYPIN_MISMATCH, ==, LONE_RSA("Johnnies-come-lately"));
|
||||
|
||||
done:
|
||||
keypin_clear();
|
||||
}
|
||||
|
||||
static void
|
||||
test_keypin_journal(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
char *contents = NULL;
|
||||
const char *fname = get_fname("keypin-journal");
|
||||
|
||||
tt_int_op(0, ==, keypin_load_journal(fname)); /* ENOENT is okay */
|
||||
update_approx_time(1217709000);
|
||||
tt_int_op(0, ==, keypin_open_journal(fname));
|
||||
|
||||
tt_int_op(KEYPIN_ADDED, ==, ADD("king-of-the-herrings",
|
||||
"good-for-nothing attorney-at-law"));
|
||||
tt_int_op(KEYPIN_ADDED, ==, ADD("yellowish-red-yellow",
|
||||
"salt-and-pepper high-muck-a-muck"));
|
||||
tt_int_op(KEYPIN_FOUND, ==, ADD("yellowish-red-yellow",
|
||||
"salt-and-pepper high-muck-a-muck"));
|
||||
keypin_close_journal();
|
||||
keypin_clear();
|
||||
|
||||
tt_int_op(0, ==, keypin_load_journal(fname));
|
||||
update_approx_time(1231041600);
|
||||
tt_int_op(0, ==, keypin_open_journal(fname));
|
||||
tt_int_op(KEYPIN_FOUND, ==, ADD("yellowish-red-yellow",
|
||||
"salt-and-pepper high-muck-a-muck"));
|
||||
tt_int_op(KEYPIN_ADDED, ==, ADD("theatre-in-the-round",
|
||||
"holier-than-thou jack-in-the-box"));
|
||||
tt_int_op(KEYPIN_ADDED, ==, ADD("no-deposit-no-return",
|
||||
"across-the-board will-o-the-wisp"));
|
||||
tt_int_op(KEYPIN_MISMATCH, ==, ADD("intellectualizations",
|
||||
"salt-and-pepper high-muck-a-muck"));
|
||||
keypin_close_journal();
|
||||
keypin_clear();
|
||||
|
||||
tt_int_op(0, ==, keypin_load_journal(fname));
|
||||
update_approx_time(1412278354);
|
||||
tt_int_op(0, ==, keypin_open_journal(fname));
|
||||
tt_int_op(KEYPIN_FOUND, ==, ADD("yellowish-red-yellow",
|
||||
"salt-and-pepper high-muck-a-muck"));
|
||||
tt_int_op(KEYPIN_MISMATCH, ==, ADD("intellectualizations",
|
||||
"salt-and-pepper high-muck-a-muck"));
|
||||
tt_int_op(KEYPIN_FOUND, ==, ADD("theatre-in-the-round",
|
||||
"holier-than-thou jack-in-the-box"));
|
||||
tt_int_op(KEYPIN_MISMATCH, ==, ADD("counterrevolutionary",
|
||||
"holier-than-thou jack-in-the-box"));
|
||||
tt_int_op(KEYPIN_MISMATCH, ==, ADD("no-deposit-no-return",
|
||||
"floccinaucinihilipilificationism"));
|
||||
keypin_close_journal();
|
||||
|
||||
contents = read_file_to_str(fname, RFTS_BIN, NULL);
|
||||
tt_assert(contents);
|
||||
tt_str_op(contents,==,
|
||||
"\n"
|
||||
"@opened-at 2008-08-02 20:30:00\n"
|
||||
"a2luZy1vZi10aGUtaGVycmluZ3M Z29vZC1mb3Itbm90aGluZyBhdHRvcm5leS1hdC1sYXc\n"
|
||||
"eWVsbG93aXNoLXJlZC15ZWxsb3c c2FsdC1hbmQtcGVwcGVyIGhpZ2gtbXVjay1hLW11Y2s\n"
|
||||
"\n"
|
||||
"@opened-at 2009-01-04 04:00:00\n"
|
||||
"dGhlYXRyZS1pbi10aGUtcm91bmQ aG9saWVyLXRoYW4tdGhvdSBqYWNrLWluLXRoZS1ib3g\n"
|
||||
"bm8tZGVwb3NpdC1uby1yZXR1cm4 YWNyb3NzLXRoZS1ib2FyZCB3aWxsLW8tdGhlLXdpc3A\n"
|
||||
"\n"
|
||||
"@opened-at 2014-10-02 19:32:34\n");
|
||||
|
||||
done:
|
||||
tor_free(contents);
|
||||
keypin_clear();
|
||||
}
|
||||
|
||||
#undef ADD
|
||||
#undef LONE_RSA
|
||||
|
||||
#define TEST(name, flags) \
|
||||
{ #name , test_keypin_ ## name, (flags), NULL, NULL }
|
||||
|
||||
struct testcase_t keypin_tests[] = {
|
||||
TEST( parse_line, 0 ),
|
||||
TEST( parse_file, TT_FORK ),
|
||||
TEST( add_entry, TT_FORK ),
|
||||
TEST( journal, TT_FORK ),
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
914
src/test/test_link_handshake.c
Normal file
914
src/test/test_link_handshake.c
Normal file
@ -0,0 +1,914 @@
|
||||
/* Copyright (c) 2014, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "orconfig.h"
|
||||
|
||||
#define CHANNELTLS_PRIVATE
|
||||
#define CONNECTION_PRIVATE
|
||||
#define TOR_CHANNEL_INTERNAL_
|
||||
#include "or.h"
|
||||
#include "config.h"
|
||||
#include "connection.h"
|
||||
#include "connection_or.h"
|
||||
#include "channeltls.h"
|
||||
#include "link_handshake.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
var_cell_t *mock_got_var_cell = NULL;
|
||||
|
||||
static void
|
||||
mock_write_var_cell(const var_cell_t *vc, or_connection_t *conn)
|
||||
{
|
||||
(void)conn;
|
||||
|
||||
var_cell_t *newcell = var_cell_new(vc->payload_len);
|
||||
memcpy(newcell, vc, sizeof(var_cell_t));
|
||||
memcpy(newcell->payload, vc->payload, vc->payload_len);
|
||||
|
||||
mock_got_var_cell = newcell;
|
||||
}
|
||||
static int
|
||||
mock_tls_cert_matches_key(const tor_tls_t *tls, const tor_x509_cert_t *cert)
|
||||
{
|
||||
(void) tls;
|
||||
(void) cert; // XXXX look at this.
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mock_send_netinfo_called = 0;
|
||||
static int
|
||||
mock_send_netinfo(or_connection_t *conn)
|
||||
{
|
||||
(void) conn;
|
||||
++mock_send_netinfo_called;// XXX check_this
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mock_close_called = 0;
|
||||
static void
|
||||
mock_close_for_err(or_connection_t *orconn, int flush)
|
||||
{
|
||||
(void)orconn;
|
||||
(void)flush;
|
||||
++mock_close_called;
|
||||
}
|
||||
|
||||
static int mock_send_authenticate_called = 0;
|
||||
static int
|
||||
mock_send_authenticate(or_connection_t *conn, int type)
|
||||
{
|
||||
(void) conn;
|
||||
(void) type;
|
||||
++mock_send_authenticate_called;// XXX check_this
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test good certs cells */
|
||||
static void
|
||||
test_link_handshake_certs_ok(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
or_connection_t *c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
|
||||
or_connection_t *c2 = or_connection_new(CONN_TYPE_OR, AF_INET);
|
||||
var_cell_t *cell1 = NULL, *cell2 = NULL;
|
||||
certs_cell_t *cc1 = NULL, *cc2 = NULL;
|
||||
channel_tls_t *chan1 = NULL, *chan2 = NULL;
|
||||
crypto_pk_t *key1 = NULL, *key2 = NULL;
|
||||
|
||||
scheduler_init();
|
||||
|
||||
MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
|
||||
MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
|
||||
MOCK(connection_or_send_netinfo, mock_send_netinfo);
|
||||
|
||||
key1 = pk_generate(2);
|
||||
key2 = pk_generate(3);
|
||||
|
||||
/* We need to make sure that our TLS certificates are set up before we can
|
||||
* actually generate a CERTS cell.
|
||||
*/
|
||||
tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
|
||||
key1, key2, 86400), ==, 0);
|
||||
|
||||
c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
|
||||
c1->link_proto = 3;
|
||||
tt_int_op(connection_init_or_handshake_state(c1, 1), ==, 0);
|
||||
|
||||
c2->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
|
||||
c2->link_proto = 3;
|
||||
tt_int_op(connection_init_or_handshake_state(c2, 0), ==, 0);
|
||||
|
||||
tt_int_op(0, ==, connection_or_send_certs_cell(c1));
|
||||
tt_assert(mock_got_var_cell);
|
||||
cell1 = mock_got_var_cell;
|
||||
|
||||
tt_int_op(0, ==, connection_or_send_certs_cell(c2));
|
||||
tt_assert(mock_got_var_cell);
|
||||
cell2 = mock_got_var_cell;
|
||||
|
||||
tt_int_op(cell1->command, ==, CELL_CERTS);
|
||||
tt_int_op(cell1->payload_len, >, 1);
|
||||
|
||||
tt_int_op(cell2->command, ==, CELL_CERTS);
|
||||
tt_int_op(cell2->payload_len, >, 1);
|
||||
|
||||
tt_int_op(cell1->payload_len, ==,
|
||||
certs_cell_parse(&cc1, cell1->payload, cell1->payload_len));
|
||||
tt_int_op(cell2->payload_len, ==,
|
||||
certs_cell_parse(&cc2, cell2->payload, cell2->payload_len));
|
||||
|
||||
tt_int_op(2, ==, cc1->n_certs);
|
||||
tt_int_op(2, ==, cc2->n_certs);
|
||||
|
||||
tt_int_op(certs_cell_get_certs(cc1, 0)->cert_type, ==,
|
||||
CERTTYPE_RSA1024_ID_AUTH);
|
||||
tt_int_op(certs_cell_get_certs(cc1, 1)->cert_type, ==,
|
||||
CERTTYPE_RSA1024_ID_ID);
|
||||
|
||||
tt_int_op(certs_cell_get_certs(cc2, 0)->cert_type, ==,
|
||||
CERTTYPE_RSA1024_ID_LINK);
|
||||
tt_int_op(certs_cell_get_certs(cc2, 1)->cert_type, ==,
|
||||
CERTTYPE_RSA1024_ID_ID);
|
||||
|
||||
chan1 = tor_malloc_zero(sizeof(*chan1));
|
||||
channel_tls_common_init(chan1);
|
||||
c1->chan = chan1;
|
||||
chan1->conn = c1;
|
||||
c1->base_.address = tor_strdup("C1");
|
||||
c1->tls = tor_tls_new(-1, 0);
|
||||
c1->link_proto = 4;
|
||||
c1->base_.conn_array_index = -1;
|
||||
crypto_pk_get_digest(key2, c1->identity_digest);
|
||||
|
||||
channel_tls_process_certs_cell(cell2, chan1);
|
||||
|
||||
tt_assert(c1->handshake_state->received_certs_cell);
|
||||
tt_assert(c1->handshake_state->auth_cert == NULL);
|
||||
tt_assert(c1->handshake_state->id_cert);
|
||||
tt_assert(! tor_mem_is_zero(
|
||||
(char*)c1->handshake_state->authenticated_peer_id, 20));
|
||||
|
||||
chan2 = tor_malloc_zero(sizeof(*chan2));
|
||||
channel_tls_common_init(chan2);
|
||||
c2->chan = chan2;
|
||||
chan2->conn = c2;
|
||||
c2->base_.address = tor_strdup("C2");
|
||||
c2->tls = tor_tls_new(-1, 1);
|
||||
c2->link_proto = 4;
|
||||
c2->base_.conn_array_index = -1;
|
||||
crypto_pk_get_digest(key1, c2->identity_digest);
|
||||
|
||||
channel_tls_process_certs_cell(cell1, chan2);
|
||||
|
||||
tt_assert(c2->handshake_state->received_certs_cell);
|
||||
tt_assert(c2->handshake_state->auth_cert);
|
||||
tt_assert(c2->handshake_state->id_cert);
|
||||
tt_assert(tor_mem_is_zero(
|
||||
(char*)c2->handshake_state->authenticated_peer_id, 20));
|
||||
|
||||
done:
|
||||
UNMOCK(tor_tls_cert_matches_key);
|
||||
UNMOCK(connection_or_write_var_cell_to_buf);
|
||||
UNMOCK(connection_or_send_netinfo);
|
||||
connection_free_(TO_CONN(c1));
|
||||
connection_free_(TO_CONN(c2));
|
||||
tor_free(cell1);
|
||||
tor_free(cell2);
|
||||
certs_cell_free(cc1);
|
||||
certs_cell_free(cc2);
|
||||
circuitmux_free(chan1->base_.cmux);
|
||||
tor_free(chan1);
|
||||
circuitmux_free(chan2->base_.cmux);
|
||||
tor_free(chan2);
|
||||
crypto_pk_free(key1);
|
||||
crypto_pk_free(key2);
|
||||
}
|
||||
|
||||
typedef struct certs_data_s {
|
||||
or_connection_t *c;
|
||||
channel_tls_t *chan;
|
||||
certs_cell_t *ccell;
|
||||
var_cell_t *cell;
|
||||
crypto_pk_t *key1, *key2;
|
||||
} certs_data_t;
|
||||
|
||||
|
||||
static int
|
||||
recv_certs_cleanup(const struct testcase_t *test, void *obj)
|
||||
{
|
||||
(void)test;
|
||||
certs_data_t *d = obj;
|
||||
UNMOCK(tor_tls_cert_matches_key);
|
||||
UNMOCK(connection_or_send_netinfo);
|
||||
UNMOCK(connection_or_close_for_error);
|
||||
|
||||
if (d) {
|
||||
tor_free(d->cell);
|
||||
certs_cell_free(d->ccell);
|
||||
connection_free_(TO_CONN(d->c));
|
||||
circuitmux_free(d->chan->base_.cmux);
|
||||
tor_free(d->chan);
|
||||
crypto_pk_free(d->key1);
|
||||
crypto_pk_free(d->key2);
|
||||
tor_free(d);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void *
|
||||
recv_certs_setup(const struct testcase_t *test)
|
||||
{
|
||||
(void)test;
|
||||
certs_data_t *d = tor_malloc_zero(sizeof(*d));
|
||||
certs_cell_cert_t *ccc1 = NULL;
|
||||
certs_cell_cert_t *ccc2 = NULL;
|
||||
ssize_t n;
|
||||
|
||||
d->c = or_connection_new(CONN_TYPE_OR, AF_INET);
|
||||
d->chan = tor_malloc_zero(sizeof(*d->chan));
|
||||
d->c->chan = d->chan;
|
||||
d->c->base_.address = tor_strdup("HaveAnAddress");
|
||||
d->c->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
|
||||
d->chan->conn = d->c;
|
||||
tt_int_op(connection_init_or_handshake_state(d->c, 1), ==, 0);
|
||||
d->c->link_proto = 4;
|
||||
|
||||
d->key1 = pk_generate(2);
|
||||
d->key2 = pk_generate(3);
|
||||
|
||||
tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
|
||||
d->key1, d->key2, 86400), ==, 0);
|
||||
d->ccell = certs_cell_new();
|
||||
ccc1 = certs_cell_cert_new();
|
||||
certs_cell_add_certs(d->ccell, ccc1);
|
||||
ccc2 = certs_cell_cert_new();
|
||||
certs_cell_add_certs(d->ccell, ccc2);
|
||||
d->ccell->n_certs = 2;
|
||||
ccc1->cert_type = 1;
|
||||
ccc2->cert_type = 2;
|
||||
|
||||
const tor_x509_cert_t *a,*b;
|
||||
const uint8_t *enca, *encb;
|
||||
size_t lena, lenb;
|
||||
tor_tls_get_my_certs(1, &a, &b);
|
||||
tor_x509_cert_get_der(a, &enca, &lena);
|
||||
tor_x509_cert_get_der(b, &encb, &lenb);
|
||||
certs_cell_cert_setlen_body(ccc1, lena);
|
||||
ccc1->cert_len = lena;
|
||||
certs_cell_cert_setlen_body(ccc2, lenb);
|
||||
ccc2->cert_len = lenb;
|
||||
|
||||
memcpy(certs_cell_cert_getarray_body(ccc1), enca, lena);
|
||||
memcpy(certs_cell_cert_getarray_body(ccc2), encb, lenb);
|
||||
|
||||
d->cell = var_cell_new(4096);
|
||||
d->cell->command = CELL_CERTS;
|
||||
|
||||
n = certs_cell_encode(d->cell->payload, 4096, d->ccell);
|
||||
tt_int_op(n, >, 0);
|
||||
d->cell->payload_len = n;
|
||||
|
||||
MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
|
||||
MOCK(connection_or_send_netinfo, mock_send_netinfo);
|
||||
MOCK(connection_or_close_for_error, mock_close_for_err);
|
||||
|
||||
tt_int_op(0, ==, d->c->handshake_state->received_certs_cell);
|
||||
tt_int_op(0, ==, mock_send_authenticate_called);
|
||||
tt_int_op(0, ==, mock_send_netinfo_called);
|
||||
|
||||
return d;
|
||||
done:
|
||||
recv_certs_cleanup(test, d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct testcase_setup_t setup_recv_certs = {
|
||||
.setup_fn = recv_certs_setup,
|
||||
.cleanup_fn = recv_certs_cleanup
|
||||
};
|
||||
|
||||
static void
|
||||
test_link_handshake_recv_certs_ok(void *arg)
|
||||
{
|
||||
certs_data_t *d = arg;
|
||||
channel_tls_process_certs_cell(d->cell, d->chan);
|
||||
tt_int_op(0, ==, mock_close_called);
|
||||
tt_int_op(d->c->handshake_state->authenticated, ==, 1);
|
||||
tt_int_op(d->c->handshake_state->received_certs_cell, ==, 1);
|
||||
tt_assert(d->c->handshake_state->id_cert != NULL);
|
||||
tt_assert(d->c->handshake_state->auth_cert == NULL);
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_link_handshake_recv_certs_ok_server(void *arg)
|
||||
{
|
||||
certs_data_t *d = arg;
|
||||
d->c->handshake_state->started_here = 0;
|
||||
certs_cell_get_certs(d->ccell, 0)->cert_type = 3;
|
||||
certs_cell_get_certs(d->ccell, 1)->cert_type = 2;
|
||||
ssize_t n = certs_cell_encode(d->cell->payload, 2048, d->ccell);
|
||||
tt_int_op(n, >, 0);
|
||||
d->cell->payload_len = n;
|
||||
channel_tls_process_certs_cell(d->cell, d->chan);
|
||||
tt_int_op(0, ==, mock_close_called);
|
||||
tt_int_op(d->c->handshake_state->authenticated, ==, 0);
|
||||
tt_int_op(d->c->handshake_state->received_certs_cell, ==, 1);
|
||||
tt_assert(d->c->handshake_state->id_cert != NULL);
|
||||
tt_assert(d->c->handshake_state->auth_cert != NULL);
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
#define CERTS_FAIL(name, code) \
|
||||
static void \
|
||||
test_link_handshake_recv_certs_ ## name (void *arg) \
|
||||
{ \
|
||||
certs_data_t *d = arg; \
|
||||
{ code ; } \
|
||||
channel_tls_process_certs_cell(d->cell, d->chan); \
|
||||
tt_int_op(1, ==, mock_close_called); \
|
||||
tt_int_op(0, ==, mock_send_authenticate_called); \
|
||||
tt_int_op(0, ==, mock_send_netinfo_called); \
|
||||
done: \
|
||||
; \
|
||||
}
|
||||
|
||||
CERTS_FAIL(badstate, d->c->base_.state = OR_CONN_STATE_CONNECTING)
|
||||
CERTS_FAIL(badproto, d->c->link_proto = 2)
|
||||
CERTS_FAIL(duplicate, d->c->handshake_state->received_certs_cell = 1)
|
||||
CERTS_FAIL(already_authenticated,
|
||||
d->c->handshake_state->authenticated = 1)
|
||||
CERTS_FAIL(empty, d->cell->payload_len = 0)
|
||||
CERTS_FAIL(bad_circid, d->cell->circ_id = 1)
|
||||
CERTS_FAIL(truncated_1, d->cell->payload[0] = 5)
|
||||
CERTS_FAIL(truncated_2, {
|
||||
d->cell->payload_len = 4;
|
||||
memcpy(d->cell->payload, "\x01\x01\x00\x05", 4);})
|
||||
CERTS_FAIL(truncated_3, {
|
||||
d->cell->payload_len = 7;
|
||||
memcpy(d->cell->payload, "\x01\x01\x00\x05""abc", 7);})
|
||||
#define REENCODE() do { \
|
||||
ssize_t n = certs_cell_encode(d->cell->payload, 4096, d->ccell); \
|
||||
tt_int_op(n, >, 0); \
|
||||
d->cell->payload_len = n; \
|
||||
} while (0)
|
||||
|
||||
CERTS_FAIL(not_x509, {
|
||||
certs_cell_cert_setlen_body(certs_cell_get_certs(d->ccell, 0), 3);
|
||||
certs_cell_get_certs(d->ccell, 0)->cert_len = 3;
|
||||
REENCODE();
|
||||
})
|
||||
CERTS_FAIL(both_link, {
|
||||
certs_cell_get_certs(d->ccell, 0)->cert_type = 1;
|
||||
certs_cell_get_certs(d->ccell, 1)->cert_type = 1;
|
||||
REENCODE();
|
||||
})
|
||||
CERTS_FAIL(both_id_rsa, {
|
||||
certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
|
||||
certs_cell_get_certs(d->ccell, 1)->cert_type = 2;
|
||||
REENCODE();
|
||||
})
|
||||
CERTS_FAIL(both_auth, {
|
||||
certs_cell_get_certs(d->ccell, 0)->cert_type = 3;
|
||||
certs_cell_get_certs(d->ccell, 1)->cert_type = 3;
|
||||
REENCODE();
|
||||
})
|
||||
CERTS_FAIL(wrong_labels_1, {
|
||||
certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
|
||||
certs_cell_get_certs(d->ccell, 1)->cert_type = 1;
|
||||
REENCODE();
|
||||
})
|
||||
CERTS_FAIL(wrong_labels_2, {
|
||||
const tor_x509_cert_t *a;
|
||||
const tor_x509_cert_t *b;
|
||||
const uint8_t *enca;
|
||||
size_t lena;
|
||||
tor_tls_get_my_certs(1, &a, &b);
|
||||
tor_x509_cert_get_der(a, &enca, &lena);
|
||||
certs_cell_cert_setlen_body(certs_cell_get_certs(d->ccell, 1), lena);
|
||||
memcpy(certs_cell_cert_getarray_body(certs_cell_get_certs(d->ccell, 1)),
|
||||
enca, lena);
|
||||
certs_cell_get_certs(d->ccell, 1)->cert_len = lena;
|
||||
REENCODE();
|
||||
})
|
||||
CERTS_FAIL(wrong_labels_3, {
|
||||
certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
|
||||
certs_cell_get_certs(d->ccell, 1)->cert_type = 3;
|
||||
REENCODE();
|
||||
})
|
||||
CERTS_FAIL(server_missing_certs, {
|
||||
d->c->handshake_state->started_here = 0;
|
||||
})
|
||||
CERTS_FAIL(server_wrong_labels_1, {
|
||||
d->c->handshake_state->started_here = 0;
|
||||
certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
|
||||
certs_cell_get_certs(d->ccell, 1)->cert_type = 3;
|
||||
REENCODE();
|
||||
})
|
||||
|
||||
static void
|
||||
test_link_handshake_send_authchallenge(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
or_connection_t *c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
|
||||
var_cell_t *cell1=NULL, *cell2=NULL;
|
||||
|
||||
MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
|
||||
|
||||
tt_int_op(connection_init_or_handshake_state(c1, 0), ==, 0);
|
||||
c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
|
||||
tt_assert(! mock_got_var_cell);
|
||||
tt_int_op(0, ==, connection_or_send_auth_challenge_cell(c1));
|
||||
cell1 = mock_got_var_cell;
|
||||
tt_int_op(0, ==, connection_or_send_auth_challenge_cell(c1));
|
||||
cell2 = mock_got_var_cell;
|
||||
tt_int_op(36, ==, cell1->payload_len);
|
||||
tt_int_op(36, ==, cell2->payload_len);
|
||||
tt_int_op(0, ==, cell1->circ_id);
|
||||
tt_int_op(0, ==, cell2->circ_id);
|
||||
tt_int_op(CELL_AUTH_CHALLENGE, ==, cell1->command);
|
||||
tt_int_op(CELL_AUTH_CHALLENGE, ==, cell2->command);
|
||||
|
||||
tt_mem_op("\x00\x01\x00\x01", ==, cell1->payload + 32, 4);
|
||||
tt_mem_op("\x00\x01\x00\x01", ==, cell2->payload + 32, 4);
|
||||
tt_mem_op(cell1->payload, !=, cell2->payload, 32);
|
||||
|
||||
done:
|
||||
UNMOCK(connection_or_write_var_cell_to_buf);
|
||||
connection_free_(TO_CONN(c1));
|
||||
tor_free(cell1);
|
||||
tor_free(cell2);
|
||||
}
|
||||
|
||||
typedef struct authchallenge_data_s {
|
||||
or_connection_t *c;
|
||||
channel_tls_t *chan;
|
||||
var_cell_t *cell;
|
||||
} authchallenge_data_t;
|
||||
|
||||
static int
|
||||
recv_authchallenge_cleanup(const struct testcase_t *test, void *obj)
|
||||
{
|
||||
(void)test;
|
||||
authchallenge_data_t *d = obj;
|
||||
|
||||
UNMOCK(connection_or_send_netinfo);
|
||||
UNMOCK(connection_or_close_for_error);
|
||||
UNMOCK(connection_or_send_authenticate_cell);
|
||||
|
||||
if (d) {
|
||||
tor_free(d->cell);
|
||||
connection_free_(TO_CONN(d->c));
|
||||
circuitmux_free(d->chan->base_.cmux);
|
||||
tor_free(d->chan);
|
||||
tor_free(d);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void *
|
||||
recv_authchallenge_setup(const struct testcase_t *test)
|
||||
{
|
||||
(void)test;
|
||||
authchallenge_data_t *d = tor_malloc_zero(sizeof(*d));
|
||||
d->c = or_connection_new(CONN_TYPE_OR, AF_INET);
|
||||
d->chan = tor_malloc_zero(sizeof(*d->chan));
|
||||
d->c->chan = d->chan;
|
||||
d->c->base_.address = tor_strdup("HaveAnAddress");
|
||||
d->c->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
|
||||
d->chan->conn = d->c;
|
||||
tt_int_op(connection_init_or_handshake_state(d->c, 1), ==, 0);
|
||||
d->c->link_proto = 4;
|
||||
d->c->handshake_state->received_certs_cell = 1;
|
||||
d->cell = var_cell_new(128);
|
||||
d->cell->payload_len = 38;
|
||||
d->cell->payload[33] = 2;
|
||||
d->cell->payload[35] = 7;
|
||||
d->cell->payload[37] = 1;
|
||||
d->cell->command = CELL_AUTH_CHALLENGE;
|
||||
|
||||
get_options_mutable()->ORPort_set = 1;
|
||||
|
||||
MOCK(connection_or_close_for_error, mock_close_for_err);
|
||||
MOCK(connection_or_send_netinfo, mock_send_netinfo);
|
||||
MOCK(connection_or_send_authenticate_cell, mock_send_authenticate);
|
||||
|
||||
tt_int_op(0, ==, d->c->handshake_state->received_auth_challenge);
|
||||
tt_int_op(0, ==, mock_send_authenticate_called);
|
||||
tt_int_op(0, ==, mock_send_netinfo_called);
|
||||
|
||||
return d;
|
||||
done:
|
||||
recv_authchallenge_cleanup(test, d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct testcase_setup_t setup_recv_authchallenge = {
|
||||
.setup_fn = recv_authchallenge_setup,
|
||||
.cleanup_fn = recv_authchallenge_cleanup
|
||||
};
|
||||
|
||||
static void
|
||||
test_link_handshake_recv_authchallenge_ok(void *arg)
|
||||
{
|
||||
authchallenge_data_t *d = arg;
|
||||
|
||||
channel_tls_process_auth_challenge_cell(d->cell, d->chan);
|
||||
tt_int_op(0, ==, mock_close_called);
|
||||
tt_int_op(1, ==, d->c->handshake_state->received_auth_challenge);
|
||||
tt_int_op(1, ==, mock_send_authenticate_called);
|
||||
tt_int_op(1, ==, mock_send_netinfo_called);
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_link_handshake_recv_authchallenge_ok_noserver(void *arg)
|
||||
{
|
||||
authchallenge_data_t *d = arg;
|
||||
get_options_mutable()->ORPort_set = 0;
|
||||
|
||||
channel_tls_process_auth_challenge_cell(d->cell, d->chan);
|
||||
tt_int_op(0, ==, mock_close_called);
|
||||
tt_int_op(1, ==, d->c->handshake_state->received_auth_challenge);
|
||||
tt_int_op(0, ==, mock_send_authenticate_called);
|
||||
tt_int_op(0, ==, mock_send_netinfo_called);
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_link_handshake_recv_authchallenge_ok_unrecognized(void *arg)
|
||||
{
|
||||
authchallenge_data_t *d = arg;
|
||||
d->cell->payload[37] = 99;
|
||||
|
||||
channel_tls_process_auth_challenge_cell(d->cell, d->chan);
|
||||
tt_int_op(0, ==, mock_close_called);
|
||||
tt_int_op(1, ==, d->c->handshake_state->received_auth_challenge);
|
||||
tt_int_op(0, ==, mock_send_authenticate_called);
|
||||
tt_int_op(1, ==, mock_send_netinfo_called);
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
#define AUTHCHALLENGE_FAIL(name, code) \
|
||||
static void \
|
||||
test_link_handshake_recv_authchallenge_ ## name (void *arg) \
|
||||
{ \
|
||||
authchallenge_data_t *d = arg; \
|
||||
{ code ; } \
|
||||
channel_tls_process_auth_challenge_cell(d->cell, d->chan); \
|
||||
tt_int_op(1, ==, mock_close_called); \
|
||||
tt_int_op(0, ==, mock_send_authenticate_called); \
|
||||
tt_int_op(0, ==, mock_send_netinfo_called); \
|
||||
done: \
|
||||
; \
|
||||
}
|
||||
|
||||
AUTHCHALLENGE_FAIL(badstate,
|
||||
d->c->base_.state = OR_CONN_STATE_CONNECTING)
|
||||
AUTHCHALLENGE_FAIL(badproto,
|
||||
d->c->link_proto = 2)
|
||||
AUTHCHALLENGE_FAIL(as_server,
|
||||
d->c->handshake_state->started_here = 0;)
|
||||
AUTHCHALLENGE_FAIL(duplicate,
|
||||
d->c->handshake_state->received_auth_challenge = 1)
|
||||
AUTHCHALLENGE_FAIL(nocerts,
|
||||
d->c->handshake_state->received_certs_cell = 0)
|
||||
AUTHCHALLENGE_FAIL(tooshort,
|
||||
d->cell->payload_len = 33)
|
||||
AUTHCHALLENGE_FAIL(truncated,
|
||||
d->cell->payload_len = 34)
|
||||
AUTHCHALLENGE_FAIL(nonzero_circid,
|
||||
d->cell->circ_id = 1337)
|
||||
|
||||
|
||||
static tor_x509_cert_t *mock_peer_cert = NULL;
|
||||
static tor_x509_cert_t *
|
||||
mock_get_peer_cert(tor_tls_t *tls)
|
||||
{
|
||||
(void)tls;
|
||||
return mock_peer_cert;
|
||||
}
|
||||
|
||||
static int
|
||||
mock_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
|
||||
{
|
||||
(void)tls;
|
||||
memcpy(secrets_out, "int getRandomNumber(){return 4;}", 32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mock_set_circid_type(channel_t *chan,
|
||||
crypto_pk_t *identity_rcvd,
|
||||
int consider_identity)
|
||||
{
|
||||
(void) chan;
|
||||
(void) identity_rcvd;
|
||||
(void) consider_identity;
|
||||
}
|
||||
|
||||
typedef struct authenticate_data_s {
|
||||
or_connection_t *c1, *c2;
|
||||
channel_tls_t *chan2;
|
||||
var_cell_t *cell;
|
||||
crypto_pk_t *key1, *key2;
|
||||
} authenticate_data_t;
|
||||
|
||||
static int
|
||||
authenticate_data_cleanup(const struct testcase_t *test, void *arg)
|
||||
{
|
||||
(void) test;
|
||||
UNMOCK(connection_or_write_var_cell_to_buf);
|
||||
UNMOCK(tor_tls_get_peer_cert);
|
||||
UNMOCK(tor_tls_get_tlssecrets);
|
||||
UNMOCK(connection_or_close_for_error);
|
||||
UNMOCK(channel_set_circid_type);
|
||||
authenticate_data_t *d = arg;
|
||||
if (d) {
|
||||
tor_free(d->cell);
|
||||
connection_free_(TO_CONN(d->c1));
|
||||
connection_free_(TO_CONN(d->c2));
|
||||
circuitmux_free(d->chan2->base_.cmux);
|
||||
tor_free(d->chan2);
|
||||
crypto_pk_free(d->key1);
|
||||
crypto_pk_free(d->key2);
|
||||
tor_free(d);
|
||||
}
|
||||
mock_peer_cert = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void *
|
||||
authenticate_data_setup(const struct testcase_t *test)
|
||||
{
|
||||
authenticate_data_t *d = tor_malloc_zero(sizeof(*d));
|
||||
|
||||
scheduler_init();
|
||||
|
||||
MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
|
||||
MOCK(tor_tls_get_peer_cert, mock_get_peer_cert);
|
||||
MOCK(tor_tls_get_tlssecrets, mock_get_tlssecrets);
|
||||
MOCK(connection_or_close_for_error, mock_close_for_err);
|
||||
MOCK(channel_set_circid_type, mock_set_circid_type);
|
||||
d->c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
|
||||
d->c2 = or_connection_new(CONN_TYPE_OR, AF_INET);
|
||||
|
||||
d->key1 = pk_generate(2);
|
||||
d->key2 = pk_generate(3);
|
||||
tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
|
||||
d->key1, d->key2, 86400), ==, 0);
|
||||
|
||||
d->c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
|
||||
d->c1->link_proto = 3;
|
||||
tt_int_op(connection_init_or_handshake_state(d->c1, 1), ==, 0);
|
||||
|
||||
d->c2->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
|
||||
d->c2->link_proto = 3;
|
||||
tt_int_op(connection_init_or_handshake_state(d->c2, 0), ==, 0);
|
||||
var_cell_t *cell = var_cell_new(16);
|
||||
cell->command = CELL_CERTS;
|
||||
or_handshake_state_record_var_cell(d->c1, d->c1->handshake_state, cell, 1);
|
||||
or_handshake_state_record_var_cell(d->c2, d->c2->handshake_state, cell, 0);
|
||||
memset(cell->payload, 0xf0, 16);
|
||||
or_handshake_state_record_var_cell(d->c1, d->c1->handshake_state, cell, 0);
|
||||
or_handshake_state_record_var_cell(d->c2, d->c2->handshake_state, cell, 1);
|
||||
tor_free(cell);
|
||||
|
||||
d->chan2 = tor_malloc_zero(sizeof(*d->chan2));
|
||||
channel_tls_common_init(d->chan2);
|
||||
d->c2->chan = d->chan2;
|
||||
d->chan2->conn = d->c2;
|
||||
d->c2->base_.address = tor_strdup("C2");
|
||||
d->c2->tls = tor_tls_new(-1, 1);
|
||||
d->c2->handshake_state->received_certs_cell = 1;
|
||||
|
||||
const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL, *auth_cert=NULL;
|
||||
tt_assert(! tor_tls_get_my_certs(1, &link_cert, &id_cert));
|
||||
|
||||
const uint8_t *der;
|
||||
size_t sz;
|
||||
tor_x509_cert_get_der(id_cert, &der, &sz);
|
||||
d->c1->handshake_state->id_cert = tor_x509_cert_decode(der, sz);
|
||||
d->c2->handshake_state->id_cert = tor_x509_cert_decode(der, sz);
|
||||
|
||||
tor_x509_cert_get_der(link_cert, &der, &sz);
|
||||
mock_peer_cert = tor_x509_cert_decode(der, sz);
|
||||
tt_assert(mock_peer_cert);
|
||||
tt_assert(! tor_tls_get_my_certs(0, &auth_cert, &id_cert));
|
||||
tor_x509_cert_get_der(auth_cert, &der, &sz);
|
||||
d->c2->handshake_state->auth_cert = tor_x509_cert_decode(der, sz);
|
||||
|
||||
/* Make an authenticate cell ... */
|
||||
tt_int_op(0, ==, connection_or_send_authenticate_cell(d->c1,
|
||||
AUTHTYPE_RSA_SHA256_TLSSECRET));
|
||||
tt_assert(mock_got_var_cell);
|
||||
d->cell = mock_got_var_cell;
|
||||
mock_got_var_cell = NULL;
|
||||
|
||||
return d;
|
||||
done:
|
||||
authenticate_data_cleanup(test, d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct testcase_setup_t setup_authenticate = {
|
||||
.setup_fn = authenticate_data_setup,
|
||||
.cleanup_fn = authenticate_data_cleanup
|
||||
};
|
||||
|
||||
static void
|
||||
test_link_handshake_auth_cell(void *arg)
|
||||
{
|
||||
authenticate_data_t *d = arg;
|
||||
auth1_t *auth1 = NULL;
|
||||
crypto_pk_t *auth_pubkey = NULL;
|
||||
|
||||
/* Is the cell well-formed on the outer layer? */
|
||||
tt_int_op(d->cell->command, ==, CELL_AUTHENTICATE);
|
||||
tt_int_op(d->cell->payload[0], ==, 0);
|
||||
tt_int_op(d->cell->payload[1], ==, 1);
|
||||
tt_int_op(ntohs(get_uint16(d->cell->payload + 2)), ==,
|
||||
d->cell->payload_len - 4);
|
||||
|
||||
/* Check it out for plausibility... */
|
||||
auth_ctx_t ctx;
|
||||
ctx.is_ed = 0;
|
||||
tt_int_op(d->cell->payload_len-4, ==, auth1_parse(&auth1,
|
||||
d->cell->payload+4,
|
||||
d->cell->payload_len - 4, &ctx));
|
||||
tt_assert(auth1);
|
||||
|
||||
tt_mem_op(auth1->type, ==, "AUTH0001", 8);
|
||||
tt_mem_op(auth1->tlssecrets, ==, "int getRandomNumber(){return 4;}", 32);
|
||||
tt_int_op(auth1_getlen_sig(auth1), >, 120);
|
||||
|
||||
/* Is the signature okay? */
|
||||
uint8_t sig[128];
|
||||
uint8_t digest[32];
|
||||
|
||||
auth_pubkey = tor_tls_cert_get_key(d->c2->handshake_state->auth_cert);
|
||||
int n = crypto_pk_public_checksig(
|
||||
auth_pubkey,
|
||||
(char*)sig, sizeof(sig), (char*)auth1_getarray_sig(auth1),
|
||||
auth1_getlen_sig(auth1));
|
||||
tt_int_op(n, ==, 32);
|
||||
const uint8_t *start = d->cell->payload+4, *end = auth1->end_of_signed;
|
||||
crypto_digest256((char*)digest,
|
||||
(const char*)start, end-start, DIGEST_SHA256);
|
||||
tt_mem_op(sig, ==, digest, 32);
|
||||
|
||||
/* Then feed it to c2. */
|
||||
tt_int_op(d->c2->handshake_state->authenticated, ==, 0);
|
||||
channel_tls_process_authenticate_cell(d->cell, d->chan2);
|
||||
tt_int_op(mock_close_called, ==, 0);
|
||||
tt_int_op(d->c2->handshake_state->authenticated, ==, 1);
|
||||
|
||||
done:
|
||||
auth1_free(auth1);
|
||||
crypto_pk_free(auth_pubkey);
|
||||
}
|
||||
|
||||
#define AUTHENTICATE_FAIL(name, code) \
|
||||
static void \
|
||||
test_link_handshake_auth_ ## name (void *arg) \
|
||||
{ \
|
||||
authenticate_data_t *d = arg; \
|
||||
{ code ; } \
|
||||
tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \
|
||||
channel_tls_process_authenticate_cell(d->cell, d->chan2); \
|
||||
tt_int_op(mock_close_called, ==, 1); \
|
||||
tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \
|
||||
done: \
|
||||
; \
|
||||
}
|
||||
|
||||
AUTHENTICATE_FAIL(badstate,
|
||||
d->c2->base_.state = OR_CONN_STATE_CONNECTING)
|
||||
AUTHENTICATE_FAIL(badproto,
|
||||
d->c2->link_proto = 2)
|
||||
AUTHENTICATE_FAIL(atclient,
|
||||
d->c2->handshake_state->started_here = 1)
|
||||
AUTHENTICATE_FAIL(duplicate,
|
||||
d->c2->handshake_state->received_authenticate = 1)
|
||||
static void
|
||||
test_link_handshake_auth_already_authenticated(void *arg)
|
||||
{
|
||||
authenticate_data_t *d = arg;
|
||||
d->c2->handshake_state->authenticated = 1;
|
||||
channel_tls_process_authenticate_cell(d->cell, d->chan2);
|
||||
tt_int_op(mock_close_called, ==, 1);
|
||||
tt_int_op(d->c2->handshake_state->authenticated, ==, 1);
|
||||
done:
|
||||
;
|
||||
}
|
||||
AUTHENTICATE_FAIL(nocerts,
|
||||
d->c2->handshake_state->received_certs_cell = 0)
|
||||
AUTHENTICATE_FAIL(noidcert,
|
||||
tor_x509_cert_free(d->c2->handshake_state->id_cert);
|
||||
d->c2->handshake_state->id_cert = NULL)
|
||||
AUTHENTICATE_FAIL(noauthcert,
|
||||
tor_x509_cert_free(d->c2->handshake_state->auth_cert);
|
||||
d->c2->handshake_state->auth_cert = NULL)
|
||||
AUTHENTICATE_FAIL(tooshort,
|
||||
d->cell->payload_len = 3)
|
||||
AUTHENTICATE_FAIL(badtype,
|
||||
d->cell->payload[0] = 0xff)
|
||||
AUTHENTICATE_FAIL(truncated_1,
|
||||
d->cell->payload[2]++)
|
||||
AUTHENTICATE_FAIL(truncated_2,
|
||||
d->cell->payload[3]++)
|
||||
AUTHENTICATE_FAIL(tooshort_1,
|
||||
tt_int_op(d->cell->payload_len, >=, 260);
|
||||
d->cell->payload[2] -= 1;
|
||||
d->cell->payload_len -= 256;)
|
||||
AUTHENTICATE_FAIL(badcontent,
|
||||
d->cell->payload[10] ^= 0xff)
|
||||
AUTHENTICATE_FAIL(badsig_1,
|
||||
d->cell->payload[d->cell->payload_len - 5] ^= 0xff)
|
||||
|
||||
#define TEST(name, flags) \
|
||||
{ #name , test_link_handshake_ ## name, (flags), NULL, NULL }
|
||||
|
||||
#define TEST_RCV_AUTHCHALLENGE(name) \
|
||||
{ "recv_authchallenge/" #name , \
|
||||
test_link_handshake_recv_authchallenge_ ## name, TT_FORK, \
|
||||
&setup_recv_authchallenge, NULL }
|
||||
|
||||
#define TEST_RCV_CERTS(name) \
|
||||
{ "recv_certs/" #name , \
|
||||
test_link_handshake_recv_certs_ ## name, TT_FORK, \
|
||||
&setup_recv_certs, NULL }
|
||||
|
||||
#define TEST_AUTHENTICATE(name) \
|
||||
{ "authenticate/" #name , test_link_handshake_auth_ ## name, TT_FORK, \
|
||||
&setup_authenticate, NULL }
|
||||
|
||||
struct testcase_t link_handshake_tests[] = {
|
||||
TEST(certs_ok, TT_FORK),
|
||||
//TEST(certs_bad, TT_FORK),
|
||||
TEST_RCV_CERTS(ok),
|
||||
TEST_RCV_CERTS(ok_server),
|
||||
TEST_RCV_CERTS(badstate),
|
||||
TEST_RCV_CERTS(badproto),
|
||||
TEST_RCV_CERTS(duplicate),
|
||||
TEST_RCV_CERTS(already_authenticated),
|
||||
TEST_RCV_CERTS(empty),
|
||||
TEST_RCV_CERTS(bad_circid),
|
||||
TEST_RCV_CERTS(truncated_1),
|
||||
TEST_RCV_CERTS(truncated_2),
|
||||
TEST_RCV_CERTS(truncated_3),
|
||||
TEST_RCV_CERTS(not_x509),
|
||||
TEST_RCV_CERTS(both_link),
|
||||
TEST_RCV_CERTS(both_id_rsa),
|
||||
TEST_RCV_CERTS(both_auth),
|
||||
TEST_RCV_CERTS(wrong_labels_1),
|
||||
TEST_RCV_CERTS(wrong_labels_2),
|
||||
TEST_RCV_CERTS(wrong_labels_3),
|
||||
TEST_RCV_CERTS(server_missing_certs),
|
||||
TEST_RCV_CERTS(server_wrong_labels_1),
|
||||
|
||||
TEST(send_authchallenge, TT_FORK),
|
||||
TEST_RCV_AUTHCHALLENGE(ok),
|
||||
TEST_RCV_AUTHCHALLENGE(ok_noserver),
|
||||
TEST_RCV_AUTHCHALLENGE(ok_unrecognized),
|
||||
TEST_RCV_AUTHCHALLENGE(badstate),
|
||||
TEST_RCV_AUTHCHALLENGE(badproto),
|
||||
TEST_RCV_AUTHCHALLENGE(as_server),
|
||||
TEST_RCV_AUTHCHALLENGE(duplicate),
|
||||
TEST_RCV_AUTHCHALLENGE(nocerts),
|
||||
TEST_RCV_AUTHCHALLENGE(tooshort),
|
||||
TEST_RCV_AUTHCHALLENGE(truncated),
|
||||
TEST_RCV_AUTHCHALLENGE(nonzero_circid),
|
||||
|
||||
TEST_AUTHENTICATE(cell),
|
||||
TEST_AUTHENTICATE(badstate),
|
||||
TEST_AUTHENTICATE(badproto),
|
||||
TEST_AUTHENTICATE(atclient),
|
||||
TEST_AUTHENTICATE(duplicate),
|
||||
TEST_AUTHENTICATE(already_authenticated),
|
||||
TEST_AUTHENTICATE(nocerts),
|
||||
TEST_AUTHENTICATE(noidcert),
|
||||
TEST_AUTHENTICATE(noauthcert),
|
||||
TEST_AUTHENTICATE(tooshort),
|
||||
TEST_AUTHENTICATE(badtype),
|
||||
TEST_AUTHENTICATE(truncated_1),
|
||||
TEST_AUTHENTICATE(truncated_2),
|
||||
TEST_AUTHENTICATE(tooshort_1),
|
||||
TEST_AUTHENTICATE(badcontent),
|
||||
TEST_AUTHENTICATE(badsig_1),
|
||||
//TEST_AUTHENTICATE(),
|
||||
|
||||
END_OF_TESTCASES
|
||||
};
|
@ -10,6 +10,7 @@
|
||||
#include "networkstatus.h"
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "torcert.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
@ -335,6 +336,59 @@ static const char test_ri[] =
|
||||
"t0xkIE39ss/EwmQr7iIgkdVH4oRIMsjYnFFJBG26nYY=\n"
|
||||
"-----END SIGNATURE-----\n";
|
||||
|
||||
static const char test_ri2[] =
|
||||
"router test001a 127.0.0.1 5001 0 7001\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQABf/FAf5iDuKCZP2VxnAaQWdklilAh6kaEeFX4z8261Yx2T1/AQAgBADCp8vO\n"
|
||||
"B8K1F9g2DzwuwvVCnPFLSK1qknVqPpNucHLH9DY7fuIYogBAdz4zHv1qC7RKaMNG\n"
|
||||
"Jux/tMO2tzPcm62Ky5PjClMQplKUOnZNQ+RIpA3wYCIfUDy/cQnY7XWgNQ0=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"platform Tor 0.2.6.0-alpha-dev on Darwin\n"
|
||||
"protocols Link 1 2 Circuit 1\n"
|
||||
"published 2014-10-08 12:58:04\n"
|
||||
"fingerprint B7E2 7F10 4213 C36F 13E7 E982 9182 845E 4959 97A0\n"
|
||||
"uptime 0\n"
|
||||
"bandwidth 1073741824 1073741824 0\n"
|
||||
"extra-info-digest 568F27331B6D8C73E7024F1EF5D097B90DFC7CDB\n"
|
||||
"caches-extra-info\n"
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n"
|
||||
"+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n"
|
||||
"l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAN8+78KUVlgHXdMMkYJxcwh1Zv2y+Gb5eWUyltUaQRajhrT9ij2T5JZs\n"
|
||||
"M0g85xTcuM3jNVVpV79+33hiTohdC6UZ+Bk4USQ7WBFzRbVFSXoVKLBJFkCOIexg\n"
|
||||
"SMGNd5WEDtHWrXl58mizmPFu1eG6ZxHzt7RuLSol5cwBvawXPNkFAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"onion-key-crosscert\n"
|
||||
"-----BEGIN CROSSCERT-----\n"
|
||||
"ETFDzU49bvNfoZnKK1j6JeBP2gDirgj6bBCgWpUYs663OO9ypbZRO0JwWANssKl6\n"
|
||||
"oaq9vKTsKGRsaNnqnz/JGMhehymakjjNtqg7crWwsahe8+7Pw9GKmW+YjFtcOkUf\n"
|
||||
"KfOn2bmKBa1FoJb4yW3oXzHcdlLSRuCciKqPn+Hky5o=\n"
|
||||
"-----END CROSSCERT-----\n"
|
||||
"ntor-onion-key-crosscert 0\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoABf2dAcKny84HwrUX2DYPPC7C9UKc8UtIrWqSdWo+k25wcsf0AFohutG+xI06\n"
|
||||
"Ef21c5Zl1j8Hw6DzHDjYyJevXLFuOneaL3zcH2Ldn4sjrG3kc5UuVvRfTvV120UO\n"
|
||||
"xk4f5s5LGwY=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"hidden-service-dir\n"
|
||||
"contact auth1@test.test\n"
|
||||
"ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n"
|
||||
"reject *:*\n"
|
||||
"router-sig-ed25519 5aQXyTif7PExIuL2di37UvktmJECKnils2OWz2vDi"
|
||||
"hFxi+5TTAAPxYkS5clhc/Pjvw34itfjGmTKFic/8httAQ\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"BaUB+aFPQbb3BwtdzKsKqV3+6cRlSqJF5bI3UTmwRoJk+Z5Pz+W5NWokNI0xArHM\n"
|
||||
"T4T5FZCCP9350jXsUCIvzyIyktU6aVRCGFt76rFlo1OETpN8GWkMnQU0w18cxvgS\n"
|
||||
"cf34GXHv61XReJF3AlzNHFpbrPOYmowmhrTULKyMqow=\n"
|
||||
"-----END SIGNATURE-----\n";
|
||||
|
||||
static const char test_md_8[] =
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
@ -365,6 +419,26 @@ static const char test_md_18[] =
|
||||
"p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
|
||||
"id rsa1024 Cd47okjCHD83YGzThGBDptXs9Z4\n";
|
||||
|
||||
static const char test_md2_18[] =
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n"
|
||||
"+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n"
|
||||
"l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n"
|
||||
"id rsa1024 t+J/EEITw28T5+mCkYKEXklZl6A\n";
|
||||
|
||||
static const char test_md2_21[] =
|
||||
"onion-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBAL2R8EfubUcahxha4u02P4VAR0llQIMwFAmrHPjzcK7apcQgDOf2ovOA\n"
|
||||
"+YQnJFxlpBmCoCZC6ssCi+9G0mqo650lFuTMP5I90BdtjotfzESfTykHLiChyvhd\n"
|
||||
"l0dlqclb2SU/GKem/fLRXH16aNi72CdSUu/1slKs/70ILi34QixRAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key hbxdRnfVUJJY7+KcT4E3Rs7/zuClbN3hJrjSBiEGMgI=\n"
|
||||
"id ed25519 wqfLzgfCtRfYNg88LsL1QpzxS0itapJ1aj6TbnByx/Q\n";
|
||||
|
||||
static void
|
||||
test_md_generate(void *arg)
|
||||
{
|
||||
@ -391,6 +465,25 @@ test_md_generate(void *arg)
|
||||
md = dirvote_create_microdescriptor(ri, 18);
|
||||
tt_str_op(md->body, OP_EQ, test_md_18);
|
||||
|
||||
microdesc_free(md);
|
||||
md = NULL;
|
||||
md = dirvote_create_microdescriptor(ri, 21);
|
||||
tt_str_op(md->body, ==, test_md_18);
|
||||
|
||||
ri = router_parse_entry_from_string(test_ri2, NULL, 0, 0, NULL, NULL);
|
||||
|
||||
microdesc_free(md);
|
||||
md = NULL;
|
||||
md = dirvote_create_microdescriptor(ri, 18);
|
||||
tt_str_op(md->body, ==, test_md2_18);
|
||||
|
||||
microdesc_free(md);
|
||||
md = NULL;
|
||||
md = dirvote_create_microdescriptor(ri, 21);
|
||||
tt_str_op(md->body, ==, test_md2_21);
|
||||
tt_assert(ed25519_pubkey_eq(md->ed25519_identity_pkey,
|
||||
&ri->signing_key_cert->signing_key));
|
||||
|
||||
done:
|
||||
microdesc_free(md);
|
||||
routerinfo_free(ri);
|
||||
|
@ -8,11 +8,17 @@
|
||||
#include "or.h"
|
||||
#include "config.h"
|
||||
#include "router.h"
|
||||
#include "routerkeys.h"
|
||||
#include "util.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#include "torcert.h"
|
||||
#include "test.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
/* For mkdir() */
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_routerkeys_write_fingerprint(void *arg)
|
||||
{
|
||||
@ -75,11 +81,543 @@ test_routerkeys_write_fingerprint(void *arg)
|
||||
tor_free(cp2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_routerkeys_ed_certs(void *args)
|
||||
{
|
||||
(void)args;
|
||||
ed25519_keypair_t kp1, kp2;
|
||||
tor_cert_t *cert[2] = {NULL, NULL};
|
||||
tor_cert_t *parsed_cert[2] = {NULL, NULL};
|
||||
time_t now = 1412094534;
|
||||
uint8_t *junk = NULL;
|
||||
char *base64 = NULL;
|
||||
|
||||
tt_int_op(0,==,ed25519_keypair_generate(&kp1, 0));
|
||||
tt_int_op(0,==,ed25519_keypair_generate(&kp2, 0));
|
||||
|
||||
for (int i = 0; i <= 1; ++i) {
|
||||
uint32_t flags = i ? CERT_FLAG_INCLUDE_SIGNING_KEY : 0;
|
||||
|
||||
cert[i] = tor_cert_create(&kp1, 5, &kp2.pubkey, now, 10000, flags);
|
||||
tt_assert(cert[i]);
|
||||
|
||||
tt_assert(cert[i]->sig_bad == 0);
|
||||
tt_assert(cert[i]->sig_ok == 1);
|
||||
tt_assert(cert[i]->cert_expired == 0);
|
||||
tt_assert(cert[i]->cert_valid == 1);
|
||||
tt_int_op(cert[i]->cert_type, ==, 5);
|
||||
tt_mem_op(cert[i]->signed_key.pubkey, ==, &kp2.pubkey.pubkey, 32);
|
||||
tt_mem_op(cert[i]->signing_key.pubkey, ==, &kp1.pubkey.pubkey, 32);
|
||||
tt_int_op(cert[i]->signing_key_included, ==, i);
|
||||
|
||||
tt_assert(cert[i]->encoded);
|
||||
tt_int_op(cert[i]->encoded_len, ==, 104 + 36 * i);
|
||||
tt_int_op(cert[i]->encoded[0], ==, 1);
|
||||
tt_int_op(cert[i]->encoded[1], ==, 5);
|
||||
|
||||
parsed_cert[i] = tor_cert_parse(cert[i]->encoded, cert[i]->encoded_len);
|
||||
tt_assert(parsed_cert[i]);
|
||||
tt_int_op(cert[i]->encoded_len, ==, parsed_cert[i]->encoded_len);
|
||||
tt_mem_op(cert[i]->encoded, ==, parsed_cert[i]->encoded,
|
||||
cert[i]->encoded_len);
|
||||
tt_assert(parsed_cert[i]->sig_bad == 0);
|
||||
tt_assert(parsed_cert[i]->sig_ok == 0);
|
||||
tt_assert(parsed_cert[i]->cert_expired == 0);
|
||||
tt_assert(parsed_cert[i]->cert_valid == 0);
|
||||
|
||||
/* Expired */
|
||||
tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now + 30000),
|
||||
<, 0);
|
||||
tt_assert(parsed_cert[i]->cert_expired == 1);
|
||||
parsed_cert[i]->cert_expired = 0;
|
||||
|
||||
/* Wrong key */
|
||||
tt_int_op(tor_cert_checksig(parsed_cert[i], &kp2.pubkey, now), <, 0);
|
||||
tt_assert(parsed_cert[i]->sig_bad== 1);
|
||||
parsed_cert[i]->sig_bad = 0;
|
||||
|
||||
/* Missing key */
|
||||
int ok = tor_cert_checksig(parsed_cert[i], NULL, now);
|
||||
tt_int_op(ok < 0, ==, i == 0);
|
||||
tt_assert(parsed_cert[i]->sig_bad == 0);
|
||||
tt_assert(parsed_cert[i]->sig_ok == (i != 0));
|
||||
tt_assert(parsed_cert[i]->cert_valid == (i != 0));
|
||||
parsed_cert[i]->sig_bad = 0;
|
||||
parsed_cert[i]->sig_ok = 0;
|
||||
parsed_cert[i]->cert_valid = 0;
|
||||
|
||||
/* Right key */
|
||||
tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now), ==, 0);
|
||||
tt_assert(parsed_cert[i]->sig_bad == 0);
|
||||
tt_assert(parsed_cert[i]->sig_ok == 1);
|
||||
tt_assert(parsed_cert[i]->cert_expired == 0);
|
||||
tt_assert(parsed_cert[i]->cert_valid == 1);
|
||||
}
|
||||
|
||||
/* Now try some junky certs. */
|
||||
/* - Truncated */
|
||||
tt_ptr_op(NULL, ==,tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len-1));
|
||||
|
||||
/* - First byte modified */
|
||||
cert[0]->encoded[0] = 99;
|
||||
tt_ptr_op(NULL, ==,tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len));
|
||||
cert[0]->encoded[0] = 1;
|
||||
|
||||
/* - Extra byte at the end*/
|
||||
junk = tor_malloc_zero(cert[0]->encoded_len + 1);
|
||||
memcpy(junk, cert[0]->encoded, cert[0]->encoded_len);
|
||||
tt_ptr_op(NULL, ==, tor_cert_parse(junk, cert[0]->encoded_len+1));
|
||||
|
||||
/* - Multiple signing key instances */
|
||||
tor_free(junk);
|
||||
junk = tor_malloc_zero(104 + 36 * 2);
|
||||
junk[0] = 1; /* version */
|
||||
junk[1] = 5; /* cert type */
|
||||
junk[6] = 1; /* key type */
|
||||
junk[39] = 2; /* n_extensions */
|
||||
junk[41] = 32; /* extlen */
|
||||
junk[42] = 4; /* exttype */
|
||||
junk[77] = 32; /* extlen */
|
||||
junk[78] = 4; /* exttype */
|
||||
tt_ptr_op(NULL, ==, tor_cert_parse(junk, 104 + 36 * 2));
|
||||
|
||||
done:
|
||||
tor_cert_free(cert[0]);
|
||||
tor_cert_free(cert[1]);
|
||||
tor_cert_free(parsed_cert[0]);
|
||||
tor_cert_free(parsed_cert[1]);
|
||||
tor_free(junk);
|
||||
tor_free(base64);
|
||||
}
|
||||
|
||||
static void
|
||||
test_routerkeys_ed_key_create(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
tor_cert_t *cert = NULL;
|
||||
ed25519_keypair_t *kp1 = NULL, *kp2 = NULL;
|
||||
time_t now = time(NULL);
|
||||
|
||||
/* This is a simple alias for 'make a new keypair' */
|
||||
kp1 = ed_key_new(NULL, 0, 0, 0, 0, &cert);
|
||||
tt_assert(kp1);
|
||||
|
||||
/* Create a new certificate signed by kp1. */
|
||||
kp2 = ed_key_new(kp1, INIT_ED_KEY_NEEDCERT, now, 3600, 4, &cert);
|
||||
tt_assert(kp2);
|
||||
tt_assert(cert);
|
||||
tt_mem_op(&cert->signed_key, ==, &kp2->pubkey, sizeof(ed25519_public_key_t));
|
||||
tt_assert(! cert->signing_key_included);
|
||||
|
||||
tt_int_op(cert->valid_until, >=, now);
|
||||
tt_int_op(cert->valid_until, <=, now+7200);
|
||||
|
||||
/* Create a new key-including certificate signed by kp1 */
|
||||
ed25519_keypair_free(kp2);
|
||||
tor_cert_free(cert);
|
||||
cert = NULL; kp2 = NULL;
|
||||
kp2 = ed_key_new(kp1, (INIT_ED_KEY_NEEDCERT|
|
||||
INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT),
|
||||
now, 3600, 4, &cert);
|
||||
tt_assert(kp2);
|
||||
tt_assert(cert);
|
||||
tt_assert(cert->signing_key_included);
|
||||
tt_mem_op(&cert->signed_key, ==, &kp2->pubkey, sizeof(ed25519_public_key_t));
|
||||
tt_mem_op(&cert->signing_key, ==, &kp1->pubkey,sizeof(ed25519_public_key_t));
|
||||
|
||||
done:
|
||||
ed25519_keypair_free(kp1);
|
||||
ed25519_keypair_free(kp2);
|
||||
tor_cert_free(cert);
|
||||
}
|
||||
|
||||
static void
|
||||
test_routerkeys_ed_key_init_basic(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
tor_cert_t *cert = NULL, *cert2 = NULL;
|
||||
ed25519_keypair_t *kp1 = NULL, *kp2 = NULL, *kp3 = NULL;
|
||||
time_t now = time(NULL);
|
||||
char *fname1 = tor_strdup(get_fname("test_ed_key_1"));
|
||||
char *fname2 = tor_strdup(get_fname("test_ed_key_2"));
|
||||
struct stat st;
|
||||
|
||||
unlink(fname1);
|
||||
unlink(fname2);
|
||||
|
||||
/* Fail to load a key that isn't there. */
|
||||
kp1 = ed_key_init_from_file(fname1, 0, LOG_INFO, NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp1 == NULL);
|
||||
tt_assert(cert == NULL);
|
||||
|
||||
/* Create the key if requested to do so. */
|
||||
kp1 = ed_key_init_from_file(fname1, INIT_ED_KEY_CREATE, LOG_INFO,
|
||||
NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp1 != NULL);
|
||||
tt_assert(cert == NULL);
|
||||
tt_int_op(stat(get_fname("test_ed_key_1_cert"), &st), <, 0);
|
||||
tt_int_op(stat(get_fname("test_ed_key_1_secret_key"), &st), ==, 0);
|
||||
|
||||
/* Fail to load if we say we need a cert */
|
||||
kp2 = ed_key_init_from_file(fname1, INIT_ED_KEY_NEEDCERT, LOG_INFO,
|
||||
NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp2 == NULL);
|
||||
|
||||
/* Fail to load if we say the wrong key type */
|
||||
kp2 = ed_key_init_from_file(fname1, 0, LOG_INFO,
|
||||
NULL, now, 0, 6, &cert);
|
||||
tt_assert(kp2 == NULL);
|
||||
|
||||
/* Load successfully if we're not picky, whether we say "create" or not. */
|
||||
kp2 = ed_key_init_from_file(fname1, INIT_ED_KEY_CREATE, LOG_INFO,
|
||||
NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp2 != NULL);
|
||||
tt_assert(cert == NULL);
|
||||
tt_mem_op(kp1, ==, kp2, sizeof(*kp1));
|
||||
ed25519_keypair_free(kp2); kp2 = NULL;
|
||||
|
||||
kp2 = ed_key_init_from_file(fname1, 0, LOG_INFO,
|
||||
NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp2 != NULL);
|
||||
tt_assert(cert == NULL);
|
||||
tt_mem_op(kp1, ==, kp2, sizeof(*kp1));
|
||||
ed25519_keypair_free(kp2); kp2 = NULL;
|
||||
|
||||
/* Now create a key with a cert. */
|
||||
kp2 = ed_key_init_from_file(fname2, (INIT_ED_KEY_CREATE|
|
||||
INIT_ED_KEY_NEEDCERT),
|
||||
LOG_INFO, kp1, now, 7200, 7, &cert);
|
||||
tt_assert(kp2 != NULL);
|
||||
tt_assert(cert != NULL);
|
||||
tt_mem_op(kp1, !=, kp2, sizeof(*kp1));
|
||||
tt_int_op(stat(get_fname("test_ed_key_2_cert"), &st), ==, 0);
|
||||
tt_int_op(stat(get_fname("test_ed_key_2_secret_key"), &st), ==, 0);
|
||||
|
||||
tt_assert(cert->cert_valid == 1);
|
||||
tt_mem_op(&cert->signed_key, ==, &kp2->pubkey, 32);
|
||||
|
||||
/* Now verify we can load the cert... */
|
||||
kp3 = ed_key_init_from_file(fname2, (INIT_ED_KEY_CREATE|
|
||||
INIT_ED_KEY_NEEDCERT),
|
||||
LOG_INFO, kp1, now, 7200, 7, &cert2);
|
||||
tt_mem_op(kp2, ==, kp3, sizeof(*kp2));
|
||||
tt_mem_op(cert2->encoded, ==, cert->encoded, cert->encoded_len);
|
||||
ed25519_keypair_free(kp3); kp3 = NULL;
|
||||
tor_cert_free(cert2); cert2 = NULL;
|
||||
|
||||
/* ... even without create... */
|
||||
kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
|
||||
LOG_INFO, kp1, now, 7200, 7, &cert2);
|
||||
tt_mem_op(kp2, ==, kp3, sizeof(*kp2));
|
||||
tt_mem_op(cert2->encoded, ==, cert->encoded, cert->encoded_len);
|
||||
ed25519_keypair_free(kp3); kp3 = NULL;
|
||||
tor_cert_free(cert2); cert2 = NULL;
|
||||
|
||||
/* ... but that we don't crash or anything if we say we don't want it. */
|
||||
kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
|
||||
LOG_INFO, kp1, now, 7200, 7, NULL);
|
||||
tt_mem_op(kp2, ==, kp3, sizeof(*kp2));
|
||||
ed25519_keypair_free(kp3); kp3 = NULL;
|
||||
|
||||
/* Fail if we're told the wrong signing key */
|
||||
kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
|
||||
LOG_INFO, kp2, now, 7200, 7, &cert2);
|
||||
tt_assert(kp3 == NULL);
|
||||
tt_assert(cert2 == NULL);
|
||||
|
||||
done:
|
||||
ed25519_keypair_free(kp1);
|
||||
ed25519_keypair_free(kp2);
|
||||
ed25519_keypair_free(kp3);
|
||||
tor_cert_free(cert);
|
||||
tor_cert_free(cert2);
|
||||
tor_free(fname1);
|
||||
tor_free(fname2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_routerkeys_ed_key_init_split(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
tor_cert_t *cert = NULL;
|
||||
ed25519_keypair_t *kp1 = NULL, *kp2 = NULL;
|
||||
time_t now = time(NULL);
|
||||
char *fname1 = tor_strdup(get_fname("test_ed_key_3"));
|
||||
char *fname2 = tor_strdup(get_fname("test_ed_key_4"));
|
||||
struct stat st;
|
||||
const uint32_t flags = INIT_ED_KEY_SPLIT|INIT_ED_KEY_MISSING_SECRET_OK;
|
||||
|
||||
unlink(fname1);
|
||||
unlink(fname2);
|
||||
|
||||
/* Can't load key that isn't there. */
|
||||
kp1 = ed_key_init_from_file(fname1, flags, LOG_INFO, NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp1 == NULL);
|
||||
tt_assert(cert == NULL);
|
||||
|
||||
/* Create a split key */
|
||||
kp1 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
|
||||
LOG_INFO, NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp1 != NULL);
|
||||
tt_assert(cert == NULL);
|
||||
tt_int_op(stat(get_fname("test_ed_key_3_cert"), &st), <, 0);
|
||||
tt_int_op(stat(get_fname("test_ed_key_3_secret_key"), &st), ==, 0);
|
||||
tt_int_op(stat(get_fname("test_ed_key_3_public_key"), &st), ==, 0);
|
||||
|
||||
/* Load it. */
|
||||
kp2 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
|
||||
LOG_INFO, NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp2 != NULL);
|
||||
tt_assert(cert == NULL);
|
||||
tt_mem_op(kp1, ==, kp2, sizeof(*kp2));
|
||||
ed25519_keypair_free(kp2); kp2 = NULL;
|
||||
|
||||
/* Okay, try killing the secret key and loading it. */
|
||||
unlink(get_fname("test_ed_key_3_secret_key"));
|
||||
kp2 = ed_key_init_from_file(fname1, flags,
|
||||
LOG_INFO, NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp2 != NULL);
|
||||
tt_assert(cert == NULL);
|
||||
tt_mem_op(&kp1->pubkey, ==, &kp2->pubkey, sizeof(kp2->pubkey));
|
||||
tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
|
||||
sizeof(kp2->seckey.seckey)));
|
||||
ed25519_keypair_free(kp2); kp2 = NULL;
|
||||
|
||||
/* Even when we're told to "create", don't create if there's a public key */
|
||||
kp2 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
|
||||
LOG_INFO, NULL, now, 0, 7, &cert);
|
||||
tt_assert(kp2 != NULL);
|
||||
tt_assert(cert == NULL);
|
||||
tt_mem_op(&kp1->pubkey, ==, &kp2->pubkey, sizeof(kp2->pubkey));
|
||||
tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
|
||||
sizeof(kp2->seckey.seckey)));
|
||||
ed25519_keypair_free(kp2); kp2 = NULL;
|
||||
|
||||
/* Make sure we fail on a tag mismatch, though */
|
||||
kp2 = ed_key_init_from_file(fname1, flags,
|
||||
LOG_INFO, NULL, now, 0, 99, &cert);
|
||||
tt_assert(kp2 == NULL);
|
||||
|
||||
done:
|
||||
ed25519_keypair_free(kp1);
|
||||
ed25519_keypair_free(kp2);
|
||||
tor_cert_free(cert);
|
||||
tor_free(fname1);
|
||||
tor_free(fname2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_routerkeys_ed_keys_init_all(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
char *dir = tor_strdup(get_fname("test_ed_keys_init_all"));
|
||||
or_options_t *options = tor_malloc_zero(sizeof(or_options_t));
|
||||
time_t now = time(NULL);
|
||||
ed25519_public_key_t id;
|
||||
ed25519_keypair_t sign, auth;
|
||||
tor_cert_t *link_cert = NULL;
|
||||
|
||||
get_options_mutable()->ORPort_set = 1;
|
||||
|
||||
crypto_pk_t *rsa = pk_generate(0);
|
||||
|
||||
set_server_identity_key(rsa);
|
||||
set_client_identity_key(rsa);
|
||||
|
||||
router_initialize_tls_context();
|
||||
|
||||
options->SigningKeyLifetime = 30*86400;
|
||||
options->TestingAuthKeyLifetime = 2*86400;
|
||||
options->TestingLinkCertLifetime = 2*86400;
|
||||
options->TestingSigningKeySlop = 2*86400;
|
||||
options->TestingAuthKeySlop = 2*3600;
|
||||
options->TestingLinkKeySlop = 2*3600;
|
||||
|
||||
#ifdef _WIN32
|
||||
mkdir(dir);
|
||||
mkdir(get_fname("test_ed_keys_init_all/keys"));
|
||||
#else
|
||||
mkdir(dir, 0700);
|
||||
mkdir(get_fname("test_ed_keys_init_all/keys"), 0700);
|
||||
#endif
|
||||
|
||||
options->DataDirectory = dir;
|
||||
|
||||
tt_int_op(0, ==, load_ed_keys(options, now));
|
||||
tt_int_op(0, ==, generate_ed_link_cert(options, now));
|
||||
tt_assert(get_master_identity_key());
|
||||
tt_assert(get_master_identity_key());
|
||||
tt_assert(get_master_signing_keypair());
|
||||
tt_assert(get_current_auth_keypair());
|
||||
tt_assert(get_master_signing_key_cert());
|
||||
tt_assert(get_current_link_cert_cert());
|
||||
tt_assert(get_current_auth_key_cert());
|
||||
memcpy(&id, get_master_identity_key(), sizeof(id));
|
||||
memcpy(&sign, get_master_signing_keypair(), sizeof(sign));
|
||||
memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
|
||||
link_cert = tor_cert_dup(get_current_link_cert_cert());
|
||||
|
||||
/* Call load_ed_keys again, but nothing has changed. */
|
||||
tt_int_op(0, ==, load_ed_keys(options, now));
|
||||
tt_int_op(0, ==, generate_ed_link_cert(options, now));
|
||||
tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
|
||||
tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
|
||||
tt_mem_op(&auth, ==, get_current_auth_keypair(), sizeof(auth));
|
||||
tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert()));
|
||||
|
||||
/* Force a reload: we make new link/auth keys. */
|
||||
routerkeys_free_all();
|
||||
tt_int_op(0, ==, load_ed_keys(options, now));
|
||||
tt_int_op(0, ==, generate_ed_link_cert(options, now));
|
||||
tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
|
||||
tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
|
||||
tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert()));
|
||||
tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
|
||||
tt_assert(get_master_signing_key_cert());
|
||||
tt_assert(get_current_link_cert_cert());
|
||||
tt_assert(get_current_auth_key_cert());
|
||||
tor_cert_free(link_cert);
|
||||
link_cert = tor_cert_dup(get_current_link_cert_cert());
|
||||
memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
|
||||
|
||||
/* Force a link/auth-key regeneration by advancing time. */
|
||||
tt_int_op(0, ==, load_ed_keys(options, now+3*86400));
|
||||
tt_int_op(0, ==, generate_ed_link_cert(options, now+3*86400));
|
||||
tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
|
||||
tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
|
||||
tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
|
||||
tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
|
||||
tt_assert(get_master_signing_key_cert());
|
||||
tt_assert(get_current_link_cert_cert());
|
||||
tt_assert(get_current_auth_key_cert());
|
||||
tor_cert_free(link_cert);
|
||||
link_cert = tor_cert_dup(get_current_link_cert_cert());
|
||||
memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
|
||||
|
||||
/* Force a signing-key regeneration by advancing time. */
|
||||
tt_int_op(0, ==, load_ed_keys(options, now+100*86400));
|
||||
tt_int_op(0, ==, generate_ed_link_cert(options, now+100*86400));
|
||||
tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
|
||||
tt_mem_op(&sign, !=, get_master_signing_keypair(), sizeof(sign));
|
||||
tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
|
||||
tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
|
||||
tt_assert(get_master_signing_key_cert());
|
||||
tt_assert(get_current_link_cert_cert());
|
||||
tt_assert(get_current_auth_key_cert());
|
||||
memcpy(&sign, get_master_signing_keypair(), sizeof(sign));
|
||||
tor_cert_free(link_cert);
|
||||
link_cert = tor_cert_dup(get_current_link_cert_cert());
|
||||
memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
|
||||
|
||||
/* Demonstrate that we can start up with no secret identity key */
|
||||
routerkeys_free_all();
|
||||
unlink(get_fname("test_ed_keys_init_all/keys/"
|
||||
"ed25519_master_id_secret_key"));
|
||||
tt_int_op(0, ==, load_ed_keys(options, now));
|
||||
tt_int_op(0, ==, generate_ed_link_cert(options, now));
|
||||
tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
|
||||
tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
|
||||
tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
|
||||
tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
|
||||
tt_assert(get_master_signing_key_cert());
|
||||
tt_assert(get_current_link_cert_cert());
|
||||
tt_assert(get_current_auth_key_cert());
|
||||
|
||||
/* But we're in trouble if we have no id key and our signing key has
|
||||
expired. */
|
||||
log_global_min_severity_ = LOG_ERR; /* Suppress warnings.
|
||||
* XXX (better way to do this)? */
|
||||
routerkeys_free_all();
|
||||
tt_int_op(-1, ==, load_ed_keys(options, now+200*86400));
|
||||
|
||||
done:
|
||||
tor_free(dir);
|
||||
tor_free(options);
|
||||
routerkeys_free_all();
|
||||
}
|
||||
|
||||
static void
|
||||
test_routerkeys_cross_certify_ntor(void *args)
|
||||
{
|
||||
(void) args;
|
||||
|
||||
tor_cert_t *cert = NULL;
|
||||
curve25519_keypair_t onion_keys;
|
||||
ed25519_public_key_t master_key;
|
||||
ed25519_public_key_t onion_check_key;
|
||||
time_t now = time(NULL);
|
||||
int sign;
|
||||
|
||||
tt_int_op(0, ==, ed25519_public_from_base64(&master_key,
|
||||
"IamwritingthesetestsOnARainyAfternoonin2014"));
|
||||
tt_int_op(0, ==, curve25519_keypair_generate(&onion_keys, 0));
|
||||
cert = make_ntor_onion_key_crosscert(&onion_keys,
|
||||
&master_key,
|
||||
now, 10000,
|
||||
&sign);
|
||||
tt_assert(cert);
|
||||
tt_assert(sign == 0 || sign == 1);
|
||||
tt_int_op(cert->cert_type, ==, CERT_TYPE_ONION_ID);
|
||||
tt_int_op(1, ==, ed25519_pubkey_eq(&cert->signed_key, &master_key));
|
||||
tt_int_op(0, ==, ed25519_public_key_from_curve25519_public_key(
|
||||
&onion_check_key, &onion_keys.pubkey, sign));
|
||||
tt_int_op(0, ==, tor_cert_checksig(cert, &onion_check_key, now));
|
||||
|
||||
done:
|
||||
tor_cert_free(cert);
|
||||
}
|
||||
|
||||
static void
|
||||
test_routerkeys_cross_certify_tap(void *args)
|
||||
{
|
||||
(void)args;
|
||||
uint8_t *cc = NULL;
|
||||
int cc_len;
|
||||
ed25519_public_key_t master_key;
|
||||
crypto_pk_t *onion_key = pk_generate(2), *id_key = pk_generate(1);
|
||||
char digest[20];
|
||||
char buf[128];
|
||||
int n;
|
||||
|
||||
tt_int_op(0, ==, ed25519_public_from_base64(&master_key,
|
||||
"IAlreadyWroteTestsForRouterdescsUsingTheseX"));
|
||||
|
||||
cc = make_tap_onion_key_crosscert(onion_key,
|
||||
&master_key,
|
||||
id_key, &cc_len);
|
||||
tt_assert(cc);
|
||||
tt_assert(cc_len);
|
||||
|
||||
n = crypto_pk_public_checksig(onion_key, buf, sizeof(buf),
|
||||
(char*)cc, cc_len);
|
||||
tt_int_op(n,>,0);
|
||||
tt_int_op(n,==,52);
|
||||
|
||||
crypto_pk_get_digest(id_key, digest);
|
||||
tt_mem_op(buf,==,digest,20);
|
||||
tt_mem_op(buf+20,==,master_key.pubkey,32);
|
||||
|
||||
tt_int_op(0, ==, check_tap_onion_key_crosscert(cc, cc_len,
|
||||
onion_key, &master_key, (uint8_t*)digest));
|
||||
|
||||
done:
|
||||
tor_free(cc);
|
||||
}
|
||||
|
||||
#define TEST(name, flags) \
|
||||
{ #name , test_routerkeys_ ## name, (flags), NULL, NULL }
|
||||
|
||||
struct testcase_t routerkeys_tests[] = {
|
||||
TEST(write_fingerprint, TT_FORK),
|
||||
TEST(ed_certs, TT_FORK),
|
||||
TEST(ed_key_create, TT_FORK),
|
||||
TEST(ed_key_init_basic, TT_FORK),
|
||||
TEST(ed_key_init_split, TT_FORK),
|
||||
TEST(ed_keys_init_all, TT_FORK),
|
||||
TEST(cross_certify_ntor, 0),
|
||||
TEST(cross_certify_tap, 0),
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
||||
|
887
src/trunnel/ed25519_cert.c
Normal file
887
src/trunnel/ed25519_cert.c
Normal file
@ -0,0 +1,887 @@
|
||||
/* ed25519_cert.c -- generated by Trunnel v1.2.
|
||||
* https://gitweb.torproject.org/trunnel.git
|
||||
* You probably shouldn't edit this file.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include "trunnel-impl.h"
|
||||
|
||||
#include "ed25519_cert.h"
|
||||
|
||||
#define TRUNNEL_SET_ERROR_CODE(obj) \
|
||||
do { \
|
||||
(obj)->trunnel_error_code_ = 1; \
|
||||
} while (0)
|
||||
|
||||
#if defined(__COVERITY__) || defined(__clang_analyzer__)
|
||||
/* If we're runnning a static analysis tool, we don't want it to complain
|
||||
* that some of our remaining-bytes checks are dead-code. */
|
||||
int edcert_deadcode_dummy__ = 0;
|
||||
#define OR_DEADCODE_DUMMY || edcert_deadcode_dummy__
|
||||
#else
|
||||
#define OR_DEADCODE_DUMMY
|
||||
#endif
|
||||
|
||||
#define CHECK_REMAINING(nbytes, label) \
|
||||
do { \
|
||||
if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
ed25519_cert_extension_t *
|
||||
ed25519_cert_extension_new(void)
|
||||
{
|
||||
ed25519_cert_extension_t *val = trunnel_calloc(1, sizeof(ed25519_cert_extension_t));
|
||||
if (NULL == val)
|
||||
return NULL;
|
||||
return val;
|
||||
}
|
||||
|
||||
/** Release all storage held inside 'obj', but do not free 'obj'.
|
||||
*/
|
||||
static void
|
||||
ed25519_cert_extension_clear(ed25519_cert_extension_t *obj)
|
||||
{
|
||||
(void) obj;
|
||||
TRUNNEL_DYNARRAY_WIPE(&obj->un_unparsed);
|
||||
TRUNNEL_DYNARRAY_CLEAR(&obj->un_unparsed);
|
||||
}
|
||||
|
||||
void
|
||||
ed25519_cert_extension_free(ed25519_cert_extension_t *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return;
|
||||
ed25519_cert_extension_clear(obj);
|
||||
trunnel_memwipe(obj, sizeof(ed25519_cert_extension_t));
|
||||
trunnel_free_(obj);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ed25519_cert_extension_get_ext_length(ed25519_cert_extension_t *inp)
|
||||
{
|
||||
return inp->ext_length;
|
||||
}
|
||||
int
|
||||
ed25519_cert_extension_set_ext_length(ed25519_cert_extension_t *inp, uint16_t val)
|
||||
{
|
||||
inp->ext_length = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
ed25519_cert_extension_get_ext_type(ed25519_cert_extension_t *inp)
|
||||
{
|
||||
return inp->ext_type;
|
||||
}
|
||||
int
|
||||
ed25519_cert_extension_set_ext_type(ed25519_cert_extension_t *inp, uint8_t val)
|
||||
{
|
||||
inp->ext_type = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
ed25519_cert_extension_get_ext_flags(ed25519_cert_extension_t *inp)
|
||||
{
|
||||
return inp->ext_flags;
|
||||
}
|
||||
int
|
||||
ed25519_cert_extension_set_ext_flags(ed25519_cert_extension_t *inp, uint8_t val)
|
||||
{
|
||||
inp->ext_flags = val;
|
||||
return 0;
|
||||
}
|
||||
size_t
|
||||
ed25519_cert_extension_getlen_un_signing_key(const ed25519_cert_extension_t *inp)
|
||||
{
|
||||
(void)inp; return 32;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ed25519_cert_extension_get_un_signing_key(const ed25519_cert_extension_t *inp, size_t idx)
|
||||
{
|
||||
trunnel_assert(idx < 32);
|
||||
return inp->un_signing_key[idx];
|
||||
}
|
||||
|
||||
int
|
||||
ed25519_cert_extension_set_un_signing_key(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt)
|
||||
{
|
||||
trunnel_assert(idx < 32);
|
||||
inp->un_signing_key[idx] = elt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
ed25519_cert_extension_getarray_un_signing_key(ed25519_cert_extension_t *inp)
|
||||
{
|
||||
return inp->un_signing_key;
|
||||
}
|
||||
size_t
|
||||
ed25519_cert_extension_getlen_un_unparsed(const ed25519_cert_extension_t *inp)
|
||||
{
|
||||
return TRUNNEL_DYNARRAY_LEN(&inp->un_unparsed);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ed25519_cert_extension_get_un_unparsed(ed25519_cert_extension_t *inp, size_t idx)
|
||||
{
|
||||
return TRUNNEL_DYNARRAY_GET(&inp->un_unparsed, idx);
|
||||
}
|
||||
|
||||
int
|
||||
ed25519_cert_extension_set_un_unparsed(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt)
|
||||
{
|
||||
TRUNNEL_DYNARRAY_SET(&inp->un_unparsed, idx, elt);
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
ed25519_cert_extension_add_un_unparsed(ed25519_cert_extension_t *inp, uint8_t elt)
|
||||
{
|
||||
TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->un_unparsed, elt, {});
|
||||
return 0;
|
||||
trunnel_alloc_failed:
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
ed25519_cert_extension_getarray_un_unparsed(ed25519_cert_extension_t *inp)
|
||||
{
|
||||
return inp->un_unparsed.elts_;
|
||||
}
|
||||
int
|
||||
ed25519_cert_extension_setlen_un_unparsed(ed25519_cert_extension_t *inp, size_t newlen)
|
||||
{
|
||||
uint8_t *newptr;
|
||||
newptr = trunnel_dynarray_setlen(&inp->un_unparsed.allocated_,
|
||||
&inp->un_unparsed.n_, inp->un_unparsed.elts_, newlen,
|
||||
sizeof(inp->un_unparsed.elts_[0]), (trunnel_free_fn_t) NULL,
|
||||
&inp->trunnel_error_code_);
|
||||
if (newptr == NULL)
|
||||
goto trunnel_alloc_failed;
|
||||
inp->un_unparsed.elts_ = newptr;
|
||||
return 0;
|
||||
trunnel_alloc_failed:
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
const char *
|
||||
ed25519_cert_extension_check(const ed25519_cert_extension_t *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return "Object was NULL";
|
||||
if (obj->trunnel_error_code_)
|
||||
return "A set function failed on this object";
|
||||
switch (obj->ext_type) {
|
||||
|
||||
case CERTEXT_SIGNED_WITH_KEY:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ed25519_cert_extension_encoded_len(const ed25519_cert_extension_t *obj)
|
||||
{
|
||||
ssize_t result = 0;
|
||||
|
||||
if (NULL != ed25519_cert_extension_check(obj))
|
||||
return -1;
|
||||
|
||||
|
||||
/* Length of u16 ext_length */
|
||||
result += 2;
|
||||
|
||||
/* Length of u8 ext_type */
|
||||
result += 1;
|
||||
|
||||
/* Length of u8 ext_flags */
|
||||
result += 1;
|
||||
switch (obj->ext_type) {
|
||||
|
||||
case CERTEXT_SIGNED_WITH_KEY:
|
||||
|
||||
/* Length of u8 un_signing_key[32] */
|
||||
result += 32;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Length of u8 un_unparsed[] */
|
||||
result += TRUNNEL_DYNARRAY_LEN(&obj->un_unparsed);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
int
|
||||
ed25519_cert_extension_clear_errors(ed25519_cert_extension_t *obj)
|
||||
{
|
||||
int r = obj->trunnel_error_code_;
|
||||
obj->trunnel_error_code_ = 0;
|
||||
return r;
|
||||
}
|
||||
ssize_t
|
||||
ed25519_cert_extension_encode(uint8_t *output, const size_t avail, const ed25519_cert_extension_t *obj)
|
||||
{
|
||||
ssize_t result = 0;
|
||||
size_t written = 0;
|
||||
uint8_t *ptr = output;
|
||||
const char *msg;
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
const ssize_t encoded_len = ed25519_cert_extension_encoded_len(obj);
|
||||
#endif
|
||||
|
||||
uint8_t *backptr_ext_length = NULL;
|
||||
|
||||
if (NULL != (msg = ed25519_cert_extension_check(obj)))
|
||||
goto check_failed;
|
||||
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
trunnel_assert(encoded_len >= 0);
|
||||
#endif
|
||||
|
||||
/* Encode u16 ext_length */
|
||||
backptr_ext_length = ptr;
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 2)
|
||||
goto truncated;
|
||||
trunnel_set_uint16(ptr, trunnel_htons(obj->ext_length));
|
||||
written += 2; ptr += 2;
|
||||
|
||||
/* Encode u8 ext_type */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->ext_type));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u8 ext_flags */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->ext_flags));
|
||||
written += 1; ptr += 1;
|
||||
{
|
||||
size_t written_before_union = written;
|
||||
|
||||
/* Encode union un[ext_type] */
|
||||
trunnel_assert(written <= avail);
|
||||
switch (obj->ext_type) {
|
||||
|
||||
case CERTEXT_SIGNED_WITH_KEY:
|
||||
|
||||
/* Encode u8 un_signing_key[32] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 32)
|
||||
goto truncated;
|
||||
memcpy(ptr, obj->un_signing_key, 32);
|
||||
written += 32; ptr += 32;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Encode u8 un_unparsed[] */
|
||||
{
|
||||
size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->un_unparsed);
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < elt_len)
|
||||
goto truncated;
|
||||
memcpy(ptr, obj->un_unparsed.elts_, elt_len);
|
||||
written += elt_len; ptr += elt_len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Write the length field back to ext_length */
|
||||
trunnel_assert(written >= written_before_union);
|
||||
#if UINT16_MAX < SIZE_MAX
|
||||
if (written - written_before_union > UINT16_MAX)
|
||||
goto check_failed;
|
||||
#endif
|
||||
trunnel_set_uint16(backptr_ext_length, trunnel_htons(written - written_before_union));
|
||||
}
|
||||
|
||||
|
||||
trunnel_assert(ptr == output + written);
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
{
|
||||
trunnel_assert(encoded_len >= 0);
|
||||
trunnel_assert((size_t)encoded_len == written);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return written;
|
||||
|
||||
truncated:
|
||||
result = -2;
|
||||
goto fail;
|
||||
check_failed:
|
||||
(void)msg;
|
||||
result = -1;
|
||||
goto fail;
|
||||
fail:
|
||||
trunnel_assert(result < 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** As ed25519_cert_extension_parse(), but do not allocate the output
|
||||
* object.
|
||||
*/
|
||||
static ssize_t
|
||||
ed25519_cert_extension_parse_into(ed25519_cert_extension_t *obj, const uint8_t *input, const size_t len_in)
|
||||
{
|
||||
const uint8_t *ptr = input;
|
||||
size_t remaining = len_in;
|
||||
ssize_t result = 0;
|
||||
(void)result;
|
||||
|
||||
/* Parse u16 ext_length */
|
||||
CHECK_REMAINING(2, truncated);
|
||||
obj->ext_length = trunnel_ntohs(trunnel_get_uint16(ptr));
|
||||
remaining -= 2; ptr += 2;
|
||||
|
||||
/* Parse u8 ext_type */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->ext_type = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
|
||||
/* Parse u8 ext_flags */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->ext_flags = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
{
|
||||
size_t remaining_after;
|
||||
CHECK_REMAINING(obj->ext_length, truncated);
|
||||
remaining_after = remaining - obj->ext_length;
|
||||
remaining = obj->ext_length;
|
||||
|
||||
/* Parse union un[ext_type] */
|
||||
switch (obj->ext_type) {
|
||||
|
||||
case CERTEXT_SIGNED_WITH_KEY:
|
||||
|
||||
/* Parse u8 un_signing_key[32] */
|
||||
CHECK_REMAINING(32, fail);
|
||||
memcpy(obj->un_signing_key, ptr, 32);
|
||||
remaining -= 32; ptr += 32;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Parse u8 un_unparsed[] */
|
||||
TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->un_unparsed, remaining, {});
|
||||
obj->un_unparsed.n_ = remaining;
|
||||
memcpy(obj->un_unparsed.elts_, ptr, remaining);
|
||||
ptr += remaining; remaining -= remaining;
|
||||
break;
|
||||
}
|
||||
if (remaining != 0)
|
||||
goto fail;
|
||||
remaining = remaining_after;
|
||||
}
|
||||
trunnel_assert(ptr + remaining == input + len_in);
|
||||
return len_in - remaining;
|
||||
|
||||
truncated:
|
||||
return -2;
|
||||
trunnel_alloc_failed:
|
||||
return -1;
|
||||
fail:
|
||||
result = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ed25519_cert_extension_parse(ed25519_cert_extension_t **output, const uint8_t *input, const size_t len_in)
|
||||
{
|
||||
ssize_t result;
|
||||
*output = ed25519_cert_extension_new();
|
||||
if (NULL == *output)
|
||||
return -1;
|
||||
result = ed25519_cert_extension_parse_into(*output, input, len_in);
|
||||
if (result < 0) {
|
||||
ed25519_cert_extension_free(*output);
|
||||
*output = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
ed25519_cert_t *
|
||||
ed25519_cert_new(void)
|
||||
{
|
||||
ed25519_cert_t *val = trunnel_calloc(1, sizeof(ed25519_cert_t));
|
||||
if (NULL == val)
|
||||
return NULL;
|
||||
val->version = 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
/** Release all storage held inside 'obj', but do not free 'obj'.
|
||||
*/
|
||||
static void
|
||||
ed25519_cert_clear(ed25519_cert_t *obj)
|
||||
{
|
||||
(void) obj;
|
||||
{
|
||||
|
||||
unsigned idx;
|
||||
for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) {
|
||||
ed25519_cert_extension_free(TRUNNEL_DYNARRAY_GET(&obj->ext, idx));
|
||||
}
|
||||
}
|
||||
TRUNNEL_DYNARRAY_WIPE(&obj->ext);
|
||||
TRUNNEL_DYNARRAY_CLEAR(&obj->ext);
|
||||
}
|
||||
|
||||
void
|
||||
ed25519_cert_free(ed25519_cert_t *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return;
|
||||
ed25519_cert_clear(obj);
|
||||
trunnel_memwipe(obj, sizeof(ed25519_cert_t));
|
||||
trunnel_free_(obj);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ed25519_cert_get_version(ed25519_cert_t *inp)
|
||||
{
|
||||
return inp->version;
|
||||
}
|
||||
int
|
||||
ed25519_cert_set_version(ed25519_cert_t *inp, uint8_t val)
|
||||
{
|
||||
if (! ((val == 1))) {
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
inp->version = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
ed25519_cert_get_cert_type(ed25519_cert_t *inp)
|
||||
{
|
||||
return inp->cert_type;
|
||||
}
|
||||
int
|
||||
ed25519_cert_set_cert_type(ed25519_cert_t *inp, uint8_t val)
|
||||
{
|
||||
inp->cert_type = val;
|
||||
return 0;
|
||||
}
|
||||
uint32_t
|
||||
ed25519_cert_get_exp_field(ed25519_cert_t *inp)
|
||||
{
|
||||
return inp->exp_field;
|
||||
}
|
||||
int
|
||||
ed25519_cert_set_exp_field(ed25519_cert_t *inp, uint32_t val)
|
||||
{
|
||||
inp->exp_field = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
ed25519_cert_get_cert_key_type(ed25519_cert_t *inp)
|
||||
{
|
||||
return inp->cert_key_type;
|
||||
}
|
||||
int
|
||||
ed25519_cert_set_cert_key_type(ed25519_cert_t *inp, uint8_t val)
|
||||
{
|
||||
inp->cert_key_type = val;
|
||||
return 0;
|
||||
}
|
||||
size_t
|
||||
ed25519_cert_getlen_certified_key(const ed25519_cert_t *inp)
|
||||
{
|
||||
(void)inp; return 32;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ed25519_cert_get_certified_key(const ed25519_cert_t *inp, size_t idx)
|
||||
{
|
||||
trunnel_assert(idx < 32);
|
||||
return inp->certified_key[idx];
|
||||
}
|
||||
|
||||
int
|
||||
ed25519_cert_set_certified_key(ed25519_cert_t *inp, size_t idx, uint8_t elt)
|
||||
{
|
||||
trunnel_assert(idx < 32);
|
||||
inp->certified_key[idx] = elt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
ed25519_cert_getarray_certified_key(ed25519_cert_t *inp)
|
||||
{
|
||||
return inp->certified_key;
|
||||
}
|
||||
uint8_t
|
||||
ed25519_cert_get_n_extensions(ed25519_cert_t *inp)
|
||||
{
|
||||
return inp->n_extensions;
|
||||
}
|
||||
int
|
||||
ed25519_cert_set_n_extensions(ed25519_cert_t *inp, uint8_t val)
|
||||
{
|
||||
inp->n_extensions = val;
|
||||
return 0;
|
||||
}
|
||||
size_t
|
||||
ed25519_cert_getlen_ext(const ed25519_cert_t *inp)
|
||||
{
|
||||
return TRUNNEL_DYNARRAY_LEN(&inp->ext);
|
||||
}
|
||||
|
||||
struct ed25519_cert_extension_st *
|
||||
ed25519_cert_get_ext(ed25519_cert_t *inp, size_t idx)
|
||||
{
|
||||
return TRUNNEL_DYNARRAY_GET(&inp->ext, idx);
|
||||
}
|
||||
|
||||
int
|
||||
ed25519_cert_set_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt)
|
||||
{
|
||||
ed25519_cert_extension_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->ext, idx);
|
||||
if (oldval && oldval != elt)
|
||||
ed25519_cert_extension_free(oldval);
|
||||
return ed25519_cert_set0_ext(inp, idx, elt);
|
||||
}
|
||||
int
|
||||
ed25519_cert_set0_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt)
|
||||
{
|
||||
TRUNNEL_DYNARRAY_SET(&inp->ext, idx, elt);
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
ed25519_cert_add_ext(ed25519_cert_t *inp, struct ed25519_cert_extension_st * elt)
|
||||
{
|
||||
#if SIZE_MAX >= UINT8_MAX
|
||||
if (inp->ext.n_ == UINT8_MAX)
|
||||
goto trunnel_alloc_failed;
|
||||
#endif
|
||||
TRUNNEL_DYNARRAY_ADD(struct ed25519_cert_extension_st *, &inp->ext, elt, {});
|
||||
return 0;
|
||||
trunnel_alloc_failed:
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ed25519_cert_extension_st * *
|
||||
ed25519_cert_getarray_ext(ed25519_cert_t *inp)
|
||||
{
|
||||
return inp->ext.elts_;
|
||||
}
|
||||
int
|
||||
ed25519_cert_setlen_ext(ed25519_cert_t *inp, size_t newlen)
|
||||
{
|
||||
struct ed25519_cert_extension_st * *newptr;
|
||||
#if UINT8_MAX < SIZE_MAX
|
||||
if (newlen > UINT8_MAX)
|
||||
goto trunnel_alloc_failed;
|
||||
#endif
|
||||
newptr = trunnel_dynarray_setlen(&inp->ext.allocated_,
|
||||
&inp->ext.n_, inp->ext.elts_, newlen,
|
||||
sizeof(inp->ext.elts_[0]), (trunnel_free_fn_t) ed25519_cert_extension_free,
|
||||
&inp->trunnel_error_code_);
|
||||
if (newptr == NULL)
|
||||
goto trunnel_alloc_failed;
|
||||
inp->ext.elts_ = newptr;
|
||||
return 0;
|
||||
trunnel_alloc_failed:
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
size_t
|
||||
ed25519_cert_getlen_signature(const ed25519_cert_t *inp)
|
||||
{
|
||||
(void)inp; return 64;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ed25519_cert_get_signature(const ed25519_cert_t *inp, size_t idx)
|
||||
{
|
||||
trunnel_assert(idx < 64);
|
||||
return inp->signature[idx];
|
||||
}
|
||||
|
||||
int
|
||||
ed25519_cert_set_signature(ed25519_cert_t *inp, size_t idx, uint8_t elt)
|
||||
{
|
||||
trunnel_assert(idx < 64);
|
||||
inp->signature[idx] = elt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
ed25519_cert_getarray_signature(ed25519_cert_t *inp)
|
||||
{
|
||||
return inp->signature;
|
||||
}
|
||||
const char *
|
||||
ed25519_cert_check(const ed25519_cert_t *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return "Object was NULL";
|
||||
if (obj->trunnel_error_code_)
|
||||
return "A set function failed on this object";
|
||||
if (! (obj->version == 1))
|
||||
return "Integer out of bounds";
|
||||
{
|
||||
const char *msg;
|
||||
|
||||
unsigned idx;
|
||||
for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) {
|
||||
if (NULL != (msg = ed25519_cert_extension_check(TRUNNEL_DYNARRAY_GET(&obj->ext, idx))))
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
if (TRUNNEL_DYNARRAY_LEN(&obj->ext) != obj->n_extensions)
|
||||
return "Length mismatch for ext";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ed25519_cert_encoded_len(const ed25519_cert_t *obj)
|
||||
{
|
||||
ssize_t result = 0;
|
||||
|
||||
if (NULL != ed25519_cert_check(obj))
|
||||
return -1;
|
||||
|
||||
|
||||
/* Length of u8 version IN [1] */
|
||||
result += 1;
|
||||
|
||||
/* Length of u8 cert_type */
|
||||
result += 1;
|
||||
|
||||
/* Length of u32 exp_field */
|
||||
result += 4;
|
||||
|
||||
/* Length of u8 cert_key_type */
|
||||
result += 1;
|
||||
|
||||
/* Length of u8 certified_key[32] */
|
||||
result += 32;
|
||||
|
||||
/* Length of u8 n_extensions */
|
||||
result += 1;
|
||||
|
||||
/* Length of struct ed25519_cert_extension ext[n_extensions] */
|
||||
{
|
||||
|
||||
unsigned idx;
|
||||
for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) {
|
||||
result += ed25519_cert_extension_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->ext, idx));
|
||||
}
|
||||
}
|
||||
|
||||
/* Length of u8 signature[64] */
|
||||
result += 64;
|
||||
return result;
|
||||
}
|
||||
int
|
||||
ed25519_cert_clear_errors(ed25519_cert_t *obj)
|
||||
{
|
||||
int r = obj->trunnel_error_code_;
|
||||
obj->trunnel_error_code_ = 0;
|
||||
return r;
|
||||
}
|
||||
ssize_t
|
||||
ed25519_cert_encode(uint8_t *output, const size_t avail, const ed25519_cert_t *obj)
|
||||
{
|
||||
ssize_t result = 0;
|
||||
size_t written = 0;
|
||||
uint8_t *ptr = output;
|
||||
const char *msg;
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
const ssize_t encoded_len = ed25519_cert_encoded_len(obj);
|
||||
#endif
|
||||
|
||||
if (NULL != (msg = ed25519_cert_check(obj)))
|
||||
goto check_failed;
|
||||
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
trunnel_assert(encoded_len >= 0);
|
||||
#endif
|
||||
|
||||
/* Encode u8 version IN [1] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->version));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u8 cert_type */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->cert_type));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u32 exp_field */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 4)
|
||||
goto truncated;
|
||||
trunnel_set_uint32(ptr, trunnel_htonl(obj->exp_field));
|
||||
written += 4; ptr += 4;
|
||||
|
||||
/* Encode u8 cert_key_type */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->cert_key_type));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u8 certified_key[32] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 32)
|
||||
goto truncated;
|
||||
memcpy(ptr, obj->certified_key, 32);
|
||||
written += 32; ptr += 32;
|
||||
|
||||
/* Encode u8 n_extensions */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->n_extensions));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode struct ed25519_cert_extension ext[n_extensions] */
|
||||
{
|
||||
|
||||
unsigned idx;
|
||||
for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) {
|
||||
trunnel_assert(written <= avail);
|
||||
result = ed25519_cert_extension_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->ext, idx));
|
||||
if (result < 0)
|
||||
goto fail; /* XXXXXXX !*/
|
||||
written += result; ptr += result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encode u8 signature[64] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 64)
|
||||
goto truncated;
|
||||
memcpy(ptr, obj->signature, 64);
|
||||
written += 64; ptr += 64;
|
||||
|
||||
|
||||
trunnel_assert(ptr == output + written);
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
{
|
||||
trunnel_assert(encoded_len >= 0);
|
||||
trunnel_assert((size_t)encoded_len == written);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return written;
|
||||
|
||||
truncated:
|
||||
result = -2;
|
||||
goto fail;
|
||||
check_failed:
|
||||
(void)msg;
|
||||
result = -1;
|
||||
goto fail;
|
||||
fail:
|
||||
trunnel_assert(result < 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** As ed25519_cert_parse(), but do not allocate the output object.
|
||||
*/
|
||||
static ssize_t
|
||||
ed25519_cert_parse_into(ed25519_cert_t *obj, const uint8_t *input, const size_t len_in)
|
||||
{
|
||||
const uint8_t *ptr = input;
|
||||
size_t remaining = len_in;
|
||||
ssize_t result = 0;
|
||||
(void)result;
|
||||
|
||||
/* Parse u8 version IN [1] */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->version = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
if (! (obj->version == 1))
|
||||
goto fail;
|
||||
|
||||
/* Parse u8 cert_type */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->cert_type = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
|
||||
/* Parse u32 exp_field */
|
||||
CHECK_REMAINING(4, truncated);
|
||||
obj->exp_field = trunnel_ntohl(trunnel_get_uint32(ptr));
|
||||
remaining -= 4; ptr += 4;
|
||||
|
||||
/* Parse u8 cert_key_type */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->cert_key_type = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
|
||||
/* Parse u8 certified_key[32] */
|
||||
CHECK_REMAINING(32, truncated);
|
||||
memcpy(obj->certified_key, ptr, 32);
|
||||
remaining -= 32; ptr += 32;
|
||||
|
||||
/* Parse u8 n_extensions */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->n_extensions = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
|
||||
/* Parse struct ed25519_cert_extension ext[n_extensions] */
|
||||
TRUNNEL_DYNARRAY_EXPAND(ed25519_cert_extension_t *, &obj->ext, obj->n_extensions, {});
|
||||
{
|
||||
ed25519_cert_extension_t * elt;
|
||||
unsigned idx;
|
||||
for (idx = 0; idx < obj->n_extensions; ++idx) {
|
||||
result = ed25519_cert_extension_parse(&elt, ptr, remaining);
|
||||
if (result < 0)
|
||||
goto relay_fail;
|
||||
trunnel_assert((size_t)result <= remaining);
|
||||
remaining -= result; ptr += result;
|
||||
TRUNNEL_DYNARRAY_ADD(ed25519_cert_extension_t *, &obj->ext, elt, {ed25519_cert_extension_free(elt);});
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse u8 signature[64] */
|
||||
CHECK_REMAINING(64, truncated);
|
||||
memcpy(obj->signature, ptr, 64);
|
||||
remaining -= 64; ptr += 64;
|
||||
trunnel_assert(ptr + remaining == input + len_in);
|
||||
return len_in - remaining;
|
||||
|
||||
truncated:
|
||||
return -2;
|
||||
relay_fail:
|
||||
if (result >= 0) result = -1;
|
||||
return result;
|
||||
trunnel_alloc_failed:
|
||||
return -1;
|
||||
fail:
|
||||
result = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ed25519_cert_parse(ed25519_cert_t **output, const uint8_t *input, const size_t len_in)
|
||||
{
|
||||
ssize_t result;
|
||||
*output = ed25519_cert_new();
|
||||
if (NULL == *output)
|
||||
return -1;
|
||||
result = ed25519_cert_parse_into(*output, input, len_in);
|
||||
if (result < 0) {
|
||||
ed25519_cert_free(*output);
|
||||
*output = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
288
src/trunnel/ed25519_cert.h
Normal file
288
src/trunnel/ed25519_cert.h
Normal file
@ -0,0 +1,288 @@
|
||||
/* ed25519_cert.h -- generated by by Trunnel v1.2.
|
||||
* https://gitweb.torproject.org/trunnel.git
|
||||
* You probably shouldn't edit this file.
|
||||
*/
|
||||
#ifndef TRUNNEL_ED25519_CERT_H
|
||||
#define TRUNNEL_ED25519_CERT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "trunnel.h"
|
||||
|
||||
#define CERTEXT_SIGNED_WITH_KEY 4
|
||||
#define CERTEXT_FLAG_AFFECTS_VALIDATION 1
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_ED25519_CERT_EXTENSION)
|
||||
struct ed25519_cert_extension_st {
|
||||
uint16_t ext_length;
|
||||
uint8_t ext_type;
|
||||
uint8_t ext_flags;
|
||||
uint8_t un_signing_key[32];
|
||||
TRUNNEL_DYNARRAY_HEAD(, uint8_t) un_unparsed;
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct ed25519_cert_extension_st ed25519_cert_extension_t;
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_ED25519_CERT)
|
||||
struct ed25519_cert_st {
|
||||
uint8_t version;
|
||||
uint8_t cert_type;
|
||||
uint32_t exp_field;
|
||||
uint8_t cert_key_type;
|
||||
uint8_t certified_key[32];
|
||||
uint8_t n_extensions;
|
||||
TRUNNEL_DYNARRAY_HEAD(, struct ed25519_cert_extension_st *) ext;
|
||||
uint8_t signature[64];
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct ed25519_cert_st ed25519_cert_t;
|
||||
/** Return a newly allocated ed25519_cert_extension with all elements
|
||||
* set to zero.
|
||||
*/
|
||||
ed25519_cert_extension_t *ed25519_cert_extension_new(void);
|
||||
/** Release all storage held by the ed25519_cert_extension in
|
||||
* 'victim'. (Do nothing if 'victim' is NULL.)
|
||||
*/
|
||||
void ed25519_cert_extension_free(ed25519_cert_extension_t *victim);
|
||||
/** Try to parse a ed25519_cert_extension from the buffer in 'input',
|
||||
* using up to 'len_in' bytes from the input buffer. On success,
|
||||
* return the number of bytes consumed and set *output to the newly
|
||||
* allocated ed25519_cert_extension_t. On failure, return -2 if the
|
||||
* input appears truncated, and -1 if the input is otherwise invalid.
|
||||
*/
|
||||
ssize_t ed25519_cert_extension_parse(ed25519_cert_extension_t **output, const uint8_t *input, const size_t len_in);
|
||||
/** Return the number of bytes we expect to need to encode the
|
||||
* ed25519_cert_extension in 'obj'. On failure, return a negative
|
||||
* value. Note that this value may be an overestimate, and can even be
|
||||
* an underestimate for certain unencodeable objects.
|
||||
*/
|
||||
ssize_t ed25519_cert_extension_encoded_len(const ed25519_cert_extension_t *obj);
|
||||
/** Try to encode the ed25519_cert_extension from 'input' into the
|
||||
* buffer at 'output', using up to 'avail' bytes of the output buffer.
|
||||
* On success, return the number of bytes used. On failure, return -2
|
||||
* if the buffer was not long enough, and -1 if the input was invalid.
|
||||
*/
|
||||
ssize_t ed25519_cert_extension_encode(uint8_t *output, const size_t avail, const ed25519_cert_extension_t *input);
|
||||
/** Check whether the internal state of the ed25519_cert_extension in
|
||||
* 'obj' is consistent. Return NULL if it is, and a short message if
|
||||
* it is not.
|
||||
*/
|
||||
const char *ed25519_cert_extension_check(const ed25519_cert_extension_t *obj);
|
||||
/** Clear any errors that were set on the object 'obj' by its setter
|
||||
* functions. Return true iff errors were cleared.
|
||||
*/
|
||||
int ed25519_cert_extension_clear_errors(ed25519_cert_extension_t *obj);
|
||||
/** Return the value of the ext_length field of the
|
||||
* ed25519_cert_extension_t in 'inp'
|
||||
*/
|
||||
uint16_t ed25519_cert_extension_get_ext_length(ed25519_cert_extension_t *inp);
|
||||
/** Set the value of the ext_length field of the
|
||||
* ed25519_cert_extension_t in 'inp' to 'val'. Return 0 on success;
|
||||
* return -1 and set the error code on 'inp' on failure.
|
||||
*/
|
||||
int ed25519_cert_extension_set_ext_length(ed25519_cert_extension_t *inp, uint16_t val);
|
||||
/** Return the value of the ext_type field of the
|
||||
* ed25519_cert_extension_t in 'inp'
|
||||
*/
|
||||
uint8_t ed25519_cert_extension_get_ext_type(ed25519_cert_extension_t *inp);
|
||||
/** Set the value of the ext_type field of the
|
||||
* ed25519_cert_extension_t in 'inp' to 'val'. Return 0 on success;
|
||||
* return -1 and set the error code on 'inp' on failure.
|
||||
*/
|
||||
int ed25519_cert_extension_set_ext_type(ed25519_cert_extension_t *inp, uint8_t val);
|
||||
/** Return the value of the ext_flags field of the
|
||||
* ed25519_cert_extension_t in 'inp'
|
||||
*/
|
||||
uint8_t ed25519_cert_extension_get_ext_flags(ed25519_cert_extension_t *inp);
|
||||
/** Set the value of the ext_flags field of the
|
||||
* ed25519_cert_extension_t in 'inp' to 'val'. Return 0 on success;
|
||||
* return -1 and set the error code on 'inp' on failure.
|
||||
*/
|
||||
int ed25519_cert_extension_set_ext_flags(ed25519_cert_extension_t *inp, uint8_t val);
|
||||
/** Return the (constant) length of the array holding the
|
||||
* un_signing_key field of the ed25519_cert_extension_t in 'inp'.
|
||||
*/
|
||||
size_t ed25519_cert_extension_getlen_un_signing_key(const ed25519_cert_extension_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field
|
||||
* un_signing_key of the ed25519_cert_extension_t in 'inp'.
|
||||
*/
|
||||
uint8_t ed25519_cert_extension_get_un_signing_key(const ed25519_cert_extension_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field
|
||||
* un_signing_key of the ed25519_cert_extension_t in 'inp', so that it
|
||||
* will hold the value 'elt'.
|
||||
*/
|
||||
int ed25519_cert_extension_set_un_signing_key(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field un_signing_key of
|
||||
* 'inp'.
|
||||
*/
|
||||
uint8_t * ed25519_cert_extension_getarray_un_signing_key(ed25519_cert_extension_t *inp);
|
||||
/** Return the length of the dynamic array holding the un_unparsed
|
||||
* field of the ed25519_cert_extension_t in 'inp'.
|
||||
*/
|
||||
size_t ed25519_cert_extension_getlen_un_unparsed(const ed25519_cert_extension_t *inp);
|
||||
/** Return the element at position 'idx' of the dynamic array field
|
||||
* un_unparsed of the ed25519_cert_extension_t in 'inp'.
|
||||
*/
|
||||
uint8_t ed25519_cert_extension_get_un_unparsed(ed25519_cert_extension_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the dynamic array field
|
||||
* un_unparsed of the ed25519_cert_extension_t in 'inp', so that it
|
||||
* will hold the value 'elt'.
|
||||
*/
|
||||
int ed25519_cert_extension_set_un_unparsed(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt);
|
||||
/** Append a new element 'elt' to the dynamic array field un_unparsed
|
||||
* of the ed25519_cert_extension_t in 'inp'.
|
||||
*/
|
||||
int ed25519_cert_extension_add_un_unparsed(ed25519_cert_extension_t *inp, uint8_t elt);
|
||||
/** Return a pointer to the variable-length array field un_unparsed of
|
||||
* 'inp'.
|
||||
*/
|
||||
uint8_t * ed25519_cert_extension_getarray_un_unparsed(ed25519_cert_extension_t *inp);
|
||||
/** Change the length of the variable-length array field un_unparsed
|
||||
* of 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on
|
||||
* success; return -1 and set the error code on 'inp' on failure.
|
||||
*/
|
||||
int ed25519_cert_extension_setlen_un_unparsed(ed25519_cert_extension_t *inp, size_t newlen);
|
||||
/** Return a newly allocated ed25519_cert with all elements set to
|
||||
* zero.
|
||||
*/
|
||||
ed25519_cert_t *ed25519_cert_new(void);
|
||||
/** Release all storage held by the ed25519_cert in 'victim'. (Do
|
||||
* nothing if 'victim' is NULL.)
|
||||
*/
|
||||
void ed25519_cert_free(ed25519_cert_t *victim);
|
||||
/** Try to parse a ed25519_cert from the buffer in 'input', using up
|
||||
* to 'len_in' bytes from the input buffer. On success, return the
|
||||
* number of bytes consumed and set *output to the newly allocated
|
||||
* ed25519_cert_t. On failure, return -2 if the input appears
|
||||
* truncated, and -1 if the input is otherwise invalid.
|
||||
*/
|
||||
ssize_t ed25519_cert_parse(ed25519_cert_t **output, const uint8_t *input, const size_t len_in);
|
||||
/** Return the number of bytes we expect to need to encode the
|
||||
* ed25519_cert in 'obj'. On failure, return a negative value. Note
|
||||
* that this value may be an overestimate, and can even be an
|
||||
* underestimate for certain unencodeable objects.
|
||||
*/
|
||||
ssize_t ed25519_cert_encoded_len(const ed25519_cert_t *obj);
|
||||
/** Try to encode the ed25519_cert from 'input' into the buffer at
|
||||
* 'output', using up to 'avail' bytes of the output buffer. On
|
||||
* success, return the number of bytes used. On failure, return -2 if
|
||||
* the buffer was not long enough, and -1 if the input was invalid.
|
||||
*/
|
||||
ssize_t ed25519_cert_encode(uint8_t *output, const size_t avail, const ed25519_cert_t *input);
|
||||
/** Check whether the internal state of the ed25519_cert in 'obj' is
|
||||
* consistent. Return NULL if it is, and a short message if it is not.
|
||||
*/
|
||||
const char *ed25519_cert_check(const ed25519_cert_t *obj);
|
||||
/** Clear any errors that were set on the object 'obj' by its setter
|
||||
* functions. Return true iff errors were cleared.
|
||||
*/
|
||||
int ed25519_cert_clear_errors(ed25519_cert_t *obj);
|
||||
/** Return the value of the version field of the ed25519_cert_t in
|
||||
* 'inp'
|
||||
*/
|
||||
uint8_t ed25519_cert_get_version(ed25519_cert_t *inp);
|
||||
/** Set the value of the version field of the ed25519_cert_t in 'inp'
|
||||
* to 'val'. Return 0 on success; return -1 and set the error code on
|
||||
* 'inp' on failure.
|
||||
*/
|
||||
int ed25519_cert_set_version(ed25519_cert_t *inp, uint8_t val);
|
||||
/** Return the value of the cert_type field of the ed25519_cert_t in
|
||||
* 'inp'
|
||||
*/
|
||||
uint8_t ed25519_cert_get_cert_type(ed25519_cert_t *inp);
|
||||
/** Set the value of the cert_type field of the ed25519_cert_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int ed25519_cert_set_cert_type(ed25519_cert_t *inp, uint8_t val);
|
||||
/** Return the value of the exp_field field of the ed25519_cert_t in
|
||||
* 'inp'
|
||||
*/
|
||||
uint32_t ed25519_cert_get_exp_field(ed25519_cert_t *inp);
|
||||
/** Set the value of the exp_field field of the ed25519_cert_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int ed25519_cert_set_exp_field(ed25519_cert_t *inp, uint32_t val);
|
||||
/** Return the value of the cert_key_type field of the ed25519_cert_t
|
||||
* in 'inp'
|
||||
*/
|
||||
uint8_t ed25519_cert_get_cert_key_type(ed25519_cert_t *inp);
|
||||
/** Set the value of the cert_key_type field of the ed25519_cert_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int ed25519_cert_set_cert_key_type(ed25519_cert_t *inp, uint8_t val);
|
||||
/** Return the (constant) length of the array holding the
|
||||
* certified_key field of the ed25519_cert_t in 'inp'.
|
||||
*/
|
||||
size_t ed25519_cert_getlen_certified_key(const ed25519_cert_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field
|
||||
* certified_key of the ed25519_cert_t in 'inp'.
|
||||
*/
|
||||
uint8_t ed25519_cert_get_certified_key(const ed25519_cert_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field
|
||||
* certified_key of the ed25519_cert_t in 'inp', so that it will hold
|
||||
* the value 'elt'.
|
||||
*/
|
||||
int ed25519_cert_set_certified_key(ed25519_cert_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field certified_key of
|
||||
* 'inp'.
|
||||
*/
|
||||
uint8_t * ed25519_cert_getarray_certified_key(ed25519_cert_t *inp);
|
||||
/** Return the value of the n_extensions field of the ed25519_cert_t
|
||||
* in 'inp'
|
||||
*/
|
||||
uint8_t ed25519_cert_get_n_extensions(ed25519_cert_t *inp);
|
||||
/** Set the value of the n_extensions field of the ed25519_cert_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int ed25519_cert_set_n_extensions(ed25519_cert_t *inp, uint8_t val);
|
||||
/** Return the length of the dynamic array holding the ext field of
|
||||
* the ed25519_cert_t in 'inp'.
|
||||
*/
|
||||
size_t ed25519_cert_getlen_ext(const ed25519_cert_t *inp);
|
||||
/** Return the element at position 'idx' of the dynamic array field
|
||||
* ext of the ed25519_cert_t in 'inp'.
|
||||
*/
|
||||
struct ed25519_cert_extension_st * ed25519_cert_get_ext(ed25519_cert_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the dynamic array field
|
||||
* ext of the ed25519_cert_t in 'inp', so that it will hold the value
|
||||
* 'elt'. Free the previous value, if any.
|
||||
*/
|
||||
int ed25519_cert_set_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt);
|
||||
/** As ed25519_cert_set_ext, but does not free the previous value.
|
||||
*/
|
||||
int ed25519_cert_set0_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt);
|
||||
/** Append a new element 'elt' to the dynamic array field ext of the
|
||||
* ed25519_cert_t in 'inp'.
|
||||
*/
|
||||
int ed25519_cert_add_ext(ed25519_cert_t *inp, struct ed25519_cert_extension_st * elt);
|
||||
/** Return a pointer to the variable-length array field ext of 'inp'.
|
||||
*/
|
||||
struct ed25519_cert_extension_st * * ed25519_cert_getarray_ext(ed25519_cert_t *inp);
|
||||
/** Change the length of the variable-length array field ext of 'inp'
|
||||
* to 'newlen'.Fill extra elements with NULL; free removed elements.
|
||||
* Return 0 on success; return -1 and set the error code on 'inp' on
|
||||
* failure.
|
||||
*/
|
||||
int ed25519_cert_setlen_ext(ed25519_cert_t *inp, size_t newlen);
|
||||
/** Return the (constant) length of the array holding the signature
|
||||
* field of the ed25519_cert_t in 'inp'.
|
||||
*/
|
||||
size_t ed25519_cert_getlen_signature(const ed25519_cert_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field
|
||||
* signature of the ed25519_cert_t in 'inp'.
|
||||
*/
|
||||
uint8_t ed25519_cert_get_signature(const ed25519_cert_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field
|
||||
* signature of the ed25519_cert_t in 'inp', so that it will hold the
|
||||
* value 'elt'.
|
||||
*/
|
||||
int ed25519_cert_set_signature(ed25519_cert_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 64-element array field signature of 'inp'.
|
||||
*/
|
||||
uint8_t * ed25519_cert_getarray_signature(ed25519_cert_t *inp);
|
||||
|
||||
|
||||
#endif
|
76
src/trunnel/ed25519_cert.trunnel
Normal file
76
src/trunnel/ed25519_cert.trunnel
Normal file
@ -0,0 +1,76 @@
|
||||
|
||||
struct ed25519_cert {
|
||||
u8 version IN [1];
|
||||
u8 cert_type;
|
||||
u32 exp_field;
|
||||
u8 cert_key_type;
|
||||
u8 certified_key[32];
|
||||
u8 n_extensions;
|
||||
struct ed25519_cert_extension ext[n_extensions];
|
||||
u8 signature[64];
|
||||
}
|
||||
|
||||
const CERTEXT_SIGNED_WITH_KEY = 4;
|
||||
const CERTEXT_FLAG_AFFECTS_VALIDATION = 1;
|
||||
|
||||
struct ed25519_cert_extension {
|
||||
u16 ext_length;
|
||||
u8 ext_type;
|
||||
u8 ext_flags;
|
||||
union un[ext_type] with length ext_length {
|
||||
CERTEXT_SIGNED_WITH_KEY : u8 signing_key[32];
|
||||
default: u8 unparsed[];
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
struct cert_revocation {
|
||||
u8 prefix[8];
|
||||
u8 version IN [1];
|
||||
u8 keytype;
|
||||
u8 identity_key[32];
|
||||
u8 revoked_key[32];
|
||||
u64 published;
|
||||
u8 n_extensions;
|
||||
struct cert_extension ext[n_extensions];
|
||||
u8 signature[64];
|
||||
}
|
||||
|
||||
struct crosscert_ed_rsa {
|
||||
u8 ed_key[32];
|
||||
u32 expiration_date;
|
||||
u8 signature[128];
|
||||
}
|
||||
|
||||
struct auth02_cell {
|
||||
u8 type[8];
|
||||
u8 cid[32];
|
||||
u8 sid[32];
|
||||
u8 cid_ed[32];
|
||||
u8 sid_ed[32];
|
||||
u8 slog[32];
|
||||
u8 clog[32];
|
||||
u8 scert[32];
|
||||
u8 tlssecrets[32];
|
||||
u8 rand[24];
|
||||
u8 sig[64];
|
||||
}
|
||||
|
||||
const LS_IPV4 = 0x00;
|
||||
const LS_IPV6 = 0x01;
|
||||
const LS_LEGACY_ID = 0x02;
|
||||
const LS_ED25519_ID = 0x03;
|
||||
|
||||
// amended from tor.trunnel
|
||||
struct link_specifier {
|
||||
u8 ls_type;
|
||||
u8 ls_len;
|
||||
union un[ls_type] with length ls_len {
|
||||
LS_IPV4: u32 ipv4_addr; u16 ipv4_port;
|
||||
LS_IPV6: u8 ipv6_addr[16]; u16 ipv6_port;
|
||||
LS_LEGACY_ID: u8 legacy_id[20];
|
||||
LS_ED25519_ID: u8 ed25519_id[32];
|
||||
default: u8 unrecognized[];
|
||||
};
|
||||
}
|
||||
*/
|
@ -9,15 +9,24 @@ endif
|
||||
|
||||
AM_CPPFLAGS += -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel
|
||||
|
||||
TRUNNELINPUTS = \
|
||||
src/trunnel/ed25519_cert.trunnel \
|
||||
src/trunnel/link_handshake.trunnel \
|
||||
src/trunnel/pwbox.trunnel
|
||||
|
||||
TRUNNELSOURCES = \
|
||||
src/ext/trunnel/trunnel.c \
|
||||
src/trunnel/pwbox.c
|
||||
src/ext/trunnel/trunnel.c \
|
||||
src/trunnel/ed25519_cert.c \
|
||||
src/trunnel/link_handshake.c \
|
||||
src/trunnel/pwbox.c
|
||||
|
||||
TRUNNELHEADERS = \
|
||||
src/ext/trunnel/trunnel.h \
|
||||
src/ext/trunnel/trunnel-impl.h \
|
||||
src/trunnel/trunnel-local.h \
|
||||
src/trunnel/pwbox.h
|
||||
src/ext/trunnel/trunnel.h \
|
||||
src/ext/trunnel/trunnel-impl.h \
|
||||
src/trunnel/trunnel-local.h \
|
||||
src/trunnel/ed25519_cert.h \
|
||||
src/trunnel/link_handshake.h \
|
||||
src/trunnel/pwbox.h
|
||||
|
||||
src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES)
|
||||
src_trunnel_libor_trunnel_a_CPPFLAGS = -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS)
|
||||
|
1885
src/trunnel/link_handshake.c
Normal file
1885
src/trunnel/link_handshake.c
Normal file
File diff suppressed because it is too large
Load Diff
654
src/trunnel/link_handshake.h
Normal file
654
src/trunnel/link_handshake.h
Normal file
@ -0,0 +1,654 @@
|
||||
/* link_handshake.h -- generated by by Trunnel v1.4-pre.
|
||||
* https://gitweb.torproject.org/trunnel.git
|
||||
* You probably shouldn't edit this file.
|
||||
*/
|
||||
#ifndef TRUNNEL_LINK_HANDSHAKE_H
|
||||
#define TRUNNEL_LINK_HANDSHAKE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "trunnel.h"
|
||||
|
||||
#define CERTTYPE_RSA1024_ID_LINK 1
|
||||
#define CERTTYPE_RSA1024_ID_ID 2
|
||||
#define CERTTYPE_RSA1024_ID_AUTH 3
|
||||
#define CERTTYPE_ED_ID_SIGN 4
|
||||
#define CERTTYPE_ED_SIGN_LINK 5
|
||||
#define CERTTYPE_ED_SIGN_AUTH 6
|
||||
#define CERTTYPE_RSA1024_ID_EDID 7
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH_CHALLENGE_CELL)
|
||||
struct auth_challenge_cell_st {
|
||||
uint8_t challenge[32];
|
||||
uint16_t n_methods;
|
||||
TRUNNEL_DYNARRAY_HEAD(, uint16_t) methods;
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct auth_challenge_cell_st auth_challenge_cell_t;
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH_CTX)
|
||||
struct auth_ctx_st {
|
||||
uint8_t is_ed;
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct auth_ctx_st auth_ctx_t;
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CERTS_CELL_CERT)
|
||||
struct certs_cell_cert_st {
|
||||
uint8_t cert_type;
|
||||
uint16_t cert_len;
|
||||
TRUNNEL_DYNARRAY_HEAD(, uint8_t) body;
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct certs_cell_cert_st certs_cell_cert_t;
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_RSA_ED_CROSSCERT)
|
||||
struct rsa_ed_crosscert_st {
|
||||
uint8_t ed_key[32];
|
||||
uint32_t expiration;
|
||||
const uint8_t *end_of_signed;
|
||||
uint8_t sig_len;
|
||||
TRUNNEL_DYNARRAY_HEAD(, uint8_t) sig;
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct rsa_ed_crosscert_st rsa_ed_crosscert_t;
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH1)
|
||||
struct auth1_st {
|
||||
uint8_t type[8];
|
||||
uint8_t cid[32];
|
||||
uint8_t sid[32];
|
||||
uint8_t u1_cid_ed[32];
|
||||
uint8_t u1_sid_ed[32];
|
||||
uint8_t slog[32];
|
||||
uint8_t clog[32];
|
||||
uint8_t scert[32];
|
||||
uint8_t tlssecrets[32];
|
||||
const uint8_t *end_of_fixed_part;
|
||||
uint8_t rand[24];
|
||||
const uint8_t *end_of_signed;
|
||||
TRUNNEL_DYNARRAY_HEAD(, uint8_t) sig;
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct auth1_st auth1_t;
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CERTS_CELL)
|
||||
struct certs_cell_st {
|
||||
uint8_t n_certs;
|
||||
TRUNNEL_DYNARRAY_HEAD(, struct certs_cell_cert_st *) certs;
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct certs_cell_st certs_cell_t;
|
||||
/** Return a newly allocated auth_challenge_cell with all elements set
|
||||
* to zero.
|
||||
*/
|
||||
auth_challenge_cell_t *auth_challenge_cell_new(void);
|
||||
/** Release all storage held by the auth_challenge_cell in 'victim'.
|
||||
* (Do nothing if 'victim' is NULL.)
|
||||
*/
|
||||
void auth_challenge_cell_free(auth_challenge_cell_t *victim);
|
||||
/** Try to parse a auth_challenge_cell from the buffer in 'input',
|
||||
* using up to 'len_in' bytes from the input buffer. On success,
|
||||
* return the number of bytes consumed and set *output to the newly
|
||||
* allocated auth_challenge_cell_t. On failure, return -2 if the input
|
||||
* appears truncated, and -1 if the input is otherwise invalid.
|
||||
*/
|
||||
ssize_t auth_challenge_cell_parse(auth_challenge_cell_t **output, const uint8_t *input, const size_t len_in);
|
||||
/** Return the number of bytes we expect to need to encode the
|
||||
* auth_challenge_cell in 'obj'. On failure, return a negative value.
|
||||
* Note that this value may be an overestimate, and can even be an
|
||||
* underestimate for certain unencodeable objects.
|
||||
*/
|
||||
ssize_t auth_challenge_cell_encoded_len(const auth_challenge_cell_t *obj);
|
||||
/** Try to encode the auth_challenge_cell from 'input' into the buffer
|
||||
* at 'output', using up to 'avail' bytes of the output buffer. On
|
||||
* success, return the number of bytes used. On failure, return -2 if
|
||||
* the buffer was not long enough, and -1 if the input was invalid.
|
||||
*/
|
||||
ssize_t auth_challenge_cell_encode(uint8_t *output, const size_t avail, const auth_challenge_cell_t *input);
|
||||
/** Check whether the internal state of the auth_challenge_cell in
|
||||
* 'obj' is consistent. Return NULL if it is, and a short message if
|
||||
* it is not.
|
||||
*/
|
||||
const char *auth_challenge_cell_check(const auth_challenge_cell_t *obj);
|
||||
/** Clear any errors that were set on the object 'obj' by its setter
|
||||
* functions. Return true iff errors were cleared.
|
||||
*/
|
||||
int auth_challenge_cell_clear_errors(auth_challenge_cell_t *obj);
|
||||
/** Return the (constant) length of the array holding the challenge
|
||||
* field of the auth_challenge_cell_t in 'inp'.
|
||||
*/
|
||||
size_t auth_challenge_cell_getlen_challenge(const auth_challenge_cell_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field
|
||||
* challenge of the auth_challenge_cell_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth_challenge_cell_get_challenge(const auth_challenge_cell_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field
|
||||
* challenge of the auth_challenge_cell_t in 'inp', so that it will
|
||||
* hold the value 'elt'.
|
||||
*/
|
||||
int auth_challenge_cell_set_challenge(auth_challenge_cell_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field challenge of 'inp'.
|
||||
*/
|
||||
uint8_t * auth_challenge_cell_getarray_challenge(auth_challenge_cell_t *inp);
|
||||
/** Return the value of the n_methods field of the
|
||||
* auth_challenge_cell_t in 'inp'
|
||||
*/
|
||||
uint16_t auth_challenge_cell_get_n_methods(auth_challenge_cell_t *inp);
|
||||
/** Set the value of the n_methods field of the auth_challenge_cell_t
|
||||
* in 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int auth_challenge_cell_set_n_methods(auth_challenge_cell_t *inp, uint16_t val);
|
||||
/** Return the length of the dynamic array holding the methods field
|
||||
* of the auth_challenge_cell_t in 'inp'.
|
||||
*/
|
||||
size_t auth_challenge_cell_getlen_methods(const auth_challenge_cell_t *inp);
|
||||
/** Return the element at position 'idx' of the dynamic array field
|
||||
* methods of the auth_challenge_cell_t in 'inp'.
|
||||
*/
|
||||
uint16_t auth_challenge_cell_get_methods(auth_challenge_cell_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the dynamic array field
|
||||
* methods of the auth_challenge_cell_t in 'inp', so that it will hold
|
||||
* the value 'elt'.
|
||||
*/
|
||||
int auth_challenge_cell_set_methods(auth_challenge_cell_t *inp, size_t idx, uint16_t elt);
|
||||
/** Append a new element 'elt' to the dynamic array field methods of
|
||||
* the auth_challenge_cell_t in 'inp'.
|
||||
*/
|
||||
int auth_challenge_cell_add_methods(auth_challenge_cell_t *inp, uint16_t elt);
|
||||
/** Return a pointer to the variable-length array field methods of
|
||||
* 'inp'.
|
||||
*/
|
||||
uint16_t * auth_challenge_cell_getarray_methods(auth_challenge_cell_t *inp);
|
||||
/** Change the length of the variable-length array field methods of
|
||||
* 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on success;
|
||||
* return -1 and set the error code on 'inp' on failure.
|
||||
*/
|
||||
int auth_challenge_cell_setlen_methods(auth_challenge_cell_t *inp, size_t newlen);
|
||||
/** Return a newly allocated auth_ctx with all elements set to zero.
|
||||
*/
|
||||
auth_ctx_t *auth_ctx_new(void);
|
||||
/** Release all storage held by the auth_ctx in 'victim'. (Do nothing
|
||||
* if 'victim' is NULL.)
|
||||
*/
|
||||
void auth_ctx_free(auth_ctx_t *victim);
|
||||
/** Return the value of the is_ed field of the auth_ctx_t in 'inp'
|
||||
*/
|
||||
uint8_t auth_ctx_get_is_ed(auth_ctx_t *inp);
|
||||
/** Set the value of the is_ed field of the auth_ctx_t in 'inp' to
|
||||
* 'val'. Return 0 on success; return -1 and set the error code on
|
||||
* 'inp' on failure.
|
||||
*/
|
||||
int auth_ctx_set_is_ed(auth_ctx_t *inp, uint8_t val);
|
||||
/** Return a newly allocated certs_cell_cert with all elements set to
|
||||
* zero.
|
||||
*/
|
||||
certs_cell_cert_t *certs_cell_cert_new(void);
|
||||
/** Release all storage held by the certs_cell_cert in 'victim'. (Do
|
||||
* nothing if 'victim' is NULL.)
|
||||
*/
|
||||
void certs_cell_cert_free(certs_cell_cert_t *victim);
|
||||
/** Try to parse a certs_cell_cert from the buffer in 'input', using
|
||||
* up to 'len_in' bytes from the input buffer. On success, return the
|
||||
* number of bytes consumed and set *output to the newly allocated
|
||||
* certs_cell_cert_t. On failure, return -2 if the input appears
|
||||
* truncated, and -1 if the input is otherwise invalid.
|
||||
*/
|
||||
ssize_t certs_cell_cert_parse(certs_cell_cert_t **output, const uint8_t *input, const size_t len_in);
|
||||
/** Return the number of bytes we expect to need to encode the
|
||||
* certs_cell_cert in 'obj'. On failure, return a negative value. Note
|
||||
* that this value may be an overestimate, and can even be an
|
||||
* underestimate for certain unencodeable objects.
|
||||
*/
|
||||
ssize_t certs_cell_cert_encoded_len(const certs_cell_cert_t *obj);
|
||||
/** Try to encode the certs_cell_cert from 'input' into the buffer at
|
||||
* 'output', using up to 'avail' bytes of the output buffer. On
|
||||
* success, return the number of bytes used. On failure, return -2 if
|
||||
* the buffer was not long enough, and -1 if the input was invalid.
|
||||
*/
|
||||
ssize_t certs_cell_cert_encode(uint8_t *output, const size_t avail, const certs_cell_cert_t *input);
|
||||
/** Check whether the internal state of the certs_cell_cert in 'obj'
|
||||
* is consistent. Return NULL if it is, and a short message if it is
|
||||
* not.
|
||||
*/
|
||||
const char *certs_cell_cert_check(const certs_cell_cert_t *obj);
|
||||
/** Clear any errors that were set on the object 'obj' by its setter
|
||||
* functions. Return true iff errors were cleared.
|
||||
*/
|
||||
int certs_cell_cert_clear_errors(certs_cell_cert_t *obj);
|
||||
/** Return the value of the cert_type field of the certs_cell_cert_t
|
||||
* in 'inp'
|
||||
*/
|
||||
uint8_t certs_cell_cert_get_cert_type(certs_cell_cert_t *inp);
|
||||
/** Set the value of the cert_type field of the certs_cell_cert_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int certs_cell_cert_set_cert_type(certs_cell_cert_t *inp, uint8_t val);
|
||||
/** Return the value of the cert_len field of the certs_cell_cert_t in
|
||||
* 'inp'
|
||||
*/
|
||||
uint16_t certs_cell_cert_get_cert_len(certs_cell_cert_t *inp);
|
||||
/** Set the value of the cert_len field of the certs_cell_cert_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int certs_cell_cert_set_cert_len(certs_cell_cert_t *inp, uint16_t val);
|
||||
/** Return the length of the dynamic array holding the body field of
|
||||
* the certs_cell_cert_t in 'inp'.
|
||||
*/
|
||||
size_t certs_cell_cert_getlen_body(const certs_cell_cert_t *inp);
|
||||
/** Return the element at position 'idx' of the dynamic array field
|
||||
* body of the certs_cell_cert_t in 'inp'.
|
||||
*/
|
||||
uint8_t certs_cell_cert_get_body(certs_cell_cert_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the dynamic array field
|
||||
* body of the certs_cell_cert_t in 'inp', so that it will hold the
|
||||
* value 'elt'.
|
||||
*/
|
||||
int certs_cell_cert_set_body(certs_cell_cert_t *inp, size_t idx, uint8_t elt);
|
||||
/** Append a new element 'elt' to the dynamic array field body of the
|
||||
* certs_cell_cert_t in 'inp'.
|
||||
*/
|
||||
int certs_cell_cert_add_body(certs_cell_cert_t *inp, uint8_t elt);
|
||||
/** Return a pointer to the variable-length array field body of 'inp'.
|
||||
*/
|
||||
uint8_t * certs_cell_cert_getarray_body(certs_cell_cert_t *inp);
|
||||
/** Change the length of the variable-length array field body of 'inp'
|
||||
* to 'newlen'.Fill extra elements with 0. Return 0 on success; return
|
||||
* -1 and set the error code on 'inp' on failure.
|
||||
*/
|
||||
int certs_cell_cert_setlen_body(certs_cell_cert_t *inp, size_t newlen);
|
||||
/** Return a newly allocated rsa_ed_crosscert with all elements set to
|
||||
* zero.
|
||||
*/
|
||||
rsa_ed_crosscert_t *rsa_ed_crosscert_new(void);
|
||||
/** Release all storage held by the rsa_ed_crosscert in 'victim'. (Do
|
||||
* nothing if 'victim' is NULL.)
|
||||
*/
|
||||
void rsa_ed_crosscert_free(rsa_ed_crosscert_t *victim);
|
||||
/** Try to parse a rsa_ed_crosscert from the buffer in 'input', using
|
||||
* up to 'len_in' bytes from the input buffer. On success, return the
|
||||
* number of bytes consumed and set *output to the newly allocated
|
||||
* rsa_ed_crosscert_t. On failure, return -2 if the input appears
|
||||
* truncated, and -1 if the input is otherwise invalid.
|
||||
*/
|
||||
ssize_t rsa_ed_crosscert_parse(rsa_ed_crosscert_t **output, const uint8_t *input, const size_t len_in);
|
||||
/** Return the number of bytes we expect to need to encode the
|
||||
* rsa_ed_crosscert in 'obj'. On failure, return a negative value.
|
||||
* Note that this value may be an overestimate, and can even be an
|
||||
* underestimate for certain unencodeable objects.
|
||||
*/
|
||||
ssize_t rsa_ed_crosscert_encoded_len(const rsa_ed_crosscert_t *obj);
|
||||
/** Try to encode the rsa_ed_crosscert from 'input' into the buffer at
|
||||
* 'output', using up to 'avail' bytes of the output buffer. On
|
||||
* success, return the number of bytes used. On failure, return -2 if
|
||||
* the buffer was not long enough, and -1 if the input was invalid.
|
||||
*/
|
||||
ssize_t rsa_ed_crosscert_encode(uint8_t *output, const size_t avail, const rsa_ed_crosscert_t *input);
|
||||
/** Check whether the internal state of the rsa_ed_crosscert in 'obj'
|
||||
* is consistent. Return NULL if it is, and a short message if it is
|
||||
* not.
|
||||
*/
|
||||
const char *rsa_ed_crosscert_check(const rsa_ed_crosscert_t *obj);
|
||||
/** Clear any errors that were set on the object 'obj' by its setter
|
||||
* functions. Return true iff errors were cleared.
|
||||
*/
|
||||
int rsa_ed_crosscert_clear_errors(rsa_ed_crosscert_t *obj);
|
||||
/** Return the (constant) length of the array holding the ed_key field
|
||||
* of the rsa_ed_crosscert_t in 'inp'.
|
||||
*/
|
||||
size_t rsa_ed_crosscert_getlen_ed_key(const rsa_ed_crosscert_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field
|
||||
* ed_key of the rsa_ed_crosscert_t in 'inp'.
|
||||
*/
|
||||
uint8_t rsa_ed_crosscert_get_ed_key(const rsa_ed_crosscert_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field
|
||||
* ed_key of the rsa_ed_crosscert_t in 'inp', so that it will hold the
|
||||
* value 'elt'.
|
||||
*/
|
||||
int rsa_ed_crosscert_set_ed_key(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field ed_key of 'inp'.
|
||||
*/
|
||||
uint8_t * rsa_ed_crosscert_getarray_ed_key(rsa_ed_crosscert_t *inp);
|
||||
/** Return the value of the expiration field of the rsa_ed_crosscert_t
|
||||
* in 'inp'
|
||||
*/
|
||||
uint32_t rsa_ed_crosscert_get_expiration(rsa_ed_crosscert_t *inp);
|
||||
/** Set the value of the expiration field of the rsa_ed_crosscert_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int rsa_ed_crosscert_set_expiration(rsa_ed_crosscert_t *inp, uint32_t val);
|
||||
/** Return the position for end_of_signed when we parsed this object
|
||||
*/
|
||||
const uint8_t * rsa_ed_crosscert_get_end_of_signed(const rsa_ed_crosscert_t *inp);
|
||||
/** Return the value of the sig_len field of the rsa_ed_crosscert_t in
|
||||
* 'inp'
|
||||
*/
|
||||
uint8_t rsa_ed_crosscert_get_sig_len(rsa_ed_crosscert_t *inp);
|
||||
/** Set the value of the sig_len field of the rsa_ed_crosscert_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int rsa_ed_crosscert_set_sig_len(rsa_ed_crosscert_t *inp, uint8_t val);
|
||||
/** Return the length of the dynamic array holding the sig field of
|
||||
* the rsa_ed_crosscert_t in 'inp'.
|
||||
*/
|
||||
size_t rsa_ed_crosscert_getlen_sig(const rsa_ed_crosscert_t *inp);
|
||||
/** Return the element at position 'idx' of the dynamic array field
|
||||
* sig of the rsa_ed_crosscert_t in 'inp'.
|
||||
*/
|
||||
uint8_t rsa_ed_crosscert_get_sig(rsa_ed_crosscert_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the dynamic array field
|
||||
* sig of the rsa_ed_crosscert_t in 'inp', so that it will hold the
|
||||
* value 'elt'.
|
||||
*/
|
||||
int rsa_ed_crosscert_set_sig(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt);
|
||||
/** Append a new element 'elt' to the dynamic array field sig of the
|
||||
* rsa_ed_crosscert_t in 'inp'.
|
||||
*/
|
||||
int rsa_ed_crosscert_add_sig(rsa_ed_crosscert_t *inp, uint8_t elt);
|
||||
/** Return a pointer to the variable-length array field sig of 'inp'.
|
||||
*/
|
||||
uint8_t * rsa_ed_crosscert_getarray_sig(rsa_ed_crosscert_t *inp);
|
||||
/** Change the length of the variable-length array field sig of 'inp'
|
||||
* to 'newlen'.Fill extra elements with 0. Return 0 on success; return
|
||||
* -1 and set the error code on 'inp' on failure.
|
||||
*/
|
||||
int rsa_ed_crosscert_setlen_sig(rsa_ed_crosscert_t *inp, size_t newlen);
|
||||
/** Return a newly allocated auth1 with all elements set to zero.
|
||||
*/
|
||||
auth1_t *auth1_new(void);
|
||||
/** Release all storage held by the auth1 in 'victim'. (Do nothing if
|
||||
* 'victim' is NULL.)
|
||||
*/
|
||||
void auth1_free(auth1_t *victim);
|
||||
/** Try to parse a auth1 from the buffer in 'input', using up to
|
||||
* 'len_in' bytes from the input buffer. On success, return the number
|
||||
* of bytes consumed and set *output to the newly allocated auth1_t.
|
||||
* On failure, return -2 if the input appears truncated, and -1 if the
|
||||
* input is otherwise invalid.
|
||||
*/
|
||||
ssize_t auth1_parse(auth1_t **output, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx);
|
||||
/** Return the number of bytes we expect to need to encode the auth1
|
||||
* in 'obj'. On failure, return a negative value. Note that this value
|
||||
* may be an overestimate, and can even be an underestimate for
|
||||
* certain unencodeable objects.
|
||||
*/
|
||||
ssize_t auth1_encoded_len(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx);
|
||||
/** Try to encode the auth1 from 'input' into the buffer at 'output',
|
||||
* using up to 'avail' bytes of the output buffer. On success, return
|
||||
* the number of bytes used. On failure, return -2 if the buffer was
|
||||
* not long enough, and -1 if the input was invalid.
|
||||
*/
|
||||
ssize_t auth1_encode(uint8_t *output, const size_t avail, const auth1_t *input, const auth_ctx_t *auth_ctx_ctx);
|
||||
/** Check whether the internal state of the auth1 in 'obj' is
|
||||
* consistent. Return NULL if it is, and a short message if it is not.
|
||||
*/
|
||||
const char *auth1_check(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx);
|
||||
/** Clear any errors that were set on the object 'obj' by its setter
|
||||
* functions. Return true iff errors were cleared.
|
||||
*/
|
||||
int auth1_clear_errors(auth1_t *obj);
|
||||
/** Return the (constant) length of the array holding the type field
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_type(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field type
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_type(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field type
|
||||
* of the auth1_t in 'inp', so that it will hold the value 'elt'.
|
||||
*/
|
||||
int auth1_set_type(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 8-element array field type of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_type(auth1_t *inp);
|
||||
/** Return the (constant) length of the array holding the cid field of
|
||||
* the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_cid(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field cid
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_cid(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field cid
|
||||
* of the auth1_t in 'inp', so that it will hold the value 'elt'.
|
||||
*/
|
||||
int auth1_set_cid(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field cid of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_cid(auth1_t *inp);
|
||||
/** Return the (constant) length of the array holding the sid field of
|
||||
* the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_sid(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field sid
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_sid(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field sid
|
||||
* of the auth1_t in 'inp', so that it will hold the value 'elt'.
|
||||
*/
|
||||
int auth1_set_sid(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field sid of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_sid(auth1_t *inp);
|
||||
/** Return the (constant) length of the array holding the u1_cid_ed
|
||||
* field of the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_u1_cid_ed(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field
|
||||
* u1_cid_ed of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_u1_cid_ed(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field
|
||||
* u1_cid_ed of the auth1_t in 'inp', so that it will hold the value
|
||||
* 'elt'.
|
||||
*/
|
||||
int auth1_set_u1_cid_ed(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field u1_cid_ed of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_u1_cid_ed(auth1_t *inp);
|
||||
/** Return the (constant) length of the array holding the u1_sid_ed
|
||||
* field of the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_u1_sid_ed(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field
|
||||
* u1_sid_ed of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_u1_sid_ed(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field
|
||||
* u1_sid_ed of the auth1_t in 'inp', so that it will hold the value
|
||||
* 'elt'.
|
||||
*/
|
||||
int auth1_set_u1_sid_ed(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field u1_sid_ed of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_u1_sid_ed(auth1_t *inp);
|
||||
/** Return the (constant) length of the array holding the slog field
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_slog(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field slog
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_slog(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field slog
|
||||
* of the auth1_t in 'inp', so that it will hold the value 'elt'.
|
||||
*/
|
||||
int auth1_set_slog(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field slog of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_slog(auth1_t *inp);
|
||||
/** Return the (constant) length of the array holding the clog field
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_clog(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field clog
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_clog(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field clog
|
||||
* of the auth1_t in 'inp', so that it will hold the value 'elt'.
|
||||
*/
|
||||
int auth1_set_clog(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field clog of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_clog(auth1_t *inp);
|
||||
/** Return the (constant) length of the array holding the scert field
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_scert(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field
|
||||
* scert of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_scert(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field
|
||||
* scert of the auth1_t in 'inp', so that it will hold the value
|
||||
* 'elt'.
|
||||
*/
|
||||
int auth1_set_scert(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field scert of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_scert(auth1_t *inp);
|
||||
/** Return the (constant) length of the array holding the tlssecrets
|
||||
* field of the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_tlssecrets(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field
|
||||
* tlssecrets of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_tlssecrets(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field
|
||||
* tlssecrets of the auth1_t in 'inp', so that it will hold the value
|
||||
* 'elt'.
|
||||
*/
|
||||
int auth1_set_tlssecrets(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 32-element array field tlssecrets of
|
||||
* 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_tlssecrets(auth1_t *inp);
|
||||
/** Return the position for end_of_fixed_part when we parsed this
|
||||
* object
|
||||
*/
|
||||
const uint8_t * auth1_get_end_of_fixed_part(const auth1_t *inp);
|
||||
/** Return the (constant) length of the array holding the rand field
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_rand(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the fixed array field rand
|
||||
* of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_rand(const auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the fixed array field rand
|
||||
* of the auth1_t in 'inp', so that it will hold the value 'elt'.
|
||||
*/
|
||||
int auth1_set_rand(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Return a pointer to the 24-element array field rand of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_rand(auth1_t *inp);
|
||||
/** Return the position for end_of_signed when we parsed this object
|
||||
*/
|
||||
const uint8_t * auth1_get_end_of_signed(const auth1_t *inp);
|
||||
/** Return the length of the dynamic array holding the sig field of
|
||||
* the auth1_t in 'inp'.
|
||||
*/
|
||||
size_t auth1_getlen_sig(const auth1_t *inp);
|
||||
/** Return the element at position 'idx' of the dynamic array field
|
||||
* sig of the auth1_t in 'inp'.
|
||||
*/
|
||||
uint8_t auth1_get_sig(auth1_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the dynamic array field
|
||||
* sig of the auth1_t in 'inp', so that it will hold the value 'elt'.
|
||||
*/
|
||||
int auth1_set_sig(auth1_t *inp, size_t idx, uint8_t elt);
|
||||
/** Append a new element 'elt' to the dynamic array field sig of the
|
||||
* auth1_t in 'inp'.
|
||||
*/
|
||||
int auth1_add_sig(auth1_t *inp, uint8_t elt);
|
||||
/** Return a pointer to the variable-length array field sig of 'inp'.
|
||||
*/
|
||||
uint8_t * auth1_getarray_sig(auth1_t *inp);
|
||||
/** Change the length of the variable-length array field sig of 'inp'
|
||||
* to 'newlen'.Fill extra elements with 0. Return 0 on success; return
|
||||
* -1 and set the error code on 'inp' on failure.
|
||||
*/
|
||||
int auth1_setlen_sig(auth1_t *inp, size_t newlen);
|
||||
/** Return a newly allocated certs_cell with all elements set to zero.
|
||||
*/
|
||||
certs_cell_t *certs_cell_new(void);
|
||||
/** Release all storage held by the certs_cell in 'victim'. (Do
|
||||
* nothing if 'victim' is NULL.)
|
||||
*/
|
||||
void certs_cell_free(certs_cell_t *victim);
|
||||
/** Try to parse a certs_cell from the buffer in 'input', using up to
|
||||
* 'len_in' bytes from the input buffer. On success, return the number
|
||||
* of bytes consumed and set *output to the newly allocated
|
||||
* certs_cell_t. On failure, return -2 if the input appears truncated,
|
||||
* and -1 if the input is otherwise invalid.
|
||||
*/
|
||||
ssize_t certs_cell_parse(certs_cell_t **output, const uint8_t *input, const size_t len_in);
|
||||
/** Return the number of bytes we expect to need to encode the
|
||||
* certs_cell in 'obj'. On failure, return a negative value. Note that
|
||||
* this value may be an overestimate, and can even be an underestimate
|
||||
* for certain unencodeable objects.
|
||||
*/
|
||||
ssize_t certs_cell_encoded_len(const certs_cell_t *obj);
|
||||
/** Try to encode the certs_cell from 'input' into the buffer at
|
||||
* 'output', using up to 'avail' bytes of the output buffer. On
|
||||
* success, return the number of bytes used. On failure, return -2 if
|
||||
* the buffer was not long enough, and -1 if the input was invalid.
|
||||
*/
|
||||
ssize_t certs_cell_encode(uint8_t *output, const size_t avail, const certs_cell_t *input);
|
||||
/** Check whether the internal state of the certs_cell in 'obj' is
|
||||
* consistent. Return NULL if it is, and a short message if it is not.
|
||||
*/
|
||||
const char *certs_cell_check(const certs_cell_t *obj);
|
||||
/** Clear any errors that were set on the object 'obj' by its setter
|
||||
* functions. Return true iff errors were cleared.
|
||||
*/
|
||||
int certs_cell_clear_errors(certs_cell_t *obj);
|
||||
/** Return the value of the n_certs field of the certs_cell_t in 'inp'
|
||||
*/
|
||||
uint8_t certs_cell_get_n_certs(certs_cell_t *inp);
|
||||
/** Set the value of the n_certs field of the certs_cell_t in 'inp' to
|
||||
* 'val'. Return 0 on success; return -1 and set the error code on
|
||||
* 'inp' on failure.
|
||||
*/
|
||||
int certs_cell_set_n_certs(certs_cell_t *inp, uint8_t val);
|
||||
/** Return the length of the dynamic array holding the certs field of
|
||||
* the certs_cell_t in 'inp'.
|
||||
*/
|
||||
size_t certs_cell_getlen_certs(const certs_cell_t *inp);
|
||||
/** Return the element at position 'idx' of the dynamic array field
|
||||
* certs of the certs_cell_t in 'inp'.
|
||||
*/
|
||||
struct certs_cell_cert_st * certs_cell_get_certs(certs_cell_t *inp, size_t idx);
|
||||
/** Change the element at position 'idx' of the dynamic array field
|
||||
* certs of the certs_cell_t in 'inp', so that it will hold the value
|
||||
* 'elt'. Free the previous value, if any.
|
||||
*/
|
||||
int certs_cell_set_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt);
|
||||
/** As certs_cell_set_certs, but does not free the previous value.
|
||||
*/
|
||||
int certs_cell_set0_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt);
|
||||
/** Append a new element 'elt' to the dynamic array field certs of the
|
||||
* certs_cell_t in 'inp'.
|
||||
*/
|
||||
int certs_cell_add_certs(certs_cell_t *inp, struct certs_cell_cert_st * elt);
|
||||
/** Return a pointer to the variable-length array field certs of
|
||||
* 'inp'.
|
||||
*/
|
||||
struct certs_cell_cert_st * * certs_cell_getarray_certs(certs_cell_t *inp);
|
||||
/** Change the length of the variable-length array field certs of
|
||||
* 'inp' to 'newlen'.Fill extra elements with NULL; free removed
|
||||
* elements. Return 0 on success; return -1 and set the error code on
|
||||
* 'inp' on failure.
|
||||
*/
|
||||
int certs_cell_setlen_certs(certs_cell_t *inp, size_t newlen);
|
||||
|
||||
|
||||
#endif
|
57
src/trunnel/link_handshake.trunnel
Normal file
57
src/trunnel/link_handshake.trunnel
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
struct certs_cell {
|
||||
u8 n_certs;
|
||||
struct certs_cell_cert certs[n_certs];
|
||||
}
|
||||
|
||||
const CERTTYPE_RSA1024_ID_LINK = 1;
|
||||
const CERTTYPE_RSA1024_ID_ID = 2;
|
||||
const CERTTYPE_RSA1024_ID_AUTH = 3;
|
||||
const CERTTYPE_ED_ID_SIGN = 4;
|
||||
const CERTTYPE_ED_SIGN_LINK = 5;
|
||||
const CERTTYPE_ED_SIGN_AUTH = 6;
|
||||
const CERTTYPE_RSA1024_ID_EDID = 7;
|
||||
|
||||
struct certs_cell_cert {
|
||||
u8 cert_type;
|
||||
u16 cert_len;
|
||||
u8 body[cert_len];
|
||||
}
|
||||
|
||||
struct rsa_ed_crosscert {
|
||||
u8 ed_key[32];
|
||||
u32 expiration;
|
||||
@ptr end_of_signed;
|
||||
u8 sig_len;
|
||||
u8 sig[sig_len]; // mismatches spec.
|
||||
}
|
||||
|
||||
struct auth_challenge_cell {
|
||||
u8 challenge[32];
|
||||
u16 n_methods;
|
||||
u16 methods[n_methods];
|
||||
}
|
||||
|
||||
context auth_ctx {
|
||||
u8 is_ed;
|
||||
}
|
||||
|
||||
struct auth1 with context auth_ctx {
|
||||
u8 type[8];
|
||||
u8 cid[32];
|
||||
u8 sid[32];
|
||||
union u1[auth_ctx.is_ed] {
|
||||
0 : ;
|
||||
1 : u8 cid_ed[32];
|
||||
u8 sid_ed[32];
|
||||
default: fail;
|
||||
};
|
||||
u8 slog[32];
|
||||
u8 clog[32];
|
||||
u8 scert[32];
|
||||
u8 tlssecrets[32];
|
||||
@ptr end_of_fixed_part;
|
||||
u8 rand[24];
|
||||
@ptr end_of_signed;
|
||||
u8 sig[];
|
||||
}
|
Loading…
Reference in New Issue
Block a user