summaryrefslogtreecommitdiff
path: root/src/crypto_openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto_openssl.c')
-rw-r--r--src/crypto_openssl.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/crypto_openssl.c b/src/crypto_openssl.c
new file mode 100644
index 0000000..97d80b8
--- /dev/null
+++ b/src/crypto_openssl.c
@@ -0,0 +1,112 @@
+#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;
+}
+
+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;
+ }
+}
+
+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 -EIO;
+ 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 -EBADMSG;
+
+ apk_pkey_init(pkey, key);
+ return 0;
+}
+
+int apk_sign_start(struct apk_digest_ctx *dctx, struct apk_pkey *pkey)
+{
+ EVP_MD_CTX_set_pkey_ctx(dctx->mdctx, NULL);
+ if (EVP_DigestSignInit(dctx->mdctx, NULL, EVP_sha512(), NULL, pkey->key) != 1)
+ return -EIO;
+ return 0;
+}
+
+int apk_sign(struct apk_digest_ctx *dctx, void *sig, size_t *len)
+{
+ if (EVP_DigestSignFinal(dctx->mdctx, sig, len) != 1)
+ return -EBADMSG;
+ return 0;
+}
+
+int apk_verify_start(struct apk_digest_ctx *dctx, struct apk_pkey *pkey)
+{
+ EVP_MD_CTX_set_pkey_ctx(dctx->mdctx, NULL);
+ if (EVP_DigestVerifyInit(dctx->mdctx, NULL, EVP_sha512(), NULL, pkey->key) != 1)
+ return -EIO;
+ 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 -EBADMSG;
+ }
+ return 0;
+}