static int pakfire_key_create(struct pakfire_key** key, struct pakfire_ctx* ctx,
const pakfire_key_algo_t algo, const pakfire_key_id id, EVP_PKEY* pkey, const char* comment) {
- int r;
+ struct pakfire_key* k = NULL;
+ int r = 0;
- if (!pkey) {
- errno = EINVAL;
- return 1;
- }
+ if (!pkey)
+ return -EINVAL;
// Allocate memory
- struct pakfire_key* k = calloc(1, sizeof(*k));
+ k = calloc(1, sizeof(*k));
if (!k)
- return 1;
+ return -errno;
// Store a reference to the context
k->ctx = pakfire_ctx_ref(ctx);
default:
CTX_ERROR(k->ctx, "Unsupported key algorithm %u\n", algo);
- errno = ENOTSUP;
+ r = -ENOTSUP;
goto ERROR;
}
// Store the comment
if (comment) {
r = pakfire_string_set(k->comment, comment);
- if (r)
+ if (r < 0)
goto ERROR;
// Remove any trailing newline
pakfire_remove_trailing_newline(k->comment);
}
- *key = k;
- return 0;
+ // Return the pointer
+ *key = pakfire_key_ref(k);
ERROR:
- pakfire_key_unref(k);
+ if (k)
+ pakfire_key_unref(k);
- return 1;
+ return r;
}
static void pakfire_key_free(struct pakfire_key* key) {
default:
CTX_ERROR(ctx, "Invalid key algorithm %u\n", algo);
- errno = EINVAL;
- return 1;
+ return -EINVAL;
}
// Generate a random key ID
r = RAND_bytes((unsigned char*)&key_id, sizeof(key_id));
if (r < 0) {
CTX_ERROR(ctx, "Could not generate the key ID\n");
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
pctx = EVP_PKEY_CTX_new_id(id, NULL);
if (!pctx) {
CTX_ERROR(ctx, "Could not allocate the OpenSSL context: %m\n");
- r = 1;
+ r = -ENOMEM;
goto ERROR;
}
ERR_error_string_n(r, error, sizeof(error));
CTX_ERROR(ctx, "Could not prepare the context: %s\n", error);
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
ERR_error_string_n(r, error, sizeof(error));
CTX_ERROR(ctx, "Could not generate the key: %s\n", error);
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
// Create a key object
r = pakfire_key_create(key, ctx, algo, key_id, pkey, comment);
- if (r)
+ if (r < 0)
goto ERROR;
// Success
// Check the signature algorithm
if (buffer->sig_algo[0] != 'E' || buffer->sig_algo[1] != 'd') {
CTX_ERROR(ctx, "Unsupported signature algorithm\n");
- errno = ENOTSUP;
- r = 1;
+ r = -ENOTSUP;
goto ERROR;
}
// Check the KDF algorithm
if (buffer->kdf_algo[0] != 'B' || buffer->kdf_algo[1] != 'K') {
CTX_ERROR(ctx, "Unsupported KDF algorithm\n");
- errno = ENOTSUP;
- r = 1;
+ r = -ENOTSUP;
goto ERROR;
}
// We don't support encrypted keys here
if (buffer->kdf_rounds) {
CTX_ERROR(ctx, "Encrypted keys are not supported\n");
- errno = ENOTSUP;
- r = 1;
+ r = -ENOTSUP;
goto ERROR;
}
r = EVP_Digest(&buffer->keys, sizeof(buffer->keys), checksum, &length, EVP_sha512(), NULL);
if (r < 0) {
CTX_ERROR(ctx, "Could not compute the checksum: %m\n");
- r = 1;
goto ERROR;
}
// Compare the checksum
if (memcmp(buffer->checksum, checksum, sizeof(buffer->checksum)) != 0) {
CTX_ERROR(ctx, "Checksum mismatch\n");
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
CTX_ERROR(ctx, "Could not load secret key: %s\n", error);
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
// Create a new key object
r = pakfire_key_create(key, ctx, algo, buffer->id, pkey, comment);
- if (r)
+ if (r < 0)
goto ERROR;
ERROR:
if (pkey)
EVP_PKEY_free(pkey);
- return 0;
+ return r;
}
static int pakfire_key_import_public_key(struct pakfire_key** key,
int r;
// Check for input
- if (!buffer) {
- errno = EINVAL;
- return 1;
- }
+ if (!buffer)
+ return -EINVAL;
// Check the signature algorithm
if (buffer->sig_algo[0] != 'E' || buffer->sig_algo[1] != 'd') {
CTX_ERROR(ctx, "Unsupported signature algorithm\n");
- errno = ENOTSUP;
- r = 1;
+ r = -ENOTSUP;
goto ERROR;
}
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
CTX_ERROR(ctx, "Could not load public key: %s\n", error);
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
// Create a new key object
r = pakfire_key_create(key, ctx, algo, buffer->id, pkey, comment);
- if (r)
+ if (r < 0)
goto ERROR;
ERROR:
if (!pakfire_string_startswith(line, "untrusted comment: ")) {
CTX_ERROR(ctx, "The first line must start with 'untrusted comment: '"
" and not %s\n", line);
- errno = EINVAL;
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
// Copy the comment
r = pakfire_string_set(comment, line + strlen("untrusted comment: "));
- if (r) {
+ if (r < 0) {
CTX_ERROR(ctx, "Could not copy comment: %m\n");
- r = 1;
goto ERROR;
}
r = pakfire_b64decode(ctx, &buffer, &buffer_length, line);
if (r) {
CTX_ERROR(ctx, "Could not decode the key: %m\n");
- errno = EINVAL;
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
case sizeof(struct pakfire_key_public_key):
r = pakfire_key_import_public_key(key, ctx, comment,
(struct pakfire_key_public_key*)buffer);
+ if (r < 0)
+ goto ERROR;
break;
// Private Key
case sizeof(struct pakfire_key_private_key):
r = pakfire_key_import_secret_key(key, ctx, comment,
(struct pakfire_key_private_key*)buffer);
+ if (r < 0)
+ goto ERROR;
break;
// Unknown key
default:
CTX_ERROR(ctx, "Unsupported key type\n");
- errno = ENOTSUP;
- r = 1;
+ r = -ENOTSUP;
goto ERROR;
}
break;
f = fmemopen((char*)data, length, "r");
if (!f) {
CTX_ERROR(ctx, "Could not map the key to file: %m\n");
- r = 1;
+ r = -errno;
goto ERROR;
}
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
CTX_ERROR(key->ctx, "Could not extract the public key: %s\n", error);
- return 1;
+ return -EINVAL;
}
if (l > length) {
CTX_ERROR(key->ctx, "The buffer was too small to write the public key\n");
- errno = ENOBUFS;
- return 1;
+ return -ENOBUFS;
}
return 0;
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
CTX_ERROR(key->ctx, "Could not extract the secret key: %s\n", error);
- return 1;
+ return -EINVAL;
}
if (l > length) {
CTX_ERROR(key->ctx, "The buffer was too small to write the secret key\n");
- errno = ENOBUFS;
- return 1;
+ return -ENOBUFS;
}
return 0;
default:
CTX_ERROR(key->ctx, "Unknown algorithm\n");
- return 1;
+ return -ENOTSUP;
}
// Generate a salt
r = RAND_bytes(buffer->kdf_salt, sizeof(buffer->kdf_salt));
if (r < 1) {
CTX_ERROR(key->ctx, "Could not generate salt\n");
- return 1;
+ return -EINVAL;
}
// Copy the key ID
// Write the public key
r = pakfire_key_get_public_key(key, buffer->keys.public, sizeof(buffer->keys.public));
- if (r) {
+ if (r < 0) {
CTX_ERROR(key->ctx, "Could not export the public key: %m\n");
return r;
}
// Write the secret key
r = pakfire_key_get_secret_key(key, buffer->keys.secret, sizeof(buffer->keys.secret));
- if (r) {
+ if (r < 0) {
CTX_ERROR(key->ctx, "Could not export the secret key: %m\n");
return r;
}
r = EVP_Digest(&buffer->keys, sizeof(buffer->keys), checksum, &length, EVP_sha512(), NULL);
if (r < 0) {
CTX_ERROR(key->ctx, "Could not compute the checksum: %m\n");
- return 1;
+ return r;
}
// Copy the first couple of bytes of the checksum
default:
CTX_ERROR(key->ctx, "Unknown algorithm\n");
- return 1;
+ return -ENOTSUP;
}
// Copy the key ID
// Write the public key
r = pakfire_key_get_public_key(key, buffer->pubkey, sizeof(buffer->pubkey));
- if (r) {
+ if (r < 0) {
CTX_ERROR(key->ctx, "Could not export the public key: %m\n");
return r;
}
r = BIO_write(b64, &private_key, sizeof(private_key));
if (r < 0) {
CTX_ERROR(key->ctx, "Could not write the private key\n");
- r = 1;
goto ERROR;
}
break;
default:
- errno = EINVAL;
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
PAKFIRE_EXPORT char* pakfire_key_dump(struct pakfire_key* key) {
char* buffer = NULL;
FILE* f = NULL;
- int fd = -1;
+ int fd = -EBADF;
int r;
// Allocate a buffer in memory
fd = memfd_create("pakfire-key-dump", MFD_CLOEXEC);
if (fd < 0) {
CTX_ERROR(key->ctx, "Could not allocate a temporary file: %m\n");
- r = 1;
+ r = -errno;
goto ERROR;
}
f = fdopen(fd, "r+");
if (!f) {
CTX_ERROR(key->ctx, "Could not open file handle for temporary file: %m\n");
- r = 1;
+ r = -errno;
goto ERROR;
}
// Export the public part of the key
r = pakfire_key_export(key, f, PAKFIRE_KEY_EXPORT_MODE_PUBLIC);
- if (r) {
+ if (r < 0) {
CTX_ERROR(key->ctx, "Could not export key: %m\n");
goto ERROR;
}
buffer = calloc(1, length + 1);
if (!buffer) {
CTX_ERROR(key->ctx, "Could not allocate buffer of %zu byte(s)\n", length + 1);
- r = 1;
+ r = -errno;
goto ERROR;
}
size_t bytes_read = fread(buffer, 1, length, f);
if (bytes_read < length) {
CTX_ERROR(key->ctx, "Could not read back the buffer: %m\n");
- r = 1;
+ r = -errno;
goto ERROR;
}
int r;
// Check inputs
- if (!signature || !data || !length) {
- errno = EINVAL;
- return 1;
- }
+ if (!signature || !data || !length)
+ return -EINVAL;
// Set algorithm
signature->sig_algo[0] = 'E';
mdctx = EVP_MD_CTX_new();
if (!mdctx) {
CTX_ERROR(key->ctx, "Could not initialize the message digest context: %m\n");
- r = 1;
+ r = -ENOMEM;
goto ERROR;
}
r = EVP_DigestSignInit(mdctx, NULL, NULL, NULL, key->pkey);
if (r < 1) {
CTX_ERROR(key->ctx, "Could not setup context\n");
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
CTX_ERROR(key->ctx, "Could not sign content: %s\n", error);
- r = 1;
goto ERROR;
}
r = fprintf(f, "untrusted comment: %s\n", comment);
if (r < 0) {
CTX_ERROR(key->ctx, "Could not write comment: %m\n");
- r = 1;
+ r = -errno;
goto ERROR;
}
}
// Encode the signature to base64
r = pakfire_b64encode(key->ctx, &s, &signature, sizeof(signature));
- if (r)
+ if (r < 0)
goto ERROR;
// Write the signature
r = fprintf(f, "%s\n", s);
if (r < 0) {
CTX_ERROR(key->ctx, "Could not write the signature: %m\n");
- r = 1;
+ r = -errno;
goto ERROR;
}
// Load the entire content into memory
r = pakfire_read_file_into_buffer(f, &buffer, &length);
- if (r)
+ if (r < 0)
goto ERROR;
// Sign!
case 1:
if (!pakfire_string_startswith(line, "untrusted comment:")) {
CTX_ERROR(key->ctx, "The first line must start with 'untrusted comment:'\n");
- errno = EINVAL;
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
break;
r = pakfire_b64decode(key->ctx, &buffer, &buffer_length, line);
if (r) {
CTX_ERROR(key->ctx, "Could not decode the signature: %m\n");
- errno = EINVAL;
- r = 1;
+ r = -EINVAL;
goto ERROR;
}
// Check if we support the signature type
if (signature->sig_algo[0] != 'E' || signature->sig_algo[1] != 'd') {
CTX_ERROR(key->ctx, "Unknown signature type\n");
- errno = ENOTSUP;
- r = 1;
+ r = -ENOTSUP;
goto ERROR;
}
break;
default:
CTX_ERROR(key->ctx, "Unknown signature type\n");
- errno = ENOTSUP;
- r = 1;
+ r = -ENOTSUP;
goto ERROR;
}
break;
// Check the key ID
if (!pakfire_key_id_equals(&key->id, &signature->key_id)) {
CTX_ERROR(key->ctx, "The signature has been created with a different key\n");
- errno = EBADMSG;
- r = 1;
+ r = -EBADMSG;
goto ERROR;
}
mdctx = EVP_MD_CTX_new();
if (!mdctx) {
CTX_ERROR(key->ctx, "Could not create the message digest context\n");
- r = 1;
+ r = -ENOMEM;
goto ERROR;
}
r = EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, key->pkey);
if (r < 1) {
CTX_ERROR(key->ctx, "Could not setup the verification context\n");
- r = 1;
goto ERROR;
}
// Fail
case 0:
CTX_ERROR(key->ctx, "Signature verification failed\n");
- errno = EBADMSG;
- r = 1;
+ r = -EBADMSG;
break;
// Success
// Error
default:
CTX_ERROR(key->ctx, "Could not perform signature verification\n");
- r = 1;
+ r = -ENOTSUP;
goto ERROR;
}
// Read the signature
r = pakfire_key_read_signature(key, &signature, f);
- if (r) {
+ if (r < 0) {
CTX_ERROR(key->ctx, "Could not read signature: %m\n");
return r;
}
// Verify signature
r = pakfire_key_verify_signature(key, &signature, data, length);
- if (r) {
+ if (r < 0) {
CTX_ERROR(key->ctx, "Could not verify signature: %m\n");
return r;
}