404 lines
14 KiB
Diff
404 lines
14 KiB
Diff
From e91e17901e0398b9a55850123ffe2cc4a0d04f34 Mon Sep 17 00:00:00 2001
|
|
From: Juergen Christ <jchrist@linux.ibm.com>
|
|
Date: Wed, 9 Mar 2022 13:17:18 +0100
|
|
Subject: [PATCH] PKEY: Fix usage of ECX keys
|
|
|
|
ED25519, ED448, X25519, and X448 caused a segmentation fault due to wrong
|
|
usage of ECX keys.
|
|
|
|
Signed-off-by: Juergen Christ <jchrist@linux.ibm.com>
|
|
---
|
|
src/ibmca_pkey.c | 124 +++++++++++-----------------------------
|
|
src/openssl-compat.h | 131 +++++++++++++++++++++++++++++++++++++++++++
|
|
2 files changed, 164 insertions(+), 91 deletions(-)
|
|
create mode 100644 src/openssl-compat.h
|
|
|
|
diff --git a/src/ibmca_pkey.c b/src/ibmca_pkey.c
|
|
index e8ba9067..9c8de94c 100644
|
|
--- a/src/ibmca_pkey.c
|
|
+++ b/src/ibmca_pkey.c
|
|
@@ -22,65 +22,7 @@
|
|
#include "ibmca.h"
|
|
#include "e_ibmca_err.h"
|
|
|
|
-/*
|
|
- * copied from evp_int.h:
|
|
- * missing set/get methods for opaque types.
|
|
- */
|
|
-
|
|
-typedef struct {
|
|
- unsigned char pub[57];
|
|
- unsigned char *priv;
|
|
-} ECX_KEY;
|
|
-
|
|
-typedef struct evp_pkey_method_st {
|
|
- int pkey_id;
|
|
- int flags;
|
|
- int (*init) (EVP_PKEY_CTX *ctx);
|
|
- int (*copy) (EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src);
|
|
- void (*cleanup) (EVP_PKEY_CTX *ctx);
|
|
- int (*paramgen_init) (EVP_PKEY_CTX *ctx);
|
|
- int (*paramgen) (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
|
|
- int (*keygen_init) (EVP_PKEY_CTX *ctx);
|
|
- int (*keygen) (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
|
|
- int (*sign_init) (EVP_PKEY_CTX *ctx);
|
|
- int (*sign) (EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
|
|
- const unsigned char *tbs, size_t tbslen);
|
|
- int (*verify_init) (EVP_PKEY_CTX *ctx);
|
|
- int (*verify) (EVP_PKEY_CTX *ctx,
|
|
- const unsigned char *sig, size_t siglen,
|
|
- const unsigned char *tbs, size_t tbslen);
|
|
- int (*verify_recover_init) (EVP_PKEY_CTX *ctx);
|
|
- int (*verify_recover) (EVP_PKEY_CTX *ctx,
|
|
- unsigned char *rout, size_t *routlen,
|
|
- const unsigned char *sig, size_t siglen);
|
|
- int (*signctx_init) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
|
|
- int (*signctx) (EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
|
|
- EVP_MD_CTX *mctx);
|
|
- int (*verifyctx_init) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
|
|
- int (*verifyctx) (EVP_PKEY_CTX *ctx, const unsigned char *sig, int siglen,
|
|
- EVP_MD_CTX *mctx);
|
|
- int (*encrypt_init) (EVP_PKEY_CTX *ctx);
|
|
- int (*encrypt) (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
|
|
- const unsigned char *in, size_t inlen);
|
|
- int (*decrypt_init) (EVP_PKEY_CTX *ctx);
|
|
- int (*decrypt) (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
|
|
- const unsigned char *in, size_t inlen);
|
|
- int (*derive_init) (EVP_PKEY_CTX *ctx);
|
|
- int (*derive) (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
|
|
- int (*ctrl) (EVP_PKEY_CTX *ctx, int type, int p1, void *p2);
|
|
- int (*ctrl_str) (EVP_PKEY_CTX *ctx, const char *type, const char *value);
|
|
- int (*digestsign) (EVP_MD_CTX *ctx, unsigned char *sig, size_t *siglen,
|
|
- const unsigned char *tbs, size_t tbslen);
|
|
- int (*digestverify) (EVP_MD_CTX *ctx, const unsigned char *sig,
|
|
- size_t siglen, const unsigned char *tbs,
|
|
- size_t tbslen);
|
|
- int (*check) (EVP_PKEY *pkey);
|
|
- int (*public_check) (EVP_PKEY *pkey);
|
|
- int (*param_check) (EVP_PKEY *pkey);
|
|
-
|
|
- int (*digest_custom) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
|
|
-} EVP_PKEY_METHOD;
|
|
-
|
|
+#include "openssl-compat.h"
|
|
|
|
ica_x25519_ctx_new_t p_ica_x25519_ctx_new;
|
|
ica_x448_ctx_new_t p_ica_x448_ctx_new;
|
|
@@ -136,16 +78,16 @@ static int ibmca_x25519_keygen(EVP_PKEY_CTX *c, EVP_PKEY *pkey)
|
|
goto ret;
|
|
}
|
|
|
|
- key = calloc(1, sizeof(ECX_KEY));
|
|
+ key = ossl_ecx_key_new_simple(ECX_KEY_TYPE_X25519);
|
|
private = calloc(1, sizeof(priv));
|
|
- if (key == NULL) {
|
|
+ if (key == NULL || private == NULL) {
|
|
IBMCAerr(IBMCA_F_IBMCA_X25519_KEYGEN, IBMCA_R_PKEY_KEYGEN_FAILED);
|
|
goto ret;
|
|
}
|
|
|
|
memcpy(private, priv, sizeof(priv));
|
|
- memcpy(key, pub, sizeof(pub));
|
|
- key->priv = private;
|
|
+ ossl_ecx_copypubkey(key, pub, sizeof(pub));
|
|
+ ossl_ecx_set0_privkey(key, private);
|
|
|
|
EVP_PKEY_assign(pkey, NID_X25519, key);
|
|
rc = 1;
|
|
@@ -199,12 +141,12 @@ static int ibmca_x25519_derive(EVP_PKEY_CTX *pkey_ctx, unsigned char *key, size_
|
|
goto ret;
|
|
}
|
|
|
|
- if (p_ica_x25519_key_set(ctx, key_ecx->priv, NULL) != 0) {
|
|
+ if (p_ica_x25519_key_set(ctx, ossl_ecx_get0_privkey(key_ecx), NULL) != 0) {
|
|
IBMCAerr(IBMCA_F_IBMCA_X25519_DERIVE, IBMCA_R_PKEY_KEYS_NOT_SET);
|
|
- goto ret;;
|
|
+ goto ret;
|
|
}
|
|
|
|
- if (p_ica_x25519_derive(ctx, key, peerkey_ecx->pub) != 0)
|
|
+ if (p_ica_x25519_derive(ctx, key, ossl_ecx_get0_pubkey(peerkey_ecx)) != 0)
|
|
goto ret;
|
|
|
|
rc = 1;
|
|
@@ -236,16 +178,16 @@ static int ibmca_x448_keygen(EVP_PKEY_CTX *c, EVP_PKEY *pkey)
|
|
goto ret;
|
|
}
|
|
|
|
- key = calloc(1, sizeof(ECX_KEY));
|
|
+ key = ossl_ecx_key_new_simple(ECX_KEY_TYPE_X448);
|
|
private = calloc(1, sizeof(priv));
|
|
- if (key == NULL) {
|
|
+ if (key == NULL || private == NULL) {
|
|
IBMCAerr(IBMCA_F_IBMCA_X448_KEYGEN, IBMCA_R_PKEY_KEYGEN_FAILED);
|
|
goto ret;
|
|
}
|
|
|
|
memcpy(private, priv, sizeof(priv));
|
|
- memcpy(key, pub, sizeof(pub));
|
|
- key->priv = private;
|
|
+ ossl_ecx_copypubkey(key, pub, sizeof(pub));
|
|
+ ossl_ecx_set0_privkey(key, private);
|
|
|
|
EVP_PKEY_assign(pkey, NID_X448, key);
|
|
rc = 1;
|
|
@@ -299,12 +241,12 @@ static int ibmca_x448_derive(EVP_PKEY_CTX *pkey_ctx, unsigned char *key, size_t
|
|
goto ret;
|
|
}
|
|
|
|
- if (p_ica_x448_key_set(ctx, key_ecx->priv, NULL) != 0) {
|
|
+ if (p_ica_x448_key_set(ctx, ossl_ecx_get0_privkey(key_ecx), NULL) != 0) {
|
|
IBMCAerr(IBMCA_F_IBMCA_X448_DERIVE, IBMCA_R_PKEY_KEYS_NOT_SET);
|
|
- goto ret;;
|
|
+ goto ret;
|
|
}
|
|
|
|
- if (p_ica_x448_derive(ctx, key, peerkey_ecx->pub) != 0)
|
|
+ if (p_ica_x448_derive(ctx, key, ossl_ecx_get0_pubkey(peerkey_ecx)) != 0)
|
|
goto ret;
|
|
|
|
rc = 1;
|
|
@@ -341,16 +283,16 @@ static int ibmca_ed25519_keygen(EVP_PKEY_CTX *c, EVP_PKEY *pkey)
|
|
goto ret;
|
|
}
|
|
|
|
- key = calloc(1, sizeof(ECX_KEY));
|
|
+ key = ossl_ecx_key_new_simple(ECX_KEY_TYPE_ED25519);
|
|
private = calloc(1, sizeof(priv));
|
|
- if (key == NULL) {
|
|
+ if (key == NULL || private == NULL) {
|
|
IBMCAerr(IBMCA_F_IBMCA_ED25519_KEYGEN, IBMCA_R_PKEY_KEYGEN_FAILED);
|
|
goto ret;
|
|
}
|
|
|
|
memcpy(private, priv, sizeof(priv));
|
|
- memcpy(key, pub, sizeof(pub));
|
|
- key->priv = private;
|
|
+ ossl_ecx_copypubkey(key, pub, sizeof(pub));
|
|
+ ossl_ecx_set0_privkey(key, private);
|
|
|
|
EVP_PKEY_assign(pkey, NID_ED25519, key);
|
|
rc = 1;
|
|
@@ -398,9 +340,9 @@ static int ibmca_ed25519_sign(EVP_MD_CTX *md_ctx, unsigned char *sig,
|
|
goto ret;
|
|
}
|
|
|
|
- if (p_ica_ed25519_key_set(ctx, key_ecx->priv, NULL) != 0) {
|
|
+ if (p_ica_ed25519_key_set(ctx, ossl_ecx_get0_privkey(key_ecx), NULL) != 0) {
|
|
IBMCAerr(IBMCA_F_IBMCA_ED25519_SIGN, IBMCA_R_PKEY_KEYS_NOT_SET);
|
|
- goto ret;;
|
|
+ goto ret;
|
|
}
|
|
|
|
if (p_ica_ed25519_sign(ctx, sig, tbs, tbslen) != 0)
|
|
@@ -443,7 +385,7 @@ static int ibmca_ed25519_verify(EVP_MD_CTX *md_ctx, const unsigned char *sig,
|
|
goto ret;
|
|
}
|
|
|
|
- if (p_ica_ed25519_key_set(ctx, NULL, key_ecx->pub) != 0) {
|
|
+ if (p_ica_ed25519_key_set(ctx, NULL, ossl_ecx_get0_pubkey(key_ecx)) != 0) {
|
|
IBMCAerr(IBMCA_F_IBMCA_ED25519_VERIFY, IBMCA_R_PKEY_KEYS_NOT_SET);
|
|
goto ret;
|
|
}
|
|
@@ -485,16 +427,16 @@ static int ibmca_ed448_keygen(EVP_PKEY_CTX *c, EVP_PKEY *pkey)
|
|
goto ret;
|
|
}
|
|
|
|
- key = calloc(1, sizeof(ECX_KEY));
|
|
+ key = ossl_ecx_key_new_simple(ECX_KEY_TYPE_ED448);
|
|
private = calloc(1, sizeof(priv));
|
|
- if (key == NULL) {
|
|
+ if (key == NULL || private == NULL) {
|
|
IBMCAerr(IBMCA_F_IBMCA_ED448_KEYGEN, IBMCA_R_PKEY_KEYGEN_FAILED);
|
|
goto ret;
|
|
}
|
|
|
|
memcpy(private, priv, sizeof(priv));
|
|
- memcpy(key, pub, sizeof(pub));
|
|
- key->priv = private;
|
|
+ ossl_ecx_copypubkey(key, pub, sizeof(pub));
|
|
+ ossl_ecx_set0_privkey(key, private);
|
|
|
|
EVP_PKEY_assign(pkey, NID_ED448, key);
|
|
rc = 1;
|
|
@@ -542,9 +484,9 @@ static int ibmca_ed448_sign(EVP_MD_CTX *md_ctx, unsigned char *sig,
|
|
goto ret;
|
|
}
|
|
|
|
- if (p_ica_ed448_key_set(ctx, key_ecx->priv, NULL) != 0) {
|
|
+ if (p_ica_ed448_key_set(ctx, ossl_ecx_get0_privkey(key_ecx), NULL) != 0) {
|
|
IBMCAerr(IBMCA_F_IBMCA_ED448_SIGN, IBMCA_R_PKEY_KEYS_NOT_SET);
|
|
- goto ret;;
|
|
+ goto ret;
|
|
}
|
|
|
|
if (p_ica_ed448_sign(ctx, sig, tbs, tbslen) != 0)
|
|
@@ -587,7 +529,7 @@ static int ibmca_ed448_verify(EVP_MD_CTX *md_ctx, const unsigned char *sig,
|
|
goto ret;
|
|
}
|
|
|
|
- if (p_ica_ed448_key_set(ctx, NULL, key_ecx->pub) != 0) {
|
|
+ if (p_ica_ed448_key_set(ctx, NULL, ossl_ecx_get0_pubkey(key_ecx)) != 0) {
|
|
IBMCAerr(IBMCA_F_IBMCA_ED448_VERIFY, IBMCA_R_PKEY_KEYS_NOT_SET);
|
|
goto ret;
|
|
}
|
|
@@ -665,8 +607,8 @@ const EVP_PKEY_METHOD *ibmca_ed25519(void)
|
|
EVP_PKEY_meth_set_ctrl(ibmca_ed25519_pmeth, ibmca_ed_ctrl, NULL);
|
|
EVP_PKEY_meth_set_copy(ibmca_ed25519_pmeth, ibmca_ed25519_copy);
|
|
EVP_PKEY_meth_set_keygen(ibmca_ed25519_pmeth, NULL, ibmca_ed25519_keygen);
|
|
- ibmca_ed25519_pmeth->digestsign = ibmca_ed25519_sign;
|
|
- ibmca_ed25519_pmeth->digestverify = ibmca_ed25519_verify;
|
|
+ EVP_PKEY_meth_set_digestsign(ibmca_ed25519_pmeth, ibmca_ed25519_sign);
|
|
+ EVP_PKEY_meth_set_digestverify(ibmca_ed25519_pmeth, ibmca_ed25519_verify);
|
|
|
|
ret:
|
|
return ibmca_ed25519_pmeth;
|
|
@@ -684,8 +626,8 @@ const EVP_PKEY_METHOD *ibmca_ed448(void)
|
|
EVP_PKEY_meth_set_ctrl(ibmca_ed448_pmeth, ibmca_ed_ctrl, NULL);
|
|
EVP_PKEY_meth_set_copy(ibmca_ed448_pmeth, ibmca_ed448_copy);
|
|
EVP_PKEY_meth_set_keygen(ibmca_ed448_pmeth, NULL, ibmca_ed448_keygen);
|
|
- ibmca_ed448_pmeth->digestsign = ibmca_ed448_sign;
|
|
- ibmca_ed448_pmeth->digestverify = ibmca_ed448_verify;
|
|
+ EVP_PKEY_meth_set_digestsign(ibmca_ed448_pmeth, ibmca_ed448_sign);
|
|
+ EVP_PKEY_meth_set_digestverify(ibmca_ed448_pmeth, ibmca_ed448_verify);
|
|
|
|
ret:
|
|
return ibmca_ed448_pmeth;
|
|
diff --git a/src/openssl-compat.h b/src/openssl-compat.h
|
|
new file mode 100644
|
|
index 00000000..0013365b
|
|
--- /dev/null
|
|
+++ b/src/openssl-compat.h
|
|
@@ -0,0 +1,131 @@
|
|
+/*
|
|
+ * Copyright 2022 International Business Machines Corp.
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#ifndef IBMCA_OPENSSL_COMPAT_H
|
|
+#define IBMCA_OPENSSL_COMPAT_H
|
|
+
|
|
+#include <openssl/opensslv.h>
|
|
+
|
|
+#ifdef OPENSSL_VERSION_PREREQ
|
|
+/* This is 3.x */
|
|
+#include <crypto/evp.h>
|
|
+
|
|
+static inline ECX_KEY *ossl_ecx_key_new_simple(ECX_KEY_TYPE type)
|
|
+{
|
|
+ ECX_KEY *ret = OPENSSL_zalloc(sizeof(*ret));
|
|
+
|
|
+ if (ret == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ ret->libctx = NULL;
|
|
+ ret->haspubkey = 0;
|
|
+ switch (type) {
|
|
+ case ECX_KEY_TYPE_X25519:
|
|
+ ret->keylen = X25519_KEYLEN;
|
|
+ break;
|
|
+ case ECX_KEY_TYPE_X448:
|
|
+ ret->keylen = X448_KEYLEN;
|
|
+ break;
|
|
+ case ECX_KEY_TYPE_ED25519:
|
|
+ ret->keylen = ED25519_KEYLEN;
|
|
+ break;
|
|
+ case ECX_KEY_TYPE_ED448:
|
|
+ ret->keylen = ED448_KEYLEN;
|
|
+ break;
|
|
+ }
|
|
+ ret->type = type;
|
|
+ ret->references = 1;
|
|
+
|
|
+ ret->lock = CRYPTO_THREAD_lock_new();
|
|
+ if (ret->lock == NULL)
|
|
+ goto err;
|
|
+ return ret;
|
|
+err:
|
|
+ OPENSSL_free(ret);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static inline void ossl_ecx_set0_privkey(ECX_KEY *key, unsigned char *privkey)
|
|
+{
|
|
+ key->privkey = privkey;
|
|
+}
|
|
+
|
|
+static inline unsigned char *ossl_ecx_get0_privkey(ECX_KEY *key)
|
|
+{
|
|
+ return key->privkey;
|
|
+}
|
|
+
|
|
+static inline unsigned char *ossl_ecx_get0_pubkey(ECX_KEY *key)
|
|
+{
|
|
+ return key->pubkey;
|
|
+}
|
|
+
|
|
+static inline void ossl_ecx_copypubkey(ECX_KEY *key, unsigned char *pubkey, size_t len)
|
|
+{
|
|
+ memcpy(key->pubkey, pubkey, len);
|
|
+ key->haspubkey = 1;
|
|
+}
|
|
+
|
|
+#else
|
|
+/* This is 1.1.x */
|
|
+
|
|
+#include <openssl/evp.h>
|
|
+
|
|
+/*
|
|
+ * copied from evp_int.h:
|
|
+ * missing set/get methods for opaque types.
|
|
+ */
|
|
+
|
|
+typedef struct {
|
|
+ unsigned char pub[57];
|
|
+ unsigned char *priv;
|
|
+} ECX_KEY;
|
|
+
|
|
+typedef enum {
|
|
+ ECX_KEY_TYPE_X25519,
|
|
+ ECX_KEY_TYPE_X448,
|
|
+ ECX_KEY_TYPE_ED25519,
|
|
+ ECX_KEY_TYPE_ED448
|
|
+} ECX_KEY_TYPE;
|
|
+
|
|
+static inline ECX_KEY *ossl_ecx_key_new_simple(ECX_KEY_TYPE type)
|
|
+{
|
|
+ return calloc(1, sizeof(ECX_KEY));
|
|
+}
|
|
+
|
|
+static inline void ossl_ecx_set0_privkey(ECX_KEY *key, unsigned char *privkey)
|
|
+{
|
|
+ key->priv = privkey;
|
|
+}
|
|
+
|
|
+static inline unsigned char *ossl_ecx_get0_privkey(ECX_KEY *key)
|
|
+{
|
|
+ return key->priv;
|
|
+}
|
|
+
|
|
+static inline unsigned char *ossl_ecx_get0_pubkey(ECX_KEY *key)
|
|
+{
|
|
+ return key->pub;
|
|
+}
|
|
+
|
|
+static inline void ossl_ecx_copypubkey(ECX_KEY *key, unsigned char *pubkey, size_t len)
|
|
+{
|
|
+ memcpy(key->pub, pubkey, len);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+#endif
|