diff --git a/src/crypto_public.c b/src/crypto_public.c index ba519f1..7a59da0 100644 --- a/src/crypto_public.c +++ b/src/crypto_public.c @@ -13,30 +13,6 @@ /* includes '\0', undef in the end */ #define APK_CUTE_PUBLIC_SIZE 69 -union public_key_state { - unsigned char cute[crypto_sign_ed25519_PUBLICKEYBYTES]; - EVP_PKEY *pkey; -}; - -struct public_key_ops { - int (*load)(struct apk_public_key *pub, int fd); - int (*verify)(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len); - void (*free)(union public_key_state *state); -}; - -static int public_key_load_v2(struct apk_public_key *pub, int fd); -static int verify_rsa_pkcs1v15(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len); -static void public_key_free_v2(union public_key_state *state); - -static int public_key_load_cute(struct apk_public_key *pub, int fd); -static int verify_cute(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len); -static void public_key_free_cute(union public_key_state *state); - -static const struct public_key_ops ops[] = { - [APK_KEY_VERSION_V2] = {.load = public_key_load_v2, .verify = verify_rsa_pkcs1v15, .free = public_key_free_v2}, - [APK_KEY_VERSION_CUTE] = {.load = public_key_load_cute, .verify = verify_cute, .free = public_key_free_cute}, -}; - /* * The format is as follows: * uint8[ 2] header = {'q', 't'} @@ -45,8 +21,6 @@ static const struct public_key_ops ops[] = { */ static int public_key_load_cute(struct apk_public_key *pub, int fd) { - union public_key_state *state = (union public_key_state *) pub->impl; - char b64[APK_CUTE_PUBLIC_SIZE]; uint8_t raw[50]; size_t len; @@ -68,8 +42,14 @@ static int public_key_load_cute(struct apk_public_key *pub, int fd) return -APKE_CRYPTO_KEY_FORMAT; } + pub->impl = malloc(crypto_sign_ed25519_PUBLICKEYBYTES); + if (pub->impl == NULL) { + return -ENOMEM; + } + + pub->version = APK_KEY_VERSION_CUTE; memcpy(pub->id, raw + 2, sizeof pub->id); - memcpy(state->cute, raw + 18, crypto_sign_ed25519_PUBLICKEYBYTES); + memcpy(pub->impl, raw + 18, crypto_sign_ed25519_PUBLICKEYBYTES); return 0; } @@ -82,8 +62,6 @@ static int public_key_load_cute(struct apk_public_key *pub, int fd) */ static int verify_cute(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len) { - union public_key_state *state = (union public_key_state *) pub->impl; - unsigned char *sigdata = (unsigned char *) sig; struct apk_digest digest; @@ -107,24 +85,23 @@ static int verify_cute(struct apk_public_key *pub, struct apk_digest_ctx *dctx, return -APKE_SIGNATURE_INVALID; } - if (crypto_sign_ed25519_verify_detached(sigdata + 18, digest.data, digest.len, state->cute) != 0) { + if (crypto_sign_ed25519_verify_detached(sigdata + 18, digest.data, digest.len, pub->impl) != 0) { return -APKE_SIGNATURE_INVALID; } return 0; } -static void public_key_free_cute(union public_key_state *state) +static void public_key_free_cute(struct apk_public_key *pub) { - return; + free(pub->impl); } static int public_key_load_v2(struct apk_public_key *pub, int fd) { - union public_key_state *state = (union public_key_state *) pub->impl; - unsigned char *raw = NULL; struct apk_digest digest; + EVP_PKEY *pkey; BIO *bio; int len; int r = -APKE_CRYPTO_KEY_FORMAT; @@ -135,23 +112,18 @@ static int public_key_load_v2(struct apk_public_key *pub, int fd) goto err_bio_new; } - state->pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); - if (state->pkey == NULL) { + pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (pkey == NULL) { + r = -APKE_CRYPTO_KEY_FORMAT; + goto err_pem_load; + } + + if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) { r = -APKE_CRYPTO_KEY_FORMAT; goto err_load_and_check_type; } - if (state->pkey == NULL) { - r = -APKE_CRYPTO_KEY_FORMAT; - goto err_load_and_check_type; - } - - if (EVP_PKEY_id(state->pkey) != EVP_PKEY_RSA) { - r = -APKE_CRYPTO_KEY_FORMAT; - goto err_load_and_check_type; - } - - len = i2d_PublicKey(state->pkey, &raw); + len = i2d_PublicKey(pkey, &raw); if (len < 0) { r = -APKE_CRYPTO_ERROR; goto err_load_and_check_type; @@ -159,16 +131,25 @@ static int public_key_load_v2(struct apk_public_key *pub, int fd) if (apk_digest_calc(&digest, APK_DIGEST_SHA512, raw, len) != 0) { r = -APKE_CRYPTO_ERROR; - goto err_calculate_id; + goto err_calculate_id_and_finalize; } + pub->impl = pkey; + if (EVP_PKEY_up_ref(pkey) != 1) { + r = -APKE_CRYPTO_ERROR; + goto err_calculate_id_and_finalize; + } + + pub->version = APK_KEY_VERSION_V2; memcpy(pub->id, digest.data, sizeof pub->id); r = 0; -err_calculate_id: +err_calculate_id_and_finalize: OPENSSL_free(raw); err_load_and_check_type: + EVP_PKEY_free(pkey); +err_pem_load: BIO_free(bio); err_bio_new: return r; @@ -179,10 +160,8 @@ err_bio_new: * Since APK v2 hasn't switched from SHA-1 yet, we still have to work with it for now. * However, MD5 is out of the question. */ -static int verify_rsa_pkcs1v15(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len) +static int verify_v2(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len) { - union public_key_state *state = (union public_key_state *) pub->impl; - struct apk_digest digest; EVP_PKEY_CTX *pctx; const EVP_MD *md; @@ -210,7 +189,7 @@ static int verify_rsa_pkcs1v15(struct apk_public_key *pub, struct apk_digest_ctx goto err_digest_final_and_pctx_new; } - pctx = EVP_PKEY_CTX_new(state->pkey, NULL); + pctx = EVP_PKEY_CTX_new(pub->impl, NULL); if (pctx == NULL) { r = -APKE_SIGNATURE_INVALID; goto err_pctx_setup_and_verify; @@ -244,9 +223,9 @@ err_digest_final_and_pctx_new: return r; } -static void public_key_free_v2(union public_key_state *state) +static void public_key_free_v2(struct apk_public_key *pub) { - EVP_PKEY_free(state->pkey); + EVP_PKEY_free(pub->impl); } int apk_public_key_load(struct apk_public_key *pub, int dirfd, const char *fn) @@ -255,12 +234,6 @@ int apk_public_key_load(struct apk_public_key *pub, int dirfd, const char *fn) int fd = -1; int r = -APKE_CRYPTO_KEY_FORMAT; - pub->impl = malloc(sizeof(union public_key_state)); - if (pub->impl == NULL) { - r = -ENOMEM; - goto err_alloc; - } - fd = openat(dirfd, fn, O_RDONLY | O_CLOEXEC); if (fd == -1) { r = -errno; @@ -269,30 +242,19 @@ int apk_public_key_load(struct apk_public_key *pub, int dirfd, const char *fn) if (fstat(fd, &st) != 0) { r = -errno; - goto err_fstat_and_load; + goto err_fstat; } // guess if (st.st_size == APK_CUTE_PUBLIC_SIZE) { - pub->version = APK_KEY_VERSION_CUTE; + r = public_key_load_cute(pub, fd); } else { - pub->version = APK_KEY_VERSION_V2; + r = public_key_load_v2(pub, fd); } - r = ops[pub->version].load(pub, fd); - if (r != 0) { - goto err_fstat_and_load; - } - - close(fd); - - return 0; - -err_fstat_and_load: +err_fstat: close(fd); err_openat: - free(pub->impl); -err_alloc: return r; } @@ -302,13 +264,21 @@ void apk_public_key_free(struct apk_public_key *pub) return; } - if (pub->impl == NULL || pub->version >= APK_KEY_VERSION_MAX) { + if (pub->impl == NULL) { return; } - ops[pub->version].free(pub->impl); + switch (pub->version) { + case APK_KEY_VERSION_V2: + public_key_free_v2(pub); + break; + case APK_KEY_VERSION_CUTE: + public_key_free_cute(pub); + break; + default: + return; + } - free(pub->impl); pub->impl = NULL; } @@ -347,11 +317,14 @@ int apk_verify_digest_start(struct apk_digest_ctx *dctx, uint16_t signature_type int apk_verify(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len) { - if (pub->version >= APK_KEY_VERSION_MAX) { + switch (pub->version) { + case APK_KEY_VERSION_V2: + return verify_v2(pub, dctx, sig, len); + case APK_KEY_VERSION_CUTE: + return verify_cute(pub, dctx, sig, len); + default: return -APKE_CRYPTO_NOT_SUPPORTED; } - - return ops[pub->version].verify(pub, dctx, sig, len); } #undef APK_CUTE_PUBLIC_SIZE diff --git a/src/crypto_secret.c b/src/crypto_secret.c index f5771a3..869b950 100644 --- a/src/crypto_secret.c +++ b/src/crypto_secret.c @@ -13,30 +13,6 @@ /* includes '\0', undef in the end */ #define APK_CUTE_SECRET_SIZE 113 -union secret_key_state { - unsigned char cute[crypto_sign_ed25519_SECRETKEYBYTES]; - EVP_PKEY *pkey; -}; - -struct secret_key_ops { - int (*load)(struct apk_secret_key *pub, int fd); - int (*sign)(struct apk_secret_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t *len); - void (*free)(union secret_key_state *state); -}; - -static int secret_key_load_v2(struct apk_secret_key *pub, int fd); -static int sign_rsa_pkcs1v15(struct apk_secret_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t *len); -static void secret_key_free_v2(union secret_key_state *state); - -static int secret_key_load_cute(struct apk_secret_key *pub, int fd); -static int sign_cute(struct apk_secret_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t *len); -static void secret_key_free_cute(union secret_key_state *state); - -static struct secret_key_ops ops[] = { - [APK_KEY_VERSION_CUTE] = {.load = secret_key_load_cute, .sign = sign_cute, .free = secret_key_free_cute}, - [APK_KEY_VERSION_V2] = {.load = secret_key_load_v2, .sign = sign_rsa_pkcs1v15, .free = secret_key_free_v2}, -}; - /* * The format is as follows: * uint8[ 2] header = {'q', 't'} @@ -46,8 +22,6 @@ static struct secret_key_ops ops[] = { */ static int secret_key_load_cute(struct apk_secret_key *sec, int fd) { - union secret_key_state *state = (union secret_key_state *) sec->impl; - char b64[APK_CUTE_SECRET_SIZE]; uint8_t raw[82]; size_t len; @@ -71,7 +45,7 @@ static int secret_key_load_cute(struct apk_secret_key *sec, int fd) sec->version = APK_KEY_VERSION_V2; memcpy(sec->id, raw + 2, 16); - memcpy(state->cute, raw + 18, crypto_sign_ed25519_SECRETKEYBYTES); + memcpy(sec->impl, raw + 18, crypto_sign_ed25519_SECRETKEYBYTES); r = 0; @@ -81,15 +55,14 @@ err: return r; } -static void secret_key_free_cute(union secret_key_state *state) +static void secret_key_free_cute(struct apk_secret_key *sec) { - sodium_memzero(state->cute, crypto_sign_ed25519_SECRETKEYBYTES); + sodium_memzero(sec->impl, crypto_sign_ed25519_SECRETKEYBYTES); + sodium_free(sec->impl); } static int sign_cute(struct apk_secret_key *sec, struct apk_digest_ctx *dctx, void *sig, size_t *len) { - union secret_key_state *state = (union secret_key_state *) sec->impl; - unsigned char *sigdata = (unsigned char *) sig; struct apk_digest digest; @@ -108,7 +81,7 @@ static int sign_cute(struct apk_secret_key *sec, struct apk_digest_ctx *dctx, vo sigdata[0] = 'q'; sigdata[1] = 't'; memcpy(sigdata + 2, sec->id, 16); - crypto_sign_ed25519_detached(sigdata + 18, NULL, digest.data, digest.len, state->cute); + crypto_sign_ed25519_detached(sigdata + 18, NULL, digest.data, digest.len, sec->impl); *len = 82; return 0; @@ -116,10 +89,9 @@ static int sign_cute(struct apk_secret_key *sec, struct apk_digest_ctx *dctx, vo static int secret_key_load_v2(struct apk_secret_key *sec, int fd) { - union secret_key_state *state = (union secret_key_state *) sec->impl; - - struct apk_digest digest; unsigned char *raw = NULL; + struct apk_digest digest; + EVP_PKEY *pkey; BIO *bio; int len; int r = -APKE_CRYPTO_KEY_FORMAT; @@ -130,18 +102,18 @@ static int secret_key_load_v2(struct apk_secret_key *sec, int fd) goto err_bio_new; } - state->pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - if (state->pkey == NULL) { + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (pkey == NULL) { + r = -APKE_CRYPTO_KEY_FORMAT; + goto err_pem_read; + } + + if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) { r = -APKE_CRYPTO_KEY_FORMAT; goto err_load_and_check_type; } - if (EVP_PKEY_id(state->pkey) != EVP_PKEY_RSA) { - r = -APKE_CRYPTO_KEY_FORMAT; - goto err_load_and_check_type; - } - - len = i2d_PublicKey(state->pkey, &raw); + len = i2d_PublicKey(pkey, &raw); if (len < 0) { r = -APKE_CRYPTO_ERROR; goto err_load_and_check_type; @@ -149,25 +121,32 @@ static int secret_key_load_v2(struct apk_secret_key *sec, int fd) if (apk_digest_calc(&digest, APK_DIGEST_SHA512, raw, len) != 0) { r = -APKE_CRYPTO_ERROR; - goto err_digest; + goto err_calculate_id_and_finalize; } + sec->impl = pkey; + if (EVP_PKEY_up_ref(pkey) != 1) { + r = -APKE_CRYPTO_ERROR; + goto err_calculate_id_and_finalize; + } + + sec->version = APK_KEY_VERSION_V2; memcpy(sec->id, digest.data, sizeof sec->id); r = 0; -err_digest: +err_calculate_id_and_finalize: OPENSSL_free(raw); err_load_and_check_type: + EVP_PKEY_free(pkey); +err_pem_read: BIO_free(bio); err_bio_new: return r; } -static int sign_rsa_pkcs1v15(struct apk_secret_key *sec, struct apk_digest_ctx *dctx, void *sig, size_t *len) +static int sign_v2(struct apk_secret_key *sec, struct apk_digest_ctx *dctx, void *sig, size_t *len) { - union secret_key_state *state = (union secret_key_state *) sec->impl; - struct apk_digest digest; EVP_PKEY_CTX *pctx; const EVP_MD *md; @@ -196,7 +175,7 @@ static int sign_rsa_pkcs1v15(struct apk_secret_key *sec, struct apk_digest_ctx * goto err_digest_final_and_pctx_new; } - pctx = EVP_PKEY_CTX_new(state->pkey, NULL); + pctx = EVP_PKEY_CTX_new(sec->impl, NULL); if (pctx == NULL) { r = -APKE_SIGNATURE_FAIL; goto err_digest_final_and_pctx_new; @@ -241,22 +220,16 @@ err_digest_final_and_pctx_new: return r; } -static void secret_key_free_v2(union secret_key_state *state) +static void secret_key_free_v2(struct apk_secret_key *sec) { - EVP_PKEY_free(state->pkey); + EVP_PKEY_free(sec->impl); + sec->impl = NULL; } int apk_secret_key_load(struct apk_secret_key *sec, int dirfd, const char *fn) { struct stat st; - int fd = -1; - int r = -APKE_CRYPTO_KEY_FORMAT; - - sec->impl = malloc(sizeof(union secret_key_state)); - if (sec->impl == NULL) { - r = -ENOMEM; - goto err_alloc; - } + int fd, r = -APKE_CRYPTO_KEY_FORMAT; fd = openat(dirfd, fn, O_RDONLY | O_CLOEXEC); if (fd == -1) { @@ -270,26 +243,14 @@ int apk_secret_key_load(struct apk_secret_key *sec, int dirfd, const char *fn) } if (st.st_size == APK_CUTE_SECRET_SIZE) { - sec->version = APK_KEY_VERSION_CUTE; + r = secret_key_load_cute(sec, fd); } else { - sec->version = APK_KEY_VERSION_V2; + r = secret_key_load_v2(sec, fd); } - r = ops[sec->version].load(sec, fd); - if (r != 0) { - goto err_load; - } - - close(fd); - - return 0; - -err_load: err_fstat: close(fd); err_openat: - free(sec->impl); -err_alloc: return r; } @@ -299,13 +260,21 @@ void apk_secret_key_free(struct apk_secret_key *sec) return; } - if (sec->impl == NULL || sec->version >= APK_KEY_VERSION_MAX) { + if (sec->impl == NULL) { return; } - ops[sec->version].free(sec->impl); + switch (sec->version) { + case APK_KEY_VERSION_V2: + secret_key_free_v2(sec); + break; + case APK_KEY_VERSION_CUTE: + secret_key_free_cute(sec); + break; + default: + return; + } - free(sec->impl); sec->impl = NULL; } @@ -344,11 +313,14 @@ int apk_sign_digest_start(struct apk_digest_ctx *dctx, uint16_t signature_type) int apk_sign(struct apk_secret_key *sec, struct apk_digest_ctx *dctx, void *sig, size_t *len) { - if (sec->version >= APK_KEY_VERSION_MAX) { + switch (sec->version) { + case APK_KEY_VERSION_V2: + return sign_v2(sec, dctx, sig, len); + case APK_KEY_VERSION_CUTE: + return sign_cute(sec, dctx, sig, len); + default: return -APKE_CRYPTO_NOT_SUPPORTED; } - - return ops[sec->version].sign(sec, dctx, sig, len); } #undef APK_CUTE_SECRET_SIZE