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',