off_t description;
off_t license;
- char* signature;
- size_t signature_length;
+ // Signatures
+ char* signature1;
+ size_t signature1_length;
+ char* signature2;
+ size_t signature2_length;
// ASes in the database
struct loc_database_as_v1* as_v1;
return 0;
}
+static int loc_database_read_signature(struct loc_database* db,
+ char** dst, char* src, size_t length) {
+ // Check for a plausible signature length
+ if (length > LOC_SIGNATURE_MAX_LENGTH) {
+ ERROR(db->ctx, "Signature too long: %ld\n", length);
+ return -EINVAL;
+ }
+
+ DEBUG(db->ctx, "Reading signature of %ld bytes\n", length);
+
+ // Allocate space
+ *dst = malloc(length);
+ if (!*dst)
+ return -ENOMEM;
+
+ // Copy payload
+ memcpy(*dst, src, length);
+
+ return 0;
+}
+
static int loc_database_read_header_v1(struct loc_database* db) {
struct loc_database_header_v1 header;
+ int r;
// Read from file
size_t size = fread(&header, 1, sizeof(header), db->f);
db->description = be32toh(header.description);
db->license = be32toh(header.license);
- // Read signature
- db->signature_length = be32toh(header.signature_length);
- if (db->signature_length) {
- // Check for a plausible signature length
- if (db->signature_length > LOC_SIGNATURE_MAX_LENGTH) {
- ERROR(db->ctx, "Signature too long: %ld\n", db->signature_length);
- return -EINVAL;
- }
+ db->signature1_length = be32toh(header.signature1_length);
+ db->signature2_length = be32toh(header.signature2_length);
- DEBUG(db->ctx, "Reading signature of %ld bytes\n",
- db->signature_length);
+ // Read signatures
+ if (db->signature1_length) {
+ r = loc_database_read_signature(db, &db->signature1,
+ header.signature1, db->signature1_length);
+ if (r)
+ return r;
+ }
- db->signature = malloc(db->signature_length);
- for (unsigned int i = 0; i < db->signature_length; i++)
- db->signature[i] = header.signature[i];
+ if (db->signature2_length) {
+ r = loc_database_read_signature(db, &db->signature2,
+ header.signature2, db->signature2_length);
+ if (r)
+ return r;
}
// Open pool
off_t pool_offset = be32toh(header.pool_offset);
size_t pool_length = be32toh(header.pool_length);
- int r = loc_stringpool_open(db->ctx, &db->pool,
+ r = loc_stringpool_open(db->ctx, &db->pool,
db->f, pool_length, pool_offset);
if (r)
return r;
loc_stringpool_unref(db->pool);
// Free signature
- if (db->signature)
- free(db->signature);
+ if (db->signature1)
+ free(db->signature1);
+ if (db->signature2)
+ free(db->signature2);
// Close database file
if (db->f)
LOC_EXPORT int loc_database_verify(struct loc_database* db, FILE* f) {
// Cannot do this when no signature is available
- if (!db->signature) {
+ if (!db->signature1 && !db->signature2) {
DEBUG(db->ctx, "No signature available to verify\n");
return 1;
}
goto CLEANUP;
}
- // Clear signature
- for (unsigned int i = 0; i < sizeof(header_v1.signature); i++) {
- header_v1.signature[i] = '\0';
- }
- header_v1.signature_length = 0;
+ // Clear signatures
+ memset(header_v1.signature1, '\0', sizeof(header_v1.signature1));
+ header_v1.signature1_length = 0;
+ memset(header_v1.signature2, '\0', sizeof(header_v1.signature2));
+ header_v1.signature2_length = 0;
hexdump(db->ctx, &header_v1, sizeof(header_v1));
}
}
- // Finish
- r = EVP_DigestVerifyFinal(mdctx,
- (unsigned char*)db->signature, db->signature_length);
+ // Check first signature
+ if (db->signature1) {
+ hexdump(db->ctx, db->signature1, db->signature1_length);
- if (r == 0) {
- DEBUG(db->ctx, "The signature is invalid\n");
- r = 1;
- } else if (r == 1) {
- DEBUG(db->ctx, "The signature is valid\n");
- r = 0;
- } else {
- ERROR(db->ctx, "Error verifying the signature: %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- r = 1;
+ r = EVP_DigestVerifyFinal(mdctx,
+ (unsigned char*)db->signature1, db->signature1_length);
+
+ if (r == 0) {
+ DEBUG(db->ctx, "The first signature is invalid\n");
+ r = 1;
+ } else if (r == 1) {
+ DEBUG(db->ctx, "The first signature is valid\n");
+ r = 0;
+ } else {
+ ERROR(db->ctx, "Error verifying the first signature: %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ r = -1;
+ }
}
- // Dump signature
- hexdump(db->ctx, db->signature, db->signature_length);
+ // Check second signature only when the first one was invalid
+ if (r && db->signature2) {
+ hexdump(db->ctx, db->signature2, db->signature2_length);
+
+ r = EVP_DigestVerifyFinal(mdctx,
+ (unsigned char*)db->signature2, db->signature2_length);
+
+ if (r == 0) {
+ DEBUG(db->ctx, "The second signature is invalid\n");
+ r = 1;
+ } else if (r == 1) {
+ DEBUG(db->ctx, "The second signature is valid\n");
+ r = 0;
+ } else {
+ ERROR(db->ctx, "Error verifying the second signature: %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ r = -1;
+ }
+ }
clock_t end = clock();
DEBUG(db->ctx, "Signature checked in %.4fms\n",
#define LOC_DATABASE_DOMAIN "_v%u._db.location.ipfire.org"
-#define LOC_DATABASE_PAGE_SIZE 4096
-
-#define LOC_SIGNATURE_MAX_LENGTH 4096
+#define LOC_DATABASE_PAGE_SIZE 4096
+#define LOC_SIGNATURE_MAX_LENGTH (LOC_DATABASE_PAGE_SIZE / 2)
struct loc_database_magic {
char magic[7];
uint32_t pool_offset;
uint32_t pool_length;
- // Signature
- uint32_t signature_length;
- char signature[LOC_SIGNATURE_MAX_LENGTH];
+ // Some padding
+ char padding1[2];
+
+ // Signatures
+ uint32_t signature1_length;
+ uint32_t signature2_length;
+ char signature1[LOC_SIGNATURE_MAX_LENGTH];
+ char signature2[LOC_SIGNATURE_MAX_LENGTH];
// Add some padding for future extensions
- char padding[32];
+ char padding2[32];
};
struct loc_database_network_node_v1 {
struct loc_writer;
-int loc_writer_new(struct loc_ctx* ctx, struct loc_writer** writer, FILE* fkey);
+int loc_writer_new(struct loc_ctx* ctx, struct loc_writer** writer,
+ FILE* fkey1, FILE* fkey2);
struct loc_writer* loc_writer_ref(struct loc_writer* writer);
struct loc_writer* loc_writer_unref(struct loc_writer* writer);
}
// Create the writer object
- int r = loc_writer_new(loc_ctx, &self->writer, f);
+ int r = loc_writer_new(loc_ctx, &self->writer, f, NULL);
return r;
}
// Create a database
struct loc_writer* writer;
- err = loc_writer_new(ctx, &writer, NULL);
+ err = loc_writer_new(ctx, &writer, NULL, NULL);
if (err < 0)
exit(EXIT_FAILURE);
// Create a database
struct loc_writer* writer;
- err = loc_writer_new(ctx, &writer, NULL);
+ err = loc_writer_new(ctx, &writer, NULL, NULL);
if (err < 0)
exit(EXIT_FAILURE);
// Create a database
struct loc_writer* writer;
- err = loc_writer_new(ctx, &writer, NULL);
+ err = loc_writer_new(ctx, &writer, NULL, NULL);
if (err < 0)
exit(EXIT_FAILURE);
// Create a database
struct loc_writer* writer;
- err = loc_writer_new(ctx, &writer, NULL);
+ err = loc_writer_new(ctx, &writer, NULL, NULL);
if (err < 0)
exit(EXIT_FAILURE);
// Create an empty database
struct loc_writer* writer;
- err = loc_writer_new(ctx, &writer, private_key);
+ err = loc_writer_new(ctx, &writer, private_key, NULL);
if (err < 0)
exit(EXIT_FAILURE);
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++) {
}
static int loc_writer_create_signature(struct loc_writer* writer,
- struct loc_database_header_v1* header, FILE* f) {
+ struct loc_database_header_v1* header, FILE* f, EVP_PKEY* private_key,
+ char* signature, size_t* length) {
DEBUG(writer->ctx, "Signing database...\n");
// Read file from the beginning
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 %lu 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);
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.padding1, '\0', sizeof(header.padding1));
+ memset(header.padding2, '\0', sizeof(header.padding2));
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) {
+ memcpy(header.signature1, writer->signature1, writer->signature1_length);
+ header.signature1_length = htobe32(writer->signature1_length);
+ }
+
+ if (writer->signature2_length) {
+ memcpy(header.signature2, writer->signature2, writer->signature2_length);
+ header.signature2_length = htobe32(writer->signature2_length);
+ }
+
// Write the header
r = fseek(f, sizeof(magic), SEEK_SET);
if (r)