1296341Sdelphij/* 2296341Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 3296341Sdelphij * 2006. 4238384Sjkim */ 5238384Sjkim/* ==================================================================== 6238384Sjkim * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 7238384Sjkim * 8238384Sjkim * Redistribution and use in source and binary forms, with or without 9238384Sjkim * modification, are permitted provided that the following conditions 10238384Sjkim * are met: 11238384Sjkim * 12238384Sjkim * 1. Redistributions of source code must retain the above copyright 13296341Sdelphij * notice, this list of conditions and the following disclaimer. 14238384Sjkim * 15238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 16238384Sjkim * notice, this list of conditions and the following disclaimer in 17238384Sjkim * the documentation and/or other materials provided with the 18238384Sjkim * distribution. 19238384Sjkim * 20238384Sjkim * 3. All advertising materials mentioning features or use of this 21238384Sjkim * software must display the following acknowledgment: 22238384Sjkim * "This product includes software developed by the OpenSSL Project 23238384Sjkim * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24238384Sjkim * 25238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26238384Sjkim * endorse or promote products derived from this software without 27238384Sjkim * prior written permission. For written permission, please contact 28238384Sjkim * licensing@OpenSSL.org. 29238384Sjkim * 30238384Sjkim * 5. Products derived from this software may not be called "OpenSSL" 31238384Sjkim * nor may "OpenSSL" appear in their names without prior written 32238384Sjkim * permission of the OpenSSL Project. 33238384Sjkim * 34238384Sjkim * 6. Redistributions of any form whatsoever must retain the following 35238384Sjkim * acknowledgment: 36238384Sjkim * "This product includes software developed by the OpenSSL Project 37238384Sjkim * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38238384Sjkim * 39238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42238384Sjkim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE. 51238384Sjkim * ==================================================================== 52238384Sjkim * 53238384Sjkim * This product includes cryptographic software written by Eric Young 54238384Sjkim * (eay@cryptsoft.com). This product includes software written by Tim 55238384Sjkim * Hudson (tjh@cryptsoft.com). 56238384Sjkim * 57238384Sjkim */ 58238384Sjkim 59238384Sjkim#include <stdio.h> 60238384Sjkim#include "cryptlib.h" 61238384Sjkim#include <openssl/asn1t.h> 62238384Sjkim#include <openssl/x509.h> 63238384Sjkim#include <openssl/ec.h> 64238384Sjkim#include <openssl/ecdsa.h> 65238384Sjkim#include <openssl/evp.h> 66238384Sjkim#include "evp_locl.h" 67238384Sjkim 68238384Sjkim/* EC pkey context structure */ 69238384Sjkim 70296341Sdelphijtypedef struct { 71296341Sdelphij /* Key and paramgen group */ 72296341Sdelphij EC_GROUP *gen_group; 73296341Sdelphij /* message digest */ 74296341Sdelphij const EVP_MD *md; 75296341Sdelphij} EC_PKEY_CTX; 76238384Sjkim 77238384Sjkimstatic int pkey_ec_init(EVP_PKEY_CTX *ctx) 78296341Sdelphij{ 79296341Sdelphij EC_PKEY_CTX *dctx; 80296341Sdelphij dctx = OPENSSL_malloc(sizeof(EC_PKEY_CTX)); 81296341Sdelphij if (!dctx) 82296341Sdelphij return 0; 83296341Sdelphij dctx->gen_group = NULL; 84296341Sdelphij dctx->md = NULL; 85238384Sjkim 86296341Sdelphij ctx->data = dctx; 87238384Sjkim 88296341Sdelphij return 1; 89296341Sdelphij} 90238384Sjkim 91238384Sjkimstatic int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) 92296341Sdelphij{ 93296341Sdelphij EC_PKEY_CTX *dctx, *sctx; 94296341Sdelphij if (!pkey_ec_init(dst)) 95296341Sdelphij return 0; 96296341Sdelphij sctx = src->data; 97296341Sdelphij dctx = dst->data; 98296341Sdelphij if (sctx->gen_group) { 99296341Sdelphij dctx->gen_group = EC_GROUP_dup(sctx->gen_group); 100296341Sdelphij if (!dctx->gen_group) 101296341Sdelphij return 0; 102296341Sdelphij } 103296341Sdelphij dctx->md = sctx->md; 104296341Sdelphij return 1; 105296341Sdelphij} 106238384Sjkim 107238384Sjkimstatic void pkey_ec_cleanup(EVP_PKEY_CTX *ctx) 108296341Sdelphij{ 109296341Sdelphij EC_PKEY_CTX *dctx = ctx->data; 110296341Sdelphij if (dctx) { 111296341Sdelphij if (dctx->gen_group) 112296341Sdelphij EC_GROUP_free(dctx->gen_group); 113296341Sdelphij OPENSSL_free(dctx); 114296341Sdelphij } 115296341Sdelphij} 116238384Sjkim 117238384Sjkimstatic int pkey_ec_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, 118296341Sdelphij const unsigned char *tbs, size_t tbslen) 119296341Sdelphij{ 120296341Sdelphij int ret, type; 121296341Sdelphij unsigned int sltmp; 122296341Sdelphij EC_PKEY_CTX *dctx = ctx->data; 123296341Sdelphij EC_KEY *ec = ctx->pkey->pkey.ec; 124238384Sjkim 125296341Sdelphij if (!sig) { 126296341Sdelphij *siglen = ECDSA_size(ec); 127296341Sdelphij return 1; 128296341Sdelphij } else if (*siglen < (size_t)ECDSA_size(ec)) { 129296341Sdelphij ECerr(EC_F_PKEY_EC_SIGN, EC_R_BUFFER_TOO_SMALL); 130296341Sdelphij return 0; 131296341Sdelphij } 132238384Sjkim 133296341Sdelphij if (dctx->md) 134296341Sdelphij type = EVP_MD_type(dctx->md); 135296341Sdelphij else 136296341Sdelphij type = NID_sha1; 137238384Sjkim 138296341Sdelphij ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec); 139238384Sjkim 140296341Sdelphij if (ret <= 0) 141296341Sdelphij return ret; 142296341Sdelphij *siglen = (size_t)sltmp; 143296341Sdelphij return 1; 144296341Sdelphij} 145238384Sjkim 146238384Sjkimstatic int pkey_ec_verify(EVP_PKEY_CTX *ctx, 147296341Sdelphij const unsigned char *sig, size_t siglen, 148296341Sdelphij const unsigned char *tbs, size_t tbslen) 149296341Sdelphij{ 150296341Sdelphij int ret, type; 151296341Sdelphij EC_PKEY_CTX *dctx = ctx->data; 152296341Sdelphij EC_KEY *ec = ctx->pkey->pkey.ec; 153238384Sjkim 154296341Sdelphij if (dctx->md) 155296341Sdelphij type = EVP_MD_type(dctx->md); 156296341Sdelphij else 157296341Sdelphij type = NID_sha1; 158238384Sjkim 159296341Sdelphij ret = ECDSA_verify(type, tbs, tbslen, sig, siglen, ec); 160238384Sjkim 161296341Sdelphij return ret; 162296341Sdelphij} 163238384Sjkim 164279264Sdelphij#ifndef OPENSSL_NO_ECDH 165296341Sdelphijstatic int pkey_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, 166296341Sdelphij size_t *keylen) 167296341Sdelphij{ 168296341Sdelphij int ret; 169296341Sdelphij size_t outlen; 170296341Sdelphij const EC_POINT *pubkey = NULL; 171296341Sdelphij if (!ctx->pkey || !ctx->peerkey) { 172296341Sdelphij ECerr(EC_F_PKEY_EC_DERIVE, EC_R_KEYS_NOT_SET); 173296341Sdelphij return 0; 174296341Sdelphij } 175238384Sjkim 176296341Sdelphij if (!key) { 177296341Sdelphij const EC_GROUP *group; 178296341Sdelphij group = EC_KEY_get0_group(ctx->pkey->pkey.ec); 179296341Sdelphij *keylen = (EC_GROUP_get_degree(group) + 7) / 8; 180296341Sdelphij return 1; 181296341Sdelphij } 182238384Sjkim 183296341Sdelphij pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec); 184238384Sjkim 185296341Sdelphij /* 186296341Sdelphij * NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is not 187296341Sdelphij * an error, the result is truncated. 188296341Sdelphij */ 189238384Sjkim 190296341Sdelphij outlen = *keylen; 191296341Sdelphij 192296341Sdelphij ret = ECDH_compute_key(key, outlen, pubkey, ctx->pkey->pkey.ec, 0); 193296341Sdelphij if (ret < 0) 194296341Sdelphij return ret; 195296341Sdelphij *keylen = ret; 196296341Sdelphij return 1; 197296341Sdelphij} 198279264Sdelphij#endif 199238384Sjkim 200238384Sjkimstatic int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) 201296341Sdelphij{ 202296341Sdelphij EC_PKEY_CTX *dctx = ctx->data; 203296341Sdelphij EC_GROUP *group; 204296341Sdelphij switch (type) { 205296341Sdelphij case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID: 206296341Sdelphij group = EC_GROUP_new_by_curve_name(p1); 207296341Sdelphij if (group == NULL) { 208296341Sdelphij ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_CURVE); 209296341Sdelphij return 0; 210296341Sdelphij } 211296341Sdelphij if (dctx->gen_group) 212296341Sdelphij EC_GROUP_free(dctx->gen_group); 213296341Sdelphij dctx->gen_group = group; 214296341Sdelphij return 1; 215238384Sjkim 216296341Sdelphij case EVP_PKEY_CTRL_MD: 217296341Sdelphij if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 && 218296341Sdelphij EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 && 219296341Sdelphij EVP_MD_type((const EVP_MD *)p2) != NID_sha224 && 220296341Sdelphij EVP_MD_type((const EVP_MD *)p2) != NID_sha256 && 221296341Sdelphij EVP_MD_type((const EVP_MD *)p2) != NID_sha384 && 222296341Sdelphij EVP_MD_type((const EVP_MD *)p2) != NID_sha512) { 223296341Sdelphij ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_DIGEST_TYPE); 224296341Sdelphij return 0; 225296341Sdelphij } 226296341Sdelphij dctx->md = p2; 227296341Sdelphij return 1; 228238384Sjkim 229296341Sdelphij case EVP_PKEY_CTRL_PEER_KEY: 230296341Sdelphij /* Default behaviour is OK */ 231296341Sdelphij case EVP_PKEY_CTRL_DIGESTINIT: 232296341Sdelphij case EVP_PKEY_CTRL_PKCS7_SIGN: 233296341Sdelphij case EVP_PKEY_CTRL_CMS_SIGN: 234296341Sdelphij return 1; 235238384Sjkim 236296341Sdelphij default: 237296341Sdelphij return -2; 238238384Sjkim 239296341Sdelphij } 240296341Sdelphij} 241296341Sdelphij 242238384Sjkimstatic int pkey_ec_ctrl_str(EVP_PKEY_CTX *ctx, 243296341Sdelphij const char *type, const char *value) 244296341Sdelphij{ 245296341Sdelphij if (!strcmp(type, "ec_paramgen_curve")) { 246296341Sdelphij int nid; 247296341Sdelphij nid = OBJ_sn2nid(value); 248296341Sdelphij if (nid == NID_undef) 249296341Sdelphij nid = OBJ_ln2nid(value); 250296341Sdelphij if (nid == NID_undef) { 251296341Sdelphij ECerr(EC_F_PKEY_EC_CTRL_STR, EC_R_INVALID_CURVE); 252296341Sdelphij return 0; 253296341Sdelphij } 254296341Sdelphij return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid); 255296341Sdelphij } 256296341Sdelphij return -2; 257296341Sdelphij} 258238384Sjkim 259238384Sjkimstatic int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) 260296341Sdelphij{ 261296341Sdelphij EC_KEY *ec = NULL; 262296341Sdelphij EC_PKEY_CTX *dctx = ctx->data; 263296341Sdelphij int ret = 0; 264296341Sdelphij if (dctx->gen_group == NULL) { 265296341Sdelphij ECerr(EC_F_PKEY_EC_PARAMGEN, EC_R_NO_PARAMETERS_SET); 266296341Sdelphij return 0; 267296341Sdelphij } 268296341Sdelphij ec = EC_KEY_new(); 269296341Sdelphij if (!ec) 270296341Sdelphij return 0; 271296341Sdelphij ret = EC_KEY_set_group(ec, dctx->gen_group); 272296341Sdelphij if (ret) 273296341Sdelphij EVP_PKEY_assign_EC_KEY(pkey, ec); 274296341Sdelphij else 275296341Sdelphij EC_KEY_free(ec); 276296341Sdelphij return ret; 277296341Sdelphij} 278238384Sjkim 279238384Sjkimstatic int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) 280296341Sdelphij{ 281296341Sdelphij EC_KEY *ec = NULL; 282296341Sdelphij if (ctx->pkey == NULL) { 283296341Sdelphij ECerr(EC_F_PKEY_EC_KEYGEN, EC_R_NO_PARAMETERS_SET); 284296341Sdelphij return 0; 285296341Sdelphij } 286296341Sdelphij ec = EC_KEY_new(); 287296341Sdelphij if (!ec) 288296341Sdelphij return 0; 289296341Sdelphij EVP_PKEY_assign_EC_KEY(pkey, ec); 290296341Sdelphij /* Note: if error return, pkey is freed by parent routine */ 291296341Sdelphij if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) 292296341Sdelphij return 0; 293296341Sdelphij return EC_KEY_generate_key(pkey->pkey.ec); 294296341Sdelphij} 295238384Sjkim 296296341Sdelphijconst EVP_PKEY_METHOD ec_pkey_meth = { 297296341Sdelphij EVP_PKEY_EC, 298296341Sdelphij 0, 299296341Sdelphij pkey_ec_init, 300296341Sdelphij pkey_ec_copy, 301296341Sdelphij pkey_ec_cleanup, 302238384Sjkim 303296341Sdelphij 0, 304296341Sdelphij pkey_ec_paramgen, 305238384Sjkim 306296341Sdelphij 0, 307296341Sdelphij pkey_ec_keygen, 308238384Sjkim 309296341Sdelphij 0, 310296341Sdelphij pkey_ec_sign, 311238384Sjkim 312296341Sdelphij 0, 313296341Sdelphij pkey_ec_verify, 314238384Sjkim 315296341Sdelphij 0, 0, 316238384Sjkim 317296341Sdelphij 0, 0, 0, 0, 318238384Sjkim 319296341Sdelphij 0, 0, 320238384Sjkim 321296341Sdelphij 0, 0, 322238384Sjkim 323296341Sdelphij 0, 324279264Sdelphij#ifndef OPENSSL_NO_ECDH 325296341Sdelphij pkey_ec_derive, 326279264Sdelphij#else 327296341Sdelphij 0, 328279264Sdelphij#endif 329238384Sjkim 330296341Sdelphij pkey_ec_ctrl, 331296341Sdelphij pkey_ec_ctrl_str 332296341Sdelphij}; 333