Compare commits

...

11 Commits

Author SHA1 Message Date
Aydin Mercan 962eed50db
crypto/signature: remove domain seperators for now 2022-08-24 10:16:01 +03:00
Aydin Mercan b4089b97b1
crypto/signature: remove tables
State unions and operation lists aren't really useful here.
For example, if someone wanted to have cute-only signatures, we would
need to have stubs that return unsupported only.
2022-08-24 10:15:59 +03:00
Aydin Mercan 0d59807471
extract/v2: simply finding the signature type 2022-08-24 10:15:58 +03:00
Aydin Mercan 1c54a3fbb4
trust: add draft seperate public/secret loading
It isn't clear where secret keys will be located at but this should at
least allow for cleaner seperation in lists.
2022-08-24 10:15:56 +03:00
Aydin Mercan 5b020ec9ef
crypto/signature: introduce domain seperation
It might seem a bit like unnecessary bikeshedding but it shouldn't hurt
anyone.
2022-08-24 10:15:54 +03:00
Aydin Mercan dea8ded23e
crypto/digest: simply state in oneshot calculation 2022-08-24 10:15:53 +03:00
Aydin Mercan 86da6dc599
apk: better messaging when crypto init fails 2022-08-24 10:15:46 +03:00
Aydin Mercan 0b7d6dfbf2
crypto: start seperating public/private key usage
Digests now use bearssl + libsodium instead of openssl + libsodium.
It fits better with the API looking more similar and I don't think it
will be that much of a bottleneck.

Instead of a apk_pkey that mimicks the EVP_PKEY semantics, have seperate
public and private key structures. However, apk is broken because of it
and needs fixing. The rest of the code might compile but won't work
as I haven't handled the cases where pkey corressponds to public/private
keys in codebase properly. Also, DSA signatures are removed.

Public and private keys impls' now use a static array of vtables
internally. The indicies correspond to the signature scheme version and
checking `< APK_*_MAX` should be enough? I tried to make so that higher
values correspond to more desirable constructs, this might come in handy.

Signing/verifying start is free from keys as it isn't used though it
might be brought back for domain seperated hashes, ability to get
timestamps involved with epheremal keys in the future etc.

`apk_crypto.h` is free from openssl includes although some headers still
use them for now.
2022-08-24 10:15:14 +03:00
Aydin Mercan 2727846361
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
2022-08-24 10:13:22 +03:00
Timo Teräs c21f61ddd8 db: fix change detection for symlinks
apk_fileinfo_get() special cases symlink digest calculation.
Convert apk_fsdir_ops.file_digest to .file_info to fix symlink
change detection.

fixes #10853
2022-08-17 21:13:40 +03:00
Felix Yan 1ababaa99d Correct a typo in Make.rules 2022-08-15 13:04:45 +00:00
21 changed files with 1292 additions and 458 deletions

View File

@ -127,7 +127,7 @@ endif
PHONY += all compile install clean docs FORCE
# Convinient variables
# Convenient variables
comma := ,
squote := '
empty :=

View File

@ -17,11 +17,15 @@ scdoc_dep = dependency('scdoc', version: '>=1.10', required: get_option('docs'))
shared_deps = [
dependency('zlib'),
dependency('openssl'),
dependency('libsodium'),
dependency('bearssl'),
]
static_deps = [
dependency('openssl', static: true),
dependency('zlib', static: true),
dependency('libsodium', static: true),
dependency('bearssl', static: true),
]
add_project_arguments('-D_GNU_SOURCE', language: 'c')

View File

