|  | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 
|  | * project 2006. | 
|  | */ | 
|  | /* ==================================================================== | 
|  | * Copyright (c) 2006 The OpenSSL Project.  All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | * | 
|  | * 1. Redistributions of source code must retain the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer. | 
|  | * | 
|  | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer in | 
|  | *    the documentation and/or other materials provided with the | 
|  | *    distribution. | 
|  | * | 
|  | * 3. All advertising materials mentioning features or use of this | 
|  | *    software must display the following acknowledgment: | 
|  | *    "This product includes software developed by the OpenSSL Project | 
|  | *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | 
|  | * | 
|  | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | 
|  | *    endorse or promote products derived from this software without | 
|  | *    prior written permission. For written permission, please contact | 
|  | *    licensing@OpenSSL.org. | 
|  | * | 
|  | * 5. Products derived from this software may not be called "OpenSSL" | 
|  | *    nor may "OpenSSL" appear in their names without prior written | 
|  | *    permission of the OpenSSL Project. | 
|  | * | 
|  | * 6. Redistributions of any form whatsoever must retain the following | 
|  | *    acknowledgment: | 
|  | *    "This product includes software developed by the OpenSSL Project | 
|  | *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | 
|  | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|  | * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR | 
|  | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 
|  | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
|  | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
|  | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | 
|  | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
|  | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | 
|  | * OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | * ==================================================================== | 
|  | * | 
|  | * This product includes cryptographic software written by Eric Young | 
|  | * (eay@cryptsoft.com).  This product includes software written by Tim | 
|  | * Hudson (tjh@cryptsoft.com). */ | 
|  |  | 
|  | #include <openssl/evp.h> | 
|  |  | 
|  | #include <openssl/asn1t.h> | 
|  | #include <openssl/bn.h> | 
|  | #include <openssl/ec.h> | 
|  | #include <openssl/err.h> | 
|  | #include <openssl/mem.h> | 
|  | #include <openssl/obj.h> | 
|  | #include <openssl/x509.h> | 
|  |  | 
|  | #include "internal.h" | 
|  |  | 
|  |  | 
|  | static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key) { | 
|  | const EC_GROUP *group; | 
|  | int nid; | 
|  |  | 
|  | if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_param2type, EVP_R_MISSING_PARAMETERS); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | nid = EC_GROUP_get_curve_name(group); | 
|  | if (nid == NID_undef) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_param2type, EVP_R_NO_NID_FOR_CURVE); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | *ppval = (void*) OBJ_nid2obj(nid); | 
|  | *pptype = V_ASN1_OBJECT; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { | 
|  | EC_KEY *ec_key = pkey->pkey.ec; | 
|  | void *pval = NULL; | 
|  | int ptype; | 
|  | uint8_t *penc = NULL, *p; | 
|  | int penclen; | 
|  |  | 
|  | if (!eckey_param2type(&ptype, &pval, ec_key)) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_pub_encode, ERR_R_EC_LIB); | 
|  | return 0; | 
|  | } | 
|  | penclen = i2o_ECPublicKey(ec_key, NULL); | 
|  | if (penclen <= 0) { | 
|  | goto err; | 
|  | } | 
|  | penc = OPENSSL_malloc(penclen); | 
|  | if (!penc) { | 
|  | goto err; | 
|  | } | 
|  | p = penc; | 
|  | penclen = i2o_ECPublicKey(ec_key, &p); | 
|  | if (penclen <= 0) { | 
|  | goto err; | 
|  | } | 
|  | if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC), ptype, pval, penc, | 
|  | penclen)) { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | err: | 
|  | if (ptype == V_ASN1_OBJECT) { | 
|  | ASN1_OBJECT_free(pval); | 
|  | } else { | 
|  | ASN1_STRING_free(pval); | 
|  | } | 
|  | if (penc) { | 
|  | OPENSSL_free(penc); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static EC_KEY *eckey_type2param(int ptype, void *pval) { | 
|  | EC_KEY *eckey = NULL; | 
|  |  | 
|  | if (ptype == V_ASN1_SEQUENCE) { | 
|  | ASN1_STRING *pstr = pval; | 
|  | const uint8_t *pm = pstr->data; | 
|  | int pmlen = pstr->length; | 
|  |  | 
|  | eckey = d2i_ECParameters(NULL, &pm, pmlen); | 
|  | if (eckey == NULL) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_type2param, EVP_R_DECODE_ERROR); | 
|  | goto err; | 
|  | } | 
|  | } else if (ptype == V_ASN1_OBJECT) { | 
|  | ASN1_OBJECT *poid = pval; | 
|  |  | 
|  | /* type == V_ASN1_OBJECT => the parameters are given | 
|  | * by an asn1 OID */ | 
|  | eckey = EC_KEY_new_by_curve_name(OBJ_obj2nid(poid)); | 
|  | if (eckey == NULL) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_type2param, ERR_R_MALLOC_FAILURE); | 
|  | goto err; | 
|  | } | 
|  | } else { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_type2param, EVP_R_DECODE_ERROR); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | return eckey; | 
|  |  | 
|  | err: | 
|  | if (eckey) { | 
|  | EC_KEY_free(eckey); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { | 
|  | const uint8_t *p = NULL; | 
|  | void *pval; | 
|  | int ptype, pklen; | 
|  | EC_KEY *eckey = NULL; | 
|  | X509_ALGOR *palg; | 
|  |  | 
|  | if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) { | 
|  | return 0; | 
|  | } | 
|  | X509_ALGOR_get0(NULL, &ptype, &pval, palg); | 
|  |  | 
|  | eckey = eckey_type2param(ptype, pval); | 
|  | if (!eckey) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_pub_decode, ERR_R_EC_LIB); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* We have parameters now set public key */ | 
|  | if (!o2i_ECPublicKey(&eckey, &p, pklen)) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_pub_decode, EVP_R_DECODE_ERROR); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | EVP_PKEY_assign_EC_KEY(pkey, eckey); | 
|  | return 1; | 
|  |  | 
|  | err: | 
|  | if (eckey) { | 
|  | EC_KEY_free(eckey); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { | 
|  | int r; | 
|  | const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec); | 
|  | const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec), | 
|  | *pb = EC_KEY_get0_public_key(b->pkey.ec); | 
|  | r = EC_POINT_cmp(group, pa, pb, NULL); | 
|  | if (r == 0) { | 
|  | return 1; | 
|  | } else if (r == 1) { | 
|  | return 0; | 
|  | } else { | 
|  | return -2; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) { | 
|  | const uint8_t *p = NULL; | 
|  | void *pval; | 
|  | int ptype, pklen; | 
|  | EC_KEY *eckey = NULL; | 
|  | X509_ALGOR *palg; | 
|  |  | 
|  | if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) { | 
|  | return 0; | 
|  | } | 
|  | X509_ALGOR_get0(NULL, &ptype, &pval, palg); | 
|  |  | 
|  | eckey = eckey_type2param(ptype, pval); | 
|  |  | 
|  | if (!eckey) { | 
|  | goto ecliberr; | 
|  | } | 
|  |  | 
|  | /* We have parameters now set private key */ | 
|  | if (!d2i_ECPrivateKey(&eckey, &p, pklen)) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, EVP_R_DECODE_ERROR); | 
|  | goto ecerr; | 
|  | } | 
|  |  | 
|  | /* calculate public key (if necessary) */ | 
|  | if (EC_KEY_get0_public_key(eckey) == NULL) { | 
|  | const BIGNUM *priv_key; | 
|  | const EC_GROUP *group; | 
|  | EC_POINT *pub_key; | 
|  | /* the public key was not included in the SEC1 private | 
|  | * key => calculate the public key */ | 
|  | group = EC_KEY_get0_group(eckey); | 
|  | pub_key = EC_POINT_new(group); | 
|  | if (pub_key == NULL) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB); | 
|  | goto ecliberr; | 
|  | } | 
|  | if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) { | 
|  | EC_POINT_free(pub_key); | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB); | 
|  | goto ecliberr; | 
|  | } | 
|  | priv_key = EC_KEY_get0_private_key(eckey); | 
|  | if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)) { | 
|  | EC_POINT_free(pub_key); | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB); | 
|  | goto ecliberr; | 
|  | } | 
|  | if (EC_KEY_set_public_key(eckey, pub_key) == 0) { | 
|  | EC_POINT_free(pub_key); | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB); | 
|  | goto ecliberr; | 
|  | } | 
|  | EC_POINT_free(pub_key); | 
|  | } | 
|  |  | 
|  | EVP_PKEY_assign_EC_KEY(pkey, eckey); | 
|  | return 1; | 
|  |  | 
|  | ecliberr: | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB); | 
|  | ecerr: | 
|  | if (eckey) { | 
|  | EC_KEY_free(eckey); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) { | 
|  | EC_KEY *ec_key; | 
|  | uint8_t *ep, *p; | 
|  | int eplen, ptype; | 
|  | void *pval; | 
|  | unsigned int tmp_flags, old_flags; | 
|  |  | 
|  | ec_key = pkey->pkey.ec; | 
|  |  | 
|  | if (!eckey_param2type(&ptype, &pval, ec_key)) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, EVP_R_DECODE_ERROR); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* set the private key */ | 
|  |  | 
|  | /* do not include the parameters in the SEC1 private key | 
|  | * see PKCS#11 12.11 */ | 
|  | old_flags = EC_KEY_get_enc_flags(ec_key); | 
|  | tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS; | 
|  | EC_KEY_set_enc_flags(ec_key, tmp_flags); | 
|  | eplen = i2d_ECPrivateKey(ec_key, NULL); | 
|  | if (!eplen) { | 
|  | EC_KEY_set_enc_flags(ec_key, old_flags); | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, ERR_R_EC_LIB); | 
|  | return 0; | 
|  | } | 
|  | ep = (uint8_t *)OPENSSL_malloc(eplen); | 
|  | if (!ep) { | 
|  | EC_KEY_set_enc_flags(ec_key, old_flags); | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, ERR_R_MALLOC_FAILURE); | 
|  | return 0; | 
|  | } | 
|  | p = ep; | 
|  | if (!i2d_ECPrivateKey(ec_key, &p)) { | 
|  | EC_KEY_set_enc_flags(ec_key, old_flags); | 
|  | OPENSSL_free(ep); | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, ERR_R_EC_LIB); | 
|  | return 0; | 
|  | } | 
|  | /* restore old encoding flags */ | 
|  | EC_KEY_set_enc_flags(ec_key, old_flags); | 
|  |  | 
|  | if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_X9_62_id_ecPublicKey), | 
|  | 0, ptype, pval, ep, eplen)) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int int_ec_size(const EVP_PKEY *pkey) { | 
|  | return ECDSA_size(pkey->pkey.ec); | 
|  | } | 
|  |  | 
|  | static int ec_bits(const EVP_PKEY *pkey) { | 
|  | BIGNUM *order = BN_new(); | 
|  | const EC_GROUP *group; | 
|  | int ret; | 
|  |  | 
|  | if (!order) { | 
|  | ERR_clear_error(); | 
|  | return 0; | 
|  | } | 
|  | group = EC_KEY_get0_group(pkey->pkey.ec); | 
|  | if (!EC_GROUP_get_order(group, order, NULL)) { | 
|  | ERR_clear_error(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ret = BN_num_bits(order); | 
|  | BN_free(order); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int ec_missing_parameters(const EVP_PKEY *pkey) { | 
|  | return EC_KEY_get0_group(pkey->pkey.ec) == NULL; | 
|  | } | 
|  |  | 
|  | static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) { | 
|  | EC_GROUP *group = EC_GROUP_dup(EC_KEY_get0_group(from->pkey.ec)); | 
|  | if (group == NULL || | 
|  | EC_KEY_set_group(to->pkey.ec, group) == 0) { | 
|  | return 0; | 
|  | } | 
|  | EC_GROUP_free(group); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { | 
|  | const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec), | 
|  | *group_b = EC_KEY_get0_group(b->pkey.ec); | 
|  | if (EC_GROUP_cmp(group_a, group_b, NULL) != 0) { | 
|  | /* mismatch */ | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); } | 
|  |  | 
|  | static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) { | 
|  | uint8_t *buffer = NULL; | 
|  | const char *ecstr; | 
|  | size_t buf_len = 0, i; | 
|  | int ret = 0, reason = ERR_R_BIO_LIB; | 
|  | BIGNUM *order = NULL; | 
|  | BN_CTX *ctx = NULL; | 
|  | const EC_GROUP *group; | 
|  | const EC_POINT *public_key; | 
|  | const BIGNUM *priv_key; | 
|  | uint8_t *pub_key_bytes = NULL; | 
|  | size_t pub_key_bytes_len = 0; | 
|  |  | 
|  | if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { | 
|  | reason = ERR_R_PASSED_NULL_PARAMETER; | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | ctx = BN_CTX_new(); | 
|  | if (ctx == NULL) { | 
|  | reason = ERR_R_MALLOC_FAILURE; | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | if (ktype > 0) { | 
|  | public_key = EC_KEY_get0_public_key(x); | 
|  | if (public_key != NULL) { | 
|  | pub_key_bytes_len = EC_POINT_point2oct( | 
|  | group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx); | 
|  | if (pub_key_bytes_len == 0) { | 
|  | reason = ERR_R_MALLOC_FAILURE; | 
|  | goto err; | 
|  | } | 
|  | pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len); | 
|  | if (pub_key_bytes == NULL) { | 
|  | reason = ERR_R_MALLOC_FAILURE; | 
|  | goto err; | 
|  | } | 
|  | pub_key_bytes_len = | 
|  | EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x), | 
|  | pub_key_bytes, pub_key_bytes_len, ctx); | 
|  | if (pub_key_bytes_len == 0) { | 
|  | reason = ERR_R_MALLOC_FAILURE; | 
|  | goto err; | 
|  | } | 
|  | buf_len = pub_key_bytes_len; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ktype == 2) { | 
|  | priv_key = EC_KEY_get0_private_key(x); | 
|  | if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len) { | 
|  | buf_len = i; | 
|  | } | 
|  | } else { | 
|  | priv_key = NULL; | 
|  | } | 
|  |  | 
|  | if (ktype > 0) { | 
|  | buf_len += 10; | 
|  | if ((buffer = OPENSSL_malloc(buf_len)) == NULL) { | 
|  | reason = ERR_R_MALLOC_FAILURE; | 
|  | goto err; | 
|  | } | 
|  | } | 
|  | if (ktype == 2) { | 
|  | ecstr = "Private-Key"; | 
|  | } else if (ktype == 1) { | 
|  | ecstr = "Public-Key"; | 
|  | } else { | 
|  | ecstr = "ECDSA-Parameters"; | 
|  | } | 
|  |  | 
|  | if (!BIO_indent(bp, off, 128)) { | 
|  | goto err; | 
|  | } | 
|  | order = BN_new(); | 
|  | if (order == NULL || !EC_GROUP_get_order(group, order, NULL) || | 
|  | BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) { | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | if ((priv_key != NULL) && | 
|  | !ASN1_bn_print(bp, "priv:", priv_key, buffer, off)) { | 
|  | goto err; | 
|  | } | 
|  | if (pub_key_bytes != NULL) { | 
|  | BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off); | 
|  | } | 
|  | /* TODO(fork): implement */ | 
|  | /* | 
|  | if (!ECPKParameters_print(bp, group, off)) | 
|  | goto err; */ | 
|  | ret = 1; | 
|  |  | 
|  | err: | 
|  | if (!ret) { | 
|  | OPENSSL_PUT_ERROR(EVP, do_EC_KEY_print, reason); | 
|  | } | 
|  | if (pub_key_bytes) { | 
|  | OPENSSL_free(pub_key_bytes); | 
|  | } | 
|  | if (order) { | 
|  | BN_free(order); | 
|  | } | 
|  | if (ctx) { | 
|  | BN_CTX_free(ctx); | 
|  | } | 
|  | if (buffer != NULL) { | 
|  | OPENSSL_free(buffer); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int eckey_param_decode(EVP_PKEY *pkey, const uint8_t **pder, | 
|  | int derlen) { | 
|  | EC_KEY *eckey; | 
|  | if (!(eckey = d2i_ECParameters(NULL, pder, derlen))) { | 
|  | OPENSSL_PUT_ERROR(EVP, eckey_param_decode, ERR_R_EC_LIB); | 
|  | return 0; | 
|  | } | 
|  | EVP_PKEY_assign_EC_KEY(pkey, eckey); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int eckey_param_encode(const EVP_PKEY *pkey, uint8_t **pder) { | 
|  | return i2d_ECParameters(pkey->pkey.ec, pder); | 
|  | } | 
|  |  | 
|  | static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, | 
|  | ASN1_PCTX *ctx) { | 
|  | return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0); | 
|  | } | 
|  |  | 
|  | static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, | 
|  | ASN1_PCTX *ctx) { | 
|  | return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1); | 
|  | } | 
|  |  | 
|  |  | 
|  | static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, | 
|  | ASN1_PCTX *ctx) { | 
|  | return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2); | 
|  | } | 
|  |  | 
|  | static int eckey_opaque(const EVP_PKEY *pkey) { | 
|  | return EC_KEY_is_opaque(pkey->pkey.ec); | 
|  | } | 
|  |  | 
|  | static int old_ec_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, | 
|  | int derlen) { | 
|  | EC_KEY *ec; | 
|  | if (!(ec = d2i_ECPrivateKey(NULL, pder, derlen))) { | 
|  | OPENSSL_PUT_ERROR(EVP, old_ec_priv_decode, EVP_R_DECODE_ERROR); | 
|  | return 0; | 
|  | } | 
|  | EVP_PKEY_assign_EC_KEY(pkey, ec); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int old_ec_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) { | 
|  | return i2d_ECPrivateKey(pkey->pkey.ec, pder); | 
|  | } | 
|  |  | 
|  | const EVP_PKEY_ASN1_METHOD ec_asn1_meth = { | 
|  | EVP_PKEY_EC, | 
|  | EVP_PKEY_EC, | 
|  | 0, | 
|  | "EC", | 
|  | "OpenSSL EC algorithm", | 
|  |  | 
|  | eckey_pub_decode, | 
|  | eckey_pub_encode, | 
|  | eckey_pub_cmp, | 
|  | eckey_pub_print, | 
|  |  | 
|  | eckey_priv_decode, | 
|  | eckey_priv_encode, | 
|  | eckey_priv_print, | 
|  |  | 
|  | eckey_opaque, | 
|  | 0 /* pkey_supports_digest */, | 
|  |  | 
|  | int_ec_size, | 
|  | ec_bits, | 
|  |  | 
|  | eckey_param_decode, | 
|  | eckey_param_encode, | 
|  | ec_missing_parameters, | 
|  | ec_copy_parameters, | 
|  | ec_cmp_parameters, | 
|  | eckey_param_print, | 
|  | 0, | 
|  |  | 
|  | int_ec_free, | 
|  | old_ec_priv_decode, | 
|  | old_ec_priv_encode | 
|  | }; |