static void elf_phdr(struct buffer *pinput, Elf64_Phdr *phdr, int entsize, struct xdr *xdr, int bit64) { /* * The entsize need not be sizeof(*phdr). * Hence, it is easier to keep a copy of the input, * as the xdr functions may not advance the input * pointer the full entsize; rather than get tricky * we just advance it below. */ struct buffer input; buffer_clone(&input, pinput); if (bit64){ phdr->p_type = xdr->get32(&input); phdr->p_flags = xdr->get32(&input); phdr->p_offset = xdr->get64(&input); phdr->p_vaddr = xdr->get64(&input); phdr->p_paddr = xdr->get64(&input); phdr->p_filesz = xdr->get64(&input); phdr->p_memsz = xdr->get64(&input); phdr->p_align = xdr->get64(&input); } else { phdr->p_type = xdr->get32(&input); phdr->p_offset = xdr->get32(&input); phdr->p_vaddr = xdr->get32(&input); phdr->p_paddr = xdr->get32(&input); phdr->p_filesz = xdr->get32(&input); phdr->p_memsz = xdr->get32(&input); phdr->p_flags = xdr->get32(&input); phdr->p_align = xdr->get32(&input); } buffer_seek(pinput, entsize); }
bool partitioned_file_read_region(struct buffer *dest, const partitioned_file_t *file, const char *region) { assert(dest); assert(file); assert(file->buffer.data); assert(region); if (file->fmap) { const struct fmap_area *area = fmap_find_area(file->fmap, region); if (!area) { ERROR("Image is missing '%s' region\n", region); return false; } if (area->offset + area->size > file->buffer.size) { ERROR("Region '%s' runs off the end of the image file\n", region); return false; } buffer_splice(dest, &file->buffer, area->offset, area->size); } else { if (strcmp(region, SECTION_NAME_PRIMARY_CBFS) != 0) { ERROR("This is a legacy image that contains only a CBFS\n"); return false; } buffer_clone(dest, &file->buffer); } return true; }
/* * Create a new user and add it to the user store. * * The seed is optional an can be used to add entropy in addition * to the entropy provided by the OS. IMPORTANT: Don't put entropy in * here, that was generated by the OSs CPRNG! */ return_status user_store_create_user( user_store *store, const buffer_t * const seed, //optional, can be NULL buffer_t * const public_signing_key, //output, optional, can be NULL buffer_t * const public_identity_key) { //output, optional, can be NULL return_status status = return_status_init(); user_store_node *new_node = NULL; status = create_user_store_node(&new_node); throw_on_error(CREATION_ERROR, "Failed to create new user store node."); //generate the master keys status = master_keys_create( &(new_node->master_keys), seed, new_node->public_signing_key, public_identity_key); throw_on_error(CREATION_ERROR, "Failed to create master keys."); //prekeys status = prekey_store_create(&(new_node->prekeys)); throw_on_error(CREATION_ERROR, "Failed to create prekey store.") //copy the public signing key, if requested if (public_signing_key != NULL) { if (public_signing_key->buffer_length < PUBLIC_MASTER_KEY_SIZE) { throw(INCORRECT_BUFFER_SIZE, "Invalidly sized buffer for public signing key."); } if (buffer_clone(public_signing_key, new_node->public_signing_key) != 0) { throw(BUFFER_ERROR, "Failed to clone public signing key."); } } add_user_store_node(store, new_node); cleanup: on_error { if (new_node != NULL) { if (new_node->prekeys != NULL) { prekey_store_destroy(new_node->prekeys); } if (new_node->master_keys != NULL) { sodium_free_and_null_if_valid(new_node->master_keys); } sodium_free_and_null_if_valid(new_node); } } return status; }
/* * Add a section to the ELF file. Section type, flags, and memsize are * maintained from the passed in Elf64_Shdr. The buffer represents the * content of the section while the name is the name of section itself. * Returns < 0 on error, 0 on success. */ int elf_writer_add_section(struct elf_writer *ew, const Elf64_Shdr *shdr, struct buffer *contents, const char *name) { struct elf_writer_section *newsh; if (ew->num_secs == MAX_SECTIONS) return -1; newsh = &ew->sections[ew->num_secs]; ew->num_secs++; memcpy(&newsh->shdr, shdr, sizeof(newsh->shdr)); newsh->shdr.sh_offset = 0; newsh->name = name; if (contents != NULL) buffer_clone(&newsh->content, contents); return 0; }
/* * Get the public identity key. */ return_status master_keys_get_identity_key( master_keys * const keys, buffer_t * const public_identity_key) { return_status status = return_status_init(); //check input if ((keys == NULL) || (public_identity_key == NULL) || (public_identity_key->buffer_length < PUBLIC_KEY_SIZE)) { throw(INVALID_INPUT, "Invalid input to master_keys_get_identity_key."); } sodium_mprotect_readonly(keys); if (buffer_clone(public_identity_key, keys->public_identity_key) != 0) { goto cleanup; } cleanup: if (keys != NULL) { sodium_mprotect_noaccess(keys); } return status; }
/* * Get the public signing key. */ return_status master_keys_get_signing_key( master_keys * const keys, buffer_t * const public_signing_key) { return_status status = return_status_init(); //check input if ((keys == NULL) || (public_signing_key == NULL) || (public_signing_key->buffer_length < PUBLIC_MASTER_KEY_SIZE)) { throw(INVALID_INPUT, "Invalid input to master_keys_get_signing_key."); } sodium_mprotect_readonly(keys); if (buffer_clone(public_signing_key, keys->public_signing_key) != 0) { throw(BUFFER_ERROR, "Failed to copy public signing key."); } cleanup: if (keys != NULL) { sodium_mprotect_noaccess(keys); } return status; }
int rmodule_stage_to_elf(Elf64_Ehdr *ehdr, struct buffer *buff) { struct buffer reader; struct buffer elf_out; struct rmodule_header rmod; struct xdr *xdr; struct elf_writer *ew; Elf64_Shdr shdr; int bit64; size_t payload_sz; const char *section_name = ".program"; const size_t input_sz = buffer_size(buff); buffer_clone(&reader, buff); xdr = (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) ? &xdr_be : &xdr_le; bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64; rmod_deserialize(&rmod, &reader, xdr); /* Indicate that file is not an rmodule if initial checks fail. */ if (rmod.magic != RMODULE_MAGIC) return 1; if (rmod.version != RMODULE_VERSION_1) return 1; if (rmod.payload_begin_offset > input_sz || rmod.payload_end_offset > input_sz || rmod.relocations_begin_offset > input_sz || rmod.relocations_end_offset > input_sz) { ERROR("Rmodule fields out of bounds.\n"); return -1; } ehdr->e_entry = rmod.module_entry_point; ew = elf_writer_init(ehdr); if (ew == NULL) return -1; payload_sz = rmod.payload_end_offset - rmod.payload_begin_offset; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_PROGBITS; shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; shdr.sh_addr = rmod.module_link_start_address; shdr.sh_size = payload_sz; buffer_splice(&reader, buff, rmod.payload_begin_offset, payload_sz); if (elf_writer_add_section(ew, &shdr, &reader, section_name)) { ERROR("Unable to add ELF section: %s\n", section_name); elf_writer_destroy(ew); return -1; } if (payload_sz != rmod.module_program_size) { struct buffer b; buffer_init(&b, NULL, NULL, 0); memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_NOBITS; shdr.sh_flags = SHF_WRITE | SHF_ALLOC; shdr.sh_addr = rmod.module_link_start_address + payload_sz; shdr.sh_size = rmod.module_program_size - payload_sz; if (elf_writer_add_section(ew, &shdr, &b, ".empty")) { ERROR("Unable to add ELF section: .empty\n"); elf_writer_destroy(ew); return -1; } } /* Provide a section symbol so the relcoations can reference that. */ if (elf_writer_add_symbol(ew, section_name, section_name, shdr.sh_addr, 0, STB_LOCAL, STT_SECTION)) { ERROR("Unable to add section symbol to ELF.\n"); elf_writer_destroy(ew); return -1; } /* Add symbols for the parameters if they are non-zero. */ if (rmod.parameters_begin != rmod.parameters_end) { int ret = 0; ret |= elf_writer_add_symbol(ew, "_rmodule_params", section_name, rmod.parameters_begin, 0, STB_GLOBAL, STT_NOTYPE); ret |= elf_writer_add_symbol(ew, "_ermodule_params", section_name, rmod.parameters_end, 0, STB_GLOBAL, STT_NOTYPE); if (ret != 0) { ERROR("Unable to add module params symbols to ELF\n"); elf_writer_destroy(ew); return -1; } } if (elf_writer_add_symbol(ew, "_bss", section_name, rmod.bss_begin, 0, STB_GLOBAL, STT_NOTYPE) || elf_writer_add_symbol(ew, "_ebss", section_name, rmod.bss_end, 0, STB_GLOBAL, STT_NOTYPE)) { ERROR("Unable to add bss symbols to ELF\n"); elf_writer_destroy(ew); return -1; } ssize_t relocs_sz = rmod.relocations_end_offset; relocs_sz -= rmod.relocations_begin_offset; buffer_splice(&reader, buff, rmod.relocations_begin_offset, relocs_sz); while (relocs_sz > 0) { Elf64_Addr addr; if (bit64) { relocs_sz -= sizeof(Elf64_Addr); addr = xdr->get64(&reader); } else { relocs_sz -= sizeof(Elf32_Addr); addr = xdr->get32(&reader); } /* Skip any relocations that are below the link address. */ if (addr < rmod.module_link_start_address) continue; if (elf_writer_add_rel(ew, section_name, addr)) { ERROR("Relocation addition failure.\n"); elf_writer_destroy(ew); return -1; } } if (elf_writer_serialize(ew, &elf_out)) { ERROR("ELF writer serialize failure.\n"); elf_writer_destroy(ew); return -1; } elf_writer_destroy(ew); /* Flip buffer with the created ELF one. */ buffer_delete(buff); *buff = elf_out; return 0; }
static int write_elf(const struct rmod_context *ctx, const struct buffer *in, struct buffer *out) { int ret; int bit64; size_t loc; size_t rmod_data_size; struct elf_writer *ew; struct buffer rmod_data; struct buffer rmod_header; struct buffer program; struct buffer relocs; Elf64_Xword total_size; Elf64_Addr addr; Elf64_Ehdr ehdr; bit64 = ctx->pelf.ehdr.e_ident[EI_CLASS] == ELFCLASS64; /* * 3 sections will be added to the ELF file. * +------------------+ * | rmodule header | * +------------------+ * | program | * +------------------+ * | relocations | * +------------------+ */ /* Create buffer for header and relocations. */ rmod_data_size = sizeof(struct rmodule_header); if (bit64) rmod_data_size += ctx->nrelocs * sizeof(Elf64_Addr); else rmod_data_size += ctx->nrelocs * sizeof(Elf32_Addr); if (buffer_create(&rmod_data, rmod_data_size, "rmod")) return -1; buffer_splice(&rmod_header, &rmod_data, 0, sizeof(struct rmodule_header)); buffer_clone(&relocs, &rmod_data); buffer_seek(&relocs, sizeof(struct rmodule_header)); /* Reset current location. */ buffer_set_size(&rmod_header, 0); buffer_set_size(&relocs, 0); /* Program contents. */ buffer_splice(&program, in, ctx->phdr->p_offset, ctx->phdr->p_filesz); /* Create ELF writer with modified entry point. */ memcpy(&ehdr, &ctx->pelf.ehdr, sizeof(ehdr)); ew = elf_writer_init(&ehdr); if (ew == NULL) { ERROR("Failed to create ELF writer.\n"); buffer_delete(&rmod_data); return -1; } /* Write out rmodule_header. */ ctx->xdr->put16(&rmod_header, RMODULE_MAGIC); ctx->xdr->put8(&rmod_header, RMODULE_VERSION_1); ctx->xdr->put8(&rmod_header, 0); /* payload_begin_offset */ loc = sizeof(struct rmodule_header); ctx->xdr->put32(&rmod_header, loc); /* payload_end_offset */ loc += ctx->phdr->p_filesz; ctx->xdr->put32(&rmod_header, loc); /* relocations_begin_offset */ ctx->xdr->put32(&rmod_header, loc); /* relocations_end_offset */ if (bit64) loc += ctx->nrelocs * sizeof(Elf64_Addr); else loc += ctx->nrelocs * sizeof(Elf32_Addr); ctx->xdr->put32(&rmod_header, loc); /* module_link_start_address */ ctx->xdr->put32(&rmod_header, ctx->phdr->p_vaddr); /* module_program_size */ ctx->xdr->put32(&rmod_header, ctx->phdr->p_memsz); /* module_entry_point */ ctx->xdr->put32(&rmod_header, ctx->pelf.ehdr.e_entry); /* parameters_begin */ ctx->xdr->put32(&rmod_header, ctx->parameters_begin); /* parameters_end */ ctx->xdr->put32(&rmod_header, ctx->parameters_end); /* bss_begin */ ctx->xdr->put32(&rmod_header, ctx->bss_begin); /* bss_end */ ctx->xdr->put32(&rmod_header, ctx->bss_end); /* padding[4] */ ctx->xdr->put32(&rmod_header, 0); ctx->xdr->put32(&rmod_header, 0); ctx->xdr->put32(&rmod_header, 0); ctx->xdr->put32(&rmod_header, 0); /* Write the relocations. */ for (unsigned i = 0; i < ctx->nrelocs; i++) { if (bit64) ctx->xdr->put64(&relocs, ctx->emitted_relocs[i]); else ctx->xdr->put32(&relocs, ctx->emitted_relocs[i]); } total_size = 0; addr = 0; /* * There are 2 cases to deal with. The program has a large NOBITS * section and the relocations can fit entirely within occupied memory * region for the program. The other is that the relocations increase * the memory footprint of the program if it was loaded directly into * the region it would run. The rmdoule header is a fixed cost that * is considered a part of the program. */ total_size += buffer_size(&rmod_header); if (buffer_size(&relocs) + ctx->phdr->p_filesz > ctx->phdr->p_memsz) { total_size += buffer_size(&relocs); total_size += ctx->phdr->p_filesz; } else { total_size += ctx->phdr->p_memsz; } ret = add_section(ew, &rmod_header, ".header", addr, buffer_size(&rmod_header)); if (ret < 0) goto out; addr += buffer_size(&rmod_header); ret = add_section(ew, &program, ".program", addr, ctx->phdr->p_filesz); if (ret < 0) goto out; addr += ctx->phdr->p_filesz; if (ctx->nrelocs) { ret = add_section(ew, &relocs, ".relocs", addr, buffer_size(&relocs)); if (ret < 0) goto out; addr += buffer_size(&relocs); } if (total_size != addr) { ret = add_section(ew, NULL, ".empty", addr, total_size - addr); if (ret < 0) goto out; } /* * Ensure last section has a memory usage that meets the required * total size of the program in memory. */ ret = elf_writer_serialize(ew, out); if (ret < 0) ERROR("Failed to serialize ELF to buffer.\n"); out: buffer_delete(&rmod_data); elf_writer_destroy(ew); return ret; }
/* * Create a new set of master keys. * * Seed is optional, can be NULL. It can be of any length and doesn't * require to have high entropy. It will be used as entropy source * in addition to the OSs CPRNG. * * WARNING: Don't use Entropy from the OSs CPRNG as seed! */ return_status master_keys_create( master_keys ** const keys, //output const buffer_t * const seed, buffer_t * const public_signing_key, //output, optional, can be NULL buffer_t * const public_identity_key //output, optional, can be NULL ) { return_status status = return_status_init(); //seeds buffer_t *crypto_seeds = NULL; if (keys == NULL) { throw(INVALID_INPUT, "Invalid input for master_keys_create."); } *keys = sodium_malloc(sizeof(master_keys)); throw_on_failed_alloc(*keys); //initialize the buffers buffer_init_with_pointer((*keys)->public_signing_key, (*keys)->public_signing_key_storage, PUBLIC_MASTER_KEY_SIZE, PUBLIC_MASTER_KEY_SIZE); buffer_init_with_pointer((*keys)->private_signing_key, (*keys)->private_signing_key_storage, PRIVATE_MASTER_KEY_SIZE, PRIVATE_MASTER_KEY_SIZE); buffer_init_with_pointer((*keys)->public_identity_key, (*keys)->public_identity_key_storage, PUBLIC_KEY_SIZE, PUBLIC_KEY_SIZE); buffer_init_with_pointer((*keys)->private_identity_key, (*keys)->private_identity_key_storage, PRIVATE_KEY_SIZE, PRIVATE_KEY_SIZE); if (seed != NULL) { //use external seed //create the seed buffer crypto_seeds = buffer_create_with_custom_allocator( crypto_sign_SEEDBYTES + crypto_box_SEEDBYTES, crypto_sign_SEEDBYTES + crypto_box_SEEDBYTES, sodium_malloc, sodium_free); throw_on_failed_alloc(crypto_seeds); status = spiced_random(crypto_seeds, seed, crypto_seeds->buffer_length); throw_on_error(GENERIC_ERROR, "Failed to create spiced random data."); //generate the signing keypair int status_int = 0; status_int = crypto_sign_seed_keypair( (*keys)->public_signing_key->content, (*keys)->private_signing_key_storage, crypto_seeds->content); if (status_int != 0) { throw(KEYGENERATION_FAILED, "Failed to generate signing keypair."); } //generate the identity keypair status_int = crypto_box_seed_keypair( (*keys)->public_identity_key->content, (*keys)->private_identity_key->content, crypto_seeds->content + crypto_sign_SEEDBYTES); if (status_int != 0) { throw(KEYGENERATION_FAILED, "Failed to generate encryption keypair."); } } else { //don't use external seed //generate the signing keypair int status_int = 0; status_int = crypto_sign_keypair( (*keys)->public_signing_key->content, (*keys)->private_signing_key->content); if (status_int != 0) { throw(KEYGENERATION_FAILED, "Failed to generate signing keypair."); } //generate the identity keypair status_int = crypto_box_keypair( (*keys)->public_identity_key->content, (*keys)->private_identity_key->content); if (status_int != 0) { throw(KEYGENERATION_FAILED, "Failed to generate encryption keypair."); } } //copy the public keys if requested if (public_signing_key != NULL) { if (public_signing_key->buffer_length < PUBLIC_MASTER_KEY_SIZE) { public_signing_key->content_length = 0; throw(INCORRECT_BUFFER_SIZE, "Public master key buffer is too short."); } if (buffer_clone(public_signing_key, (*keys)->public_signing_key) != 0) { throw(BUFFER_ERROR, "Failed to copy public signing key."); } } if (public_identity_key != NULL) { if (public_identity_key->buffer_length < PUBLIC_KEY_SIZE) { public_identity_key->content_length = 0; throw(INCORRECT_BUFFER_SIZE, "Public encryption key buffer is too short."); } if (buffer_clone(public_identity_key, (*keys)->public_identity_key) != 0) { throw(BUFFER_ERROR, "Failed to copy public encryption key."); } } cleanup: buffer_destroy_with_custom_deallocator_and_null_if_valid(crypto_seeds, sodium_free); on_error { if (keys != NULL) { sodium_free_and_null_if_valid(*keys); } return status; } if ((keys != NULL) && (*keys != NULL)) { sodium_mprotect_noaccess(*keys); } return status; }
int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags) { struct xdr *xdr = &xdr_le; int bit64 = 0; struct buffer input; Elf64_Ehdr *ehdr; /* Zero out the parsed elf structure. */ memset(pelf, 0, sizeof(*pelf)); if (!iself(buffer_get(pinput))) { ERROR("The stage file is not in ELF format!\n"); return -1; } buffer_clone(&input, pinput); ehdr = &pelf->ehdr; elf_eident(&input, ehdr); bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64; /* Assume LE unless we are sure otherwise. * We're not going to take on the task of * fully validating the ELF file. That way * lies madness. */ if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) xdr = &xdr_be; elf_ehdr(&input, ehdr, xdr, bit64); /* Relocation processing requires section header parsing. */ if (flags & ELF_PARSE_RELOC) flags |= ELF_PARSE_SHDR; /* String table processing requires section header parsing. */ if (flags & ELF_PARSE_STRTAB) flags |= ELF_PARSE_SHDR; /* Symbole table processing requires section header parsing. */ if (flags & ELF_PARSE_SYMTAB) flags |= ELF_PARSE_SHDR; if ((flags & ELF_PARSE_PHDR) && phdr_read(pinput, pelf, xdr, bit64)) goto fail; if ((flags & ELF_PARSE_SHDR) && shdr_read(pinput, pelf, xdr, bit64)) goto fail; if ((flags & ELF_PARSE_RELOC) && reloc_read(pinput, pelf, xdr, bit64)) goto fail; if ((flags & ELF_PARSE_STRTAB) && strtab_read(pinput, pelf)) goto fail; if ((flags & ELF_PARSE_SYMTAB) && symtab_read(pinput, pelf, xdr, bit64)) goto fail; return 0; fail: parsed_elf_destroy(pelf); return -1; }
int main(void) { if (sodium_init() == -1) { return -1; } return_status status = return_status_init(); buffer_t *public_prekey = buffer_create_on_heap(PUBLIC_KEY_SIZE, PUBLIC_KEY_SIZE); buffer_t *private_prekey1 = buffer_create_on_heap(PRIVATE_KEY_SIZE, PRIVATE_KEY_SIZE); buffer_t *private_prekey2 = buffer_create_on_heap(PRIVATE_KEY_SIZE, PRIVATE_KEY_SIZE); buffer_t *prekey_list = buffer_create_on_heap(PREKEY_AMOUNT * PUBLIC_KEY_SIZE, PREKEY_AMOUNT * PUBLIC_KEY_SIZE); Prekey **protobuf_export_prekeys = NULL; buffer_t **protobuf_export_prekeys_buffers = NULL; size_t protobuf_export_prekeys_size = 0; Prekey **protobuf_export_deprecated_prekeys = NULL; buffer_t **protobuf_export_deprecated_prekeys_buffers = NULL; size_t protobuf_export_deprecated_prekeys_size = 0; Prekey **protobuf_second_export_prekeys = NULL; buffer_t **protobuf_second_export_prekeys_buffers = NULL; size_t protobuf_second_export_prekeys_size = 0; Prekey **protobuf_second_export_deprecated_prekeys = NULL; buffer_t **protobuf_second_export_deprecated_prekeys_buffers = NULL; size_t protobuf_second_export_deprecated_prekeys_size = 0; prekey_store *store = NULL; status = prekey_store_create(&store); throw_on_error(CREATION_ERROR, "Failed to create a prekey store."); status = prekey_store_list(store, prekey_list); throw_on_error(DATA_FETCH_ERROR, "Failed to list prekeys."); printf("Prekey list:\n"); print_hex(prekey_list); putchar('\n'); //compare the public keys with the ones in the prekey store for (size_t i = 0; i < PREKEY_AMOUNT; i++) { if (buffer_compare_partial(prekey_list, PUBLIC_KEY_SIZE * i, store->prekeys[i].public_key, 0, PUBLIC_KEY_SIZE) != 0) { throw(INCORRECT_DATA, "Key list doesn't match the prekey store."); } } printf("Prekey list matches the prekey store!\n"); //get a private key const size_t prekey_index = 10; if (buffer_clone(public_prekey, store->prekeys[prekey_index].public_key) != 0) { throw(BUFFER_ERROR, "Failed to clone public key."); } status = prekey_store_get_prekey(store, public_prekey, private_prekey1); throw_on_error(DATA_FETCH_ERROR, "Failed to get prekey.") printf("Get a Prekey:\n"); printf("Public key:\n"); print_hex(public_prekey); printf("Private key:\n"); print_hex(private_prekey1); putchar('\n'); if (store->deprecated_prekeys == NULL) { throw(GENERIC_ERROR, "Failed to deprecate requested key."); } if ((buffer_compare(public_prekey, store->deprecated_prekeys->public_key) != 0) || (buffer_compare(private_prekey1, store->deprecated_prekeys->private_key) != 0)) { throw(INCORRECT_DATA, "Deprecated key is incorrect."); } if (buffer_compare(store->prekeys[prekey_index].public_key, public_prekey) == 0) { throw(KEYGENERATION_FAILED, "Failed to generate new key for deprecated one."); } printf("Successfully deprecated requested key!\n"); //check if the prekey can be obtained from the deprecated keys status = prekey_store_get_prekey(store, public_prekey, private_prekey2); throw_on_error(DATA_FETCH_ERROR, "Failed to get key from the deprecated area."); if (buffer_compare(private_prekey1, private_prekey2) != 0) { throw(INCORRECT_DATA, "Prekey from the deprecated area didn't match."); } printf("Successfully got prekey from the deprecated area!\n"); //try to get a nonexistent key if (buffer_fill_random(public_prekey, PUBLIC_KEY_SIZE) != 0) { throw(KEYGENERATION_FAILED, "Failed to generate invalid public prekey."); } status = prekey_store_get_prekey(store, public_prekey, private_prekey1); if (status.status == SUCCESS) { throw(GENERIC_ERROR, "Didn't complain about invalid public key."); } printf("Detected invalid public prekey!\n"); //reset return status return_status_destroy_errors(&status); status.status = SUCCESS; //Protobuf-C export printf("Protobuf-C export\n"); status = protobuf_export( store, &protobuf_export_prekeys, &protobuf_export_prekeys_size, &protobuf_export_prekeys_buffers, &protobuf_export_deprecated_prekeys, &protobuf_export_deprecated_prekeys_size, &protobuf_export_deprecated_prekeys_buffers); throw_on_error(EXPORT_ERROR, "Failed to export prekey store to protobuf."); printf("Prekeys:\n"); puts("[\n"); for (size_t i = 0; i < protobuf_export_prekeys_size; i++) { print_hex(protobuf_export_prekeys_buffers[i]); puts(",\n"); } puts("]\n\n"); printf("Deprecated Prekeys:\n"); puts("[\n"); for (size_t i = 0; i < protobuf_export_deprecated_prekeys_size; i++) { print_hex(protobuf_export_deprecated_prekeys_buffers[i]); puts(",\n"); } puts("]\n\n"); prekey_store_destroy(store); store = NULL; printf("Import from Protobuf-C\n"); status = protobuf_import( &store, protobuf_export_prekeys_buffers, protobuf_export_prekeys_size, protobuf_export_deprecated_prekeys_buffers, protobuf_export_deprecated_prekeys_size); throw_on_error(IMPORT_ERROR, "Failed to import from protobuf."); printf("Protobuf-C export again\n"); status = protobuf_export( store, &protobuf_second_export_prekeys, &protobuf_second_export_prekeys_size, &protobuf_second_export_prekeys_buffers, &protobuf_second_export_deprecated_prekeys, &protobuf_second_export_deprecated_prekeys_size, &protobuf_second_export_deprecated_prekeys_buffers); throw_on_error(EXPORT_ERROR, "Failed to export prekey store to protobuf."); //compare both prekey lists printf("Compare normal prekeys\n"); if (protobuf_export_prekeys_size != protobuf_second_export_prekeys_size) { throw(INCORRECT_DATA, "Both prekey exports contain different amounts of keys."); } for (size_t i = 0; i < protobuf_export_prekeys_size; i++) { if (buffer_compare(protobuf_export_prekeys_buffers[i], protobuf_second_export_prekeys_buffers[i]) != 0) { throw(INCORRECT_DATA, "First and second prekey export are not identical."); } } //compare both deprecated prekey lists printf("Compare deprecated prekeys\n"); if (protobuf_export_deprecated_prekeys_size != protobuf_second_export_deprecated_prekeys_size) { throw(INCORRECT_DATA, "Both depcated prekey exports contain different amounts of keys."); } for (size_t i = 0; i < protobuf_export_deprecated_prekeys_size; i++) { if (buffer_compare(protobuf_export_deprecated_prekeys_buffers[i], protobuf_second_export_deprecated_prekeys_buffers[i]) != 0) { throw(INCORRECT_DATA, "First and second deprecated prekey export are not identical."); } } //test the automatic deprecation of old keys if (buffer_clone(public_prekey, store->prekeys[PREKEY_AMOUNT-1].public_key) != 0) { throw(BUFFER_ERROR, "Failed to clone public key."); } store->prekeys[PREKEY_AMOUNT-1].expiration_date -= 365 * 24 * 3600; //one year store->oldest_expiration_date = store->prekeys[PREKEY_AMOUNT - 1].expiration_date; status = prekey_store_rotate(store); throw_on_error(GENERIC_ERROR, "Failed to rotate the prekeys."); if (buffer_compare(store->deprecated_prekeys->public_key, public_prekey) != 0) { throw(GENERIC_ERROR, "Failed to deprecate outdated key."); } printf("Successfully deprecated outdated key!\n"); //test the automatic removal of old deprecated keys! if (buffer_clone(public_prekey, store->deprecated_prekeys->next->public_key) != 0) { throw(BUFFER_ERROR, "Failed to clone public key."); } store->deprecated_prekeys->next->expiration_date -= 24 * 3600; store->oldest_deprecated_expiration_date = store->deprecated_prekeys->next->expiration_date; status = prekey_store_rotate(store); throw_on_error(GENERIC_ERROR, "Failed to rotate the prekeys."); if (store->deprecated_prekeys->next != NULL) { throw(GENERIC_ERROR, "Failed to remove outdated key."); } printf("Successfully removed outdated deprecated key!\n"); status = protobuf_no_deprecated_keys(); throw_on_error(GENERIC_ERROR, "Failed to im-/export a prekey store without deprecated prekeys."); cleanup: buffer_destroy_from_heap_and_null_if_valid(public_prekey); buffer_destroy_from_heap_and_null_if_valid(private_prekey1); buffer_destroy_from_heap_and_null_if_valid(private_prekey2); buffer_destroy_from_heap_and_null_if_valid(prekey_list); prekey_store_destroy(store); if (protobuf_export_prekeys != NULL) { for (size_t i = 0; i < protobuf_export_prekeys_size; i++) { if (protobuf_export_prekeys[i] != NULL) { prekey__free_unpacked(protobuf_export_prekeys[i], &protobuf_c_allocators); protobuf_export_prekeys[i] = NULL; } } zeroed_free_and_null_if_valid(protobuf_export_prekeys); } if (protobuf_export_deprecated_prekeys != NULL) { for (size_t i = 0; i < protobuf_export_deprecated_prekeys_size; i++) { if (protobuf_export_deprecated_prekeys[i] != NULL) { prekey__free_unpacked(protobuf_export_deprecated_prekeys[i], &protobuf_c_allocators); protobuf_export_deprecated_prekeys[i] = NULL; } } zeroed_free_and_null_if_valid(protobuf_export_deprecated_prekeys); } if (protobuf_export_prekeys_buffers != NULL) { for (size_t i = 0; i < protobuf_export_prekeys_size; i++) { buffer_destroy_from_heap_and_null_if_valid(protobuf_export_prekeys_buffers[i]); } zeroed_free_and_null_if_valid(protobuf_export_prekeys_buffers); } if (protobuf_export_deprecated_prekeys_buffers != NULL) { for (size_t i = 0; i < protobuf_export_deprecated_prekeys_size; i++) { buffer_destroy_from_heap_and_null_if_valid(protobuf_export_deprecated_prekeys_buffers[i]); } zeroed_free_and_null_if_valid(protobuf_export_deprecated_prekeys_buffers); } if (protobuf_second_export_prekeys != NULL) { for (size_t i = 0; i < protobuf_second_export_prekeys_size; i++) { if (protobuf_second_export_prekeys[i] != NULL) { prekey__free_unpacked(protobuf_second_export_prekeys[i], &protobuf_c_allocators); protobuf_second_export_prekeys[i] = NULL; } } zeroed_free_and_null_if_valid(protobuf_second_export_prekeys); } if (protobuf_second_export_deprecated_prekeys != NULL) { for (size_t i = 0; i < protobuf_second_export_deprecated_prekeys_size; i++) { if (protobuf_second_export_deprecated_prekeys[i] != NULL) { prekey__free_unpacked(protobuf_second_export_deprecated_prekeys[i], &protobuf_c_allocators); protobuf_second_export_deprecated_prekeys[i] = NULL; } } zeroed_free_and_null_if_valid(protobuf_second_export_deprecated_prekeys); } if (protobuf_second_export_prekeys_buffers != NULL) { for (size_t i = 0; i < protobuf_second_export_prekeys_size; i++) { buffer_destroy_from_heap_and_null_if_valid(protobuf_second_export_prekeys_buffers[i]); } zeroed_free_and_null_if_valid(protobuf_second_export_prekeys_buffers); } if (protobuf_second_export_deprecated_prekeys_buffers != NULL) { for (size_t i = 0; i < protobuf_second_export_deprecated_prekeys_size; i++) { buffer_destroy_from_heap_and_null_if_valid(protobuf_second_export_deprecated_prekeys_buffers[i]); } zeroed_free_and_null_if_valid(protobuf_second_export_deprecated_prekeys_buffers); } on_error { print_errors(&status); } return_status_destroy_errors(&status); return status.status; }
int parse_elf_to_xip_stage(const struct buffer *input, struct buffer *output, uint32_t *location, const char *ignore_section) { struct xip_context xipctx; struct rmod_context *rmodctx; struct reloc_filter filter; struct parsed_elf *pelf; size_t output_sz; uint32_t adjustment; struct buffer binput; struct buffer boutput; Elf64_Xword i; int ret = -1; xipctx.ignored_section_idx = 0; rmodctx = &xipctx.rmodctx; pelf = &rmodctx->pelf; if (rmodule_init(rmodctx, input)) return -1; /* Only support x86 XIP currently. */ if (rmodctx->pelf.ehdr.e_machine != EM_386) { ERROR("Only support XIP stages for x86\n"); goto out; } xipctx.ignored_section = find_ignored_section_header(pelf, ignore_section); if (xipctx.ignored_section != NULL) xipctx.ignored_section_idx = xipctx.ignored_section - pelf->shdr; filter.filter = rmod_filter; filter.context = &xipctx; if (rmodule_collect_relocations(rmodctx, &filter)) goto out; output_sz = sizeof(struct cbfs_stage) + pelf->phdr->p_filesz; if (buffer_create(output, output_sz, input->name) != 0) { ERROR("Unable to allocate memory: %m\n"); goto out; } buffer_clone(&boutput, output); memset(buffer_get(&boutput), 0, output_sz); buffer_set_size(&boutput, 0); /* Single loadable segment. The entire segment moves to final * location from based on virtual address of loadable segment. */ adjustment = *location - pelf->phdr->p_vaddr; DEBUG("Relocation adjustment: %08x\n", adjustment); fill_cbfs_stage(&boutput, CBFS_COMPRESS_NONE, (uint32_t)pelf->ehdr.e_entry + adjustment, (uint32_t)pelf->phdr->p_vaddr + adjustment, pelf->phdr->p_filesz, pelf->phdr->p_memsz); /* Need an adjustable buffer. */ buffer_clone(&binput, input); buffer_seek(&binput, pelf->phdr->p_offset); bputs(&boutput, buffer_get(&binput), pelf->phdr->p_filesz); buffer_clone(&boutput, output); buffer_seek(&boutput, sizeof(struct cbfs_stage)); /* Make adjustments to all the relocations within the program. */ for (i = 0; i < rmodctx->nrelocs; i++) { size_t reloc_offset; uint32_t val; struct buffer in, out; /* The relocations represent in-program addresses of the * linked program. Obtain the offset into the program to do * the adjustment. */ reloc_offset = rmodctx->emitted_relocs[i] - pelf->phdr->p_vaddr; buffer_clone(&out, &boutput); buffer_seek(&out, reloc_offset); buffer_clone(&in, &out); /* Appease around xdr semantics: xdr decrements buffer * size when get()ing and appends to size when put()ing. */ buffer_set_size(&out, 0); val = xdr_le.get32(&in); DEBUG("reloc %zx %08x -> %08x\n", reloc_offset, val, val + adjustment); xdr_le.put32(&out, val + adjustment); } /* Need to back up the location to include cbfs stage metadata. */ *location -= sizeof(struct cbfs_stage); ret = 0; out: rmodule_cleanup(rmodctx); return ret; }