@ -15,13 +15,16 @@ 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 \
extract_v2.o extract_v3.o fs_fsys.o fs_uvol.o io.o io_gunzip.o io_url.o tar.o \
atom.o blob.o commit.o common.o context.o crypto_core.o crypto_digest.o crypto_public.o crypto_secret.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
libapk.so.$(libapk_soname)-libs := libfetch/libfetch.a
@ -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
@ -136,7 +139,8 @@ install: $(obj)/apk $(libapk_so) $(libapk_a) $(apklua_so)
$(install-libapk_a)
$(install-apklua_so)
$(INSTALLDIR) $(DESTDIR)$(INCLUDEDIR)/apk
$(INSTALL) -m644 src/*.h $(DESTDIR)$(INCLUDEDIR)/apk
$(INSTALL) -m644 src/apk_*.h $(DESTDIR)$(INCLUDEDIR)/apk
$(INSTALL) -m644 src/help.h $(DESTDIR)$(INCLUDEDIR)/apk
$(INSTALLDIR) $(DESTDIR)$(PKGCONFIGDIR)
$(INSTALL) -m644 $(obj)/apk.pc $(DESTDIR)$(PKGCONFIGDIR)

View File

@ -1180,7 +1180,7 @@ int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct a
struct adb_sign_v0 v0;
unsigned char buf[ADB_MAX_SIGNATURE_LEN];
} sig;
struct apk_trust_key *tkey;
struct apk_trust_secret_key *tkey;
apk_blob_t md;
size_t siglen;
int r;
@ -1202,10 +1202,20 @@ int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct a
siglen = sizeof sig.buf - sizeof sig.v0;
if ((r = apk_sign_start(&trust->dctx, &tkey->key)) != 0 ||
(r = adb_digest_v0_signature(&trust->dctx, db->schema, &sig.v0, md)) != 0 ||
(r = apk_sign(&trust->dctx, sig.v0.sig, &siglen)) != 0)
r = apk_sign_digest_start(&trust->dctx, tkey->key.version);
if (r != 0) {
goto err;
}
r = adb_digest_v0_signature(&trust->dctx, db->schema, &sig.v0, md);
if (r != 0) {
goto err;
}
r = apk_sign(&tkey->key, &trust->dctx, sig.v0.sig, &siglen);
if (r != 0) {
goto err;
}
r = adb_c_block(os, ADB_BLOCK_SIG, APK_BLOB_PTR_LEN((char*) &sig, sizeof(sig.v0) + siglen));
if (r < 0) goto err;
@ -1234,10 +1244,17 @@ int adb_trust_verify_signature(struct apk_trust *trust, struct adb *db, struct a
if (memcmp(sig0->id, tkey->key.id, sizeof sig0->id) != 0) continue;
if (adb_digest_adb(vfy, sig->hash_alg, db->adb, &md) != 0) continue;
if (apk_verify_start(&trust->dctx, &tkey->key) != 0 ||
adb_digest_v0_signature(&trust->dctx, db->schema, sig0, md) != 0 ||
apk_verify(&trust->dctx, sig0->sig, sigb.len - sizeof *sig0) != 0)
if (apk_verify_digest_start(&trust->dctx, tkey->key.version) != 0) {
continue;
}
if (adb_digest_v0_signature(&trust->dctx, db->schema, sig0, md) != 0) {
continue;
}
if (apk_verify(&tkey->key, &trust->dctx, sig0->sig, sigb.len - sizeof *sig0) != 0) {
continue;
}
return 0;
}

View File

@ -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 cryptographic functionality");
return 1;
}
setup_automatic_flags(&ctx);
fetchConnectionCacheInit(32, 4);

View File

@ -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}

View File

@ -9,119 +9,81 @@
#ifndef APK_CRYPTO_H
#define APK_CRYPTO_H
#include <assert.h>
#include <string.h>
#include <openssl/evp.h>
#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;
};
#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 0x06
#define APK_DIGEST_MAX_LENGTH 64 // longest is SHA512
#define APK_DIGEST_MAX_LENGTH 64 // longest is SHA512
const char *apk_digest_alg_str(uint8_t);
uint8_t apk_digest_alg_from_csum(int);
#define APK_KEY_VERSION_V2 0x00
#define APK_KEY_VERSION_CUTE 0x01
#define APK_KEY_VERSION_MAX 0x02
#define APK_SIGNATURE_RSA 0x00
#define APK_SIGNATURE_RSA512 0x01
#define APK_SIGNATURE_RSA256 0x02
#define APK_SIGNATURE_CUTE 0x03
#define APK_SIGNATURE_MAX 0x04
const char *apk_digest_alg_str(uint8_t alg);
uint8_t apk_digest_alg_from_csum(int csum);
struct apk_digest {
uint8_t alg, len;
uint8_t alg;
uint8_t len;
uint8_t data[APK_DIGEST_MAX_LENGTH];
};
#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) {
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_SHA256_160:
case APK_DIGEST_SHA256: return EVP_sha256();
case APK_DIGEST_SHA512: return EVP_sha512();
default:
assert(alg);
return EVP_md_null();
}
}
#define APK_DIGEST_BLOB(d) APK_BLOB_PTR_LEN((void *) ((d).data), (d).len)
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);
}
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;
if (EVP_Digest(ptr, sz, d->data, &md_sz, apk_digest_alg_to_evp(alg), 0) != 1)
return -APKE_CRYPTO_ERROR;
d->alg = alg;
d->len = apk_digest_alg_len(alg);
return 0;
}
int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void *ptr, size_t sz);
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);
int 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)
{
return apk_blob_compare(APK_DIGEST_BLOB(*d), APK_BLOB_CSUM(*csum));
@ -138,49 +100,34 @@ 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;
struct apk_public_key {
uint16_t version;
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);
struct apk_secret_key {
uint16_t version;
uint8_t id[16];
void *impl;
};
int apk_public_key_load(struct apk_public_key *pub, int dirfd, const char *fn);
void apk_public_key_free(struct apk_public_key *pub);
int apk_secret_key_load(struct apk_secret_key *sec, int dirfd, const char *fn);
void apk_secret_key_free(struct apk_secret_key *sec);
// Signing
int apk_sign_start(struct apk_digest_ctx *, struct apk_pkey *);
int apk_sign(struct apk_digest_ctx *, void *, size_t *);
int apk_verify_start(struct apk_digest_ctx *, struct apk_pkey *);
int apk_verify(struct apk_digest_ctx *, void *, size_t);
int apk_sign_digest_start(struct apk_digest_ctx *dctx, uint16_t version);
int apk_sign(struct apk_secret_key *sec, struct apk_digest_ctx *dctx, void *sig, size_t *len);
int apk_verify_digest_start(struct apk_digest_ctx *dctx, uint16_t version);
int apk_verify(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len);
// 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

View File

@ -42,7 +42,7 @@ struct apk_fsdir_ops {
int (*file_extract)(struct apk_ctx *, const struct apk_file_info *, struct apk_istream *, apk_progress_cb, void *, unsigned int, apk_blob_t);
int (*file_control)(struct apk_fsdir *, apk_blob_t, int);
int (*file_digest)(struct apk_fsdir *, apk_blob_t, uint8_t alg, struct apk_digest *);
int (*file_info)(struct apk_fsdir *, apk_blob_t, unsigned int, struct apk_file_info *);
};
#define APK_FSEXTRACTF_NO_CHOWN 0x0001
@ -72,8 +72,8 @@ static inline int apk_fsdir_update_perms(struct apk_fsdir *fs, mode_t mode, uid_
static inline int apk_fsdir_file_control(struct apk_fsdir *fs, apk_blob_t filename, int ctrl) {
return fs->ops->file_control(fs, filename, ctrl);
}
static inline int apk_fsdir_file_digest(struct apk_fsdir *fs, apk_blob_t filename, uint8_t alg, struct apk_digest *dgst) {
return fs->ops->file_digest(fs, filename, alg, dgst);
static inline int apk_fsdir_file_info(struct apk_fsdir *fs, apk_blob_t filename, unsigned int flags, struct apk_file_info *fi) {
return fs->ops->file_info(fs, filename, flags, fi);
}
#endif

View File

@ -14,9 +14,14 @@
struct apk_trust_key {
struct list_head key_node;
struct apk_pkey key;
struct apk_public_key key;
char *filename;
};
struct apk_trust_secret_key {
struct list_head key_node;
struct apk_secret_key key;
char *filename;
};
struct apk_trust {
@ -30,6 +35,6 @@ struct apk_trust {
void apk_trust_init(struct apk_trust *trust);
void apk_trust_free(struct apk_trust *trust);
int apk_trust_load_keys(struct apk_trust *trust, int keysfd);
struct apk_pkey *apk_trust_key_by_name(struct apk_trust *trust, const char *filename);
struct apk_public_key *apk_trust_public_key_by_name(struct apk_trust *trust, const char *filename);
#endif

38
src/crypto_core.c Normal file
View File

@ -0,0 +1,38 @@
#include <sodium.h>
#include <openssl/evp.h>
#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;
}

250
src/crypto_digest.c Normal file
View File

@ -0,0 +1,250 @@
#include <bearssl.h>
#include <sodium.h>
#include "apk_crypto.h"
// Union tag is in apk_digest_ctx->alg
union digest_state {
crypto_hash_sha256_state sha256;
crypto_hash_sha512_state sha512;
br_sha1_context sha1;
br_md5_context md5;
};
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) {
case APK_DIGEST_MD5:
return 16;
case APK_DIGEST_SHA1:
return 20;
case APK_DIGEST_SHA256_160:
return 20;
case APK_DIGEST_SHA256:
return 32;
case APK_DIGEST_SHA512:
return 64;
default:
return 0;
}
}
uint8_t apk_digest_alg_by_len(int len)
{
switch (len) {
case 0:
return APK_DIGEST_NONE;
case 16:
return APK_DIGEST_MD5;
case 20:
return APK_DIGEST_SHA1;
case 32:
return APK_DIGEST_SHA256;
case 64:
return APK_DIGEST_SHA512;
default:
return APK_DIGEST_NONE;
}
}
uint8_t apk_digest_alg_from_csum(int csum)
{
switch (csum) {
case APK_CHECKSUM_NONE:
return APK_DIGEST_NONE;
case APK_CHECKSUM_MD5:
return APK_DIGEST_MD5;
case APK_CHECKSUM_SHA1:
return APK_DIGEST_SHA1;
default:
return APK_DIGEST_NONE;
}
}
uint8_t apk_digest_from_blob(struct apk_digest *d, apk_blob_t b)
{
d->alg = apk_digest_alg_by_len(b.len);
d->len = 0;
if (d->alg != APK_DIGEST_NONE) {
d->len = b.len;
memcpy(d->data, b.ptr, d->len);
}
return d->alg;
}
int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void *ptr, size_t sz)
{
union {
br_sha1_context sha1;
br_md5_context md5;
} state;
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:
br_md5_init(&state.md5);
br_md5_update(&state.md5, ptr, sz);
br_md5_out(&state.md5, d->data);
break;
case APK_DIGEST_SHA1:
br_sha1_init(&state.sha1);
br_sha1_update(&state.sha1, ptr, sz);
br_sha1_out(&state.sha1, d->data);
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
d->alg = alg;
d->len = apk_digest_alg_len(d->alg);
return 0;
}
int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg)
{
union digest_state *state;
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_MD5:
br_md5_init(&state->md5);
break;
case APK_DIGEST_SHA1:
br_sha1_init(&state->sha1);
break;
case APK_DIGEST_NONE:
break;
default:
free(dctx->impl);
return -APKE_CRYPTO_NOT_SUPPORTED;
}
return 0;
}
int apk_digest_ctx_reset(struct apk_digest_ctx *dctx, uint8_t alg)
{
apk_digest_ctx_free(dctx);
return apk_digest_ctx_init(dctx, alg);
}
void apk_digest_ctx_free(struct apk_digest_ctx *dctx)
{
if (dctx->impl == NULL) {
return;
}
switch (dctx->alg) {
case APK_DIGEST_NONE:
case APK_DIGEST_MD5:
case APK_DIGEST_SHA1:
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA512:
case APK_DIGEST_SHA256_160:
free(dctx->impl);
dctx->impl = NULL;
break;
default:
/* illegal state, don't touch impl? */
return;
}
}
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_MD5:
br_md5_update(&state->md5, ptr, sz);
break;
case APK_DIGEST_SHA1:
br_sha1_update(&state->sha1, ptr, sz);
break;
case APK_DIGEST_NONE:
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 = (union digest_state *) dctx->impl;
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_MD5:
br_md5_out(&state->md5, d->data);
break;
case APK_DIGEST_SHA1:
br_sha1_out(&state->sha1, d->data);
break;
case APK_DIGEST_NONE:
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
d->alg = dctx->alg;
d->len = apk_digest_alg_len(d->alg);
return 0;
}

