Add cross-certification to authority key certificates. Partial implementation of proposal 157.

svn:r17610
This commit is contained in:
Nick Mathewson 2008-12-12 18:31:39 +00:00
parent 6c2dbc56bf
commit 69ce955484
8 changed files with 151 additions and 57 deletions

View File

@ -19,6 +19,9 @@ Changes in version 0.2.1.9-alpha - 200?-??-??
- Try not to open more than one descriptor-downloading connection to an - Try not to open more than one descriptor-downloading connection to an
authority at once. This should reduce load on directory authorities. authority at once. This should reduce load on directory authorities.
Fixes bug 366. Fixes bug 366.
- Add cross-certification to newly generated certificates, so that
a signing key is enough information to use to look up a certificate.
Partial implementation of proposal 157.
o Minor features (controller): o Minor features (controller):
- New CONSENSUS_ARRIVED event to note when a new consensus has - New CONSENSUS_ARRIVED event to note when a new consensus has

View File

@ -758,6 +758,25 @@ $Id$
The directory server's public signing key. This key MUST be at The directory server's public signing key. This key MUST be at
least 1024 bits, and MAY be longer. least 1024 bits, and MAY be longer.
"dir-key-crosscert" NL CrossSignature NL
[At most once.]
NOTE: Authorities MUST include this field in all newly generated
certificates. A future version of this specification will make
the field required.
CrossSignature is a signature, made using the certificate's signing
key, of the digest of the PKCS1-padded hash of the certificate's
identity key. For backward compatibility with broken versions of the
parser, we wrap the base64-encoded signature in -----BEGIN ID
SIGNATURE---- and -----END ID SIGNATURE----- tags. Implementations
MUST allow the "ID " portion to be omitted, however.
When encountering a certificate with a dir-key-crosscert entry,
implementations MUST verify that the signature is a correct signature
of the hash of the identity key using the signing key.
"dir-key-certification" NL Signature NL "dir-key-certification" NL Signature NL
[At end, exactly once.] [At end, exactly once.]

View File

@ -13,6 +13,11 @@ History:
Changed name of cross certification field to match the other authority Changed name of cross certification field to match the other authority
certificate fields. certificate fields.
Status:
Cross-certification is implemented for new certificates, but not yet
required.
Overview: Overview:
Tor's directory specification gives two ways to download a certificate: Tor's directory specification gives two ways to download a certificate:

View File

