summaryrefslogtreecommitdiff
path: root/src/apk_crypto.h
blob: d3ce24bc57541bf04bd55cec84f69e5df3a01223 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* apk_crypt.c - Alpine Package Keeper (APK)
 *
 * Copyright (C) 2021 Timo Teräs <timo.teras@iki.fi>
 * All rights reserved.
 *
 * SPDX-License-Identifier: GPL-2.0-only
 */

#ifndef APK_CRYPTO_H
#define APK_CRYPTO_H

#include <assert.h>
#include <string.h>
#include <openssl/evp.h>
#include "apk_defines.h"
#include "apk_openssl.h"

// Digest

struct apk_digest_ctx {
	EVP_MD_CTX *mdctx;
	uint8_t alg;
};

#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_MAX_LENGTH	64	// longest is SHA512

const char *apk_digest_alg_str(uint8_t);
uint8_t apk_digest_alg_from_csum(int);

struct apk_digest {
	uint8_t alg, 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:	return EVP_sha256();
	case APK_DIGEST_SHA512:	return EVP_sha512();
	default:
		assert(alg);
		return EVP_md_null();
	}
}

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;
	return memcmp(a->data, b->data, a->len);
}

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) {
	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 = md_sz;
	return 0;
}

static inline int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg) {
	dctx->mdctx = EVP_MD_CTX_new();
	if (!dctx->mdctx) return -ENOMEM;
	dctx->alg = alg;
#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;
}

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 = mdlen;
	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));
}
static inline void apk_checksum_from_digest(struct apk_checksum *csum, const struct apk_digest *d)
{
	csum->type = d->len;
	memcpy(csum->data, d->data, d->len);
}

// Asymmetric keys

struct apk_pkey {
	uint8_t		id[16];
	EVP_PKEY	*key;
};

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

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

// 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

#endif