View File

@ -1,150 +0,0 @@
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#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) {
case APK_DIGEST_MD5: return 16;
case APK_DIGEST_SHA1: return 20;
case APK_DIGEST_SHA256_160: return 20;
case APK_DIGEST_SHA256: return 32;
case APK_DIGEST_SHA512: return 64;
default: return 0;
}
}
uint8_t apk_digest_alg_by_len(int len)
{
switch (len) {
case 0: return APK_DIGEST_NONE;
case 16: return APK_DIGEST_MD5;
case 20: return APK_DIGEST_SHA1;
case 32: return APK_DIGEST_SHA256;
case 64: return APK_DIGEST_SHA512;
default: return APK_DIGEST_NONE;
}
}
uint8_t apk_digest_alg_from_csum(int csum)
{
switch (csum) {
case APK_CHECKSUM_NONE: return APK_DIGEST_NONE;
case APK_CHECKSUM_MD5: return APK_DIGEST_MD5;
case APK_CHECKSUM_SHA1: return APK_DIGEST_SHA1;
default: return APK_DIGEST_NONE;
}
}
uint8_t apk_digest_from_blob(struct apk_digest *d, apk_blob_t b)
{
d->alg = apk_digest_alg_by_len(b.len);
d->len = 0;
if (d->alg != APK_DIGEST_NONE) {
d->len = b.len;
memcpy(d->data, b.ptr, d->len);
}
return d->alg;
}
int apk_pkey_init(struct apk_pkey *pkey, EVP_PKEY *key)
{
unsigned char dig[EVP_MAX_MD_SIZE], *pub = NULL;
unsigned int dlen = sizeof dig;
int len;
if ((len = i2d_PublicKey(key, &pub)) < 0) return -APKE_CRYPTO_ERROR;
EVP_Digest(pub, len, dig, &dlen, EVP_sha512(), NULL);
memcpy(pkey->id, dig, sizeof pkey->id);
OPENSSL_free(pub);
pkey->key = key;
return 0;
}
void apk_pkey_free(struct apk_pkey *pkey)
{
EVP_PKEY_free(pkey->key);
}
int apk_pkey_load(struct apk_pkey *pkey, int dirfd, const char *fn)
{
EVP_PKEY *key;
BIO *bio;
int fd;
fd = openat(dirfd, fn, O_RDONLY|O_CLOEXEC);
if (fd < 0) return -errno;
bio = BIO_new_fp(fdopen(fd, "r"), BIO_CLOSE);
if (!bio) return -ENOMEM;
key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
if (!key) {
(void)BIO_reset(bio);
key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
}
ERR_clear_error();
BIO_free(bio);
if (!key) return -APKE_CRYPTO_KEY_FORMAT;
apk_pkey_init(pkey, key);
return 0;
}
int apk_sign_start(struct apk_digest_ctx *dctx, struct apk_pkey *pkey)
{
if (EVP_MD_CTX_reset(dctx->mdctx) != 1 ||
EVP_DigestSignInit(dctx->mdctx, NULL, EVP_sha512(), NULL, pkey->key) != 1)
return -APKE_CRYPTO_ERROR;
return 0;
}
int apk_sign(struct apk_digest_ctx *dctx, void *sig, size_t *len)
{
if (EVP_DigestSignFinal(dctx->mdctx, sig, len) != 1) {
ERR_print_errors_fp(stderr);
return -APKE_SIGNATURE_FAIL;
}
return 0;
}
int apk_verify_start(struct apk_digest_ctx *dctx, struct apk_pkey *pkey)
{
if (EVP_MD_CTX_reset(dctx->mdctx) != 1 ||
EVP_DigestVerifyInit(dctx->mdctx, NULL, EVP_sha512(), NULL, pkey->key) != 1)
return -APKE_CRYPTO_ERROR;
return 0;
}
int apk_verify(struct apk_digest_ctx *dctx, void *sig, size_t len)
{
if (EVP_DigestVerifyFinal(dctx->mdctx, sig, len) != 1) {
ERR_print_errors_fp(stderr);
return -APKE_SIGNATURE_INVALID;
}
return 0;
}

323
src/crypto_public.c Normal file
View File