@ -1729,6 +1729,7 @@ typedef struct authority_cert_t {
time_t expires; time_t expires;
uint32_t addr; uint32_t addr;
uint16_t dir_port; uint16_t dir_port;
uint8_t is_cross_certified;
} authority_cert_t; } authority_cert_t;
/** Bitfield enum type listing types of directory authority/directory /** Bitfield enum type listing types of directory authority/directory

View File

@ -70,6 +70,7 @@ typedef enum {
K_DIR_KEY_PUBLISHED, K_DIR_KEY_PUBLISHED,
K_DIR_KEY_EXPIRES, K_DIR_KEY_EXPIRES,
K_DIR_KEY_CERTIFICATION, K_DIR_KEY_CERTIFICATION,
K_DIR_KEY_CROSSCERT,
K_DIR_ADDRESS, K_DIR_ADDRESS,
K_VOTE_STATUS, K_VOTE_STATUS,
@ -328,6 +329,7 @@ static token_rule_t dir_token_table[] = {
T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ), \ T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ), \
T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ), \ T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ), \
T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\ T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\
T01("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),\
T1("dir-key-certification", K_DIR_KEY_CERTIFICATION, \ T1("dir-key-certification", K_DIR_KEY_CERTIFICATION, \
NO_ARGS, NEED_OBJ), \ NO_ARGS, NEED_OBJ), \
T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ), T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ),
@ -468,10 +470,12 @@ static directory_token_t *get_next_token(memarea_t *area,
const char **s, const char **s,
const char *eos, const char *eos,
token_rule_t *table); token_rule_t *table);
#define CST_CHECK_AUTHORITY (1<<0)
#define CST_NO_CHECK_OBJTYPE (1<<1)
static int check_signature_token(const char *digest, static int check_signature_token(const char *digest,
directory_token_t *tok, directory_token_t *tok,
crypto_pk_env_t *pkey, crypto_pk_env_t *pkey,
int check_authority, int flags,
const char *doctype); const char *doctype);
static crypto_pk_env_t *find_dir_signing_key(const char *str, const char *eos); static crypto_pk_env_t *find_dir_signing_key(const char *str, const char *eos);
static int tor_version_same_series(tor_version_t *a, tor_version_t *b); static int tor_version_same_series(tor_version_t *a, tor_version_t *b);
@ -714,7 +718,8 @@ router_parse_directory(const char *str)
} }
declared_key = find_dir_signing_key(str, str+strlen(str)); declared_key = find_dir_signing_key(str, str+strlen(str));
note_crypto_pk_op(VERIFY_DIR); note_crypto_pk_op(VERIFY_DIR);
if (check_signature_token(digest, tok, declared_key, 1, "directory")<0) if (check_signature_token(digest, tok, declared_key,
CST_CHECK_AUTHORITY, "directory")<0)
goto err; goto err;
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t)); SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
@ -805,7 +810,8 @@ router_parse_runningrouters(const char *str)
} }
declared_key = find_dir_signing_key(str, eos); declared_key = find_dir_signing_key(str, eos);
note_crypto_pk_op(VERIFY_DIR); note_crypto_pk_op(VERIFY_DIR);
if (check_signature_token(digest, tok, declared_key, 1, "running-routers") if (check_signature_token(digest, tok, declared_key,
CST_CHECK_AUTHORITY, "running-routers")
< 0) < 0)
goto err; goto err;
@ -896,18 +902,22 @@ dir_signing_key_is_trusted(crypto_pk_env_t *key)
/** Check whether the object body of the token in <b>tok</b> has a good /** Check whether the object body of the token in <b>tok</b> has a good
* signature for <b>digest</b> using key <b>pkey</b>. If * signature for <b>digest</b> using key <b>pkey</b>. If
* <b>check_authority</b> is set, make sure that <b>pkey</b> is the key of a * <b>CST_CHECK_AUTHORITY</b> is set, make sure that <b>pkey</b> is the key of
* directory authority. Use <b>doctype</b> as the type of the document when * a directory authority. If <b>CST_NO_CHECK_OBJTYPE</b> is set, do not check
* generating log messages. Return 0 on success, negative on failure. * the object type of the signature object. Use <b>doctype</b> as the type of
* the document when generating log messages. Return 0 on success, negative
* on failure.
*/ */
static int static int
check_signature_token(const char *digest, check_signature_token(const char *digest,
directory_token_t *tok, directory_token_t *tok,
crypto_pk_env_t *pkey, crypto_pk_env_t *pkey,
int check_authority, int flags,
const char *doctype) const char *doctype)
{ {
char *signed_digest; char *signed_digest;
const int check_authority = (flags & CST_CHECK_AUTHORITY);
const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
tor_assert(pkey); tor_assert(pkey);
tor_assert(tok); tor_assert(tok);
@ -920,9 +930,11 @@ check_signature_token(const char *digest,
return -1; return -1;
} }
if (strcmp(tok->object_type, "SIGNATURE")) { if (check_objtype) {
log_warn(LD_DIR, "Bad object type on %s signature", doctype); if (strcmp(tok->object_type, "SIGNATURE")) {
return -1; log_warn(LD_DIR, "Bad object type on %s signature", doctype);
return -1;
}
} }
signed_digest = tor_malloc(tok->object_size); signed_digest = tor_malloc(tok->object_size);
@ -1664,6 +1676,7 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string)
log_debug(LD_DIR, "We already checked the signature on this " log_debug(LD_DIR, "We already checked the signature on this "
"certificate; no need to do so again."); "certificate; no need to do so again.");
found = 1; found = 1;
cert->is_cross_certified = old_cert->is_cross_certified;
} }
} }
if (!found) { if (!found) {
@ -1671,6 +1684,19 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string)
"key certificate")) { "key certificate")) {
goto err; goto err;
} }
if ((tok = find_opt_by_keyword(tokens, K_DIR_KEY_CROSSCERT))) {
/* XXXX Once all authorities generate cross-certified certificates,
* make this field mandatory. */
if (check_signature_token(cert->cache_info.identity_digest,
tok,
cert->signing_key,
CST_NO_CHECK_OBJTYPE,
"key cross-certification")) {
goto err;
}
cert->is_cross_certified = 1;
}
} }
cert->cache_info.signed_descriptor_len = len; cert->cache_info.signed_descriptor_len = len;

