summaryrefslogtreecommitdiff
path: root/src/crypto_openssl.c
blob: b32f23875530d50ba74dbf085d5a43427489ec32 (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
#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]	= "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:	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) {
		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;
}