@ -0,0 +1,323 @@
#include <errno.h>
#include <fcntl.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <sodium.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "apk_crypto.h"
/* includes '\0', undef in the end */
#define APK_CUTE_PUBLIC_SIZE 69
/*
* The format is as follows:
* uint8[ 2] header = {'q', 't'}
* uint8[16] key_id
* uint8[32] public_key
*/
static int public_key_load_cute(struct apk_public_key *pub, int fd)
{
char b64[APK_CUTE_PUBLIC_SIZE];
uint8_t raw[50];
size_t len;
if (read(fd, b64, APK_CUTE_PUBLIC_SIZE) != APK_CUTE_PUBLIC_SIZE) {
return -errno;
}
if (sodium_base642bin(raw, 50, b64, APK_CUTE_PUBLIC_SIZE, NULL, &len, NULL, sodium_base64_VARIANT_ORIGINAL)
!= 0) {
return -APKE_CRYPTO_KEY_FORMAT;
}
if (len != 50) {
return -APKE_CRYPTO_KEY_FORMAT;
}
if (raw[0] != 'q' || raw[1] != 't') {
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(pub->impl, raw + 18, crypto_sign_ed25519_PUBLICKEYBYTES);
return 0;
}
/*
* The signature format is as follows:
* uint8[ 2] header = {'q', 't'}
* uint8[16] key_id
* uint8[64] signature
*/
static int verify_cute(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len)
{
unsigned char *sigdata = (unsigned char *) sig;
struct apk_digest digest;
if (len != 82) {
return -APKE_SIGNATURE_INVALID;
}
if (sigdata[0] != 'q' || sigdata[1] != 't') {
return -APKE_SIGNATURE_INVALID;
}
if (sodium_memcmp(pub->id, sigdata + 2, sizeof pub->id) != 0) {
return -APKE_SIGNATURE_INVALID;
}
if (dctx->alg != APK_DIGEST_SHA256) {
return -APKE_SIGNATURE_INVALID;
}
if (apk_digest_ctx_final(dctx, &digest) != 0) {
return -APKE_SIGNATURE_INVALID;
}
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(struct apk_public_key *pub)
{
free(pub->impl);
}
static int public_key_load_v2(struct apk_public_key *pub, int fd)
{
unsigned char *raw = NULL;
struct apk_digest digest;
EVP_PKEY *pkey;
BIO *bio;
int len;
int r = -APKE_CRYPTO_KEY_FORMAT;
bio = BIO_new_fd(fd, BIO_NOCLOSE);
if (bio == NULL) {
r = -ENOMEM;
goto err_bio_new;
}
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;
}
len = i2d_PublicKey(pkey, &raw);
if (len < 0) {
r = -APKE_CRYPTO_ERROR;
goto err_load_and_check_type;
}
if (apk_digest_calc(&digest, APK_DIGEST_SHA512, raw, len) != 0) {
r = -APKE_CRYPTO_ERROR;
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_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;
}
/*
* RSA-PKCS1 v1.5 can work with different hashes.
* 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_v2(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len)
{
struct apk_digest digest;
EVP_PKEY_CTX *pctx;
const EVP_MD *md;
int r = -APKE_SIGNATURE_INVALID;
if (apk_digest_ctx_final(dctx, &digest) != 0) {
r = -APKE_SIGNATURE_INVALID;
goto err_digest_final_and_pctx_new;
}
switch (dctx->alg) {
case APK_DIGEST_SHA1:
md = EVP_sha1();
break;
case APK_DIGEST_SHA256:
md = EVP_sha256();
break;
case APK_DIGEST_SHA512:
md = EVP_sha512();
break;
case APK_DIGEST_NONE:
case APK_DIGEST_MD5:
default:
r = -APKE_SIGNATURE_INVALID;
goto err_digest_final_and_pctx_new;
}
pctx = EVP_PKEY_CTX_new(pub->impl, NULL);
if (pctx == NULL) {
r = -APKE_SIGNATURE_INVALID;
goto err_pctx_setup_and_verify;
}
if (EVP_PKEY_verify_init(pctx) != 1) {
r = -APKE_SIGNATURE_INVALID;
goto err_pctx_setup_and_verify;
}
if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1) {
r = -APKE_SIGNATURE_INVALID;
goto err_pctx_setup_and_verify;
}
if (EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
r = -APKE_SIGNATURE_INVALID;
goto err_pctx_setup_and_verify;
}
if (EVP_PKEY_verify(pctx, sig, len, digest.data, digest.len) != 1) {
r = -APKE_SIGNATURE_INVALID;
goto err_pctx_setup_and_verify;
}
r = 0;
err_pctx_setup_and_verify:
EVP_PKEY_CTX_free(pctx);
err_digest_final_and_pctx_new:
return r;
}
static void public_key_free_v2(struct apk_public_key *pub)
{
EVP_PKEY_free(pub->impl);
}
int apk_public_key_load(struct apk_public_key *pub, int dirfd, const char *fn)
{
struct stat st;
int fd = -1;
int r = -APKE_CRYPTO_KEY_FORMAT;
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;
}
// guess
if (st.st_size == APK_CUTE_PUBLIC_SIZE) {
r = public_key_load_cute(pub, fd);
} else {
r = public_key_load_v2(pub, fd);
}
err_fstat:
close(fd);
err_openat:
return r;
}
void apk_public_key_free(struct apk_public_key *pub)
{
if (pub == NULL) {
return;
}
if (pub->impl == NULL) {
return;
}
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;
}
pub->impl = NULL;
}
int apk_verify_digest_start(struct apk_digest_ctx *dctx, uint16_t signature_type)
{
uint8_t digest;
switch (signature_type) {
case APK_SIGNATURE_CUTE:
case APK_SIGNATURE_RSA256:
digest = APK_DIGEST_SHA256;
break;
case APK_SIGNATURE_RSA512:
digest = APK_DIGEST_SHA512;
break;
case APK_SIGNATURE_RSA:
digest = APK_DIGEST_SHA1;
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
if (apk_digest_ctx_reset(dctx, digest) != 0) {
return -APKE_CRYPTO_ERROR;
}
return 0;
}
int apk_verify(struct apk_public_key *pub, struct apk_digest_ctx *dctx, void *sig, size_t len)
{
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;
}
}
#undef APK_CUTE_PUBLIC_SIZE

319
src/crypto_secret.c Normal file
View File

@ -0,0 +1,319 @@
#include <errno.h>
#include <fcntl.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <sodium.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "apk_crypto.h"
/* includes '\0', undef in the end */
#define APK_CUTE_SECRET_SIZE 113
/*
* The format is as follows:
* uint8[ 2] header = {'q', 't'}
* uint8[16] key_id
* uint8[64] secret_key
*
*/
static int secret_key_load_cute(struct apk_secret_key *sec, int fd)
{
char b64[APK_CUTE_SECRET_SIZE];
uint8_t raw[82];
size_t len;
int r = -APKE_CRYPTO_KEY_FORMAT;
if (read(fd, b64, APK_CUTE_SECRET_SIZE) != APK_CUTE_SECRET_SIZE) {
r = -errno;
goto err;
}
if (sodium_base642bin(raw, 82, b64, APK_CUTE_SECRET_SIZE, NULL, &len, NULL, sodium_base64_VARIANT_ORIGINAL)
!= 0) {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err;
}
if (raw[0] != 'q' || raw[1] != 't') {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err;
}
sec->version = APK_KEY_VERSION_V2;
memcpy(sec->id, raw + 2, 16);
memcpy(sec->impl, raw + 18, crypto_sign_ed25519_SECRETKEYBYTES);
r = 0;
err:
sodium_memzero(b64, sizeof b64);
sodium_memzero(raw, sizeof raw);
return r;
}
static void secret_key_free_cute(struct apk_secret_key *sec)
{
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)
{
unsigned char *sigdata = (unsigned char *) sig;
struct apk_digest digest;
if (*len < 82) {
return -APKE_SIGNATURE_FAIL;
}
if (dctx->alg != APK_DIGEST_SHA256) {
return -APKE_SIGNATURE_FAIL;
}
if (apk_digest_ctx_final(dctx, &digest) != 0) {
return -APKE_SIGNATURE_FAIL;
}
sigdata[0] = 'q';
sigdata[1] = 't';
memcpy(sigdata + 2, sec->id, 16);
crypto_sign_ed25519_detached(sigdata + 18, NULL, digest.data, digest.len, sec->impl);
*len = 82;
return 0;
}
static int secret_key_load_v2(struct apk_secret_key *sec, int fd)
{
unsigned char *raw = NULL;
struct apk_digest digest;
EVP_PKEY *pkey;
BIO *bio;
int len;
int r = -APKE_CRYPTO_KEY_FORMAT;
bio = BIO_new_fd(fd, BIO_NOCLOSE);
if (bio == NULL) {
r = -ENOMEM;
goto err_bio_new;
}
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;
}
len = i2d_PublicKey(pkey, &raw);
if (len < 0) {
r = -APKE_CRYPTO_ERROR;
goto err_load_and_check_type;
}
if (apk_digest_calc(&digest, APK_DIGEST_SHA512, raw, len) != 0) {
r = -APKE_CRYPTO_ERROR;
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_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_v2(struct apk_secret_key *sec, struct apk_digest_ctx *dctx, void *sig, size_t *len)
{
struct apk_digest digest;
EVP_PKEY_CTX *pctx;
const EVP_MD *md;
int r = -APKE_SIGNATURE_FAIL;
size_t needed;
if (apk_digest_ctx_final(dctx, &digest) != 0) {
r = -APKE_SIGNATURE_FAIL;
goto err_digest_final_and_pctx_new;
}
switch (dctx->alg) {
case APK_DIGEST_SHA1:
md = EVP_sha1();
break;
case APK_DIGEST_SHA256:
md = EVP_sha256();
break;
case APK_DIGEST_SHA512:
md = EVP_sha512();
break;
case APK_DIGEST_NONE:
case APK_DIGEST_MD5:
default:
r = -APKE_SIGNATURE_FAIL;
goto err_digest_final_and_pctx_new;
}
pctx = EVP_PKEY_CTX_new(sec->impl, NULL);
if (pctx == NULL) {
r = -APKE_SIGNATURE_FAIL;
goto err_digest_final_and_pctx_new;
}
if (EVP_PKEY_sign_init(pctx) != 1) {
r = -APKE_SIGNATURE_FAIL;
goto err_pctx_setup_and_sign;
}
if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1) {
r = -APKE_SIGNATURE_FAIL;
goto err_pctx_setup_and_sign;
}
if (EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
r = -APKE_SIGNATURE_INVALID;
goto err_pctx_setup_and_sign;
}
/* Determine minimum required buffer size */
if (EVP_PKEY_sign(pctx, NULL, &needed, digest.data, digest.len) != 1) {
r = -APKE_SIGNATURE_FAIL;
goto err_pctx_setup_and_sign;
}
if (needed < *len) {
r = -APKE_SIGNATURE_FAIL;
goto err_pctx_setup_and_sign;
}
if (EVP_PKEY_sign(pctx, sig, len, digest.data, digest.len) != 1) {
r = -APKE_SIGNATURE_FAIL;
goto err_pctx_setup_and_sign;
}
r = 0;
err_pctx_setup_and_sign:
EVP_PKEY_CTX_free(pctx);
err_digest_final_and_pctx_new:
return r;
}
static void secret_key_free_v2(struct apk_secret_key *sec)
{
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, r = -APKE_CRYPTO_KEY_FORMAT;
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;
}
if (st.st_size == APK_CUTE_SECRET_SIZE) {
r = secret_key_load_cute(sec, fd);
} else {
r = secret_key_load_v2(sec, fd);
}
err_fstat:
close(fd);
err_openat:
return r;
}
void apk_secret_key_free(struct apk_secret_key *sec)
{
if (sec == NULL) {
return;
}
if (sec->impl == NULL) {
return;
}
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;
}
sec->impl = NULL;
}
int apk_sign_digest_start(struct apk_digest_ctx *dctx, uint16_t signature_type)
{
uint8_t digest;
switch (signature_type) {
case APK_SIGNATURE_CUTE:
case APK_SIGNATURE_RSA256:
digest = APK_DIGEST_SHA256;
break;
case APK_SIGNATURE_RSA512:
digest = APK_DIGEST_SHA512;
break;
case APK_SIGNATURE_RSA:
digest = APK_DIGEST_SHA1;
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
if (apk_digest_ctx_reset(dctx, digest) != 0) {
return -APKE_CRYPTO_ERROR;
}
return 0;
}
int apk_sign(struct apk_secret_key *sec, struct apk_digest_ctx *dctx, void *sig, size_t *len)
{
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;
}
}
#undef APK_CUTE_SECRET_SIZE