View File

@ -3084,6 +3084,7 @@ test_v3_networkstatus(void)
/* Parse certificates and keys. */ /* Parse certificates and keys. */
cert1 = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL); cert1 = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
test_assert(cert1); test_assert(cert1);
test_assert(cert1->is_cross_certified);
cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL); cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL);
test_assert(cert2); test_assert(cert2);
cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL); cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL);
@ -3360,15 +3361,15 @@ test_v3_networkstatus(void)
test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/ test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/
/* The voter id digests should be in this order. */ /* The voter id digests should be in this order. */
test_assert(memcmp(cert2->cache_info.identity_digest, test_assert(memcmp(cert2->cache_info.identity_digest,
cert3->cache_info.identity_digest,DIGEST_LEN)<0);
test_assert(memcmp(cert3->cache_info.identity_digest,
cert1->cache_info.identity_digest,DIGEST_LEN)<0); cert1->cache_info.identity_digest,DIGEST_LEN)<0);
test_assert(memcmp(cert1->cache_info.identity_digest,
cert3->cache_info.identity_digest,DIGEST_LEN)<0);
test_same_voter(smartlist_get(con->voters, 1), test_same_voter(smartlist_get(con->voters, 1),
smartlist_get(v2->voters, 0)); smartlist_get(v2->voters, 0));
test_same_voter(smartlist_get(con->voters, 2), test_same_voter(smartlist_get(con->voters, 2),
smartlist_get(v3->voters, 0));
test_same_voter(smartlist_get(con->voters, 3),
smartlist_get(v1->voters, 0)); smartlist_get(v1->voters, 0));
test_same_voter(smartlist_get(con->voters, 3),
smartlist_get(v3->voters, 0));
test_assert(!con->cert); test_assert(!con->cert);
test_eq(2, smartlist_len(con->routerstatus_list)); test_eq(2, smartlist_len(con->routerstatus_list));
@ -3412,20 +3413,22 @@ test_v3_networkstatus(void)
test_assert(rs->is_valid); test_assert(rs->is_valid);
test_assert(!rs->is_named); test_assert(!rs->is_named);
/* XXXX check version */ /* XXXX check version */
// x231
// x213
/* Check signatures. the first voter is pseudo. The second one hasn't /* Check signatures. the first voter is a pseudo-entry with a legacy key.
signed. The third one has signed: validate it. */ * The second one hasn't signed. The fourth one has signed: validate it. */
voter = smartlist_get(con->voters, 1); voter = smartlist_get(con->voters, 1);
test_assert(!voter->signature); test_assert(!voter->signature);
test_assert(!voter->good_signature); test_assert(!voter->good_signature);
test_assert(!voter->bad_signature); test_assert(!voter->bad_signature);
voter = smartlist_get(con->voters, 2); voter = smartlist_get(con->voters, 3);
test_assert(voter->signature); test_assert(voter->signature);
test_assert(!voter->good_signature); test_assert(!voter->good_signature);
test_assert(!voter->bad_signature); test_assert(!voter->bad_signature);
test_assert(!networkstatus_check_voter_signature(con, test_assert(!networkstatus_check_voter_signature(con,
smartlist_get(con->voters, 2), smartlist_get(con->voters, 3),
cert3)); cert3));
test_assert(voter->signature); test_assert(voter->signature);
test_assert(voter->good_signature); test_assert(voter->good_signature);
@ -3503,7 +3506,7 @@ test_v3_networkstatus(void)
smartlist_get(con->voters, 1), smartlist_get(con->voters, 1),
cert2)); cert2));
test_assert(!networkstatus_check_voter_signature(con, test_assert(!networkstatus_check_voter_signature(con,
smartlist_get(con->voters, 3), smartlist_get(con->voters, 2),
cert1)); cert1));
} }

