/** 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; }
/** 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) { // It is later than 1985, since otherwise there would be no C89 // compilers. (Try to diagnose #22466.) tor_assert_nonfatal(expires >= 15 * 365 * 86400); 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); crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA256); crypto_digest_add_bytes(d, RSA_ED_CROSSCERT_PREFIX, strlen(RSA_ED_CROSSCERT_PREFIX)); const int signed_part_len = 32 + 4; crypto_digest_add_bytes(d, (char*)res, signed_part_len); uint8_t digest[DIGEST256_LEN]; crypto_digest_get_digest(d, (char*)digest, sizeof(digest)); crypto_digest_free(d); int siglen = crypto_pk_private_sign(rsa_key, (char*)rsa_ed_crosscert_getarray_sig(cc), rsa_ed_crosscert_getlen_sig(cc), (char*)digest, sizeof(digest)); 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; }
ssize_t rsa_ed_crosscert_encode(uint8_t *output, const size_t avail, const rsa_ed_crosscert_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 = rsa_ed_crosscert_encoded_len(obj); #endif if (NULL != (msg = rsa_ed_crosscert_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN trunnel_assert(encoded_len >= 0); #endif /* Encode u8 ed_key[32] */ trunnel_assert(written <= avail); if (avail - written < 32) goto truncated; memcpy(ptr, obj->ed_key, 32); written += 32; ptr += 32; /* Encode u32 expiration */ trunnel_assert(written <= avail); if (avail - written < 4) goto truncated; trunnel_set_uint32(ptr, trunnel_htonl(obj->expiration)); written += 4; ptr += 4; /* Encode u8 sig_len */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->sig_len)); written += 1; ptr += 1; /* Encode u8 sig[sig_len] */ { size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->sig); trunnel_assert(obj->sig_len == elt_len); trunnel_assert(written <= avail); if (avail - written < elt_len) goto truncated; memcpy(ptr, obj->sig.elts_, elt_len); written += elt_len; ptr += elt_len; } 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; }