Compare commits

...

5 Commits

Author SHA1 Message Date
Aydin Mercan e02ab1d0be
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-07-25 14:23:37 +03:00
Timo Teräs ff7c8f6ee9 fetch: implement --world
fixes #10838
2022-05-04 19:56:04 +03:00
Timo Teräs f8cf7a0a0d add: allow specifying a version for --virtual package
fixes #10835
2022-05-04 19:56:00 +03:00
Ariadne Conill 44994a46d4 portability: check for qsort_r which does not match POSIX-next definition
FreeBSD (and also Darwin) introduced its own qsort_r, which has different
semantics than the one slated for inclusion in POSIX.  Add a portability
thunk to deal with translating between implementations.

[TT: minor stylistic fixes]
2022-04-11 09:35:47 +03:00
Timo Teräs 191e2d412d io: move make_dirs as apk_make_dirs and use it 2022-04-05 10:53:52 +03:00
21 changed files with 673 additions and 167 deletions

View File

@ -42,7 +42,9 @@ following options:
*-t, --virtual* _NAME_
Create virtual package _NAME_ with given dependencies. This new package
will get the _packages_ as dependencies instead of _world_. Finally the
_NAME_ is added to _world_.
_NAME_ is added to _world_. An optional version specifier for the virtual
package can be given via syntax _NAME_=_VERSION_. The version defaults
to synthesized version based on time.
One can use this to ensure that selected set of packages are installed,
and later the temporary modification be undone with *apk-del*(8) _NAME_

View File

@ -32,6 +32,9 @@ specified.
*Note*: this option is incompatible with *-o*, *-R*, and the global
*--progress* option.
*-w, --world*
Download packages needed to satisfy _world_. Implies *--recursive*.
*--simulate*
Simulate the requested operation without making any changes.

View File

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

View File