View File

@ -8,54 +8,60 @@ const char test_data_c_id[] =
const char AUTHORITY_CERT_1[] = const char AUTHORITY_CERT_1[] =
"dir-key-certificate-version 3\n" "dir-key-certificate-version 3\n"
"fingerprint F810C0CB4974A9C407A8D8F5B0394E3D87BF4794\n" "fingerprint D867ACF56A9D229B35C25F0090BC9867E906BE69\n"
"dir-key-published 2007-06-13 16:52:25\n" "dir-key-published 2008-12-12 18:07:24\n"
"dir-key-expires 2008-06-13 16:52:25\n" "dir-key-expires 2009-12-12 18:07:24\n"
"dir-identity-key\n" "dir-identity-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n" "-----BEGIN RSA PUBLIC KEY-----\n"
"MIIBigKCAYEAwqvEOhA+aSNp0JQFd0bZ2OIdamIS6EGVuhOHFkmIS4P2hw99Nkx/\n" "MIIBigKCAYEAveMpKlw8oD1YqFqpJchuwSR82BDhutbqgHiez3QO9FmzOctJpV+Y\n"
"YJGXPbHB5uLxMYE539DHKuGztIHOanIqczG8P501F+sGfi1q00rzjYfliGuGnQRQ\n" "mpTYIJLS/qC+4GBKFF1VK0C4SoBrS3zri0qdXdE+vBGcyrxrjMklpxoqSKRY2011\n"
"5+A7Iu6am+KeEP/cnWZt63kiPV2Jt9D8qwlnZTKqMQvnhOz10QCApV0LgFHr/2VO\n" "4eqYPghKlo5RzuqteBclGCHyNxWjUJeRKDWgvh+U/gr2uYM6fRm5q0fCzg4aECE7\n"
"1jEO/Ve+EMO/+fZf8a6graw4ur1foVjLAwUW1fo0QUo0342WSlTA1VouyhZv1LsH\n" "VP6fDGZrMbQI8jHpiMSoC9gkUASNEa6chLInlnP8/H5qUEW4TB9CN/q095pefuwL\n"
"LTmA0VFTQnsNnG9V1sPAuqaPDeNntSS3bAWmCAUA6eQS4LF7Pz4OAsRtAurMf98z\n" "P+F+1Nz5hnM7fa5XmeMB8iM4RriUmOQlLBZgpQBMpEfWMIPcR9F1Gh3MxERqqUcH\n"
"Pz/thkNa9OBJfLH1zaAmaiUTdEqMNwoT1YHwqav4994tyO7oadV6PdVIAcXD2I4S\n" "tmij+IZdeXg9OkCXykcabaYIhZD3meErn9Tax4oA/THduLfgli9zM0ExwzH1OooN\n"
"9tf0NPfaIHwfJPDUY9loKIrGNbrfBLTECrQ3QLNtU3yrYkEyQjcgT8FlBGDcDGqj\n" "L8rIcJ+2eBo3bQiQUbdYW71sl9w7nSPtircbJUa1mUvWYLPWQxFliPiQSetgJLMj\n"
"r8diBPlz+K5iXfl0lIudie4hAFZK+uDu7yQ4y7+N5fVuoBdQDt8S0eMho/PO3Hoe\n" "VQqtPmV2hvN2Xk3lLfJO50qMTK7w7Gsaw8UtV4YDM1Hcjp/hQaIB1xfwhXgl+eUU\n"
"638jhngjy5L5AgMBAAE=\n" "btUa4c+cUTjHAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n" "-----END RSA PUBLIC KEY-----\n"
"dir-signing-key\n" "dir-signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n" "-----BEGIN RSA PUBLIC KEY-----\n"
"MIGJAoGBALQJryeKty8evkxsG1xrj3hezAt3qbTSfigptATGdd2CH+VvMKVdY7EM\n" "MIGJAoGBALPSUInyuEu6NV3NjozplaniIEBzQXEjv1x9/+mqnwZABpYVmuy9A8nx\n"
"UiiFNuYp3iZTptIKiiUtbmEGUgPsOaL6Ab9aoY80oXWxZ/shBFoIaAjOmn1qNQiA\n" "eoyY3sZFsnYwNW/IZjAgG23pEmevu3F+L4myMjjaa6ORl3MgRYQ4gmuFqpefrGdm\n"
"jPNH7YVbJGjZiuJydT+ZuZabqh58ij8mMgdJnflFO7wG39q3QBrdAgMBAAE=\n" "ywRCleh2JerkQ4VxOuq10dn/abITzLyaZzMw30KXWp5pxKXOLtxFAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n" "-----END RSA PUBLIC KEY-----\n"
"dir-key-crosscert\n"
"-----BEGIN ID SIGNATURE-----\n"
"FTBJNR/Hlt4T53yUMp1r/QCSMCpkHJCbYBT0R0pvYqhqFfYN5qHRSICRXaFFImIF\n"
"0DGWmwRza6DxPKNzkm5/b7I0de9zJW1jNNdQAQK5xppAtQcAafRdu8cBonnmh9KX\n"
"k1NrAK/X00FYywju3yl/SxCn1GddVNkHYexEudmJMPM=\n"
"-----END ID SIGNATURE-----\n"
"dir-key-certification\n" "dir-key-certification\n"
"-----BEGIN SIGNATURE-----\n" "-----BEGIN SIGNATURE-----\n"
"Hp6PuryATzAOM0PsmhlxsxTqoxKcI8lv6ti2/4Gnyug4lTx1rPweoZdt4GGttFAe\n" "pjWguLFBfELZDc6DywL6Do21SCl7LcutfpM92MEn4WYeSNcTXNR6lRX7reOEJk4e\n"
"Td9zcUfLUlC0R5eDIlWpR+rxJsRLxuHcVTSr+P0N/Y5xoFzPAqPsVYz6lnvb7vIG\n" "NwEaMt+Hl7slgeR5wjnW3OmMmRPZK9bquNWbfD+sAOV9bRFZTpXIdleAQFPlwvMF\n"
"9XtixG9jXvVhEqpCZUwoRyPXXwjJoEZE1EuyuvPmlEny8O5thAx1gvZIwUk9hGLU\n" "z/Gzwspzn4i2Yh6hySShrctMmW8YL3OM8LsBXzBhp/rG2uHlsxmIsc13DA6HWt61\n"
"xcErXkajDgfWEGmFWgcs+uk/Sa6n+vjPBwJD9k2hGcoCVZhelU0duCORJaz33twU\n" "ffY72uNE6KckDGsQ4wPGP9q69y6g+X+TNio1KPbsILbePv6EjbO+rS8FiS4njPlg\n"
"tebJ/iPMAEkMBIlMvnnr+lKXk548rwE6GHUXWtu/Tho4piV58A0hKAHKpGbVUYEF\n" "SPYry1RaUvxzxTkswIzdE1tjJrUiqpbWlTGxrH9N4OszoLm45Pc784KLULrjKIoi\n"
"+11x7n5klsYkUedltrCMajtjB8oawWmRPZZp+sUBmnEtunlCGaBnJNQ3pnCvAalJ\n" "Q+vRsGrcMBAa+kDowWU6H1ryKR7KOhzRTcf2uqLE/W3ezaRwmOG+ETmoVFwbhk2X\n"
"yPCSGeQhrW8ZKGWE4aZ8xzyUc5K0zF0KEefPFyHpK61ZDaXr/6TQPz3UF4ndxVjS\n" "OlbXEM9fWP+INvFkr6Z93VYL2jGkCjV7e3xXmre/Lb92fUcYi6t5dwzfV8gJnIoG\n"
"sxRWj3HyMv6Ax5bASOLgP2ikdXGnZLHau93yKJ6N8U57JjCTavxMlRXONbLS0qYe\n" "eCHd0K8NrQK0ipVk/7zcPDKOPeo9Y5aj/f6X/pDHtb+Dd5sT+l82G/Tqy4DIYUYR\n"
"-----END SIGNATURE-----\n"; "-----END SIGNATURE-----\n";
const char AUTHORITY_SIGNKEY_1[] = const char AUTHORITY_SIGNKEY_1[] =
"-----BEGIN RSA PRIVATE KEY-----\n" "-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXAIBAAKBgQC0Ca8nircvHr5MbBtca494XswLd6m00n4oKbQExnXdgh/lbzCl\n" "MIICWwIBAAKBgQCz0lCJ8rhLujVdzY6M6ZWp4iBAc0FxI79cff/pqp8GQAaWFZrs\n"
"XWOxDFIohTbmKd4mU6bSCoolLW5hBlID7Dmi+gG/WqGPNKF1sWf7IQRaCGgIzpp9\n" "vQPJ8XqMmN7GRbJ2MDVvyGYwIBtt6RJnr7txfi+JsjI42mujkZdzIEWEOIJrhaqX\n"
"ajUIgIzzR+2FWyRo2YricnU/mbmWm6oefIo/JjIHSZ35RTu8Bt/at0Aa3QIDAQAB\n" "n6xnZssEQpXodiXq5EOFcTrqtdHZ/2myE8y8mmczMN9Cl1qeacSlzi7cRQIDAQAB\n"
"AoGAKujz+jSxnGVzbbuGeeyY8VOGxmTq6dIRh3kJEupKRVUyTPjHW2J61EPfgRDf\n" "AoGASpzUkDinIbzU0eQt5ugxEnliOnvYRpK3nzAk1JbYPyan1PSIAPz4qn1JBTeV\n"
"GNR5wiDF7eHdMyc026MqAQ1YXv007K9D22cABhe8BivCbibhzUrmcv76vQHIRgp/\n" "EB3xS7r7ITO8uvFHkFZqLZ2sH1uE6e4sAytJGO+kyqnlkiDTPEXpcGe99j8PH1yj\n"
"AbT9fRjhmB/NqjLf6NkBHzx2UAWKbmxcO4pAGSQIY+TnXXECQQDkqTPxUrg2y8kC\n" "xUOrHRlAYWjG8NEkQi+APA+HZkswE3L/viFwR2AARoE2ac0CQQDsOLdNJa+mqn6N\n"
"nvEa2O1yYSCU0cB1EmPaIg0cH5vV/lA/EFbhLIBbA+CUsbX0qxuEBX6B9c36y3AO\n" "1L76nEl/YgXHtKUks+beOR3IgknKEjcsJJEUHyiu0wjbXZV6gTtyQvcAePglUUD1\n"
"UOAi7NXnAkEAyZA8rKBIjhHFur9e/U9ApDAjvW1BSy7nDP5GKqw2ayLIt1hfnxZd\n" "R2OkOOADAkEAwuCxvHEAPeQbVt8fSvxw74vqew6LITP2Utb1dQK0E26IRPF36BsJ\n"
"0YXb53iAsf/YHT/wk4+nBYtQ83xL2U2omwJAfgRaIgcqithoYU9jJR6kTcMFh77J\n" "buO/gqMZv6ALq+/KxpA/pUsApbgog9uUFwJAYvHCvbrKX1pM1iXFtP1fv86UMzlU\n"
"SDvoV9EoVHV/FsJfS0If/1zdKEvMu2XtF3gtY+b7P3hOGod/rAQaYmUPxQJBALz4\n" "bxI34t8zvXftZonIuGG8rxv6E3hr3k7NvNmCx/KKuZTyA9eMCPFVKEV2dwJACn8j\n"
"2JmzsDJaITpDXwg4PE9yvp9DBjs5nu9EmX46dM6fDvUuCoA5VP4x9IigJnA7gF9z\n" "06yagLrqphE6lEVop953cM1lvRIZcHjXm8fbfzhy6pO/C6d5KJnn1NeIKYQrXMV7\n"
"6dY+kQWWpu+QcgAqWc8CQDYRUK/qhdbBLdv30CyGrU6Pu0Iij6KZXLGW/zavSDmw\n" "vJpEc1jI3iQ/Omr3XQJAEBIt5MlP2wlrX9om7B+32XBygUssY3cw/bXybZrtSU0/\n"
"4FgbRYYTjukvSs3zUX+52znjYn7wTngIm312A37pHUU=\n" "Yx4lqK0ca5IkTp3HevwnlWaJgbaOTUspCVshzJBhDA==\n"
"-----END RSA PRIVATE KEY-----\n"; "-----END RSA PRIVATE KEY-----\n";
const char AUTHORITY_CERT_2[] = const char AUTHORITY_CERT_2[] =

