/**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; }
/** 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; }
/** * Retrieve our currently-in-use Ed25519 link certificate and id certificate, * and, if they would expire soon (based on the time <b>now</b>, generate new * certificates (without embedding the public part of the signing key inside). * If <b>force</b> is true, always generate a new certificate. * * The signed_key from the current id->signing certificate will be used to * sign the new key within newly generated X509 certificate. * * Returns -1 upon error. Otherwise, returns 0 upon success (either when the * current certificate is still valid, or when a new certificate was * successfully generated, or no certificate was needed). */ int generate_ed_link_cert(const or_options_t *options, time_t now, int force) { 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) { if (!server_mode(options)) { /* No need to make an Ed25519->Link cert: we are a client */ return 0; } log_warn(LD_OR, "Can't get my x509 link cert."); return -1; } const common_digests_t *digests = tor_x509_cert_get_cert_digests(link_); if (force == 0 && 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; }
/** * 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; }
/** * 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 try to load a * secret key unless no public key is found. Do not return a secret key. (but * create and save one if needed). * * If INIT_ED_KEY_NO_LOAD_SECRET is set in <b>flags</b>, don't try to load * a secret key, no matter what. * * If INIT_ED_KEY_TRY_ENCRYPTED is set, we look for an encrypted secret key * and consider encrypting any new secret key. * * If INIT_ED_KEY_NO_REPAIR is set, and there is any issue loading the keys * from disk _other than their absence_ (full or partial), we do not try to * replace them. * * If INIT_ED_KEY_SUGGEST_KEYGEN is set, have log messages about failures * refer to the --keygen option. * * If INIT_ED_KEY_EXPLICIT_FNAME is set, use the provided file name for the * secret key file, encrypted or not. */ 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 *encrypted_secret_fname = NULL; char *public_fname = NULL; char *cert_fname = NULL; const char *loaded_secret_fname = NULL; int created_pk = 0, created_sk = 0, created_cert = 0; const int try_to_load = ! (flags & INIT_ED_KEY_REPLACE); const int encrypt_key = !! (flags & INIT_ED_KEY_TRY_ENCRYPTED); const int norepair = !! (flags & INIT_ED_KEY_NO_REPAIR); const int split = !! (flags & INIT_ED_KEY_SPLIT); const int omit_secret = !! (flags & INIT_ED_KEY_OMIT_SECRET); const int offline_secret = !! (flags & INIT_ED_KEY_OFFLINE_SECRET); const int explicit_fname = !! (flags & INIT_ED_KEY_EXPLICIT_FNAME); /* we don't support setting both of these flags at once. */ tor_assert((flags & (INIT_ED_KEY_NO_REPAIR|INIT_ED_KEY_NEEDCERT)) != (INIT_ED_KEY_NO_REPAIR|INIT_ED_KEY_NEEDCERT)); 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)); if (explicit_fname) { secret_fname = tor_strdup(fname); encrypted_secret_fname = tor_strdup(fname); } else { tor_asprintf(&secret_fname, "%s_secret_key", fname); tor_asprintf(&encrypted_secret_fname, "%s_secret_key_encrypted", fname); } tor_asprintf(&public_fname, "%s_public_key", fname); tor_asprintf(&cert_fname, "%s_cert", fname); /* Try to read the secret key. */ int have_secret = 0; int load_secret = try_to_load && !offline_secret && (!omit_secret || file_status(public_fname)==FN_NOENT); if (load_secret) { int rv = ed25519_seckey_read_from_file(&keypair->seckey, &got_tag, secret_fname); if (rv == 0) { have_secret = 1; loaded_secret_fname = secret_fname; tor_assert(got_tag); } else { if (errno != ENOENT && norepair) { tor_log(severity, LD_OR, "Unable to read %s: %s", secret_fname, strerror(errno)); goto err; } } } /* Should we try for an encrypted key? */ int have_encrypted_secret_file = 0; if (!have_secret && try_to_load && encrypt_key) { int r = read_encrypted_secret_key(&keypair->seckey, encrypted_secret_fname); if (r > 0) { have_secret = 1; have_encrypted_secret_file = 1; tor_free(got_tag); /* convince coverity we aren't leaking */ got_tag = tor_strdup(tag); loaded_secret_fname = encrypted_secret_fname; } else if (errno != ENOENT && norepair) { tor_log(severity, LD_OR, "Unable to read %s: %s", encrypted_secret_fname, strerror(errno)); goto err; } } else { if (try_to_load) { /* Check if it's there anyway, so we don't replace it. */ if (file_status(encrypted_secret_fname) != FN_NOENT) have_encrypted_secret_file = 1; } } if (have_secret) { if (strcmp(got_tag, tag)) { tor_log(severity, LD_OR, "%s has wrong tag", loaded_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", loaded_secret_fname); goto err; } } /* If we do split keys here, try to read the pubkey. */ int found_public = 0; if (try_to_load && (!have_secret || split)) { ed25519_public_key_t pubkey_tmp; tor_free(got_tag); found_public = ed25519_pubkey_read_from_file(&pubkey_tmp, &got_tag, public_fname) == 0; if (!found_public && errno != ENOENT && norepair) { tor_log(severity, LD_OR, "Unable to read %s: %s", public_fname, strerror(errno)); goto err; } if (found_public && strcmp(got_tag, tag)) { tor_log(severity, LD_OR, "%s has wrong tag", public_fname); goto err; } if (found_public) { if (have_secret) { /* If we have a secret key and we're reloading the public key, * the key must match! */ if (! ed25519_pubkey_eq(&keypair->pubkey, &pubkey_tmp)) { tor_log(severity, LD_OR, "%s does not match %s! If you are trying " "to restore from backup, make sure you didn't mix up the " "key files. If you are absolutely sure that %s is the right " "key for this relay, delete %s or move it out of the way.", public_fname, loaded_secret_fname, loaded_secret_fname, public_fname); goto err; } } else { /* We only have the public key; better use that. */ tor_assert(split); memcpy(&keypair->pubkey, &pubkey_tmp, sizeof(pubkey_tmp)); } } else { /* We have no public key file, but we do have a secret key, make the * public key file! */ if (have_secret) { if (ed25519_pubkey_write_to_file(&keypair->pubkey, public_fname, tag) < 0) { tor_log(severity, LD_OR, "Couldn't repair %s", public_fname); goto err; } else { tor_log(LOG_NOTICE, LD_OR, "Found secret key but not %s. Regenerating.", public_fname); } } } } /* 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)) { if (have_encrypted_secret_file) { tor_log(severity, LD_OR, "We needed to load a secret key from %s, " "but it was encrypted. Try 'tor --keygen' instead, so you " "can enter the passphrase.", secret_fname); } else { tor_log(severity, LD_OR, "We needed to load a secret key from %s, " "but couldn't find it. %s", secret_fname, (flags & INIT_ED_KEY_SUGGEST_KEYGEN) ? "If you're keeping your master secret key offline, you will " "need to run 'tor --keygen' to generate new signing keys." : "Did you forget to copy it over when you copied the rest of the " "signing key material?"); } 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)) { if (split) { tor_log(severity, LD_OR, "No key found in %s or %s.", secret_fname, public_fname); } else { tor_log(severity, LD_OR, "No key found in %s.", secret_fname); } goto err; } /* If the secret key is absent, but the encrypted key would be present, * that's an error */ if (!have_secret && !found_public && have_encrypted_secret_file) { tor_assert(!encrypt_key); tor_log(severity, LD_OR, "Found an encrypted secret key, " "but not public key file %s!", public_fname); goto err; } /* if it's absent, make a new keypair... */ if (!have_secret && !found_public) { 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; } /* Write it to disk if we're supposed to do with a new passphrase, or if * we just created it. */ if (created_sk || (have_secret && get_options()->change_key_passphrase)) { if (write_secret_key(&keypair->seckey, encrypt_key, secret_fname, tag, encrypted_secret_fname) < 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. */ tor_free(got_tag); 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. */ 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 (signing_key && tor_cert_checksig(cert, &signing_key->pubkey, now) < 0) { tor_log(severity, LD_OR, "Can't check certificate"); bad_cert = 1; } else if (cert->cert_expired) { tor_log(severity, LD_OR, "Certificate is expired"); bad_cert = 1; } else if (signing_key && cert->signing_key_included && ! ed25519_pubkey_eq(&signing_key->pubkey, &cert->signing_key)) { tor_log(severity, LD_OR, "Certificate signed by unexpectd key!"); 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)) { tor_log(severity, LD_OR, "Without signing key, can't create certificate"); 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) { tor_log(severity, LD_OR, "Couldn't create certificate"); 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: if (keypair) 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(encrypted_secret_fname); tor_free(secret_fname); tor_free(public_fname); tor_free(cert_fname); tor_free(got_tag); return keypair; }
hs_desc_intro_point_t * hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, const char *addr, int legacy) { int ret; ed25519_keypair_t auth_kp; hs_desc_intro_point_t *intro_point = NULL; hs_desc_intro_point_t *ip = hs_desc_intro_point_new(); /* For a usable intro point we need at least two link specifiers: One legacy * keyid and one ipv4 */ { tor_addr_t a; tor_addr_make_unspec(&a); link_specifier_t *ls_legacy = link_specifier_new(); link_specifier_t *ls_ip = link_specifier_new(); link_specifier_set_ls_type(ls_legacy, LS_LEGACY_ID); memset(link_specifier_getarray_un_legacy_id(ls_legacy), 'C', link_specifier_getlen_un_legacy_id(ls_legacy)); int family = tor_addr_parse(&a, addr); switch (family) { case AF_INET: link_specifier_set_ls_type(ls_ip, LS_IPV4); link_specifier_set_un_ipv4_addr(ls_ip, tor_addr_to_ipv4h(&a)); link_specifier_set_un_ipv4_port(ls_ip, 9001); break; case AF_INET6: link_specifier_set_ls_type(ls_ip, LS_IPV6); memcpy(link_specifier_getarray_un_ipv6_addr(ls_ip), tor_addr_to_in6_addr8(&a), link_specifier_getlen_un_ipv6_addr(ls_ip)); link_specifier_set_un_ipv6_port(ls_ip, 9001); break; default: /* Stop the test, not supposed to have an error. * Compare with -1 to show the actual family. */ tt_int_op(family, OP_EQ, -1); } smartlist_add(ip->link_specifiers, ls_legacy); smartlist_add(ip->link_specifiers, ls_ip); } ret = ed25519_keypair_generate(&auth_kp, 0); tt_int_op(ret, ==, 0); ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY, &auth_kp.pubkey, now, HS_DESC_CERT_LIFETIME, CERT_FLAG_INCLUDE_SIGNING_KEY); tt_assert(ip->auth_key_cert); if (legacy) { ip->legacy.key = crypto_pk_new(); tt_assert(ip->legacy.key); ret = crypto_pk_generate_key(ip->legacy.key); tt_int_op(ret, ==, 0); ssize_t cert_len = tor_make_rsa_ed25519_crosscert( &signing_kp->pubkey, ip->legacy.key, now + HS_DESC_CERT_LIFETIME, &ip->legacy.cert.encoded); tt_assert(ip->legacy.cert.encoded); tt_u64_op(cert_len, OP_GT, 0); ip->legacy.cert.len = cert_len; } /* Encryption key. */ { int signbit; curve25519_keypair_t curve25519_kp; ed25519_keypair_t ed25519_kp; tor_cert_t *cross_cert; ret = curve25519_keypair_generate(&curve25519_kp, 0); tt_int_op(ret, ==, 0); ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit, &curve25519_kp); cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS, &ed25519_kp.pubkey, time(NULL), HS_DESC_CERT_LIFETIME, CERT_FLAG_INCLUDE_SIGNING_KEY); tt_assert(cross_cert); ip->enc_key_cert = cross_cert; } intro_point = ip; done: if (intro_point == NULL) tor_free(ip); return intro_point; }
/* Return a valid hs_descriptor_t object. If no_ip is set, no introduction * points are added. */ static hs_descriptor_t * hs_helper_build_hs_desc_impl(unsigned int no_ip, const ed25519_keypair_t *signing_kp) { int ret; int i; time_t now = approx_time(); ed25519_keypair_t blinded_kp; curve25519_keypair_t auth_ephemeral_kp; hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc)); desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX; /* Copy only the public key into the descriptor. */ memcpy(&desc->plaintext_data.signing_pubkey, &signing_kp->pubkey, sizeof(ed25519_public_key_t)); uint64_t current_time_period = hs_get_time_period_num(0); hs_build_blinded_keypair(signing_kp, NULL, 0, current_time_period, &blinded_kp); /* Copy only the public key into the descriptor. */ memcpy(&desc->plaintext_data.blinded_pubkey, &blinded_kp.pubkey, sizeof(ed25519_public_key_t)); desc->plaintext_data.signing_key_cert = tor_cert_create(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC, &signing_kp->pubkey, now, 3600, CERT_FLAG_INCLUDE_SIGNING_KEY); tt_assert(desc->plaintext_data.signing_key_cert); desc->plaintext_data.revision_counter = 42; desc->plaintext_data.lifetime_sec = 3 * 60 * 60; hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey, desc->subcredential); /* Setup superencrypted data section. */ ret = curve25519_keypair_generate(&auth_ephemeral_kp, 0); tt_int_op(ret, ==, 0); memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey, &auth_ephemeral_kp.pubkey, sizeof(curve25519_public_key_t)); desc->superencrypted_data.clients = smartlist_new(); for (i = 0; i < HS_DESC_AUTH_CLIENT_MULTIPLE; i++) { hs_desc_authorized_client_t *desc_client = hs_desc_build_fake_authorized_client(); smartlist_add(desc->superencrypted_data.clients, desc_client); } /* Setup encrypted data section. */ desc->encrypted_data.create2_ntor = 1; desc->encrypted_data.intro_auth_types = smartlist_new(); desc->encrypted_data.single_onion_service = 1; smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519")); desc->encrypted_data.intro_points = smartlist_new(); if (!no_ip) { /* Add four intro points. */ smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0)); /* IPv6-only introduction points are not supported yet, see #23588 */ #if 0 smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0)); #endif smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1)); smartlist_add(desc->encrypted_data.intro_points, hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1)); } descp = desc; done: if (descp == NULL) tor_free(desc); return descp; }
static void test_routerkeys_ed_certs(void *args) { (void)args; ed25519_keypair_t kp1, kp2; tor_cert_t *cert[2] = {NULL, NULL}, *nocert = NULL; tor_cert_t *parsed_cert[2] = {NULL, NULL}; time_t now = 1412094534; uint8_t *junk = NULL; char *base64 = NULL; tt_int_op(0,OP_EQ,ed25519_keypair_generate(&kp1, 0)); tt_int_op(0,OP_EQ,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_uint_op(cert[i]->sig_bad, OP_EQ, 0); tt_uint_op(cert[i]->sig_ok, OP_EQ, 1); tt_uint_op(cert[i]->cert_expired, OP_EQ, 0); tt_uint_op(cert[i]->cert_valid, OP_EQ, 1); tt_int_op(cert[i]->cert_type, OP_EQ, 5); tt_mem_op(cert[i]->signed_key.pubkey, OP_EQ, &kp2.pubkey.pubkey, 32); tt_mem_op(cert[i]->signing_key.pubkey, OP_EQ, &kp1.pubkey.pubkey, 32); tt_int_op(cert[i]->signing_key_included, OP_EQ, i); tt_assert(cert[i]->encoded); tt_int_op(cert[i]->encoded_len, OP_EQ, 104 + 36 * i); tt_int_op(cert[i]->encoded[0], OP_EQ, 1); tt_int_op(cert[i]->encoded[1], OP_EQ, 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, OP_EQ, parsed_cert[i]->encoded_len); tt_mem_op(cert[i]->encoded, OP_EQ, parsed_cert[i]->encoded, cert[i]->encoded_len); tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 0); tt_uint_op(parsed_cert[i]->sig_ok, OP_EQ, 0); tt_uint_op(parsed_cert[i]->cert_expired, OP_EQ, 0); tt_uint_op(parsed_cert[i]->cert_valid, OP_EQ, 0); /* Expired */ tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now + 30000), OP_LT, 0); tt_uint_op(parsed_cert[i]->cert_expired, OP_EQ, 1); parsed_cert[i]->cert_expired = 0; /* Wrong key */ tt_int_op(tor_cert_checksig(parsed_cert[i], &kp2.pubkey, now), OP_LT, 0); tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 1); parsed_cert[i]->sig_bad = 0; /* Missing key */ int ok = tor_cert_checksig(parsed_cert[i], NULL, now); tt_int_op(ok < 0, OP_EQ, i == 0); tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 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), OP_EQ, 0); tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 0); tt_uint_op(parsed_cert[i]->sig_ok, OP_EQ, 1); tt_uint_op(parsed_cert[i]->cert_expired, OP_EQ, 0); tt_uint_op(parsed_cert[i]->cert_valid, OP_EQ, 1); } /* Now try some junky certs. */ /* - Truncated */ nocert = tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len-1); tt_ptr_op(NULL, OP_EQ, nocert); /* - First byte modified */ cert[0]->encoded[0] = 99; nocert = tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len); tt_ptr_op(NULL, OP_EQ, nocert); 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); nocert = tor_cert_parse(junk, cert[0]->encoded_len+1); tt_ptr_op(NULL, OP_EQ, nocert); /* - 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 */ nocert = tor_cert_parse(junk, 104 + 36 * 2); tt_ptr_op(NULL, OP_EQ, nocert); done: tor_cert_free(cert[0]); tor_cert_free(cert[1]); tor_cert_free(parsed_cert[0]); tor_cert_free(parsed_cert[1]); tor_cert_free(nocert); tor_free(junk); tor_free(base64); }