diff options
Diffstat (limited to 'crypto/dh/dh_pmeth.c')
-rw-r--r-- | crypto/dh/dh_pmeth.c | 147 |
1 files changed, 140 insertions, 7 deletions
diff --git a/crypto/dh/dh_pmeth.c b/crypto/dh/dh_pmeth.c index 095227bc2f..941801df46 100644 --- a/crypto/dh/dh_pmeth.c +++ b/crypto/dh/dh_pmeth.c @@ -65,6 +65,7 @@ #ifndef OPENSSL_NO_DSA #include <openssl/dsa.h> #endif +#include <openssl/objects.h> #include "evp_locl.h" /* DH pkey context structure */ @@ -76,11 +77,22 @@ typedef struct int generator; int use_dsa; int subprime_len; + /* message digest used for parameter generation */ const EVP_MD *md; int rfc5114_param; /* Keygen callback info */ int gentmp[2]; - /* message digest */ + /* KDF (if any) to use for DH */ + char kdf_type; + /* OID to use for KDF */ + ASN1_OBJECT *kdf_oid; + /* Message digest to use for key derivation */ + const EVP_MD *kdf_md; + /* User key material */ + unsigned char *kdf_ukm; + size_t kdf_ukmlen; + /* KDF output length */ + size_t kdf_outlen; } DH_PKEY_CTX; static int pkey_dh_init(EVP_PKEY_CTX *ctx) @@ -96,6 +108,13 @@ static int pkey_dh_init(EVP_PKEY_CTX *ctx) dctx->md = NULL; dctx->rfc5114_param = 0; + dctx->kdf_type = EVP_PKEY_DH_KDF_NONE; + dctx->kdf_oid = NULL; + dctx->kdf_md = NULL; + dctx->kdf_ukm = NULL; + dctx->kdf_ukmlen = 0; + dctx->kdf_outlen = 0; + ctx->data = dctx; ctx->keygen_info = dctx->gentmp; ctx->keygen_info_count = 2; @@ -116,6 +135,18 @@ static int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) dctx->use_dsa = sctx->use_dsa; dctx->md = sctx->md; dctx->rfc5114_param = sctx->rfc5114_param; + + dctx->kdf_type = sctx->kdf_type; + dctx->kdf_oid = OBJ_dup(sctx->kdf_oid); + if (!dctx->kdf_oid) + return 0; + dctx->kdf_md = sctx->kdf_md; + if (dctx->kdf_ukm) + { + dctx->kdf_ukm = BUF_memdup(sctx->kdf_ukm, sctx->kdf_ukmlen); + dctx->kdf_ukmlen = sctx->kdf_ukmlen; + } + dctx->kdf_outlen = sctx->kdf_outlen; return 1; } @@ -123,7 +154,13 @@ static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx) { DH_PKEY_CTX *dctx = ctx->data; if (dctx) + { + if (dctx->kdf_ukm) + OPENSSL_free(dctx->kdf_ukm); + if (dctx->kdf_oid) + ASN1_OBJECT_free(dctx->kdf_oid); OPENSSL_free(dctx); + } } static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) @@ -170,6 +207,57 @@ static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) /* Default behaviour is OK */ return 1; + case EVP_PKEY_CTRL_DH_KDF_TYPE: + if (p1 == -2) + return dctx->kdf_type; + if (p1 != EVP_PKEY_DH_KDF_NONE && + p1 != EVP_PKEY_DH_KDF_X9_42) + return -2; + dctx->kdf_type = p1; + return 1; + + case EVP_PKEY_CTRL_DH_KDF_MD: + dctx->kdf_md = p2; + return 1; + + case EVP_PKEY_CTRL_GET_DH_KDF_MD: + *(const EVP_MD **)p2 = dctx->kdf_md; + return 1; + + case EVP_PKEY_CTRL_DH_KDF_OUTLEN: + if (p1 <= 0) + return -2; + dctx->kdf_outlen = (size_t)p1; + return 1; + + case EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN: + *(int *)p2 = dctx->kdf_outlen; + return 1; + + case EVP_PKEY_CTRL_DH_KDF_UKM: + if (dctx->kdf_ukm) + OPENSSL_free(dctx->kdf_ukm); + dctx->kdf_ukm = p2; + if (p2) + dctx->kdf_ukmlen = p1; + else + dctx->kdf_ukmlen = 0; + return 1; + + case EVP_PKEY_CTRL_GET_DH_KDF_UKM: + *(unsigned char **)p2 = dctx->kdf_ukm; + return dctx->kdf_ukmlen; + + case EVP_PKEY_CTRL_DH_KDF_OID: + if (dctx->kdf_oid) + ASN1_OBJECT_free(dctx->kdf_oid); + dctx->kdf_oid = p2; + return 1; + + case EVP_PKEY_CTRL_GET_DH_KDF_OID: + *(ASN1_OBJECT **)p2 = dctx->kdf_oid; + return 1; + default: return -2; @@ -356,23 +444,68 @@ static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) static int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) { int ret; + DH *dh; + DH_PKEY_CTX *dctx = ctx->data; + BIGNUM *dhpub; if (!ctx->pkey || !ctx->peerkey) { DHerr(DH_F_PKEY_DH_DERIVE, DH_R_KEYS_NOT_SET); return 0; } - ret = DH_compute_key(key, ctx->peerkey->pkey.dh->pub_key, - ctx->pkey->pkey.dh); - if (ret < 0) + dh = ctx->pkey->pkey.dh; + dhpub = ctx->peerkey->pkey.dh->pub_key; + if (dctx->kdf_type == EVP_PKEY_DH_KDF_NONE) + { + if (key == NULL) + { + *keylen = DH_size(dh); + return 1; + } + ret = DH_compute_key(key, dhpub, dh); + if (ret < 0) + return ret; + *keylen = ret; + return 1; + } + else if (dctx->kdf_type == EVP_PKEY_DH_KDF_X9_42) + { + unsigned char *Z = NULL; + size_t Zlen = 0; + if (!dctx->kdf_outlen || !dctx->kdf_oid) + return 0; + if (key == NULL) + { + *keylen = dctx->kdf_outlen; + return 1; + } + if (*keylen != dctx->kdf_outlen) + return 0; + ret = 0; + Zlen = DH_size(dh); + Z = OPENSSL_malloc(Zlen); + if (DH_compute_key_padded(Z, dhpub, dh) <= 0) + goto err; + if (!DH_KDF_X9_42(key, *keylen, Z, Zlen, dctx->kdf_oid, + dctx->kdf_ukm, dctx->kdf_ukmlen, + dctx->kdf_md)) + goto err; + *keylen = dctx->kdf_outlen; + ret = 1; + err: + if (Z) + { + OPENSSL_cleanse(Z, Zlen); + OPENSSL_free(Z); + } return ret; - *keylen = ret; + } return 1; } const EVP_PKEY_METHOD dh_pkey_meth = { EVP_PKEY_DH, - EVP_PKEY_FLAG_AUTOARGLEN, + 0, pkey_dh_init, pkey_dh_copy, pkey_dh_cleanup, @@ -408,7 +541,7 @@ const EVP_PKEY_METHOD dh_pkey_meth = const EVP_PKEY_METHOD dhx_pkey_meth = { EVP_PKEY_DHX, - EVP_PKEY_FLAG_AUTOARGLEN, + 0, pkey_dh_init, pkey_dh_copy, pkey_dh_cleanup, |