off_t description;
off_t license;
- // Private key to sign any databases
- EVP_PKEY* private_key;
+ // Private keys to sign any databases
+ EVP_PKEY* private_key1;
+ EVP_PKEY* private_key2;
+
+ // Signatures
+ char signature1[LOC_SIGNATURE_MAX_LENGTH];
+ size_t signature1_length;
+ char signature2[LOC_SIGNATURE_MAX_LENGTH];
+ size_t signature2_length;
struct loc_as** as;
size_t as_count;
struct loc_network_tree* networks;
};
-static int parse_private_key(struct loc_writer* writer, FILE* f) {
+static int parse_private_key(struct loc_writer* writer, EVP_PKEY** private_key, FILE* f) {
// Free any previously loaded keys
- if (writer->private_key)
- EVP_PKEY_free(writer->private_key);
+ if (*private_key)
+ EVP_PKEY_free(*private_key);
// Read the key
- writer->private_key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
+ *private_key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
// Log any errors
- if (!writer->private_key) {
+ if (!*private_key) {
char* error = ERR_error_string(ERR_get_error(), NULL);
ERROR(writer->ctx, "Could not parse private key: %s\n", error);
return 0;
}
-LOC_EXPORT int loc_writer_new(struct loc_ctx* ctx, struct loc_writer** writer, FILE* fkey) {
+LOC_EXPORT int loc_writer_new(struct loc_ctx* ctx, struct loc_writer** writer,
+ FILE* fkey1, FILE* fkey2) {
struct loc_writer* w = calloc(1, sizeof(*w));
if (!w)
return -ENOMEM;
return r;
}
- // Load the private key to sign databases
- if (fkey) {
- r = parse_private_key(w, fkey);
+ // Load the private keys to sign databases
+ if (fkey1) {
+ r = parse_private_key(w, &w->private_key1, fkey1);
+ if (r) {
+ loc_writer_unref(w);
+ return r;
+ }
+ }
+
+ if (fkey2) {
+ r = parse_private_key(w, &w->private_key2, fkey2);
if (r) {
loc_writer_unref(w);
return r;
static void loc_writer_free(struct loc_writer* writer) {
DEBUG(writer->ctx, "Releasing writer at %p\n", writer);
- // Free private key
- if (writer->private_key)
- EVP_PKEY_free(writer->private_key);
+ // Free private keys
+ if (writer->private_key1)
+ EVP_PKEY_free(writer->private_key1);
+ if (writer->private_key2)
+ EVP_PKEY_free(writer->private_key2);
// Unref all AS
- for (unsigned int i = 0; i < writer->as_count; i++) {
- loc_as_unref(writer->as[i]);
+ if (writer->as) {
+ for (unsigned int i = 0; i < writer->as_count; i++) {
+ loc_as_unref(writer->as[i]);
+ }
+ free(writer->as);
+ }
+
+ // Unref all countries
+ if (writer->countries) {
+ for (unsigned int i = 0; i < writer->countries_count; i++) {
+ loc_country_unref(writer->countries[i]);
+ }
+ free(writer->countries);
}
// Release network tree
return 0;
}
-static void make_magic(struct loc_writer* writer, struct loc_database_magic* magic) {
+static void make_magic(struct loc_writer* writer, struct loc_database_magic* magic,
+ enum loc_database_version version) {
// Copy magic bytes
for (unsigned int i = 0; i < strlen(LOC_DATABASE_MAGIC); i++)
magic->magic[i] = LOC_DATABASE_MAGIC[i];
// Set version
- magic->version = htobe16(LOC_DATABASE_VERSION);
+ magic->version = version;
}
static void align_page_boundary(off_t* offset, FILE* f) {
}
static int loc_database_write_pool(struct loc_writer* writer,
- struct loc_database_header_v0* header, off_t* offset, FILE* f) {
+ struct loc_database_header_v1* header, off_t* offset, FILE* f) {
// Save the offset of the pool section
DEBUG(writer->ctx, "Pool starts at %jd bytes\n", (intmax_t)*offset);
header->pool_offset = htobe32(*offset);
}
static int loc_database_write_as_section(struct loc_writer* writer,
- struct loc_database_header_v0* header, off_t* offset, FILE* f) {
+ struct loc_database_header_v1* header, off_t* offset, FILE* f) {
DEBUG(writer->ctx, "AS section starts at %jd bytes\n", (intmax_t)*offset);
header->as_offset = htobe32(*offset);
size_t as_length = 0;
- struct loc_database_as_v0 as;
+ struct loc_database_as_v1 as;
for (unsigned int i = 0; i < writer->as_count; i++) {
// Convert AS into database format
- loc_as_to_database_v0(writer->as[i], writer->pool, &as);
+ loc_as_to_database_v1(writer->as[i], writer->pool, &as);
// Write to disk
*offset += fwrite(&as, 1, sizeof(as), f);
}
static int loc_database_write_networks(struct loc_writer* writer,
- struct loc_database_header_v0* header, off_t* offset, FILE* f) {
+ struct loc_database_header_v1* header, off_t* offset, FILE* f) {
// Write the network tree
DEBUG(writer->ctx, "Network tree starts at %jd bytes\n", (intmax_t)*offset);
header->network_tree_offset = htobe32(*offset);
uint32_t index = 0;
uint32_t network_index = 0;
- struct loc_database_network_v0 db_network;
- struct loc_database_network_node_v0 db_node;
+ struct loc_database_network_v1 db_network;
+ struct loc_database_network_node_v1 db_node;
// Initialize queue for nodes
TAILQ_HEAD(node_t, node) nodes;
TAILQ_REMOVE(&networks, nw, networks);
// Prepare what we are writing to disk
- int r = loc_network_to_database_v0(nw->network, &db_network);
+ int r = loc_network_to_database_v1(nw->network, &db_network);
if (r)
return r;
}
static int loc_database_write_countries(struct loc_writer* writer,
- struct loc_database_header_v0* header, off_t* offset, FILE* f) {
+ struct loc_database_header_v1* header, off_t* offset, FILE* f) {
DEBUG(writer->ctx, "Countries section starts at %jd bytes\n", (intmax_t)*offset);
header->countries_offset = htobe32(*offset);
size_t countries_length = 0;
- struct loc_database_country_v0 country;
+ struct loc_database_country_v1 country;
for (unsigned int i = 0; i < writer->countries_count; i++) {
// Convert country into database format
- loc_country_to_database_v0(writer->countries[i], writer->pool, &country);
+ loc_country_to_database_v1(writer->countries[i], writer->pool, &country);
// Write to disk
*offset += fwrite(&country, 1, sizeof(country), f);
}
static int loc_writer_create_signature(struct loc_writer* writer,
- struct loc_database_header_v0* header, FILE* f) {
- DEBUG(writer->ctx, "Signing database...\n");
+ struct loc_database_header_v1* header, FILE* f, EVP_PKEY* private_key,
+ char* signature, size_t* length) {
+ DEBUG(writer->ctx, "Creating signature...\n");
// Read file from the beginning
rewind(f);
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
// Initialise the context
- int r = EVP_DigestSignInit(mdctx, NULL, NULL, NULL, writer->private_key);
+ int r = EVP_DigestSignInit(mdctx, NULL, NULL, NULL, private_key);
if (r != 1) {
ERROR(writer->ctx, "%s\n", ERR_error_string(ERR_get_error(), NULL));
goto END;
r = EVP_DigestSignUpdate(mdctx, buffer, bytes_read);
if (r != 1) {
ERROR(writer->ctx, "%s\n", ERR_error_string(ERR_get_error(), NULL));
+ r = -1;
goto END;
}
}
// Compute the signature
- size_t signature_length = sizeof(header->signature);
-
r = EVP_DigestSignFinal(mdctx,
- (unsigned char*)header->signature, &signature_length);
+ (unsigned char*)signature, length);
if (r != 1) {
ERROR(writer->ctx, "%s\n", ERR_error_string(ERR_get_error(), NULL));
+ r = -1;
goto END;
}
- // Save length of the signature
- header->signature_length = htobe32(signature_length);
-
- DEBUG(writer->ctx, "Successfully generated signature of %lu bytes\n",
- signature_length);
+ DEBUG(writer->ctx, "Successfully generated signature of %zu bytes\n", *length);
r = 0;
// Dump signature
- hexdump(writer->ctx, header->signature, signature_length);
+ hexdump(writer->ctx, signature, *length);
END:
EVP_MD_CTX_free(mdctx);
return r;
}
-LOC_EXPORT int loc_writer_write(struct loc_writer* writer, FILE* f) {
+LOC_EXPORT int loc_writer_write(struct loc_writer* writer, FILE* f, enum loc_database_version version) {
+ // Check version
+ switch (version) {
+ case LOC_DATABASE_VERSION_UNSET:
+ version = LOC_DATABASE_VERSION_LATEST;
+ break;
+
+ case LOC_DATABASE_VERSION_1:
+ break;
+
+ default:
+ ERROR(writer->ctx, "Invalid database version: %d\n", version);
+ return -1;
+ }
+
+ DEBUG(writer->ctx, "Writing database in version %d\n", version);
+
struct loc_database_magic magic;
- make_magic(writer, &magic);
+ make_magic(writer, &magic, version);
// Make the header
- struct loc_database_header_v0 header;
+ struct loc_database_header_v1 header;
header.vendor = htobe32(writer->vendor);
header.description = htobe32(writer->description);
header.license = htobe32(writer->license);
time_t now = time(NULL);
header.created_at = htobe64(now);
- // Clear the signature
- header.signature_length = 0;
- for (unsigned int i = 0; i < sizeof(header.signature); i++)
- header.signature[i] = '\0';
+ // Clear the signatures
+ memset(header.signature1, '\0', sizeof(header.signature1));
+ header.signature1_length = 0;
+ memset(header.signature2, '\0', sizeof(header.signature2));
+ header.signature2_length = 0;
// Clear the padding
- for (unsigned int i = 0; i < sizeof(header.padding); i++)
- header.padding[i] = '\0';
+ memset(header.padding, '\0', sizeof(header.padding));
int r;
off_t offset = 0;
if (r)
return r;
- // Create the signature
- if (writer->private_key) {
- r = loc_writer_create_signature(writer, &header, f);
+ // Create the signatures
+ if (writer->private_key1) {
+ DEBUG(writer->ctx, "Creating signature with first private key\n");
+
+ writer->signature1_length = sizeof(writer->signature1);
+
+ r = loc_writer_create_signature(writer, &header, f,
+ writer->private_key1, writer->signature1, &writer->signature1_length);
+ if (r)
+ return r;
+ }
+
+ if (writer->private_key2) {
+ DEBUG(writer->ctx, "Creating signature with second private key\n");
+
+ writer->signature2_length = sizeof(writer->signature2);
+
+ r = loc_writer_create_signature(writer, &header, f,
+ writer->private_key2, writer->signature2, &writer->signature2_length);
if (r)
return r;
}
+ // Copy the signatures into the header
+ if (writer->signature1_length) {
+ DEBUG(writer->ctx, "Copying first signature of %zu byte(s)\n",
+ writer->signature1_length);
+
+ memcpy(header.signature1, writer->signature1, writer->signature1_length);
+ header.signature1_length = htobe16(writer->signature1_length);
+ }
+
+ if (writer->signature2_length) {
+ DEBUG(writer->ctx, "Copying second signature of %zu byte(s)\n",
+ writer->signature1_length);
+
+ memcpy(header.signature2, writer->signature2, writer->signature2_length);
+ header.signature2_length = htobe16(writer->signature2_length);
+ }
+
// Write the header
r = fseek(f, sizeof(magic), SEEK_SET);
if (r)