@ -21,6 +21,20 @@ foreach f : check_functions
endforeach
# Check for wrong (non-POSIX) qsort_r prototype
qsort_r_test = '''
#define _GNU_SOURCE
#include <stdlib.h>
_Static_assert(_Generic((qsort_r),
void (*)(void *, size_t, size_t, void *,
int (*)(void *, const void *, const void *)) : 1, default: 0),
"Bad prototype not matched");
'''
if cc.compiles(qsort_r_test, name: 'Test qsort_r non-POSIX prototype')
add_project_arguments('-DHAVE_BROKEN_QSORT_R', language: 'c')
endif
if libportability_src.length() > 0
libportability = static_library(
'portability',

View File

@ -1,3 +1,4 @@
#pragma once
#include_next <stdlib.h>
#ifdef NEED_QSORT_R
@ -5,3 +6,28 @@ void qsort_r(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg);
#endif
#ifdef HAVE_BROKEN_QSORT_R
struct __portable_qsort_r_compat_arg {
int (*compar)(const void *, const void *, void *);
void *arg;
};
static inline int __portable_qsort_r_compar_compat(void *arg, const void *a, const void *b)
{
struct __portable_qsort_r_compat_arg *compat_arg = arg;
return compat_arg->compar(a, b, compat_arg->arg);
}
static inline void __portable_qsort_r(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg)
{
struct __portable_qsort_r_compat_arg compat_arg = {
.compar = compar,
.arg = arg,
};
qsort_r(base, nmemb, size, &compat_arg, __portable_qsort_r_compar_compat);
}
#define qsort_r(...) __portable_qsort_r(__VA_ARGS__)
#endif

View File

@ -15,12 +15,15 @@ OPENSSL_LIBS := $(shell $(PKG_CONFIG) --libs openssl)
ZLIB_CFLAGS := $(shell $(PKG_CONFIG) --cflags zlib)
ZLIB_LIBS := $(shell $(PKG_CONFIG) --libs zlib)
SODIUM_FLAGS := $(shell $(PKG_CONFIG) --cflags libsodium)
SODIUM_LIBS := $(shell $(PKG_CONFIG) --libs libsodium)
# Dynamic library
libapk_soname := 2.99.0
libapk_so := $(obj)/libapk.so.$(libapk_soname)
libapk.so.$(libapk_soname)-objs := \
adb.o adb_comp.o adb_walk_adb.o adb_walk_genadb.o adb_walk_gentext.o adb_walk_text.o apk_adb.o \
atom.o blob.o commit.o common.o context.o crypto_openssl.o database.o hash.o \
atom.o blob.o commit.o common.o context.o crypto_core.o crypto_digest.o crypto_openssl.o database.o hash.o \
extract_v2.o extract_v3.o fs_fsys.o fs_uvol.o io.o io_gunzip.o io_url.o tar.o \
package.o pathbuilder.o print.o solver.o trust.o version.o
@ -90,9 +93,9 @@ LIBS_apk.static := -Wl,--as-needed -ldl -Wl,--no-as-needed
LDFLAGS_apk += -L$(obj)
LDFLAGS_apk-test += -L$(obj)
CFLAGS_ALL += $(OPENSSL_CFLAGS) $(ZLIB_CFLAGS)
CFLAGS_ALL += $(OPENSSL_CFLAGS) $(ZLIB_CFLAGS) $(SODIUM_CFLAGS)
LIBS := -Wl,--as-needed \
$(OPENSSL_LIBS) $(ZLIB_LIBS) \
$(OPENSSL_LIBS) $(ZLIB_LIBS) $(SODIUM_LIBS) \
-Wl,--no-as-needed
# Help generation

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");
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

@ -10,26 +10,39 @@
#define APK_CRYPTO_H
#include <assert.h>
#include <string.h>
#include <openssl/evp.h>
#include <string.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;
EVP_MD_CTX *mdctx;
};
#define APK_DIGEST_NONE 0x00
#define APK_DIGEST_MD5 0x01
#define APK_DIGEST_SHA1 0x02
#define APK_DIGEST_SHA256 0x03
#define APK_DIGEST_SHA512 0x04
#define APK_DIGEST_SHA256_160 0x05
#define APK_DIGEST_NONE 0x00
#define APK_DIGEST_MD5 0x01
#define APK_DIGEST_SHA1 0x02
#define APK_DIGEST_SHA256 0x03
#define APK_DIGEST_SHA512 0x04
#define APK_DIGEST_SHA256_160 0x05
#define APK_DIGEST_MAX_LENGTH 64 // longest is SHA512
#define APK_DIGEST_MAX_LENGTH 64 // longest is SHA512
#define APK_PKEY_ED25519 0x00
#define APK_PKEY_RSAPKCS1v15 0x01
#define APK_PKEY_TYPE_PUBLIC 0x00
#define APK_PKEY_TYPE_SECRET 0x01
// includes '\0'
#define APK_PKEY_CUTE_PUBLIC_SIZE 69
#define APK_PKEY_CUTE_SECRET_SIZE 113
const char *apk_digest_alg_str(uint8_t);
uint8_t apk_digest_alg_from_csum(int);
@ -39,16 +52,22 @@ struct apk_digest {
uint8_t data[APK_DIGEST_MAX_LENGTH];
};
#define APK_DIGEST_BLOB(d) APK_BLOB_PTR_LEN((void*)((d).data), (d).len)
#define APK_DIGEST_BLOB(d) APK_BLOB_PTR_LEN((void *) ((d).data), (d).len)
static inline const EVP_MD *apk_digest_alg_to_evp(uint8_t alg) {
static inline const EVP_MD *apk_digest_alg_to_evp(uint8_t alg)
{
switch (alg) {
case APK_DIGEST_NONE: return EVP_md_null();
case APK_DIGEST_MD5: return EVP_md5();
case APK_DIGEST_SHA1: return EVP_sha1();
case APK_DIGEST_NONE:
return EVP_md_null();
case APK_DIGEST_MD5:
return EVP_md5();
case APK_DIGEST_SHA1:
return EVP_sha1();
case APK_DIGEST_SHA256_160:
case APK_DIGEST_SHA256: return EVP_sha256();
case APK_DIGEST_SHA512: return EVP_sha512();
case APK_DIGEST_SHA256:
return EVP_sha256();
case APK_DIGEST_SHA512:
return EVP_sha512();
default:
assert(alg);
return EVP_md_null();
@ -58,21 +77,27 @@ static inline const EVP_MD *apk_digest_alg_to_evp(uint8_t alg) {
int apk_digest_alg_len(uint8_t alg);
uint8_t apk_digest_alg_by_len(int len);
static inline int apk_digest_cmp(struct apk_digest *a, struct apk_digest *b) {
if (a->alg != b->alg) return b->alg - a->alg;
static inline int apk_digest_cmp(struct apk_digest *a, struct apk_digest *b)
{
if (a->alg != b->alg)
return b->alg - a->alg;
return memcmp(a->data, b->data, a->len);
}
static inline void apk_digest_reset(struct apk_digest *d) {
static inline void apk_digest_reset(struct apk_digest *d)
{
d->alg = APK_DIGEST_NONE;
d->len = 0;
}
static inline void apk_digest_set(struct apk_digest *d, uint8_t alg) {
static inline void apk_digest_set(struct apk_digest *d, uint8_t alg)
{
d->alg = alg;
d->len = apk_digest_alg_len(alg);
}
int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void *ptr, size_t sz);
/*
static inline int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void *ptr, size_t sz)
{
unsigned int md_sz = sizeof d->data;
@ -82,45 +107,14 @@ static inline int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void
d->len = apk_digest_alg_len(alg);
return 0;
}
*/
static inline int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg) {
dctx->alg = alg;
dctx->mdctx = EVP_MD_CTX_new();
if (!dctx->mdctx) return -ENOMEM;
#ifdef EVP_MD_CTX_FLAG_FINALISE
EVP_MD_CTX_set_flags(dctx->mdctx, EVP_MD_CTX_FLAG_FINALISE);
#endif
if (alg != APK_DIGEST_NONE) EVP_DigestInit_ex(dctx->mdctx, apk_digest_alg_to_evp(alg), 0);
return 0;
}
int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg);
void apk_digest_ctx_reset(struct apk_digest_ctx *dctx, uint8_t alg);
void apk_digest_ctx_free(struct apk_digest_ctx *dctx);
int apk_digest_ctx_update(struct apk_digest_ctx *dctx, const void *ptr, size_t sz);
int apk_digest_ctx_final(struct apk_digest_ctx *dctx, struct apk_digest *d);
static inline void apk_digest_ctx_reset(struct apk_digest_ctx *dctx, uint8_t alg)
{
dctx->alg = alg;
EVP_DigestInit_ex(dctx->mdctx, apk_digest_alg_to_evp(alg), 0);
}
static inline void apk_digest_ctx_free(struct apk_digest_ctx *dctx) {
EVP_MD_CTX_free(dctx->mdctx);
dctx->mdctx = 0;
}
static inline int apk_digest_ctx_update(struct apk_digest_ctx *dctx, const void *ptr, size_t sz) {
return EVP_DigestUpdate(dctx->mdctx, ptr, sz) == 1 ? 0 : -APKE_CRYPTO_ERROR;
}
static inline int apk_digest_ctx_final(struct apk_digest_ctx *dctx, struct apk_digest *d) {
unsigned int mdlen = sizeof d->data;
if (EVP_DigestFinal_ex(dctx->mdctx, d->data, &mdlen) != 1) {
apk_digest_reset(d);
return -APKE_CRYPTO_ERROR;
}
d->alg = dctx->alg;
d->len = apk_digest_alg_len(d->alg);
return 0;
}
#include "apk_blob.h"
uint8_t apk_digest_from_blob(struct apk_digest *d, apk_blob_t b);
static inline int apk_digest_cmp_csum(const struct apk_digest *d, const struct apk_checksum *csum)
{
@ -139,13 +133,14 @@ static inline void apk_checksum_from_digest(struct apk_checksum *csum, const str
// Asymmetric keys
struct apk_pkey {
uint8_t id[16];
EVP_PKEY *key;
uint8_t type;
uint8_t alg;
uint8_t id[16];
void *impl;
};
int apk_pkey_init(struct apk_pkey *pkey, EVP_PKEY *key);
void apk_pkey_free(struct apk_pkey *pkey);
int apk_pkey_load(struct apk_pkey *pkey, int dirfd, const char *fn);
void apk_pkey_free(struct apk_pkey *pkey);
// Signing
@ -156,31 +151,6 @@ int apk_verify(struct apk_digest_ctx *, void *, size_t);
// Initializiation
#if OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
static inline void apk_crypto_cleanup(void)
{
EVP_cleanup();
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif
CRYPTO_cleanup_all_ex_data();
}
static inline void apk_crypto_init(void)
{
atexit(apk_crypto_cleanup);
OpenSSL_add_all_algorithms();
#ifndef OPENSSL_NO_ENGINE
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
#endif
}
#else
static inline void apk_crypto_init(void) {}
#endif
int apk_crypto_init(void);
#endif

View File

@ -18,6 +18,7 @@
#include "apk_atom.h"
#include "apk_crypto.h"
int apk_make_dirs(int root_fd, const char *dirname, mode_t dirmode, mode_t parentmode);
ssize_t apk_write_fully(int fd, const void *ptr, size_t size);
struct apk_id_hash {

View File

@ -81,32 +81,26 @@ static int non_repository_check(struct apk_database *db)
return 1;
}
static struct apk_package *create_virtual_package(struct apk_database *db, struct apk_name *name)
static struct apk_package *create_virtual_package(struct apk_database *db, struct apk_dependency *dep)
{
char ver[32];
struct apk_package *virtpkg;
struct apk_digest_ctx dctx;
struct apk_digest d;
struct tm tm;
time_t now = time(NULL);
pid_t pid = getpid();
gmtime_r(&now, &tm);
strftime(ver, sizeof ver, "%Y%m%d.%H%M%S", &tm);
virtpkg = apk_pkg_new();
if (virtpkg == NULL) return 0;
virtpkg->name = name;
virtpkg->version = apk_atomize_dup(&db->atoms, APK_BLOB_STR(ver));
virtpkg->name = dep->name;
virtpkg->version = dep->version;
virtpkg->description = strdup("virtual meta package");
virtpkg->arch = apk_atomize(&db->atoms, APK_BLOB_STR("noarch"));
virtpkg->repos |= BIT(APK_REPOSITORY_CACHED);
apk_digest_ctx_init(&dctx, APK_DIGEST_SHA1);
apk_digest_ctx_update(&dctx, &tm, sizeof tm);
apk_digest_ctx_update(&dctx, &pid, sizeof pid);
apk_digest_ctx_update(&dctx, virtpkg->name->name, strlen(virtpkg->name->name) + 1);
apk_digest_ctx_update(&dctx, dep->version->ptr, dep->version->len);
apk_digest_ctx_final(&dctx, &d);
apk_digest_ctx_free(&dctx);
apk_checksum_from_digest(&virtpkg->csum, &d);
@ -114,6 +108,17 @@ static struct apk_package *create_virtual_package(struct apk_database *db, struc
return virtpkg;
}
static apk_blob_t *generate_version(struct apk_database *db)
{
char ver[32];
struct tm tm;
time_t now = time(NULL);
gmtime_r(&now, &tm);
strftime(ver, sizeof ver, "%Y%m%d.%H%M%S", &tm);
return apk_atomize_dup(&db->atoms, APK_BLOB_STR(ver));
}
static int add_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *args)
{
struct apk_out *out = &ac->out;
@ -133,24 +138,32 @@ static int add_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *args
if (actx->virtpkg) {
apk_blob_t b = APK_BLOB_STR(actx->virtpkg);
apk_blob_pull_dep(&b, db, &virtdep);
if (APK_BLOB_IS_NULL(b) || virtdep.conflict ||
virtdep.result_mask != APK_DEPMASK_ANY ||
virtdep.version != &apk_atom_null) {
(virtdep.name->name[0] != '.' && non_repository_check(db)))
goto bad_spec;
switch (virtdep.result_mask) {
case APK_DEPMASK_ANY:
if (virtdep.version != &apk_atom_null) goto bad_spec;
virtdep.result_mask = APK_VERSION_EQUAL;
virtdep.version = generate_version(db);
break;
case APK_VERSION_EQUAL:
if (virtdep.version == &apk_atom_null) goto bad_spec;
break;
default:
bad_spec:
apk_err(out, "%s: bad package specifier", actx->virtpkg);
return -1;
}
if (virtdep.name->name[0] != '.' && non_repository_check(db))
return -1;
virtpkg = create_virtual_package(db, virtdep.name);
virtpkg = create_virtual_package(db, &virtdep);
if (!virtpkg) {
apk_err(out, "Failed to allocate virtual meta package");
return -1;
}
virtdep.result_mask = APK_VERSION_EQUAL;
virtdep.version = virtpkg->version;
if (!args->num) apk_warn(out, "creating empty virtual package");
}

View File

@ -20,10 +20,11 @@
#include "apk_print.h"
#include "apk_solver.h"
#define FETCH_RECURSIVE 1
#define FETCH_STDOUT 2
#define FETCH_LINK 4
#define FETCH_URL 8
#define FETCH_RECURSIVE 0x01
#define FETCH_STDOUT 0x02
#define FETCH_LINK 0x04
#define FETCH_URL 0x08
#define FETCH_WORLD 0x10
struct fetch_ctx {
unsigned int flags;
@ -75,6 +76,7 @@ static int cup(void)
OPT(OPT_FETCH_simulate, "simulate") \
OPT(OPT_FETCH_stdout, APK_OPT_SH("s") "stdout") \
OPT(OPT_FETCH_url, "url") \
OPT(OPT_FETCH_world, APK_OPT_SH("w") "world") \
APK_OPT_APPLET(option_desc, FETCH_OPTIONS);
@ -101,6 +103,10 @@ static int option_parse_applet(void *ctx, struct apk_ctx *ac, int opt, const cha
case OPT_FETCH_url:
fctx->flags |= FETCH_URL;
break;
case OPT_FETCH_world:
fctx->flags |= FETCH_WORLD | FETCH_RECURSIVE;
ac->open_flags &= ~APK_OPENF_NO_WORLD;
break;
default:
return -ENOTSUP;
}
@ -218,6 +224,12 @@ static void mark_error(struct fetch_ctx *ctx, const char *match, struct apk_name
ctx->errors++;
}
static void mark_dep_flags(struct fetch_ctx *ctx, struct apk_dependency *dep)
{
dep->name->auto_select_virtual = 1;
apk_deps_add(&ctx->world, dep);
}
static void mark_name_flags(struct apk_database *db, const char *match, struct apk_name *name, void *pctx)
{
struct fetch_ctx *ctx = (struct fetch_ctx *) pctx;
@ -228,8 +240,7 @@ static void mark_name_flags(struct apk_database *db, const char *match, struct a
};
if (name) {
name->auto_select_virtual = 1;
apk_deps_add(&ctx->world, &dep);
mark_dep_flags(ctx, &dep);
} else {
ctx->errors++;
mark_error(ctx, match, name);
@ -310,6 +321,7 @@ static int fetch_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
struct apk_out *out = &ac->out;
struct apk_database *db = ac->db;
struct fetch_ctx *ctx = (struct fetch_ctx *) pctx;
struct apk_dependency *dep;
ctx->db = db;
ctx->prog = db->ctx->progress;
@ -329,6 +341,8 @@ static int fetch_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
if (ctx->flags & FETCH_RECURSIVE) {
apk_dependency_array_init(&ctx->world);
foreach_array_item(dep, db->world)
mark_dep_flags(ctx, dep);
apk_name_foreach_matching(db, args, apk_foreach_genid(), mark_name_flags, ctx);
if (ctx->errors == 0)
mark_names_recursive(db, args, ctx);
@ -349,7 +363,7 @@ static int fetch_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
static struct apk_applet apk_fetch = {
.name = "fetch",
.open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE,
.open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE,
.context_size = sizeof(struct fetch_ctx),
.optgroups = { &optgroup_global, &optgroup_applet },
.main = fetch_main,

View File

@ -74,8 +74,7 @@ int apk_ctx_prepare(struct apk_ctx *ac)
const int lflags = O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC;
int fd = openat(ac->root_fd, log_path, lflags, 0644);
if (fd < 0 && (ac->open_flags & APK_OPENF_CREATE)) {
mkdirat(ac->root_fd, "var", 0755);
mkdirat(ac->root_fd, "var/log", 0755);
apk_make_dirs(ac->root_fd, "var/log", 0755, 0755);
fd = openat(ac->root_fd, log_path, lflags, 0644);
}
if (fd < 0) {

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

209
src/crypto_digest.c Normal file
View File

@ -0,0 +1,209 @@
#include <sodium.h>
#include "apk_crypto.h"
/*
static inline int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg) {
dctx->alg = alg;
dctx->mdctx = EVP_MD_CTX_new();
if (!dctx->mdctx) return -ENOMEM;
#ifdef EVP_MD_CTX_FLAG_FINALISE
EVP_MD_CTX_set_flags(dctx->mdctx, EVP_MD_CTX_FLAG_FINALISE);
#endif
if (alg != APK_DIGEST_NONE) EVP_DigestInit_ex(dctx->mdctx, apk_digest_alg_to_evp(alg), 0);
return 0;
}
*/
union digest_state {
crypto_hash_sha256_state sha256;
crypto_hash_sha512_state sha512;
EVP_MD_CTX *mdctx;
};
static const char *apk_digest_str[] = {
[APK_DIGEST_NONE] = "none",
[APK_DIGEST_MD5] = "md5",
[APK_DIGEST_SHA1] = "sha1",
[APK_DIGEST_SHA256_160] = "sha256-160",
[APK_DIGEST_SHA256] = "sha256",
[APK_DIGEST_SHA512] = "sha512",
};
const char *apk_digest_alg_str(uint8_t alg)
{
const char *alg_str = "unknown";
if (alg < ARRAY_SIZE(apk_digest_str))
alg_str = apk_digest_str[alg];
return alg_str;
}
int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void *ptr, size_t sz)
{
switch (alg) {
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA256_160:
crypto_hash_sha256(d->data, ptr, sz);
break;
case APK_DIGEST_SHA512:
crypto_hash_sha512(d->data, ptr, sz);
break;
case APK_DIGEST_NONE:
break;
case APK_DIGEST_MD5:
break;
case APK_DIGEST_SHA1:
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
d->alg = alg;
return 0;
}
int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg)
{
union digest_state *state = NULL;
const EVP_MD *evp_md = NULL;
dctx->impl = malloc(sizeof(union digest_state));
if (dctx->impl == NULL) {
return -ENOMEM;
}
state = (union digest_state *) dctx->impl;
dctx->alg = alg;
switch (alg) {
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA256_160:
crypto_hash_sha256_init(&state->sha256);
break;
case APK_DIGEST_SHA512:
crypto_hash_sha512_init(&state->sha512);
break;
case APK_DIGEST_NONE:
evp_md = EVP_md_null();
case APK_DIGEST_MD5:
evp_md = EVP_md5();
break;
case APK_DIGEST_SHA1:
evp_md = EVP_sha1();
break;
default:
free(dctx->impl);
return -APKE_CRYPTO_NOT_SUPPORTED;
}
if (evp_md != NULL) {
state->mdctx = EVP_MD_CTX_new();
if (state->mdctx == NULL) {
goto a;
}
#ifdef EVP_MD_CTX_FLAG_FINALISE
EVP_MD_CTX_set_flags(dctx->mdctx, EVP_MD_CTX_FLAG_FINALISE);
#endif
EVP_DigestInit_ex(dctx->mdctx, apk_digest_alg_to_evp(alg), 0);
}
return 0;
a:
free(dctx->impl);
return -APKE_CRYPTO_ERROR;
}
void apk_digest_ctx_reset(struct apk_digest_ctx *dctx, uint8_t alg)
{
apk_digest_ctx_free(dctx);
apk_digest_ctx_init(dctx, alg);
}
void apk_digest_ctx_free(struct apk_digest_ctx *dctx)
{
union digest_state *state = (union digest_state *) dctx->impl;
if (dctx->impl == NULL) {
return;
}
switch (dctx->alg) {
case APK_DIGEST_NONE:
case APK_DIGEST_MD5:
case APK_DIGEST_SHA1:
EVP_MD_CTX_free(state->mdctx);
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA512:
case APK_DIGEST_SHA256_160:
break;
default:
/* illegal state, don't touch impl? */
return;
}
free(dctx->impl);
dctx->impl = NULL;
}
int apk_digest_ctx_update(struct apk_digest_ctx *dctx, const void *ptr, size_t sz)
{
union digest_state *state = (union digest_state *) dctx->impl;
switch (dctx->alg) {
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA256_160:
crypto_hash_sha256_update(&state->sha256, ptr, sz);
break;
case APK_DIGEST_SHA512:
crypto_hash_sha512_update(&state->sha512, ptr, sz);
break;
case APK_DIGEST_NONE:
case APK_DIGEST_MD5:
case APK_DIGEST_SHA1:
if (EVP_DigestUpdate(state->mdctx, ptr, sz) != 1) {
return -APKE_CRYPTO_ERROR;
}
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
return 0;
}
int apk_digest_ctx_final(struct apk_digest_ctx *dctx, struct apk_digest *d)
{
union digest_state *state = dctx->impl;
unsigned int mdlen;
switch (dctx->alg) {
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA256_160:
crypto_hash_sha256_final(&state->sha256, d->data);
break;
case APK_DIGEST_SHA512:
crypto_hash_sha512_final(&state->sha512, d->data);
break;
case APK_DIGEST_NONE:
case APK_DIGEST_MD5:
case APK_DIGEST_SHA1:
mdlen = sizeof d->data;
if (EVP_DigestFinal_ex(state->mdctx, d->data, &mdlen) != 1) {
apk_digest_reset(d);
return -APKE_CRYPTO_ERROR;
}
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
d->alg = dctx->alg;
d->len = apk_digest_alg_len(d->alg);
return 0;
}

View File

@ -7,23 +7,6 @@
#include "apk_crypto.h"
static const char *apk_digest_str[] = {
[APK_DIGEST_NONE] = "none",
[APK_DIGEST_MD5] = "md5",
[APK_DIGEST_SHA1] = "sha1",
[APK_DIGEST_SHA256_160] = "sha256-160",
[APK_DIGEST_SHA256] = "sha256",
[APK_DIGEST_SHA512] = "sha512",
};
const char *apk_digest_alg_str(uint8_t alg)
{
const char *alg_str = "unknown";
if (alg < ARRAY_SIZE(apk_digest_str))
alg_str = apk_digest_str[alg];
return alg_str;
}
int apk_digest_alg_len(uint8_t alg)
{
switch (alg) {

232
src/crypto_sign.c Normal file
View File

@ -0,0 +1,232 @@
#include <fcntl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <sodium.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "apk_crypto.h"
union pkey_state {
unsigned char cute_pk[crypto_sign_ed25519_PUBLICKEYBYTES];
unsigned char cute_sk[crypto_sign_ed25519_SECRETKEYBYTES];
EVP_PKEY *pkey;
};
static int load_openssl(int fd, struct apk_pkey *pkey)
{
int r = -APKE_CRYPTO_KEY_FORMAT;
union pkey_state *state;
BIO *bio;
pkey->impl = malloc(sizeof(union pkey_state));
if (pkey->impl == NULL) {
r = -ENOMEM;
goto err_alloc;
}
bio = BIO_new_fd(fd, BIO_NOCLOSE);
if (bio == NULL) {
r = -ENOMEM;
goto err_bio_new;
}
state = (union pkey_state *) pkey->impl;
pkey->type = APK_PKEY_TYPE_PUBLIC;
state->pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
if (state->pkey == NULL) {
pkey->type = APK_PKEY_TYPE_SECRET;
BIO_reset(bio);
state->pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
}
ERR_clear_error();
if (state->pkey == NULL) {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err_load;
}
BIO_free(bio);
return 0;
err_load:
BIO_free(bio);
err_bio_new:
free(pkey->impl);
err_alloc:
return r;
}
static int load_public_cute(int fd, struct apk_pkey *pkey)
{
char b64[APK_PKEY_CUTE_PUBLIC_SIZE];
int r = -APKE_CRYPTO_KEY_FORMAT;
union pkey_state *state;
uint8_t raw[50]; // 2 + 16 + 32
size_t len;
pkey->impl = malloc(sizeof(union pkey_state));
if (pkey->impl == NULL) {
r = -ENOMEM;
goto err_alloc;
}
state = (union pkey_state *) pkey->impl;
if (read(fd, b64, APK_PKEY_CUTE_PUBLIC_SIZE) != APK_PKEY_CUTE_PUBLIC_SIZE) {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err_read;
}
if (sodium_base642bin(raw,
50,
b64,
APK_PKEY_CUTE_PUBLIC_SIZE,
NULL,
&len,
NULL,
sodium_base64_VARIANT_URLSAFE)
!= 0) {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err_b64decode;
}
if (raw[0] != 'q' || raw[1] != 't') {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err_rawheader;
}
pkey->type = APK_PKEY_TYPE_PUBLIC;
pkey->alg = APK_PKEY_ED25519;
memcpy(pkey->id, raw + 2, 16);
memcpy(state->cute_pk, raw + 18, crypto_sign_ed25519_PUBLICKEYBYTES);
return 0;
err_rawheader:
err_b64decode:
err_read:
free(pkey->impl);
err_alloc:
return r;
}
static int load_secret_cute(int fd, struct apk_pkey *pkey)
{
char b64[APK_PKEY_CUTE_SECRET_SIZE];
int r = -APKE_CRYPTO_KEY_FORMAT;
union pkey_state *state;
uint8_t raw[82]; // 2 + 16 + 64
size_t len;
pkey->impl = malloc(sizeof(union pkey_state));
if (pkey->impl == NULL) {
r = -ENOMEM;
goto err_alloc;
}
state = (union pkey_state *) pkey->impl;
if (read(fd, b64, APK_PKEY_CUTE_SECRET_SIZE) != APK_PKEY_CUTE_SECRET_SIZE) {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err_read;
}
if (sodium_base642bin(raw,
82,
b64,
APK_PKEY_CUTE_PUBLIC_SIZE,
NULL,
&len,
NULL,
sodium_base64_VARIANT_URLSAFE)
!= 0) {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err_b64decode;
}
if (len != 82) {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err_decodelen;
}
if (raw[0] != 'q' || raw[1] != 't') {
r = -APKE_CRYPTO_KEY_FORMAT;
goto err_rawheader;
}
pkey->type = APK_PKEY_TYPE_SECRET;
pkey->alg = APK_PKEY_ED25519;
memcpy(pkey->id, raw + 2, 16);
memcpy(state->cute_sk, raw + 18, crypto_sign_ed25519_SECRETKEYBYTES);
return 0;
err_rawheader:
err_decodelen:
err_b64decode:
err_read:
free(pkey->impl);
err_alloc:
return r;
}
void apk_pkey_free(struct apk_pkey *pkey)
{
union pkey_state *state = (union pkey_state *) pkey->impl;
switch (pkey->alg) {
case APK_PKEY_ED25519:
break;
case APK_PKEY_RSAPKCS1v15:
EVP_PKEY_free(state->pkey);
break;
default:
/* invalid state, don't touch impl */
return;
}
free(pkey->impl);
pkey->impl = NULL;
}
int apk_pkey_load(struct apk_pkey *pkey, int dirfd, const char *fn)
{
struct stat st;
int fd, r = 0;
fd = openat(dirfd, fn, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
r = -errno;
goto err_openat;
}
if (fstat(fd, &st) != 0) {
r = -errno;
goto err_fstat;
}
switch (st.st_size) {
case APK_PKEY_CUTE_SECRET_SIZE:
r = load_secret_cute(fd, pkey);
break;
case APK_PKEY_CUTE_PUBLIC_SIZE:
r = load_public_cute(fd, pkey);
break;
default:
r = load_openssl(fd, pkey);
break;
}
err_fstat:
close(fd);
err_openat:
return r;
}

View File

@ -1451,9 +1451,7 @@ static inline int setup_static_cache(struct apk_database *db, struct apk_ctx *ac
db->cache_dir = apk_static_cache_dir;
db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY | O_CLOEXEC);
if (db->cache_fd < 0) {
mkdirat(db->root_fd, "var", 0755);
mkdirat(db->root_fd, "var/cache", 0755);
mkdirat(db->root_fd, "var/cache/apk", 0755);
apk_make_dirs(db->root_fd, db->cache_dir, 0755, 0755);
db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY | O_CLOEXEC);
if (db->cache_fd < 0) {
if (ac->open_flags & APK_OPENF_WRITE) return -EROFS;
@ -1884,15 +1882,8 @@ int apk_db_write_config(struct apk_database *db)
return 0;
if (db->ctx->open_flags & APK_OPENF_CREATE) {
if (faccessat(db->root_fd, "lib/apk/db", F_OK, 0) != 0) {
mkdirat(db->root_fd, "lib", 0755);
mkdirat(db->root_fd, "lib/apk", 0755);
mkdirat(db->root_fd, "lib/apk/db", 0755);
}
if (faccessat(db->root_fd, "etc/apk", F_OK, 0) != 0) {
mkdirat(db->root_fd, "etc", 0755);
mkdirat(db->root_fd, "etc/apk", 0755);
}
apk_make_dirs(db->root_fd, "lib/apk/db", 0755, 0755);
apk_make_dirs(db->root_fd, "etc/apk", 0755, 0755);
} else if (db->lock_fd == 0) {
apk_err(out, "Refusing to write db without write lock!");
return -1;

View File

@ -38,6 +38,21 @@ static inline int atfd_error(int atfd)
return atfd < -1 && atfd != AT_FDCWD;
}
int apk_make_dirs(int root_fd, const char *dirname, mode_t dirmode, mode_t parentmode)
{
char parentdir[PATH_MAX], *slash;
if (faccessat(root_fd, dirname, F_OK, 0) == 0) return 0;
if (mkdirat(root_fd, dirname, dirmode) == 0) return 0;
if (errno != ENOENT || !parentmode) return -1;
slash = strrchr(dirname, '/');
if (!slash || slash == dirname || slash-dirname+1 >= sizeof parentdir) return -1;
strlcpy(parentdir, dirname, slash-dirname+1);
if (apk_make_dirs(root_fd, parentdir, parentmode, parentmode) < 0) return -1;
return mkdirat(root_fd, dirname, dirmode);
}
ssize_t apk_write_fully(int fd, const void *ptr, size_t size)
{
ssize_t i = 0, r;

View File

@ -12,6 +12,8 @@ libapk_src = [
'commit.c',
'common.c',
'context.c',
'crypto_core.c',
'crypto_digest.c',
'crypto_openssl.c',
'database.c',
'extract_v2.c',

View File

@ -768,21 +768,6 @@ int apk_ipkg_add_script(struct apk_installed_package *ipkg,
return apk_ipkg_assign_script(ipkg, type, apk_blob_from_istream(is, size));
}
static inline int make_dirs(int root_fd, const char *dirname, mode_t dirmode, mode_t parentmode)
{
char parentdir[PATH_MAX], *slash;
if (faccessat(root_fd, dirname, F_OK, 0) == 0) return 0;
if (mkdirat(root_fd, dirname, dirmode) == 0) return 0;
if (errno != ENOENT || !parentmode) return -1;
slash = strrchr(dirname, '/');
if (!slash || slash == dirname || slash-dirname+1 >= sizeof parentdir) return -1;
strlcpy(parentdir, dirname, slash-dirname+1);
if (make_dirs(root_fd, parentdir, parentmode, parentmode) < 0) return -1;
return mkdirat(root_fd, dirname, dirmode);
}
#ifdef __linux__
static inline int make_device_tree(struct apk_database *db)
{
@ -834,8 +819,8 @@ void apk_ipkg_run_script(struct apk_installed_package *ipkg,
return;
if (!db->script_dirs_checked) {
if (make_dirs(root_fd, "tmp", 01777, 0) <0 ||
make_dirs(root_fd, script_exec_dir, 0700, 0755) < 0||
if (apk_make_dirs(root_fd, "tmp", 01777, 0) <0 ||
apk_make_dirs(root_fd, script_exec_dir, 0700, 0755) < 0||
make_device_tree(db) < 0) {
apk_err(out, "failed to prepare dirs for hook scripts: %s",
apk_error_str(errno));