diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2018-06-02 17:40:34 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2018-06-02 17:40:34 +0000 |
commit | b88d3d9fff155aa8e1226d630c76efaec2384933 (patch) | |
tree | 9f1a8c3ee9dd57982edccc25bfe381c3106d96a7 /lib/libcsi/csi_dh.c | |
parent | 5d7a3af82666bb6979a9031de75b16ef0d50c68d (diff) |
Initial version of Crypto Simplified Interface (CSI).
This is a code base that intends on providing a simplified interface for
mid-level cryptographic operations. In due course various applications and
libraries will be able to benefit from a clean and robust API, rather than
using libcrypto or other similar APIs directly.
Discussed at length with deraadt@, djm@, markus@, beck@ and others.
Diffstat (limited to 'lib/libcsi/csi_dh.c')
-rw-r--r-- | lib/libcsi/csi_dh.c | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/lib/libcsi/csi_dh.c b/lib/libcsi/csi_dh.c new file mode 100644 index 00000000000..39f18423c4a --- /dev/null +++ b/lib/libcsi/csi_dh.c @@ -0,0 +1,310 @@ +/* $OpenBSD: csi_dh.c,v 1.1 2018/06/02 17:40:33 jsing Exp $ */ +/* + * Copyright (c) 2018 Joel Sing <jsing@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <limits.h> +#include <string.h> + +#include <openssl/ec.h> +#include <openssl/ecdh.h> + +#include <csi.h> + +#include "csi_internal.h" + +struct csi_dh * +csi_dh_new() +{ + return calloc(1, sizeof(struct csi_dh)); +} + +static void +csi_dh_reset(struct csi_dh *cdh) +{ + DH_free(cdh->dh); + cdh->dh = NULL; + + BN_free(cdh->peer_pubkey); + cdh->peer_pubkey = NULL; + + csi_err_clear(&cdh->err); +} + +void +csi_dh_free(struct csi_dh *cdh) +{ + if (cdh == NULL) + return; + + csi_dh_reset(cdh); + + freezero(cdh, sizeof(*cdh)); +} + +const char * +csi_dh_error(struct csi_dh *cdh) +{ + return cdh->err.msg; +} + +int +csi_dh_error_code(struct csi_dh *cdh) +{ + return cdh->err.code; +} + +static int +csi_dh_init(struct csi_dh *cdh) +{ + csi_dh_reset(cdh); + + if ((cdh->dh = DH_new()) == NULL) { + csi_err_setx(&cdh->err, CSI_ERR_MEM, "out of memory"); + return -1; + } + + return 0; +} + +struct csi_dh_params * +csi_dh_params_dup(struct csi_dh_params *cdhp) +{ + struct csi_dh_params *ncdhp = NULL; + + if ((ncdhp = calloc(1, sizeof(*ncdhp))) == NULL) + goto err; + + if ((ncdhp->p.data = malloc(cdhp->p.len)) == NULL) + goto err; + ncdhp->p.len = cdhp->p.len; + memcpy((uint8_t *)ncdhp->p.data, cdhp->p.data, cdhp->p.len); + + if ((ncdhp->g.data = malloc(cdhp->g.len)) == NULL) + goto err; + ncdhp->g.len = cdhp->g.len; + memcpy((uint8_t *)ncdhp->g.data, cdhp->g.data, cdhp->g.len); + + return ncdhp; + + err: + csi_dh_params_free(ncdhp); + + return NULL; +} + +void +csi_dh_params_free(struct csi_dh_params *cdhp) +{ + if (cdhp == NULL) + return; + + free((uint8_t *)cdhp->p.data); + free((uint8_t *)cdhp->g.data); + free(cdhp); +} + +void +csi_dh_public_free(struct csi_dh_public *cdhp) +{ + if (cdhp == NULL) + return; + + free((uint8_t *)cdhp->key.data); + free(cdhp); +} + +void +csi_dh_shared_free(struct csi_dh_shared *cdhs) +{ + if (cdhs == NULL) + return; + + freezero((uint8_t *)cdhs->key.data, cdhs->key.len); + freezero(cdhs, sizeof(*cdhs)); +} + +int +csi_dh_set_params(struct csi_dh *cdh, struct csi_dh_params *params) +{ + if (csi_dh_init(cdh) == -1) + goto err; + + if (csi_integer_to_bn(&cdh->err, "p", ¶ms->p, + &cdh->dh->p) == -1) + goto err; + if (csi_integer_to_bn(&cdh->err, "g", ¶ms->g, + &cdh->dh->g) == -1) + goto err; + + return 0; + + err: + return -1; +} + +int +csi_dh_set_peer_public(struct csi_dh *cdh, struct csi_dh_public *peer) +{ + BIGNUM *ppk = NULL; + + if (cdh->dh == NULL) { + csi_err_setx(&cdh->err, CSI_ERR_INVAL, "no params set"); + goto err; + } + + if (csi_integer_to_bn(&cdh->err, "key", &peer->key, &ppk) == -1) + goto err; + + cdh->peer_pubkey = ppk; + + return 0; + + err: + BN_clear_free(ppk); + + return -1; +} + +struct csi_dh_params * +csi_dh_params(struct csi_dh *cdh) +{ + struct csi_dh_params *cdhp; + + if ((cdhp = calloc(1, sizeof(*cdhp))) == NULL) + goto errmem; + if (csi_bn_to_integer(&cdh->err, cdh->dh->p, &cdhp->p) != 0) + goto err; + if (csi_bn_to_integer(&cdh->err, cdh->dh->g, &cdhp->g) != 0) + goto err; + + return cdhp; + + errmem: + csi_err_setx(&cdh->err, CSI_ERR_MEM, "out of memory"); + err: + csi_dh_params_free(cdhp); + + return NULL; +} + +struct csi_dh_public * +csi_dh_public_key(struct csi_dh *cdh) +{ + struct csi_dh_public *cdhp; + + if ((cdhp = calloc(1, sizeof(*cdhp))) == NULL) + goto errmem; + if (csi_bn_to_integer(&cdh->err, cdh->dh->pub_key, &cdhp->key) != 0) + goto err; + + return cdhp; + + errmem: + csi_err_setx(&cdh->err, CSI_ERR_MEM, "out of memory"); + err: + csi_dh_public_free(cdhp); + + return NULL; +} + +struct csi_dh_public * +csi_dh_peer_public_key(struct csi_dh *cdh) +{ + struct csi_dh_public *cdhp; + + if ((cdhp = calloc(1, sizeof(*cdhp))) == NULL) + goto errmem; + if (csi_bn_to_integer(&cdh->err, cdh->peer_pubkey, &cdhp->key) != 0) + goto err; + + return cdhp; + + errmem: + csi_err_setx(&cdh->err, CSI_ERR_MEM, "out of memory"); + err: + csi_dh_public_free(cdhp); + + return NULL; +} + +int +csi_dh_generate_keys(struct csi_dh *cdh, size_t length, + struct csi_dh_public **public) +{ + if (cdh->dh == NULL) { + csi_err_setx(&cdh->err, CSI_ERR_INVAL, "no params set"); + goto err; + } + + if (!DH_generate_key(cdh->dh)) { + csi_err_setx(&cdh->err, CSI_ERR_CRYPTO, "dh generation failed"); + goto err; + } + + if (public != NULL) { + csi_dh_public_free(*public); + if ((*public = csi_dh_public_key(cdh)) == NULL) + goto err; + } + + return 0; + + err: + return -1; +} + +int +csi_dh_derive_shared_key(struct csi_dh *cdh, struct csi_dh_shared **cdhs) +{ + struct csi_dh_shared *dhs = NULL; + uint8_t *key = NULL; + size_t key_len = 0; + int len; + + csi_dh_shared_free(*cdhs); + *cdhs = NULL; + + if (cdh->dh == NULL) { + csi_err_setx(&cdh->err, CSI_ERR_INVAL, "no params set"); + goto err; + } + + if ((len = DH_size(cdh->dh)) <= 0) { + csi_err_setx(&cdh->err, CSI_ERR_INVAL, "invalid dh size %i", len); + goto err; + } + key_len = (size_t)len; + if ((key = calloc(1, key_len)) == NULL) + goto errmem; + if (DH_compute_key(key, cdh->peer_pubkey, cdh->dh) != len) { + csi_err_setx(&cdh->err, CSI_ERR_CRYPTO, "failed to derive key"); + goto err; + } + + if ((dhs = calloc(1, sizeof(*dhs))) == NULL) + goto errmem; + dhs->key.data = key; + dhs->key.len = key_len; + + *cdhs = dhs; + + return 0; + + errmem: + csi_err_setx(&cdh->err, CSI_ERR_MEM, "out of memory"); + err: + return -1; +} |