View File

@ -7,19 +7,20 @@
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <libgen.h>
#include <limits.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#ifdef __linux__
# include <mntent.h>
@ -2757,6 +2758,18 @@ static const struct apk_extract_ops extract_installer = {
.file = apk_db_install_file,
};
static int apk_db_audit_file(struct apk_fsdir *d, apk_blob_t filename, struct apk_db_file *dbf)
{
struct apk_file_info fi;
int r;
// Check file first
r = apk_fsdir_file_info(d, filename, APK_FI_NOFOLLOW | APK_FI_DIGEST(apk_dbf_digest(dbf)), &fi);
if (r != 0 || !dbf || dbf->csum.type == APK_CHECKSUM_NONE) return r != -ENOENT;
if (apk_digest_cmp_csum(&fi.digest, &dbf->csum) != 0) return 1;
return 0;
}
static void apk_db_purge_pkg(struct apk_database *db,
struct apk_installed_package *ipkg,
int is_installed)
@ -2766,7 +2779,6 @@ static void apk_db_purge_pkg(struct apk_database *db,
struct apk_db_file *file;
struct apk_db_file_hash_key key;
struct apk_fsdir d;
struct apk_digest dgst;
struct hlist_node *dc, *dn, *fc, *fn;
unsigned long hash;
int ctrl = is_installed ? APK_FS_CTRL_DELETE : APK_FS_CTRL_CANCEL;
@ -2785,9 +2797,7 @@ static void apk_db_purge_pkg(struct apk_database *db,
if (!is_installed ||
(diri->dir->protect_mode == APK_PROTECT_NONE) ||
(db->ctx->flags & APK_PURGE) ||
(file->csum.type != APK_CHECKSUM_NONE &&
apk_fsdir_file_digest(&d, key.filename, apk_dbf_digest(file), &dgst) == 0 &&
apk_digest_cmp_csum(&dgst, &file->csum) == 0))
apk_db_audit_file(&d, key.filename, file) == 0)
apk_fsdir_file_control(&d, key.filename, ctrl);
apk_dbg2(out, DIR_FILE_FMT, DIR_FILE_PRINTF(diri->dir, file));
@ -2813,7 +2823,6 @@ static uint8_t apk_db_migrate_files_for_priority(struct apk_database *db,
struct apk_db_file_hash_key key;
struct hlist_node *dc, *dn, *fc, *fn;
struct apk_fsdir d;
struct apk_digest dgst;
unsigned long hash;
apk_blob_t dirname;
int r, ctrl;
@ -2848,21 +2857,17 @@ static uint8_t apk_db_migrate_files_for_priority(struct apk_database *db,
// File was from overlay, delete the package's version
ctrl = APK_FS_CTRL_CANCEL;
} else if (diri->dir->protect_mode != APK_PROTECT_NONE &&
apk_fsdir_file_digest(&d, key.filename, apk_dbf_digest(ofile), &dgst) == 0 &&
(!ofile || ofile->csum.type == APK_CHECKSUM_NONE ||
apk_digest_cmp_csum(&dgst, &ofile->csum) != 0)) {
apk_db_audit_file(&d, key.filename, ofile) != 0) {
// Protected directory, and a file without db entry
// or with local modifications. Keep the filesystem file.
// Determine if the package's file should be kept as .apk-new
if ((db->ctx->flags & APK_CLEAN_PROTECTED) ||
(file->csum.type != APK_CHECKSUM_NONE &&
(apk_fsdir_file_digest(&d, key.filename, apk_dbf_digest(file), &dgst) == 0 &&
apk_digest_cmp_csum(&dgst, &file->csum) == 0))) {
apk_db_audit_file(&d, key.filename, file) == 0) {
// No .apk-new files allowed, or the file on disk has the same
// hash as the file from new package. Keep the on disk one.
ctrl = APK_FS_CTRL_CANCEL;
} else {
// All files difference. Use the package's file as .apk-new.
// All files differ. Use the package's file as .apk-new.
ctrl = APK_FS_CTRL_APKNEW;
}
}

View File

@ -8,20 +8,20 @@
*/
#include "apk_context.h"
#include "apk_crypto.h"
#include "apk_extract.h"
#include "apk_package.h"
#include "apk_tar.h"
#define APK_SIGN_NONE 0
#define APK_SIGN_VERIFY 1
#define APK_SIGN_VERIFY_IDENTITY 2
#define APK_SIGN_GENERATE 4
#define APK_SIGN_VERIFY_AND_GENERATE 5
#define APK_SIGN_NONE 0
#define APK_SIGN_VERIFY 1
#define APK_SIGN_VERIFY_IDENTITY 2
#define APK_SIGN_GENERATE 4
#define APK_SIGN_VERIFY_AND_GENERATE 5
struct apk_sign_ctx {
struct apk_trust *trust;
int action;
const EVP_MD *md;
int num_signatures;
int control_started : 1;
int data_started : 1;
@ -29,57 +29,65 @@ struct apk_sign_ctx {
int control_verified : 1;
int data_verified : 1;
int allow_untrusted : 1;
char data_checksum[EVP_MAX_MD_SIZE];
char data_checksum[APK_DIGEST_MAX_LENGTH];
struct apk_checksum identity;
EVP_MD_CTX *mdctx;
struct apk_digest_ctx digest_ctx;
struct {
struct apk_public_key *public_key;
apk_blob_t data;
EVP_PKEY *pkey;
uint16_t type;
char *identity;
} signature;
};
static void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action, struct apk_checksum *identity, struct apk_trust *trust)
static void
apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action, struct apk_checksum *identity, struct apk_trust *trust)
{
uint8_t digest_alg;
memset(ctx, 0, sizeof(struct apk_sign_ctx));
ctx->trust = trust;
ctx->action = action;
ctx->trust = trust;
ctx->action = action;
ctx->allow_untrusted = trust->allow_untrusted;
switch (action) {
case APK_SIGN_VERIFY:
/* If we're only verifing, we're going to start with a
* signature section, which we don't need a hash of */
ctx->md = EVP_md_null();
digest_alg = APK_DIGEST_NONE;
break;
case APK_SIGN_VERIFY_IDENTITY:
/* If we're checking the package against a particular hash,
* we need to start with that hash, because there may not
* be a signature section to deduce it from */
ctx->md = EVP_sha1();
digest_alg = APK_DIGEST_SHA1;
memcpy(&ctx->identity, identity, sizeof(ctx->identity));
break;
case APK_SIGN_GENERATE:
case APK_SIGN_VERIFY_AND_GENERATE:
ctx->md = EVP_sha1();
digest_alg = APK_DIGEST_SHA1;
break;
default:
ctx->action = APK_SIGN_NONE;
ctx->md = EVP_md_null();
ctx->action = APK_SIGN_NONE;
ctx->control_started = 1;
ctx->data_started = 1;
ctx->data_started = 1;
digest_alg = APK_DIGEST_NONE;
break;
}
ctx->mdctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx->mdctx, ctx->md, NULL);
EVP_MD_CTX_set_flags(ctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
apk_digest_ctx_init(&ctx->digest_ctx, digest_alg);
}
static void apk_sign_ctx_free(struct apk_sign_ctx *ctx)
{
if (ctx->signature.data.ptr != NULL)
if (ctx->signature.data.ptr != NULL) {
free(ctx->signature.data.ptr);
EVP_MD_CTX_free(ctx->mdctx);
}
apk_public_key_free(ctx->signature.public_key);
}
static int check_signing_key_trust(struct apk_sign_ctx *sctx)
@ -87,55 +95,60 @@ static int check_signing_key_trust(struct apk_sign_ctx *sctx)
switch (sctx->action) {
case APK_SIGN_VERIFY:
case APK_SIGN_VERIFY_AND_GENERATE:
if (sctx->signature.pkey == NULL) {
if (sctx->allow_untrusted)
if (sctx->signature.public_key == NULL) {
if (sctx->allow_untrusted) {
break;
}
return -APKE_SIGNATURE_UNTRUSTED;
}
}
return 0;
}
static int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, const struct apk_file_info *fi,
struct apk_istream *is)
static int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, const struct apk_file_info *fi, struct apk_istream *is)
{
static struct {
char type[8];
unsigned int nid;
} signature_type[] = {
{ "RSA512", NID_sha512 },
{ "RSA256", NID_sha256 },
{ "RSA", NID_sha1 },
{ "DSA", NID_dsa },
static const char *signature_type[4] = {
[APK_SIGNATURE_RSA] = "RSA",
[APK_SIGNATURE_RSA512] = "RSA512",
[APK_SIGNATURE_RSA256] = "RSA256",
[APK_SIGNATURE_CUTE] = "CUTE",
};
const EVP_MD *md = NULL;
const char *name = NULL;
struct apk_pkey *pkey;
int r, i;
if (ctx->data_started)
uint16_t signature_alg = APK_SIGNATURE_MAX;
struct apk_public_key *public_key;
const char *name = NULL;
int r;
if (ctx->data_started) {
return 1;
}
if (fi->name[0] != '.' || strchr(fi->name, '/') != NULL) {
/* APKv1.0 compatibility - first non-hidden file is
* considered to start the data section of the file.
* This does not make any sense if the file has v2.0
* style .PKGINFO */
if (ctx->has_data_checksum)
if (ctx->has_data_checksum) {
return -APKE_V2PKG_FORMAT;
}
/* Error out early if identity part is missing */
if (ctx->action == APK_SIGN_VERIFY_IDENTITY)
if (ctx->action == APK_SIGN_VERIFY_IDENTITY) {
return -APKE_V2PKG_FORMAT;
ctx->data_started = 1;
}
ctx->data_started = 1;
ctx->control_started = 1;
r = check_signing_key_trust(ctx);
if (r < 0)
if (r < 0) {
return r;
}
return 1;
}
if (ctx->control_started)
if (ctx->control_started) {
return 1;
}
if (strncmp(fi->name, ".SIGN.", 6) != 0) {
ctx->control_started = 1;
@ -146,32 +159,37 @@ static int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, const struct apk_
ctx->num_signatures++;
/* Already found a signature by a trusted key; no need to keep searching */
if ((ctx->action != APK_SIGN_VERIFY &&
ctx->action != APK_SIGN_VERIFY_AND_GENERATE) ||
ctx->signature.pkey != NULL)
if ((ctx->action != APK_SIGN_VERIFY && ctx->action != APK_SIGN_VERIFY_AND_GENERATE)
|| ctx->signature.public_key != NULL)
return 0;
for (i = 0; i < ARRAY_SIZE(signature_type); i++) {
size_t slen = strlen(signature_type[i].type);
if (strncmp(&fi->name[6], signature_type[i].type, slen) == 0 &&
fi->name[6+slen] == '.') {
md = EVP_get_digestbynid(signature_type[i].nid);
name = &fi->name[6+slen+1];
for (uint16_t i = 0; i < ARRAY_SIZE(signature_type); i++) {
size_t slen = strlen(signature_type[i]);
if (strncmp(&fi->name[6], signature_type[i], slen) == 0 && fi->name[6 + slen] == '.') {
signature_alg = i;
name = &fi->name[6 + slen + 1];
break;
}
}
if (!md) return 0;
pkey = apk_trust_key_by_name(ctx->trust, name);
if (pkey) {
ctx->md = md;
ctx->signature.pkey = pkey->key;
ctx->signature.data = apk_blob_from_istream(is, fi->size);
if (signature_alg == APK_SIGNATURE_MAX) {
return 0;
}
public_key = apk_trust_public_key_by_name(ctx->trust, name);
if (public_key != NULL) {
ctx->signature.public_key = public_key;
ctx->signature.type = signature_alg;
ctx->signature.data = apk_blob_from_istream(is, fi->size);
}
// TODO: check if its really a good idea to reset here
apk_verify_digest_start(&ctx->digest_ctx, signature_alg);
return 0;
}
/* apk_sign_ctx_mpart_cb() handles hashing archives and checking signatures, but
it can't do it alone. apk_sign_ctx_process_file() must be in the loop to
actually select which signature is to be verified and load the corresponding
@ -181,42 +199,43 @@ static int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, const struct apk_
static int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
{
struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
unsigned char calculated[EVP_MAX_MD_SIZE];
struct apk_digest digest;
int r, end_of_control;
if ((part == APK_MPART_DATA) ||
(part == APK_MPART_BOUNDARY && sctx->data_started))
if ((part == APK_MPART_DATA) || (part == APK_MPART_BOUNDARY && sctx->data_started)) {
goto update_digest;
}
/* Still in signature blocks? */
if (!sctx->control_started) {
if (part == APK_MPART_END)
if (part == APK_MPART_END) {
return -APKE_V2PKG_FORMAT;
}
goto reset_digest;
}
/* Grab state and mark all remaining block as data */
end_of_control = (sctx->data_started == 0);
end_of_control = (sctx->data_started == 0);
sctx->data_started = 1;
/* End of control-block and control does not have data checksum? */
if (sctx->has_data_checksum == 0 && end_of_control &&
part != APK_MPART_END)
if (sctx->has_data_checksum == 0 && end_of_control && part != APK_MPART_END)
goto update_digest;
/* Drool in the remainder of the digest block now, we will finish
* hashing it in all cases */
EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
apk_digest_ctx_update(&sctx->digest_ctx, data.ptr, data.len);
if (sctx->has_data_checksum && !end_of_control) {
/* End of data-block with a checksum read from the control block */
EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
if (EVP_MD_CTX_size(sctx->mdctx) == 0 ||
memcmp(calculated, sctx->data_checksum, EVP_MD_CTX_size(sctx->mdctx)) != 0)
apk_digest_ctx_final(&sctx->digest_ctx, &digest);
if (digest.len == 0 || memcmp(digest.data, sctx->data_checksum, digest.len) != 0) {
return -APKE_V2PKG_INTEGRITY;
}
sctx->data_verified = 1;
if (!sctx->allow_untrusted && !sctx->control_verified)
if (!sctx->allow_untrusted && !sctx->control_verified) {
return -APKE_SIGNATURE_UNTRUSTED;
}
return 0;
}
@ -230,51 +249,60 @@ static int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
switch (sctx->action) {
case APK_SIGN_VERIFY:
case APK_SIGN_VERIFY_AND_GENERATE:
if (sctx->signature.pkey != NULL) {
r = EVP_VerifyFinal(sctx->mdctx,
(unsigned char *) sctx->signature.data.ptr,
sctx->signature.data.len,
sctx->signature.pkey);
if (r != 1 && !sctx->allow_untrusted)
if (sctx->signature.public_key != NULL) {
r = apk_verify(sctx->signature.public_key,
&sctx->digest_ctx,
sctx->signature.data.ptr,
sctx->signature.data.len);
if (r != 0 && !sctx->allow_untrusted) {
return -APKE_SIGNATURE_INVALID;
}
} else {
r = 0;
if (!sctx->allow_untrusted)
if (!sctx->allow_untrusted) {
return -APKE_SIGNATURE_UNTRUSTED;
}
}
if (r == 1) {
sctx->control_verified = 1;
if (!sctx->has_data_checksum && part == APK_MPART_END)
if (!sctx->has_data_checksum && part == APK_MPART_END) {
sctx->data_verified = 1;
}
}
if (sctx->action == APK_SIGN_VERIFY_AND_GENERATE) {
goto generate_identity;
}
if (sctx->action == APK_SIGN_VERIFY_AND_GENERATE) goto generate_identity;
break;
case APK_SIGN_VERIFY_IDENTITY:
/* Reset digest for hashing data */
EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
if (memcmp(calculated, sctx->identity.data,
sctx->identity.type) != 0)
apk_digest_ctx_final(&sctx->digest_ctx, &digest);
if (memcmp(digest.data, sctx->identity.data, sctx->identity.type) != 0) {
return -APKE_V2PKG_INTEGRITY;
}
sctx->control_verified = 1;
if (!sctx->has_data_checksum && part == APK_MPART_END)
if (!sctx->has_data_checksum && part == APK_MPART_END) {
sctx->data_verified = 1;
}
break;
case APK_SIGN_GENERATE:
generate_identity:
generate_identity:
/* Package identity is the checksum */
sctx->identity.type = EVP_MD_CTX_size(sctx->mdctx);
EVP_DigestFinal_ex(sctx->mdctx, sctx->identity.data, NULL);
if (!sctx->has_data_checksum) return -APKE_V2PKG_FORMAT;
sctx->identity.type = apk_digest_alg_len(sctx->digest_ctx.alg);
apk_digest_ctx_final(&sctx->digest_ctx, &digest);
memcpy(sctx->identity.data, digest.data, sctx->identity.type);
if (!sctx->has_data_checksum) {
return -APKE_V2PKG_FORMAT;
}
break;
}
reset_digest:
EVP_DigestInit_ex(sctx->mdctx, sctx->md, NULL);
EVP_MD_CTX_set_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
apk_digest_ctx_reset(&sctx->digest_ctx, sctx->digest_ctx.alg);
return 0;
update_digest:
EVP_MD_CTX_clear_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
apk_digest_ctx_update(&sctx->digest_ctx, data.ptr, data.len);
return 0;
}
@ -283,43 +311,56 @@ static int apk_extract_verify_v2index(struct apk_extract_ctx *ectx, apk_blob_t *
return 0;
}
static int apk_extract_verify_v2file(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, struct apk_istream *is)
static int
apk_extract_verify_v2file(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, struct apk_istream *is)
{
return 0;
}
static const struct apk_extract_ops extract_v2verify_ops = {
.v2index = apk_extract_verify_v2index,
.v2meta = apk_extract_v2_meta,
.file = apk_extract_verify_v2file,
.v2index = apk_extract_verify_v2index,
.v2meta = apk_extract_v2_meta,
.file = apk_extract_verify_v2file,
};
static int apk_extract_v2_entry(void *pctx, const struct apk_file_info *fi, struct apk_istream *is)
{
struct apk_extract_ctx *ectx = pctx;
struct apk_sign_ctx *sctx = ectx->pctx;
struct apk_sign_ctx *sctx = ectx->pctx;
int r, type;
r = apk_sign_ctx_process_file(sctx, fi, is);
if (r <= 0) return r;
if (r <= 0)
return r;
if (!sctx->control_started) return 0;
if (!sctx->control_started)
return 0;
if (!sctx->data_started || !sctx->has_data_checksum) {
if (fi->name[0] == '.') {
ectx->is_package = 1;
if (ectx->is_index) return -APKE_V2NDX_FORMAT;
if (!ectx->ops->v2meta) return -APKE_FORMAT_NOT_SUPPORTED;
if (ectx->is_index) {
return -APKE_V2NDX_FORMAT;
}
if (!ectx->ops->v2meta) {
return -APKE_FORMAT_NOT_SUPPORTED;
}
if (strcmp(fi->name, ".PKGINFO") == 0) {
return ectx->ops->v2meta(ectx, is);
} else if (strcmp(fi->name, ".INSTALL") == 0) {
return -APKE_V2PKG_FORMAT;
} else if ((type = apk_script_type(&fi->name[1])) != APK_SCRIPT_INVALID) {
if (ectx->ops->script) return ectx->ops->script(ectx, type, fi->size, is);
if (ectx->ops->script) {
return ectx->ops->script(ectx, type, fi->size, is);
}
}
} else {
ectx->is_index = 1;
if (ectx->is_package) return -APKE_V2PKG_FORMAT;
if (!ectx->ops->v2index) return -APKE_FORMAT_NOT_SUPPORTED;
if (ectx->is_package) {
return -APKE_V2PKG_FORMAT;
}
if (!ectx->ops->v2index) {
return -APKE_FORMAT_NOT_SUPPORTED;
}
if (strcmp(fi->name, "DESCRIPTION") == 0) {
free(ectx->desc.ptr);
ectx->desc = apk_blob_from_istream(is, fi->size);
@ -330,35 +371,47 @@ static int apk_extract_v2_entry(void *pctx, const struct apk_file_info *fi, stru
return 0;
}
if (!sctx->data_started) return 0;
if (!ectx->ops->file) return -ECANCELED;
if (!sctx->data_started)
return 0;
if (!ectx->ops->file)
return -ECANCELED;
return ectx->ops->file(ectx, fi, is);
}
int apk_extract_v2(struct apk_extract_ctx *ectx, struct apk_istream *is)
{
struct apk_ctx *ac = ectx->ac;
struct apk_ctx *ac = ectx->ac;
struct apk_trust *trust = apk_ctx_get_trust(ac);
struct apk_sign_ctx sctx;
int r, action;
if (ectx->generate_identity)
if (ectx->generate_identity) {
action = trust->allow_untrusted ? APK_SIGN_GENERATE : APK_SIGN_VERIFY_AND_GENERATE;
else if (ectx->identity)
} else if (ectx->identity) {
action = APK_SIGN_VERIFY_IDENTITY;
else
} else {
action = APK_SIGN_VERIFY;
}
if (!ectx->ops) {
ectx->ops = &extract_v2verify_ops;
}
if (!ectx->ops) ectx->ops = &extract_v2verify_ops;
ectx->pctx = &sctx;
apk_sign_ctx_init(&sctx, action, ectx->identity, trust);
r = apk_tar_parse(
apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx),
apk_extract_v2_entry, ectx, apk_ctx_get_id_cache(ac));
if (r == -ECANCELED) r = 0;
if ((r == 0 || r == -APKE_EOF) && !ectx->is_package && !ectx->is_index)
r = apk_tar_parse(apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx),
apk_extract_v2_entry,
ectx,
apk_ctx_get_id_cache(ac));
if (r == -ECANCELED) {
r = 0;
}
if ((r == 0 || r == -APKE_EOF) && !ectx->is_package && !ectx->is_index) {
r = ectx->ops->v2index ? -APKE_V2NDX_FORMAT : -APKE_V2PKG_FORMAT;
if (ectx->generate_identity) *ectx->identity = sctx.identity;
}
if (ectx->generate_identity) {
*ectx->identity = sctx.identity;
}
apk_sign_ctx_free(&sctx);
free(ectx->desc.ptr);
apk_extract_reset(ectx);
@ -370,14 +423,15 @@ void apk_extract_v2_control(struct apk_extract_ctx *ectx, apk_blob_t l, apk_blob
{
struct apk_sign_ctx *sctx = ectx->pctx;
if (!sctx || !sctx->control_started || sctx->data_started) return;
if (!sctx || !sctx->control_started || sctx->data_started) {
return;
}
// TODO check if reset is ok
if (apk_blob_compare(APK_BLOB_STR("datahash"), l) == 0) {
sctx->has_data_checksum = 1;
sctx->md = EVP_sha256();
apk_blob_pull_hexdump(
&r, APK_BLOB_PTR_LEN(sctx->data_checksum,
EVP_MD_size(sctx->md)));
apk_digest_ctx_reset(&sctx->digest_ctx, APK_DIGEST_SHA256);
apk_blob_pull_hexdump(&r, APK_BLOB_PTR_LEN(sctx->data_checksum, apk_digest_alg_len(APK_DIGEST_SHA256)));
}
}
@ -385,11 +439,13 @@ int apk_extract_v2_meta(struct apk_extract_ctx *ectx, struct apk_istream *is)
{
apk_blob_t k, v, token = APK_BLOB_STRLIT("\n");
while (apk_istream_get_delim(is, token, &k) == 0) {
if (k.len < 1 || k.ptr[0] == '#') continue;
if (k.len < 1 || k.ptr[0] == '#') {
continue;
}
if (apk_blob_split(k, APK_BLOB_STRLIT(" = "), &k, &v)) {
apk_extract_v2_control(ectx, k, v);
}
}
return 0;
}

View File

@ -12,6 +12,7 @@
#include "apk_fs.h"
#include "apk_xattr.h"
#include "apk_database.h" // for db->atoms
#define TMPNAME_MAX (PATH_MAX + 64)
@ -265,23 +266,16 @@ static int fsys_file_control(struct apk_fsdir *d, apk_blob_t filename, int ctrl)
return rc;
}
static int fsys_file_digest(struct apk_fsdir *d, apk_blob_t filename, uint8_t alg, struct apk_digest *dgst)
static int fsys_file_info(struct apk_fsdir *d, apk_blob_t filename,
unsigned int flags, struct apk_file_info *fi)
{
struct apk_ctx *ac = d->ac;
struct apk_istream *is;
apk_blob_t blob;
int n;
int n, r;
n = apk_pathbuilder_pushb(&d->pb, filename);
is = apk_istream_from_file(apk_ctx_fd_dest(ac), apk_pathbuilder_cstr(&d->pb));
r = apk_fileinfo_get(apk_ctx_fd_dest(ac), apk_pathbuilder_cstr(&d->pb), flags, fi, &ac->db->atoms);
apk_pathbuilder_pop(&d->pb, n);
if (IS_ERR(is)) return PTR_ERR(is);
apk_digest_ctx_reset(&ac->dctx, alg);
while (apk_istream_get_all(is, &blob) == 0)
apk_digest_ctx_update(&ac->dctx, blob.ptr, blob.len);
apk_digest_ctx_final(&ac->dctx, dgst);
return apk_istream_close(is);
return r;
}
static const struct apk_fsdir_ops fsdir_ops_fsys = {
@ -292,7 +286,7 @@ static const struct apk_fsdir_ops fsdir_ops_fsys = {
.dir_update_perms = fsys_dir_update_perms,
.file_extract = fsys_file_extract,
.file_control = fsys_file_control,
.file_digest = fsys_file_digest,
.file_info = fsys_file_info,
};
static const struct apk_fsdir_ops *apk_fsops_get(apk_blob_t dir)

View File

@ -150,7 +150,7 @@ static int uvol_file_control(struct apk_fsdir *d, apk_blob_t filename, int ctrl)
}
}
static int uvol_file_digest(struct apk_fsdir *d, apk_blob_t filename, uint8_t alg, struct apk_digest *dgst)
static int uvol_file_info(struct apk_fsdir *d, apk_blob_t filename, unsigned int flags, struct apk_file_info *fi)
{
return -APKE_UVOL_ERROR;
}
@ -163,5 +163,5 @@ const struct apk_fsdir_ops fsdir_ops_uvol = {
.dir_update_perms = uvol_dir_update_perms,
.file_extract = uvol_file_extract,
.file_control = uvol_file_control,
.file_digest = uvol_file_digest,
.file_info = uvol_file_info,
};

View File

@ -12,7 +12,10 @@ libapk_src = [
'commit.c',
'common.c',
'context.c',
'crypto_openssl.c',
'crypto_core.c',
'crypto_digest.c',
'crypto_public.c',
'crypto_secret.c',
'database.c',
'extract_v2.c',
'extract_v3.c',
@ -42,7 +45,6 @@ libapk_headers = [
'apk_fs.h',
'apk_hash.h',
'apk_io.h',
'apk_openssl.h',
'apk_package.h',
'apk_pathbuilder.h',
'apk_print.h',

View File

@ -19,9 +19,6 @@
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include "apk_openssl.h"
#include <openssl/pem.h>
#include "apk_defines.h"
#include "apk_package.h"
#include "apk_database.h"
@ -440,7 +437,7 @@ int apk_deps_write_layer(struct apk_database *db, struct apk_dependency_array *d
apk_blob_push_dep(&blob, db, &deps->item[i]);
blob = apk_blob_pushed(APK_BLOB_BUF(tmp), blob);
if (APK_BLOB_IS_NULL(blob) ||
if (APK_BLOB_IS_NULL(blob) ||
apk_ostream_write(os, blob.ptr, blob.len) < 0)
return -1;

View File

@ -2,7 +2,7 @@
#include "apk_trust.h"
#include "apk_io.h"
static struct apk_trust_key *apk_trust_load_key(int dirfd, const char *filename)
static struct apk_trust_key *apk_trust_load_public(int dirfd, const char *filename)
{
struct apk_trust_key *key;
int r;
@ -10,7 +10,7 @@ static struct apk_trust_key *apk_trust_load_key(int dirfd, const char *filename)
key = calloc(1, sizeof *key);
if (!key) return ERR_PTR(-ENOMEM);
r = apk_pkey_load(&key->key, dirfd, filename);
r = apk_public_key_load(&key->key, dirfd, filename);
if (r) {
free(key);
return ERR_PTR(r);
@ -21,10 +21,29 @@ static struct apk_trust_key *apk_trust_load_key(int dirfd, const char *filename)
return key;
}
static struct apk_trust_secret_key *apk_trust_load_secret(int dirfd, const char *filename)
{
struct apk_trust_secret_key *key;
int r;
key = calloc(1, sizeof *key);
if (!key) return ERR_PTR(-ENOMEM);
r = apk_secret_key_load(&key->key, dirfd, filename);
if (r != 0) {
free(key);
return ERR_PTR(r);
}
list_init(&key->key_node);
key->filename = strdup(filename);
return key;
}
static int __apk_trust_load_pubkey(void *pctx, int dirfd, const char *filename)
{
struct apk_trust *trust = pctx;
struct apk_trust_key *key = apk_trust_load_key(dirfd, filename);
struct apk_trust_key *key = apk_trust_load_public(dirfd, filename);
if (!IS_ERR(key))
list_add_tail(&key->key_node, &trust->trusted_key_list);
@ -56,7 +75,7 @@ static void __apk_trust_free_keys(struct list_head *h)
list_for_each_entry_safe(tkey, n, h, key_node) {
list_del(&tkey->key_node);
apk_pkey_free(&tkey->key);
apk_public_key_free(&tkey->key);
free(tkey->filename);
free(tkey);
}
@ -69,7 +88,7 @@ void apk_trust_free(struct apk_trust *trust)
apk_digest_ctx_free(&trust->dctx);
}
struct apk_pkey *apk_trust_key_by_name(struct apk_trust *trust, const char *filename)
struct apk_public_key *apk_trust_public_key_by_name(struct apk_trust *trust, const char *filename)
{
struct apk_trust_key *tkey;
@ -93,11 +112,11 @@ static int option_parse_signing(void *ctx, struct apk_ctx *ac, int optch, const
{
struct apk_trust *trust = &ac->trust;
struct apk_out *out = &ac->out;
struct apk_trust_key *key;
struct apk_trust_secret_key *key;
switch (optch) {
case OPT_SIGN_sign_key:
key = apk_trust_load_key(AT_FDCWD, optarg);
key = apk_trust_load_secret(AT_FDCWD, optarg);
if (IS_ERR(key)) {
apk_err(out, "Failed to load signing key: %s: %s",
optarg, apk_error_str(PTR_ERR(key)));