195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * project 2006.
395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley */
495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* ====================================================================
595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Redistribution and use in source and binary forms, with or without
895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * modification, are permitted provided that the following conditions
995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * are met:
1095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
1195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 1. Redistributions of source code must retain the above copyright
1295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    notice, this list of conditions and the following disclaimer.
1395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
1495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 2. Redistributions in binary form must reproduce the above copyright
1595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    notice, this list of conditions and the following disclaimer in
1695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    the documentation and/or other materials provided with the
1795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    distribution.
1895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
1995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 3. All advertising materials mentioning features or use of this
2095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    software must display the following acknowledgment:
2195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    "This product includes software developed by the OpenSSL Project
2295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
2495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    endorse or promote products derived from this software without
2695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    prior written permission. For written permission, please contact
2795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    licensing@OpenSSL.org.
2895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
2995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 5. Products derived from this software may not be called "OpenSSL"
3095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    nor may "OpenSSL" appear in their names without prior written
3195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    permission of the OpenSSL Project.
3295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
3395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 6. Redistributions of any form whatsoever must retain the following
3495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    acknowledgment:
3595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    "This product includes software developed by the OpenSSL Project
3695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
3895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
3995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
4995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * OF THE POSSIBILITY OF SUCH DAMAGE.
5095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ====================================================================
5195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
5295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * This product includes cryptographic software written by Eric Young
5395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * (eay@cryptsoft.com).  This product includes software written by Tim
5495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Hudson (tjh@cryptsoft.com). */
5595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
5695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/evp.h>
5795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
5895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/asn1.h>
5995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/bn.h>
6095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/buf.h>
6195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/digest.h>
6295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/ec.h>
6395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/ec_key.h>
6495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/ecdh.h>
6595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/ecdsa.h>
6695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/err.h>
6795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/mem.h>
6895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/obj.h>
6995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "internal.h"
7195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "../ec/internal.h"
7295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleytypedef struct {
7595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* Key and paramgen group */
7695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_GROUP *gen_group;
7795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* message digest */
7895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const EVP_MD *md;
7995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* Duplicate key if custom cofactor needed */
8095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_KEY *co_key;
8195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* Cofactor mode */
8295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  signed char cofactor_mode;
8395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* KDF (if any) to use for ECDH */
8495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  char kdf_type;
8595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* Message digest to use for key derivation */
8695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const EVP_MD *kdf_md;
8795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* User key material */
8895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  unsigned char *kdf_ukm;
8995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  size_t kdf_ukmlen;
9095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* KDF output length */
9195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  size_t kdf_outlen;
9295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley} EC_PKEY_CTX;
9395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
9495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
9595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int pkey_ec_init(EVP_PKEY_CTX *ctx) {
9695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx;
9795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  dctx = OPENSSL_malloc(sizeof(EC_PKEY_CTX));
9895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!dctx) {
9995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
10095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
10195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  memset(dctx, 0, sizeof(EC_PKEY_CTX));
10295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  dctx->cofactor_mode = -1;
10395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  dctx->kdf_type = EVP_PKEY_ECDH_KDF_NONE;
10495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
10595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ctx->data = dctx;
10695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
10795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return 1;
10895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
10995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
11195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx, *sctx;
11295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!pkey_ec_init(dst)) {
11395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
11495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
11595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  sctx = src->data;
11695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  dctx = dst->data;
11795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (sctx->gen_group) {
11995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    dctx->gen_group = EC_GROUP_dup(sctx->gen_group);
12095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!dctx->gen_group) {
12195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 0;
12295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
12395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
12495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  dctx->md = sctx->md;
12595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
12695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (sctx->co_key) {
12795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    dctx->co_key = EC_KEY_dup(sctx->co_key);
12895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!dctx->co_key) {
12995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 0;
13095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
13195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
13295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  dctx->kdf_type = sctx->kdf_type;
13395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  dctx->kdf_md = sctx->kdf_md;
13495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  dctx->kdf_outlen = sctx->kdf_outlen;
13595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (sctx->kdf_ukm) {
13695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    dctx->kdf_ukm = BUF_memdup(sctx->kdf_ukm, sctx->kdf_ukmlen);
13795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!dctx->kdf_ukm) {
13895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 0;
13995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
14095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else {
14195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    dctx->kdf_ukm = NULL;
14295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
14395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  dctx->kdf_ukmlen = sctx->kdf_ukmlen;
14495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return 1;
14595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
14695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
14795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic void pkey_ec_cleanup(EVP_PKEY_CTX *ctx) {
14895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx = ctx->data;
14995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!dctx) {
15095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return;
15195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
15295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
15395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (dctx->gen_group) {
15495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    EC_GROUP_free(dctx->gen_group);
15595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
15695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (dctx->co_key) {
15795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    EC_KEY_free(dctx->co_key);
15895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
15995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (dctx->kdf_ukm) {
16095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_free(dctx->kdf_ukm);
16195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
16295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_free(dctx);
16395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
16495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
16595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int pkey_ec_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
16695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                        const uint8_t *tbs, size_t tbslen) {
1675129e2d69582c0c54a335eb7e0bc794a02418403Adam Langley  int type;
16895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  unsigned int sltmp;
16995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx = ctx->data;
17095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_KEY *ec = ctx->pkey->pkey.ec;
17195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
17295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!sig) {
17395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    *siglen = ECDSA_size(ec);
17495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 1;
17595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else if (*siglen < (size_t)ECDSA_size(ec)) {
17695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(EVP, pkey_ec_sign, EVP_R_BUFFER_TOO_SMALL);
17795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
17895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
17995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
18095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  type = NID_sha1;
18195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (dctx->md) {
18295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    type = EVP_MD_type(dctx->md);
18395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
18495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
1855129e2d69582c0c54a335eb7e0bc794a02418403Adam Langley  if (!ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec)) {
1865129e2d69582c0c54a335eb7e0bc794a02418403Adam Langley    return 0;
18795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
18895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  *siglen = (size_t)sltmp;
18995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return 1;
19095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
19195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int pkey_ec_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen,
19395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                          const uint8_t *tbs, size_t tbslen) {
19495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int type;
19595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx = ctx->data;
19695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_KEY *ec = ctx->pkey->pkey.ec;
19795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  type = NID_sha1;
19995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (dctx->md) {
20095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    type = EVP_MD_type(dctx->md);
20195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
20295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return ECDSA_verify(type, tbs, tbslen, sig, siglen, ec);
20495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
20595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int pkey_ec_derive(EVP_PKEY_CTX *ctx, uint8_t *key,
20795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                          size_t *keylen) {
20895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int ret;
20995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  size_t outlen;
21095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const EC_POINT *pubkey = NULL;
21195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_KEY *eckey;
21295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx = ctx->data;
21395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!ctx->pkey || !ctx->peerkey) {
21595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(EVP, pkey_ec_derive, EVP_R_KEYS_NOT_SET);
21695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
21795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
21895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  eckey = dctx->co_key ? dctx->co_key : ctx->pkey->pkey.ec;
22095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!key) {
22295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const EC_GROUP *group;
22395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    group = EC_KEY_get0_group(eckey);
22495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    *keylen = (EC_GROUP_get_degree(group) + 7) / 8;
22595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 1;
22695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
22795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec);
22895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is
23095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   * not an error, the result is truncated. */
23195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  outlen = *keylen;
23395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0);
23595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (ret < 0) {
2365129e2d69582c0c54a335eb7e0bc794a02418403Adam Langley    return 0;
23795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
23895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  *keylen = ret;
23995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return 1;
24095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
24195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int pkey_ec_kdf_derive(EVP_PKEY_CTX *ctx, uint8_t *key,
24395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                              size_t *keylen) {
24495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx = ctx->data;
24595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  uint8_t *ktmp = NULL;
24695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  size_t ktmplen;
24795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int rv = 0;
24895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (dctx->kdf_type == EVP_PKEY_ECDH_KDF_NONE) {
25095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return pkey_ec_derive(ctx, key, keylen);
25195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
25295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!key) {
25395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    *keylen = dctx->kdf_outlen;
25495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 1;
25595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
25695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (*keylen != dctx->kdf_outlen ||
25795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      !pkey_ec_derive(ctx, NULL, &ktmplen)) {
25895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
25995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
26095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ktmp = OPENSSL_malloc(ktmplen);
26195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!ktmp) {
26295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
26395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
26495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!pkey_ec_derive(ctx, ktmp, &ktmplen)) {
26595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
26695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
26795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
26895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!ECDH_KDF_X9_62(key, *keylen, ktmp, ktmplen, dctx->kdf_ukm,
26995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                      dctx->kdf_ukmlen, dctx->kdf_md)) {
27095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
27195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
27295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  rv = 1;
27395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
27495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyerr:
27595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (ktmp) {
27695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_cleanse(ktmp, ktmplen);
27795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_free(ktmp);
27895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
27995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return rv;
28095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
28195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
28295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
28395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx = ctx->data;
28495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_GROUP *group;
28595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
28695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  switch (type) {
28795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
28895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      group = EC_GROUP_new_by_curve_name(p1);
28995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (group == NULL) {
29095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        OPENSSL_PUT_ERROR(EVP, pkey_ec_ctrl, EVP_R_INVALID_CURVE);
29195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        return 0;
29295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      }
29395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (dctx->gen_group)
29495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        EC_GROUP_free(dctx->gen_group);
29595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      dctx->gen_group = group;
29695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
29795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
29895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_EC_KDF_TYPE:
29995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (p1 == -2)
30095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        return dctx->kdf_type;
30195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (p1 != EVP_PKEY_ECDH_KDF_NONE && p1 != EVP_PKEY_ECDH_KDF_X9_62)
30295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        return -2;
30395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      dctx->kdf_type = p1;
30495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
30595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
30695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_EC_KDF_MD:
30795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      dctx->kdf_md = p2;
30895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
30995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
31095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_GET_EC_KDF_MD:
31195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      *(const EVP_MD **)p2 = dctx->kdf_md;
31295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
31395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
31495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_EC_KDF_OUTLEN:
31595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (p1 <= 0)
31695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        return -2;
31795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      dctx->kdf_outlen = (size_t)p1;
31895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
31995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
32095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN:
32195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      *(int *)p2 = dctx->kdf_outlen;
32295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
32395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
32495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_EC_KDF_UKM:
32595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (dctx->kdf_ukm)
32695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        OPENSSL_free(dctx->kdf_ukm);
32795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      dctx->kdf_ukm = p2;
32895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (p2)
32995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        dctx->kdf_ukmlen = p1;
33095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      else
33195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        dctx->kdf_ukmlen = 0;
33295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
33395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
33495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_GET_EC_KDF_UKM:
33595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      *(unsigned char **)p2 = dctx->kdf_ukm;
33695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return dctx->kdf_ukmlen;
33795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
33895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_MD:
33995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 &&
34095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 &&
34195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          EVP_MD_type((const EVP_MD *)p2) != NID_sha224 &&
34295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          EVP_MD_type((const EVP_MD *)p2) != NID_sha256 &&
34395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          EVP_MD_type((const EVP_MD *)p2) != NID_sha384 &&
34495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          EVP_MD_type((const EVP_MD *)p2) != NID_sha512) {
34595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        OPENSSL_PUT_ERROR(EVP, pkey_ec_ctrl, EVP_R_INVALID_DIGEST_TYPE);
34695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        return 0;
34795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      }
34895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      dctx->md = p2;
34995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
35095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
35195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_GET_MD:
35295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      *(const EVP_MD **)p2 = dctx->md;
35395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
35495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
35595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_PEER_KEY:
35695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    /* Default behaviour is OK */
35795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    case EVP_PKEY_CTRL_DIGESTINIT:
35895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 1;
35995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
36095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    default:
36195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return -2;
36295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
36395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
36495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
36595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
36695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_KEY *ec = NULL;
36795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx = ctx->data;
36895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int ret = 0;
36995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
37095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (dctx->gen_group == NULL) {
37195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(EVP, pkey_ec_paramgen, EVP_R_NO_PARAMETERS_SET);
37295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
37395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
37495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ec = EC_KEY_new();
37595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!ec) {
37695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
37795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
37895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ret = EC_KEY_set_group(ec, dctx->gen_group);
37995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (ret) {
38095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    EVP_PKEY_assign_EC_KEY(pkey, ec);
38195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else {
38295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    EC_KEY_free(ec);
38395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
38495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return ret;
38595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
38695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
38795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
38895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_KEY *ec = NULL;
38995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EC_PKEY_CTX *dctx = ctx->data;
39095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (ctx->pkey == NULL && dctx->gen_group == NULL) {
39195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(EVP, pkey_ec_keygen, EVP_R_NO_PARAMETERS_SET);
39295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
39395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
39495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ec = EC_KEY_new();
39595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!ec) {
39695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
39795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
39895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EVP_PKEY_assign_EC_KEY(pkey, ec);
39995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (ctx->pkey) {
40095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    /* Note: if error return, pkey is freed by parent routine */
40195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) {
40295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 0;
40395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
40495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else {
40595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!EC_KEY_set_group(ec, dctx->gen_group)) {
40695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 0;
40795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
40895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
40995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return EC_KEY_generate_key(pkey->pkey.ec);
41095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
41195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
41295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyconst EVP_PKEY_METHOD ec_pkey_meth = {
41395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    EVP_PKEY_EC,            0 /* flags */,        pkey_ec_init,
41495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    pkey_ec_copy,           pkey_ec_cleanup,      0 /* paramgen_init */,
41595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    pkey_ec_paramgen,       0 /* keygen_init */,  pkey_ec_keygen,
41695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    0 /* sign_init */,      pkey_ec_sign,         0 /* verify_init */,
41795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    pkey_ec_verify,         0 /* signctx_init */, 0 /* signctx */,
41895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    0 /* verifyctx_init */, 0 /* verifyctx */,    0 /* encrypt_init */,
41995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    0 /* encrypt */,        0 /* decrypt_init */, 0 /* decrypt */,
42095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    0 /* derive_init */,    pkey_ec_kdf_derive,   pkey_ec_ctrl,
42195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
422