From 272784636112c84b57b3bd4742ab9f0235abe5b8 Mon Sep 17 00:00:00 2001 From: Aydin Mercan Date: Mon, 25 Jul 2022 14:23:37 +0300 Subject: [PATCH] crypto: start tinkering Start working on "cute" signatures because why not? Cute signatures are inspired/ripped of from the signify and minisign design: Key (URL-Safe, padded base64): - 2 bytes of version tag (specifies the algorithm) - 16 bytes of key ID - Public/Private key (size depending on the version tag) Signature (raw): - 2 bytes of version tag (specifies the algorithm) - Signature depending (size depending on the version tag) The new scheme uses libsodium and thus the work of abstracting cryptographic operations from libcrypto should also be completed. Also, since the key of the signature is provided in the filename, there shouldn't be a need for ID There is also the possibility of using epheremal keys for signatures and sign the package's public key, signature and signing timestamp in the header such as: - 2 bytes of version tag - signing timestamp - epheremal public key used - epheremal signature - signature of the previous sections --- meson.build | 2 + src/Makefile | 9 +- src/apk.c | 6 +- src/apk.pc.in | 4 +- src/apk_crypto.h | 144 +++++++++++---------------- src/crypto_core.c | 38 +++++++ src/crypto_digest.c | 209 ++++++++++++++++++++++++++++++++++++++ src/crypto_openssl.c | 17 ---- src/crypto_sign.c | 232 +++++++++++++++++++++++++++++++++++++++++++ src/meson.build | 2 + 10 files changed, 553 insertions(+), 110 deletions(-) create mode 100644 src/crypto_core.c create mode 100644 src/crypto_digest.c create mode 100644 src/crypto_sign.c diff --git a/meson.build b/meson.build index 1b884c1..5c7f2db 100644 --- a/meson.build +++ b/meson.build @@ -17,11 +17,13 @@ scdoc_dep = dependency('scdoc', version: '>=1.10', required: get_option('docs')) shared_deps = [ dependency('zlib'), dependency('openssl'), + dependency('libsodium'), ] static_deps = [ dependency('openssl', static: true), dependency('zlib', static: true), + dependency('libsodium', static: true), ] add_project_arguments('-D_GNU_SOURCE', language: 'c') diff --git a/src/Makefile b/src/Makefile index 19b2d53..a85cbdd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -15,12 +15,15 @@ OPENSSL_LIBS := $(shell $(PKG_CONFIG) --libs openssl) ZLIB_CFLAGS := $(shell $(PKG_CONFIG) --cflags zlib) ZLIB_LIBS := $(shell $(PKG_CONFIG) --libs zlib) +SODIUM_FLAGS := $(shell $(PKG_CONFIG) --cflags libsodium) +SODIUM_LIBS := $(shell $(PKG_CONFIG) --libs libsodium) + # Dynamic library libapk_soname := 2.99.0 libapk_so := $(obj)/libapk.so.$(libapk_soname) libapk.so.$(libapk_soname)-objs := \ adb.o adb_comp.o adb_walk_adb.o adb_walk_genadb.o adb_walk_gentext.o adb_walk_text.o apk_adb.o \ - atom.o blob.o commit.o common.o context.o crypto_openssl.o database.o hash.o \ + atom.o blob.o commit.o common.o context.o crypto_core.o crypto_digest.o crypto_openssl.o database.o hash.o \ extract_v2.o extract_v3.o fs_fsys.o fs_uvol.o io.o io_gunzip.o io_url.o tar.o \ package.o pathbuilder.o print.o solver.o trust.o version.o @@ -90,9 +93,9 @@ LIBS_apk.static := -Wl,--as-needed -ldl -Wl,--no-as-needed LDFLAGS_apk += -L$(obj) LDFLAGS_apk-test += -L$(obj) -CFLAGS_ALL += $(OPENSSL_CFLAGS) $(ZLIB_CFLAGS) +CFLAGS_ALL += $(OPENSSL_CFLAGS) $(ZLIB_CFLAGS) $(SODIUM_CFLAGS) LIBS := -Wl,--as-needed \ - $(OPENSSL_LIBS) $(ZLIB_LIBS) \ + $(OPENSSL_LIBS) $(ZLIB_LIBS) $(SODIUM_LIBS) \ -Wl,--no-as-needed # Help generation diff --git a/src/apk.c b/src/apk.c index 2c5fddf..f998583 100644 --- a/src/apk.c +++ b/src/apk.c @@ -441,7 +441,11 @@ int main(int argc, char **argv) ctx.force |= applet->forced_force; } - apk_crypto_init(); + if (apk_crypto_init() != 0) { + apk_err(out, "failure to initialize"); + return 1; + } + setup_automatic_flags(&ctx); fetchConnectionCacheInit(32, 4); diff --git a/src/apk.pc.in b/src/apk.pc.in index d9b05cb..d21e23b 100644 --- a/src/apk.pc.in +++ b/src/apk.pc.in @@ -5,6 +5,6 @@ includedir=@INCLUDE_DIR@ Name: apk Description: Alpine Package Manager Version: @VERSION@ -Requires: zlib openssl -Libs: -L${libdir} -lapk +Requires: zlib openssl sodium +Libs: -L${libdir} -lapk -lsodium Cflags: -I${includedir} diff --git a/src/apk_crypto.h b/src/apk_crypto.h index 18bf3b5..219817c 100644 --- a/src/apk_crypto.h +++ b/src/apk_crypto.h @@ -10,26 +10,39 @@ #define APK_CRYPTO_H #include -#include #include +#include + +#include "apk_blob.h" #include "apk_defines.h" #include "apk_openssl.h" // Digest struct apk_digest_ctx { - EVP_MD_CTX *mdctx; uint8_t alg; + void *impl; + EVP_MD_CTX *mdctx; }; -#define APK_DIGEST_NONE 0x00 -#define APK_DIGEST_MD5 0x01 -#define APK_DIGEST_SHA1 0x02 -#define APK_DIGEST_SHA256 0x03 -#define APK_DIGEST_SHA512 0x04 -#define APK_DIGEST_SHA256_160 0x05 +#define APK_DIGEST_NONE 0x00 +#define APK_DIGEST_MD5 0x01 +#define APK_DIGEST_SHA1 0x02 +#define APK_DIGEST_SHA256 0x03 +#define APK_DIGEST_SHA512 0x04 +#define APK_DIGEST_SHA256_160 0x05 -#define APK_DIGEST_MAX_LENGTH 64 // longest is SHA512 +#define APK_DIGEST_MAX_LENGTH 64 // longest is SHA512 + +#define APK_PKEY_ED25519 0x00 +#define APK_PKEY_RSAPKCS1v15 0x01 + +#define APK_PKEY_TYPE_PUBLIC 0x00 +#define APK_PKEY_TYPE_SECRET 0x01 + +// includes '\0' +#define APK_PKEY_CUTE_PUBLIC_SIZE 69 +#define APK_PKEY_CUTE_SECRET_SIZE 113 const char *apk_digest_alg_str(uint8_t); uint8_t apk_digest_alg_from_csum(int); @@ -39,16 +52,22 @@ struct apk_digest { uint8_t data[APK_DIGEST_MAX_LENGTH]; }; -#define APK_DIGEST_BLOB(d) APK_BLOB_PTR_LEN((void*)((d).data), (d).len) +#define APK_DIGEST_BLOB(d) APK_BLOB_PTR_LEN((void *) ((d).data), (d).len) -static inline const EVP_MD *apk_digest_alg_to_evp(uint8_t alg) { +static inline const EVP_MD *apk_digest_alg_to_evp(uint8_t alg) +{ switch (alg) { - case APK_DIGEST_NONE: return EVP_md_null(); - case APK_DIGEST_MD5: return EVP_md5(); - case APK_DIGEST_SHA1: return EVP_sha1(); + case APK_DIGEST_NONE: + return EVP_md_null(); + case APK_DIGEST_MD5: + return EVP_md5(); + case APK_DIGEST_SHA1: + return EVP_sha1(); case APK_DIGEST_SHA256_160: - case APK_DIGEST_SHA256: return EVP_sha256(); - case APK_DIGEST_SHA512: return EVP_sha512(); + case APK_DIGEST_SHA256: + return EVP_sha256(); + case APK_DIGEST_SHA512: + return EVP_sha512(); default: assert(alg); return EVP_md_null(); @@ -58,21 +77,27 @@ static inline const EVP_MD *apk_digest_alg_to_evp(uint8_t alg) { int apk_digest_alg_len(uint8_t alg); uint8_t apk_digest_alg_by_len(int len); -static inline int apk_digest_cmp(struct apk_digest *a, struct apk_digest *b) { - if (a->alg != b->alg) return b->alg - a->alg; +static inline int apk_digest_cmp(struct apk_digest *a, struct apk_digest *b) +{ + if (a->alg != b->alg) + return b->alg - a->alg; return memcmp(a->data, b->data, a->len); } -static inline void apk_digest_reset(struct apk_digest *d) { +static inline void apk_digest_reset(struct apk_digest *d) +{ d->alg = APK_DIGEST_NONE; d->len = 0; } -static inline void apk_digest_set(struct apk_digest *d, uint8_t alg) { +static inline void apk_digest_set(struct apk_digest *d, uint8_t alg) +{ d->alg = alg; d->len = apk_digest_alg_len(alg); } +int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void *ptr, size_t sz); +/* static inline int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void *ptr, size_t sz) { unsigned int md_sz = sizeof d->data; @@ -82,45 +107,14 @@ static inline int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void d->len = apk_digest_alg_len(alg); return 0; } +*/ -static inline int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg) { - dctx->alg = alg; - dctx->mdctx = EVP_MD_CTX_new(); - if (!dctx->mdctx) return -ENOMEM; -#ifdef EVP_MD_CTX_FLAG_FINALISE - EVP_MD_CTX_set_flags(dctx->mdctx, EVP_MD_CTX_FLAG_FINALISE); -#endif - if (alg != APK_DIGEST_NONE) EVP_DigestInit_ex(dctx->mdctx, apk_digest_alg_to_evp(alg), 0); - return 0; -} +int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg); +void apk_digest_ctx_reset(struct apk_digest_ctx *dctx, uint8_t alg); +void apk_digest_ctx_free(struct apk_digest_ctx *dctx); +int apk_digest_ctx_update(struct apk_digest_ctx *dctx, const void *ptr, size_t sz); +int apk_digest_ctx_final(struct apk_digest_ctx *dctx, struct apk_digest *d); -static inline void apk_digest_ctx_reset(struct apk_digest_ctx *dctx, uint8_t alg) -{ - dctx->alg = alg; - EVP_DigestInit_ex(dctx->mdctx, apk_digest_alg_to_evp(alg), 0); -} - -static inline void apk_digest_ctx_free(struct apk_digest_ctx *dctx) { - EVP_MD_CTX_free(dctx->mdctx); - dctx->mdctx = 0; -} - -static inline int apk_digest_ctx_update(struct apk_digest_ctx *dctx, const void *ptr, size_t sz) { - return EVP_DigestUpdate(dctx->mdctx, ptr, sz) == 1 ? 0 : -APKE_CRYPTO_ERROR; -} - -static inline int apk_digest_ctx_final(struct apk_digest_ctx *dctx, struct apk_digest *d) { - unsigned int mdlen = sizeof d->data; - if (EVP_DigestFinal_ex(dctx->mdctx, d->data, &mdlen) != 1) { - apk_digest_reset(d); - return -APKE_CRYPTO_ERROR; - } - d->alg = dctx->alg; - d->len = apk_digest_alg_len(d->alg); - return 0; -} - -#include "apk_blob.h" uint8_t apk_digest_from_blob(struct apk_digest *d, apk_blob_t b); static inline int apk_digest_cmp_csum(const struct apk_digest *d, const struct apk_checksum *csum) { @@ -139,13 +133,14 @@ static inline void apk_checksum_from_digest(struct apk_checksum *csum, const str // Asymmetric keys struct apk_pkey { - uint8_t id[16]; - EVP_PKEY *key; + uint8_t type; + uint8_t alg; + uint8_t id[16]; + void *impl; }; -int apk_pkey_init(struct apk_pkey *pkey, EVP_PKEY *key); -void apk_pkey_free(struct apk_pkey *pkey); int apk_pkey_load(struct apk_pkey *pkey, int dirfd, const char *fn); +void apk_pkey_free(struct apk_pkey *pkey); // Signing @@ -156,31 +151,6 @@ int apk_verify(struct apk_digest_ctx *, void *, size_t); // Initializiation -#if OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - -static inline void apk_crypto_cleanup(void) -{ - EVP_cleanup(); -#ifndef OPENSSL_NO_ENGINE - ENGINE_cleanup(); -#endif - CRYPTO_cleanup_all_ex_data(); -} - -static inline void apk_crypto_init(void) -{ - atexit(apk_crypto_cleanup); - OpenSSL_add_all_algorithms(); -#ifndef OPENSSL_NO_ENGINE - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); -#endif -} - -#else - -static inline void apk_crypto_init(void) {} - -#endif +int apk_crypto_init(void); #endif diff --git a/src/crypto_core.c b/src/crypto_core.c new file mode 100644 index 0000000..a4fbd9d --- /dev/null +++ b/src/crypto_core.c @@ -0,0 +1,38 @@ +#include +#include + +#include "apk_crypto.h" +#include "apk_defines.h" + +#if OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) +static void apk_crypto_cleanup(void) +{ + EVP_cleanup(); +#ifndef OPENSSL_NO_ENGINE + ENGINE_cleanup(); +#endif + CRYPTO_cleanup_all_ex_data(); + +} +#endif + +int apk_crypto_init(void) +{ + if (sodium_init() < 0) { + return -APKE_CRYPTO_ERROR; + } + +#if OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) + atexit(apk_crypto_cleanup); + OpenSSL_add_all_algorithms(); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); +#endif + + +#endif + + return 0; +} diff --git a/src/crypto_digest.c b/src/crypto_digest.c new file mode 100644 index 0000000..ff26de2 --- /dev/null +++ b/src/crypto_digest.c @@ -0,0 +1,209 @@ +#include + +#include "apk_crypto.h" + +/* +static inline int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg) { + dctx->alg = alg; + dctx->mdctx = EVP_MD_CTX_new(); + if (!dctx->mdctx) return -ENOMEM; +#ifdef EVP_MD_CTX_FLAG_FINALISE + EVP_MD_CTX_set_flags(dctx->mdctx, EVP_MD_CTX_FLAG_FINALISE); +#endif + if (alg != APK_DIGEST_NONE) EVP_DigestInit_ex(dctx->mdctx, apk_digest_alg_to_evp(alg), 0); + return 0; +} +*/ + +union digest_state { + crypto_hash_sha256_state sha256; + crypto_hash_sha512_state sha512; + EVP_MD_CTX *mdctx; +}; + +static const char *apk_digest_str[] = { + [APK_DIGEST_NONE] = "none", + [APK_DIGEST_MD5] = "md5", + [APK_DIGEST_SHA1] = "sha1", + [APK_DIGEST_SHA256_160] = "sha256-160", + [APK_DIGEST_SHA256] = "sha256", + [APK_DIGEST_SHA512] = "sha512", +}; + +const char *apk_digest_alg_str(uint8_t alg) +{ + const char *alg_str = "unknown"; + if (alg < ARRAY_SIZE(apk_digest_str)) + alg_str = apk_digest_str[alg]; + return alg_str; +} + +int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void *ptr, size_t sz) +{ + switch (alg) { + case APK_DIGEST_SHA256: + case APK_DIGEST_SHA256_160: + crypto_hash_sha256(d->data, ptr, sz); + break; + case APK_DIGEST_SHA512: + crypto_hash_sha512(d->data, ptr, sz); + break; + case APK_DIGEST_NONE: + break; + case APK_DIGEST_MD5: + break; + case APK_DIGEST_SHA1: + break; + default: + return -APKE_CRYPTO_NOT_SUPPORTED; + } + + d->alg = alg; + + return 0; +} + +int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg) +{ + union digest_state *state = NULL; + const EVP_MD *evp_md = NULL; + + dctx->impl = malloc(sizeof(union digest_state)); + if (dctx->impl == NULL) { + return -ENOMEM; + } + + state = (union digest_state *) dctx->impl; + + dctx->alg = alg; + switch (alg) { + case APK_DIGEST_SHA256: + case APK_DIGEST_SHA256_160: + crypto_hash_sha256_init(&state->sha256); + break; + case APK_DIGEST_SHA512: + crypto_hash_sha512_init(&state->sha512); + break; + case APK_DIGEST_NONE: + evp_md = EVP_md_null(); + case APK_DIGEST_MD5: + evp_md = EVP_md5(); + break; + case APK_DIGEST_SHA1: + evp_md = EVP_sha1(); + break; + default: + free(dctx->impl); + return -APKE_CRYPTO_NOT_SUPPORTED; + } + + if (evp_md != NULL) { + state->mdctx = EVP_MD_CTX_new(); + if (state->mdctx == NULL) { + goto a; + } + +#ifdef EVP_MD_CTX_FLAG_FINALISE + EVP_MD_CTX_set_flags(dctx->mdctx, EVP_MD_CTX_FLAG_FINALISE); +#endif + + EVP_DigestInit_ex(dctx->mdctx, apk_digest_alg_to_evp(alg), 0); + } + + return 0; + +a: + free(dctx->impl); + return -APKE_CRYPTO_ERROR; +} + +void apk_digest_ctx_reset(struct apk_digest_ctx *dctx, uint8_t alg) +{ + apk_digest_ctx_free(dctx); + apk_digest_ctx_init(dctx, alg); +} + +void apk_digest_ctx_free(struct apk_digest_ctx *dctx) +{ + union digest_state *state = (union digest_state *) dctx->impl; + + if (dctx->impl == NULL) { + return; + } + + switch (dctx->alg) { + case APK_DIGEST_NONE: + case APK_DIGEST_MD5: + case APK_DIGEST_SHA1: + EVP_MD_CTX_free(state->mdctx); + case APK_DIGEST_SHA256: + case APK_DIGEST_SHA512: + case APK_DIGEST_SHA256_160: + break; + default: + /* illegal state, don't touch impl? */ + return; + } + + free(dctx->impl); + + dctx->impl = NULL; +} + +int apk_digest_ctx_update(struct apk_digest_ctx *dctx, const void *ptr, size_t sz) +{ + union digest_state *state = (union digest_state *) dctx->impl; + + switch (dctx->alg) { + case APK_DIGEST_SHA256: + case APK_DIGEST_SHA256_160: + crypto_hash_sha256_update(&state->sha256, ptr, sz); + break; + case APK_DIGEST_SHA512: + crypto_hash_sha512_update(&state->sha512, ptr, sz); + break; + case APK_DIGEST_NONE: + case APK_DIGEST_MD5: + case APK_DIGEST_SHA1: + if (EVP_DigestUpdate(state->mdctx, ptr, sz) != 1) { + return -APKE_CRYPTO_ERROR; + } + break; + default: + return -APKE_CRYPTO_NOT_SUPPORTED; + } + + return 0; +} + +int apk_digest_ctx_final(struct apk_digest_ctx *dctx, struct apk_digest *d) +{ + union digest_state *state = dctx->impl; + unsigned int mdlen; + + switch (dctx->alg) { + case APK_DIGEST_SHA256: + case APK_DIGEST_SHA256_160: + crypto_hash_sha256_final(&state->sha256, d->data); + break; + case APK_DIGEST_SHA512: + crypto_hash_sha512_final(&state->sha512, d->data); + break; + case APK_DIGEST_NONE: + case APK_DIGEST_MD5: + case APK_DIGEST_SHA1: + mdlen = sizeof d->data; + if (EVP_DigestFinal_ex(state->mdctx, d->data, &mdlen) != 1) { + apk_digest_reset(d); + return -APKE_CRYPTO_ERROR; + } + break; + default: + return -APKE_CRYPTO_NOT_SUPPORTED; + } + + d->alg = dctx->alg; + d->len = apk_digest_alg_len(d->alg); + + return 0; +} diff --git a/src/crypto_openssl.c b/src/crypto_openssl.c index a9eda6f..b0915cf 100644 --- a/src/crypto_openssl.c +++ b/src/crypto_openssl.c @@ -7,23 +7,6 @@ #include "apk_crypto.h" -static const char *apk_digest_str[] = { - [APK_DIGEST_NONE] = "none", - [APK_DIGEST_MD5] = "md5", - [APK_DIGEST_SHA1] = "sha1", - [APK_DIGEST_SHA256_160] = "sha256-160", - [APK_DIGEST_SHA256] = "sha256", - [APK_DIGEST_SHA512] = "sha512", -}; - -const char *apk_digest_alg_str(uint8_t alg) -{ - const char *alg_str = "unknown"; - if (alg < ARRAY_SIZE(apk_digest_str)) - alg_str = apk_digest_str[alg]; - return alg_str; -} - int apk_digest_alg_len(uint8_t alg) { switch (alg) { diff --git a/src/crypto_sign.c b/src/crypto_sign.c new file mode 100644 index 0000000..1041cf0 --- /dev/null +++ b/src/crypto_sign.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/src/meson.build b/src/meson.build index 24362d7..24ed5fd 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,6 +12,8 @@ libapk_src = [ 'commit.c', 'common.c', 'context.c', + 'crypto_core.c', + 'crypto_digest.c', 'crypto_openssl.c', 'database.c', 'extract_v2.c',