Path: blob/main/crypto/krb5/src/plugins/preauth/spake/openssl.c
34907 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* plugins/preauth/spake/openssl.c - SPAKE implementations using OpenSSL */2/*3* Copyright (C) 2015 by the Massachusetts Institute of Technology.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9*10* * Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in15* the documentation and/or other materials provided with the16* distribution.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS19* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT20* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS21* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE22* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,23* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES24* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR25* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,27* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED29* OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132#include "k5-int.h"3334#include "groups.h"35#include "iana.h"3637#ifdef SPAKE_OPENSSL38#include <openssl/bn.h>39#include <openssl/ec.h>40#include <openssl/obj_mac.h>41#include <openssl/evp.h>4243/* OpenSSL 1.1 standardizes constructor and destructor names, renaming44* EVP_MD_CTX_create and EVP_MD_CTX_destroy. */45#if OPENSSL_VERSION_NUMBER < 0x10100000L46#define EVP_MD_CTX_new EVP_MD_CTX_create47#define EVP_MD_CTX_free EVP_MD_CTX_destroy48#endif4950struct groupdata_st {51const groupdef *gdef;52EC_GROUP *group;53BIGNUM *order;54BN_CTX *ctx;55EC_POINT *M;56EC_POINT *N;57const EVP_MD *md;58};5960static void61ossl_fini(groupdata *gd)62{63if (gd == NULL)64return;6566EC_GROUP_free(gd->group);67EC_POINT_free(gd->M);68EC_POINT_free(gd->N);69BN_CTX_free(gd->ctx);70BN_free(gd->order);71free(gd);72}7374static krb5_error_code75ossl_init(krb5_context context, const groupdef *gdef, groupdata **gdata_out)76{77const spake_iana *reg = gdef->reg;78const EVP_MD *md;79groupdata *gd;80int nid;8182switch (reg->id) {83case SPAKE_GROUP_P256:84nid = NID_X9_62_prime256v1;85md = EVP_sha256();86break;87case SPAKE_GROUP_P384:88nid = NID_secp384r1;89md = EVP_sha384();90break;91case SPAKE_GROUP_P521:92nid = NID_secp521r1;93md = EVP_sha512();94break;95default:96return EINVAL;97};9899gd = calloc(1, sizeof(*gd));100if (gd == NULL)101return ENOMEM;102gd->gdef = gdef;103104gd->group = EC_GROUP_new_by_curve_name(nid);105if (gd->group == NULL)106goto error;107108gd->ctx = BN_CTX_new();109if (gd->ctx == NULL)110goto error;111112gd->order = BN_new();113if (gd->order == NULL)114goto error;115if (!EC_GROUP_get_order(gd->group, gd->order, gd->ctx))116goto error;117118gd->M = EC_POINT_new(gd->group);119if (gd->M == NULL)120goto error;121if (!EC_POINT_oct2point(gd->group, gd->M, reg->m, reg->elem_len, gd->ctx))122goto error;123124gd->N = EC_POINT_new(gd->group);125if (gd->N == NULL)126goto error;127if (!EC_POINT_oct2point(gd->group, gd->N, reg->n, reg->elem_len, gd->ctx))128goto error;129130gd->md = md;131132*gdata_out = gd;133return 0;134135error:136ossl_fini(gd);137return ENOMEM;138}139140/* Convert pseudo-random bytes into a scalar value in constant time.141* Return NULL on failure. */142static BIGNUM *143unmarshal_w(const groupdata *gdata, const uint8_t *wbytes)144{145const spake_iana *reg = gdata->gdef->reg;146BIGNUM *w = NULL;147148w = BN_new();149if (w == NULL)150return NULL;151152BN_set_flags(w, BN_FLG_CONSTTIME);153154if (BN_bin2bn(wbytes, reg->mult_len, w) &&155BN_div(NULL, w, w, gdata->order, gdata->ctx))156return w;157158BN_free(w);159return NULL;160}161162static krb5_error_code163ossl_keygen(krb5_context context, groupdata *gdata, const uint8_t *wbytes,164krb5_boolean use_m, uint8_t *priv_out, uint8_t *pub_out)165{166const spake_iana *reg = gdata->gdef->reg;167const EC_POINT *constant = use_m ? gdata->M : gdata->N;168krb5_boolean success = FALSE;169EC_POINT *pub = NULL;170BIGNUM *priv = NULL, *w = NULL;171size_t len;172173w = unmarshal_w(gdata, wbytes);174if (w == NULL)175goto cleanup;176177pub = EC_POINT_new(gdata->group);178if (pub == NULL)179goto cleanup;180181priv = BN_new();182if (priv == NULL)183goto cleanup;184185if (!BN_rand_range(priv, gdata->order))186goto cleanup;187188/* Compute priv*G + w*constant; EC_POINT_mul() does this in one call. */189if (!EC_POINT_mul(gdata->group, pub, priv, constant, w, gdata->ctx))190goto cleanup;191192/* Marshal priv into priv_out. */193memset(priv_out, 0, reg->mult_len);194BN_bn2bin(priv, &priv_out[reg->mult_len - BN_num_bytes(priv)]);195196/* Marshal pub into pub_out. */197len = EC_POINT_point2oct(gdata->group, pub, POINT_CONVERSION_COMPRESSED,198pub_out, reg->elem_len, gdata->ctx);199if (len != reg->elem_len)200goto cleanup;201202success = TRUE;203204cleanup:205EC_POINT_free(pub);206BN_clear_free(priv);207BN_clear_free(w);208return success ? 0 : ENOMEM;209}210211static krb5_error_code212ossl_result(krb5_context context, groupdata *gdata, const uint8_t *wbytes,213const uint8_t *ourpriv, const uint8_t *theirpub,214krb5_boolean use_m, uint8_t *elem_out)215{216const spake_iana *reg = gdata->gdef->reg;217const EC_POINT *constant = use_m ? gdata->M : gdata->N;218krb5_boolean success = FALSE, invalid = FALSE;219EC_POINT *result = NULL, *pub = NULL;220BIGNUM *priv = NULL, *w = NULL;221size_t len;222223w = unmarshal_w(gdata, wbytes);224if (w == NULL)225goto cleanup;226227priv = BN_bin2bn(ourpriv, reg->mult_len, NULL);228if (priv == NULL)229goto cleanup;230231pub = EC_POINT_new(gdata->group);232if (pub == NULL)233goto cleanup;234if (!EC_POINT_oct2point(gdata->group, pub, theirpub, reg->elem_len,235gdata->ctx)) {236invalid = TRUE;237goto cleanup;238}239240/* Compute result = priv*(pub - w*constant), using result to hold the241* intermediate steps. */242result = EC_POINT_new(gdata->group);243if (result == NULL)244goto cleanup;245if (!EC_POINT_mul(gdata->group, result, NULL, constant, w, gdata->ctx))246goto cleanup;247if (!EC_POINT_invert(gdata->group, result, gdata->ctx))248goto cleanup;249if (!EC_POINT_add(gdata->group, result, pub, result, gdata->ctx))250goto cleanup;251if (!EC_POINT_mul(gdata->group, result, NULL, result, priv, gdata->ctx))252goto cleanup;253254/* Marshal result into elem_out. */255len = EC_POINT_point2oct(gdata->group, result, POINT_CONVERSION_COMPRESSED,256elem_out, reg->elem_len, gdata->ctx);257if (len != reg->elem_len)258goto cleanup;259260success = TRUE;261262cleanup:263BN_clear_free(priv);264BN_clear_free(w);265EC_POINT_free(pub);266EC_POINT_clear_free(result);267return invalid ? EINVAL : (success ? 0 : ENOMEM);268}269270static krb5_error_code271ossl_hash(krb5_context context, groupdata *gdata, const krb5_data *dlist,272size_t ndata, uint8_t *result_out)273{274EVP_MD_CTX *ctx;275size_t i;276int ok;277278ctx = EVP_MD_CTX_new();279if (ctx == NULL)280return ENOMEM;281ok = EVP_DigestInit_ex(ctx, gdata->md, NULL);282for (i = 0; i < ndata; i++)283ok = ok && EVP_DigestUpdate(ctx, dlist[i].data, dlist[i].length);284ok = ok && EVP_DigestFinal_ex(ctx, result_out, NULL);285EVP_MD_CTX_free(ctx);286return ok ? 0 : ENOMEM;287}288289groupdef ossl_P256 = {290.reg = &spake_iana_p256,291.init = ossl_init,292.fini = ossl_fini,293.keygen = ossl_keygen,294.result = ossl_result,295.hash = ossl_hash,296};297298groupdef ossl_P384 = {299.reg = &spake_iana_p384,300.init = ossl_init,301.fini = ossl_fini,302.keygen = ossl_keygen,303.result = ossl_result,304.hash = ossl_hash,305};306307groupdef ossl_P521 = {308.reg = &spake_iana_p521,309.init = ossl_init,310.fini = ossl_fini,311.keygen = ossl_keygen,312.result = ossl_result,313.hash = ossl_hash,314};315#endif /* SPAKE_OPENSSL */316317318