233 lines
4.5 KiB
C
233 lines
4.5 KiB
C
#include <fcntl.h>
|
|
#include <openssl/bio.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/evp.h>
|
|
#include <openssl/pem.h>
|
|
#include <sodium.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include "apk_crypto.h"
|
|
|
|
union pkey_state {
|
|
unsigned char cute_pk[crypto_sign_ed25519_PUBLICKEYBYTES];
|
|
unsigned char cute_sk[crypto_sign_ed25519_SECRETKEYBYTES];
|
|
EVP_PKEY *pkey;
|
|
};
|
|
|
|
static int load_openssl(int fd, struct apk_pkey *pkey)
|
|
{
|
|
int r = -APKE_CRYPTO_KEY_FORMAT;
|
|
union pkey_state *state;
|
|
BIO *bio;
|
|
|
|
pkey->impl = malloc(sizeof(union pkey_state));
|
|
if (pkey->impl == NULL) {
|
|
r = -ENOMEM;
|
|
goto err_alloc;
|
|
}
|
|
|
|
bio = BIO_new_fd(fd, BIO_NOCLOSE);
|
|
if (bio == NULL) {
|
|
r = -ENOMEM;
|
|
goto err_bio_new;
|
|
}
|
|
|
|
state = (union pkey_state *) pkey->impl;
|
|
|
|
pkey->type = APK_PKEY_TYPE_PUBLIC;
|
|
state->pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
|
|
if (state->pkey == NULL) {
|
|
pkey->type = APK_PKEY_TYPE_SECRET;
|
|
BIO_reset(bio);
|
|
state->pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
|
|
}
|
|
|
|
ERR_clear_error();
|
|
|
|
if (state->pkey == NULL) {
|
|
r = -APKE_CRYPTO_KEY_FORMAT;
|
|
goto err_load;
|
|
}
|
|
|
|
BIO_free(bio);
|
|
|
|
return 0;
|
|
|
|
err_load:
|
|
BIO_free(bio);
|
|
err_bio_new:
|
|
free(pkey->impl);
|
|
err_alloc:
|
|
return r;
|
|
}
|
|
|
|
static int load_public_cute(int fd, struct apk_pkey *pkey)
|
|
{
|
|
char b64[APK_PKEY_CUTE_PUBLIC_SIZE];
|
|
int r = -APKE_CRYPTO_KEY_FORMAT;
|
|
union pkey_state *state;
|
|
uint8_t raw[50]; // 2 + 16 + 32
|
|
size_t len;
|
|
|
|
pkey->impl = malloc(sizeof(union pkey_state));
|
|
if (pkey->impl == NULL) {
|
|
r = -ENOMEM;
|
|
goto err_alloc;
|
|
}
|
|
|
|
state = (union pkey_state *) pkey->impl;
|
|
|
|
if (read(fd, b64, APK_PKEY_CUTE_PUBLIC_SIZE) != APK_PKEY_CUTE_PUBLIC_SIZE) {
|
|
r = -APKE_CRYPTO_KEY_FORMAT;
|
|
goto err_read;
|
|
}
|
|
|
|
if (sodium_base642bin(raw,
|
|
50,
|
|
b64,
|
|
APK_PKEY_CUTE_PUBLIC_SIZE,
|
|
NULL,
|
|
&len,
|
|
NULL,
|
|
sodium_base64_VARIANT_URLSAFE)
|
|
!= 0) {
|
|
r = -APKE_CRYPTO_KEY_FORMAT;
|
|
goto err_b64decode;
|
|
}
|
|
|
|
if (raw[0] != 'q' || raw[1] != 't') {
|
|
r = -APKE_CRYPTO_KEY_FORMAT;
|
|
goto err_rawheader;
|
|
}
|
|
|
|
pkey->type = APK_PKEY_TYPE_PUBLIC;
|
|
pkey->alg = APK_PKEY_ED25519;
|
|
memcpy(pkey->id, raw + 2, 16);
|
|
memcpy(state->cute_pk, raw + 18, crypto_sign_ed25519_PUBLICKEYBYTES);
|
|
|
|
return 0;
|
|
|
|
err_rawheader:
|
|
err_b64decode:
|
|
err_read:
|
|
free(pkey->impl);
|
|
err_alloc:
|
|
return r;
|
|
}
|
|
|
|
static int load_secret_cute(int fd, struct apk_pkey *pkey)
|
|
{
|
|
char b64[APK_PKEY_CUTE_SECRET_SIZE];
|
|
int r = -APKE_CRYPTO_KEY_FORMAT;
|
|
union pkey_state *state;
|
|
uint8_t raw[82]; // 2 + 16 + 64
|
|
size_t len;
|
|
|
|
pkey->impl = malloc(sizeof(union pkey_state));
|
|
if (pkey->impl == NULL) {
|
|
r = -ENOMEM;
|
|
goto err_alloc;
|
|
}
|
|
|
|
state = (union pkey_state *) pkey->impl;
|
|
|
|
if (read(fd, b64, APK_PKEY_CUTE_SECRET_SIZE) != APK_PKEY_CUTE_SECRET_SIZE) {
|
|
r = -APKE_CRYPTO_KEY_FORMAT;
|
|
goto err_read;
|
|
}
|
|
|
|
if (sodium_base642bin(raw,
|
|
82,
|
|
b64,
|
|
APK_PKEY_CUTE_PUBLIC_SIZE,
|
|
NULL,
|
|
&len,
|
|
NULL,
|
|
sodium_base64_VARIANT_URLSAFE)
|
|
!= 0) {
|
|
r = -APKE_CRYPTO_KEY_FORMAT;
|
|
goto err_b64decode;
|
|
}
|
|
|
|
if (len != 82) {
|
|
r = -APKE_CRYPTO_KEY_FORMAT;
|
|
goto err_decodelen;
|
|
}
|
|
|
|
if (raw[0] != 'q' || raw[1] != 't') {
|
|
r = -APKE_CRYPTO_KEY_FORMAT;
|
|
goto err_rawheader;
|
|
}
|
|
|
|
pkey->type = APK_PKEY_TYPE_SECRET;
|
|
pkey->alg = APK_PKEY_ED25519;
|
|
memcpy(pkey->id, raw + 2, 16);
|
|
memcpy(state->cute_sk, raw + 18, crypto_sign_ed25519_SECRETKEYBYTES);
|
|
|
|
return 0;
|
|
|
|
err_rawheader:
|
|
err_decodelen:
|
|
err_b64decode:
|
|
err_read:
|
|
free(pkey->impl);
|
|
err_alloc:
|
|
return r;
|
|
}
|
|
|
|
void apk_pkey_free(struct apk_pkey *pkey)
|
|
{
|
|
union pkey_state *state = (union pkey_state *) pkey->impl;
|
|
|
|
switch (pkey->alg) {
|
|
case APK_PKEY_ED25519:
|
|
break;
|
|
case APK_PKEY_RSAPKCS1v15:
|
|
EVP_PKEY_free(state->pkey);
|
|
break;
|
|
default:
|
|
/* invalid state, don't touch impl */
|
|
return;
|
|
}
|
|
|
|
free(pkey->impl);
|
|
|
|
pkey->impl = NULL;
|
|
}
|
|
|
|
int apk_pkey_load(struct apk_pkey *pkey, int dirfd, const char *fn)
|
|
{
|
|
struct stat st;
|
|
int fd, r = 0;
|
|
|
|
fd = openat(dirfd, fn, O_RDONLY | O_CLOEXEC);
|
|
if (fd == -1) {
|
|
r = -errno;
|
|
goto err_openat;
|
|
}
|
|
|
|
if (fstat(fd, &st) != 0) {
|
|
r = -errno;
|
|
goto err_fstat;
|
|
}
|
|
|
|
switch (st.st_size) {
|
|
case APK_PKEY_CUTE_SECRET_SIZE:
|
|
r = load_secret_cute(fd, pkey);
|
|
break;
|
|
case APK_PKEY_CUTE_PUBLIC_SIZE:
|
|
r = load_public_cute(fd, pkey);
|
|
break;
|
|
default:
|
|
r = load_openssl(fd, pkey);
|
|
break;
|
|
}
|
|
|
|
err_fstat:
|
|
close(fd);
|
|
err_openat:
|
|
return r;
|
|
}
|