Compare commits
11 Commits
8cd49f8535
...
962eed50db
Author | SHA1 | Date |
---|---|---|
Aydin Mercan | 962eed50db | |
Aydin Mercan | b4089b97b1 | |
Aydin Mercan | 0d59807471 | |
Aydin Mercan | 1c54a3fbb4 | |
Aydin Mercan | 5b020ec9ef | |
Aydin Mercan | dea8ded23e | |
Aydin Mercan | 86da6dc599 | |
Aydin Mercan | 0b7d6dfbf2 | |
Aydin Mercan | 2727846361 | |
Timo Teräs | c21f61ddd8 | |
Felix Yan | 1ababaa99d |
|
@ -127,7 +127,7 @@ endif
|
|||
|
||||
PHONY += all compile install clean docs FORCE
|
||||
|
||||
# Convinient variables
|
||||
# Convenient variables
|
||||
comma := ,
|
||||
squote := '
|
||||
empty :=
|
||||
|
|
|
@ -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')
|
||||
|
|
14
src/Makefile
14
src/Makefile
|
@ -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)
|
||||
|
||||
|
|
31
src/adb.c
31
src/adb.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
177
src/apk_crypto.h
177
src/apk_crypto.h
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
308
src/extract_v2.c
308
src/extract_v2.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
33
src/trust.c
33
src/trust.c
|
@ -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)));
|
||||
|
|
Loading…
Reference in New Issue