View File

@ -394,6 +394,20 @@ get_fingerprint(EVP_PKEY *pkey, char *out)
return r; return r;
} }
/** Set <b>out</b> to the hex-encoded fingerprint of <b>pkey</b>. */
static int
get_digest(EVP_PKEY *pkey, char *out)
{
int r = 1;
crypto_pk_env_t *pk = _crypto_new_pk_env_rsa(EVP_PKEY_get1_RSA(pkey));
if (pk) {
r = crypto_pk_get_digest(pk, out);
crypto_free_pk_env(pk);
}
return r;
}
/** Generate a new certificate for our loaded or generated keys, and write it /** Generate a new certificate for our loaded or generated keys, and write it
* to disk. Return 0 on success, nonzero on failure. */ * to disk. Return 0 on success, nonzero on failure. */
static int static int
@ -404,6 +418,7 @@ generate_certificate(void)
struct tm tm; struct tm tm;
char published[ISO_TIME_LEN+1]; char published[ISO_TIME_LEN+1];
char expires[ISO_TIME_LEN+1]; char expires[ISO_TIME_LEN+1];
char id_digest[DIGEST_LEN];
char fingerprint[FINGERPRINT_LEN+1]; char fingerprint[FINGERPRINT_LEN+1];
char *ident = key_to_string(identity_key); char *ident = key_to_string(identity_key);
char *signing = key_to_string(signing_key); char *signing = key_to_string(signing_key);
@ -414,6 +429,7 @@ generate_certificate(void)
int r; int r;
get_fingerprint(identity_key, fingerprint); get_fingerprint(identity_key, fingerprint);
get_digest(identity_key, id_digest);
tor_localtime_r(&now, &tm); tor_localtime_r(&now, &tm);
tm.tm_mon += months_lifetime; tm.tm_mon += months_lifetime;
@ -429,11 +445,26 @@ generate_certificate(void)
"dir-key-expires %s\n" "dir-key-expires %s\n"
"dir-identity-key\n%s" "dir-identity-key\n%s"
"dir-signing-key\n%s" "dir-signing-key\n%s"
"dir-key-certification\n", "dir-key-crosscert\n"
"-----BEGIN ID SIGNATURE-----\n",
address?"\ndir-address ":"", address?address:"", address?"\ndir-address ":"", address?address:"",
fingerprint, published, expires, ident, signing); fingerprint, published, expires, ident, signing
);
tor_free(ident); tor_free(ident);
tor_free(signing); tor_free(signing);
/* Append a cross-certification */
r = RSA_private_encrypt(DIGEST_LEN, (unsigned char*)id_digest,
(unsigned char*)signature,
EVP_PKEY_get1_RSA(signing_key),
RSA_PKCS1_PADDING);
signed_len = strlen(buf);
base64_encode(buf+signed_len, sizeof(buf)-signed_len, signature, r);
strlcat(buf,
"-----END ID SIGNATURE-----\n"
"dir-key-certification\n", sizeof(buf));
signed_len = strlen(buf); signed_len = strlen(buf);
SHA1((const unsigned char*)buf,signed_len,(unsigned char*)digest); SHA1((const unsigned char*)buf,signed_len,(unsigned char*)digest);