| /* Written by Nils Larsch for the OpenSSL project. */ |
| /* ==================================================================== |
| * Copyright (c) 2000-2003 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/ec.h> |
| |
| #include <openssl/asn1.h> |
| #include <openssl/asn1t.h> |
| #include <openssl/bn.h> |
| #include <openssl/err.h> |
| #include <openssl/mem.h> |
| #include <openssl/obj.h> |
| |
| #include "internal.h" |
| |
| |
| typedef struct x9_62_fieldid_st { |
| ASN1_OBJECT *fieldType; |
| union { |
| char *ptr; |
| /* NID_X9_62_prime_field */ |
| ASN1_INTEGER *prime; |
| /* anything else */ |
| ASN1_TYPE *other; |
| } p; |
| } X9_62_FIELDID; |
| |
| ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY); |
| |
| ASN1_ADB(X9_62_FIELDID) = { |
| ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)), |
| } ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL); |
| |
| ASN1_SEQUENCE(X9_62_FIELDID) = { |
| ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT), |
| ASN1_ADB_OBJECT(X9_62_FIELDID) |
| } ASN1_SEQUENCE_END(X9_62_FIELDID); |
| |
| typedef struct x9_62_curve_st { |
| ASN1_OCTET_STRING *a; |
| ASN1_OCTET_STRING *b; |
| ASN1_BIT_STRING *seed; |
| } X9_62_CURVE; |
| |
| ASN1_SEQUENCE(X9_62_CURVE) = { |
| ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING), |
| ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING), |
| ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING) |
| } ASN1_SEQUENCE_END(X9_62_CURVE); |
| |
| typedef struct ec_parameters_st { |
| long version; |
| X9_62_FIELDID *fieldID; |
| X9_62_CURVE *curve; |
| ASN1_OCTET_STRING *base; |
| ASN1_INTEGER *order; |
| ASN1_INTEGER *cofactor; |
| } ECPARAMETERS; |
| |
| DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS); |
| |
| ASN1_SEQUENCE(ECPARAMETERS) = { |
| ASN1_SIMPLE(ECPARAMETERS, version, LONG), |
| ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID), |
| ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE), |
| ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING), |
| ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER), |
| ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER) |
| } ASN1_SEQUENCE_END(ECPARAMETERS); |
| |
| IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS); |
| |
| typedef struct ecpk_parameters_st { |
| int type; |
| union { |
| ASN1_OBJECT *named_curve; |
| ECPARAMETERS *parameters; |
| } value; |
| } ECPKPARAMETERS; |
| |
| /* SEC1 ECPrivateKey */ |
| typedef struct ec_privatekey_st { |
| long version; |
| ASN1_OCTET_STRING *privateKey; |
| ECPKPARAMETERS *parameters; |
| ASN1_BIT_STRING *publicKey; |
| } EC_PRIVATEKEY; |
| |
| DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS); |
| DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS); |
| |
| ASN1_CHOICE(ECPKPARAMETERS) = { |
| ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT), |
| ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS), |
| } ASN1_CHOICE_END(ECPKPARAMETERS); |
| |
| IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS); |
| |
| DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY); |
| DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY); |
| |
| ASN1_SEQUENCE(EC_PRIVATEKEY) = { |
| ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG), |
| ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING), |
| ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0), |
| ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1), |
| } ASN1_SEQUENCE_END(EC_PRIVATEKEY); |
| |
| IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY); |
| |
| |
| ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *group, |
| ECPKPARAMETERS *params) { |
| int ok = 0, nid; |
| ECPKPARAMETERS *ret = params; |
| |
| if (ret == NULL) { |
| ret = ECPKPARAMETERS_new(); |
| if (ret == NULL) { |
| OPENSSL_PUT_ERROR(EC, ec_asn1_group2pkparameters, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| } else { |
| if (ret->value.named_curve) { |
| ASN1_OBJECT_free(ret->value.named_curve); |
| } |
| } |
| |
| /* use the ASN.1 OID to describe the the elliptic curve parameters. */ |
| nid = EC_GROUP_get_curve_name(group); |
| if (nid) { |
| ret->type = 0; |
| ret->value.named_curve = (ASN1_OBJECT*) OBJ_nid2obj(nid); |
| ok = ret->value.named_curve != NULL; |
| } |
| |
| if (!ok) { |
| ECPKPARAMETERS_free(ret); |
| return NULL; |
| } |
| |
| return ret; |
| } |
| |
| EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *params) { |
| EC_GROUP *ret = NULL; |
| int nid = NID_undef; |
| |
| if (params == NULL) { |
| OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_MISSING_PARAMETERS); |
| return NULL; |
| } |
| |
| if (params->type == 0) { |
| nid = OBJ_obj2nid(params->value.named_curve); |
| } else if (params->type == 1) { |
| /* We don't support arbitary curves so we attempt to recognise it from the |
| * group order. */ |
| const ECPARAMETERS *ecparams = params->value.parameters; |
| unsigned i; |
| const struct built_in_curve *curve; |
| |
| for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) { |
| curve = &OPENSSL_built_in_curves[i]; |
| const unsigned param_len = curve->data->param_len; |
| if (ecparams->order->length == param_len && |
| memcmp(ecparams->order->data, &curve->data->data[param_len * 5], |
| param_len) == 0) { |
| nid = curve->nid; |
| break; |
| } |
| } |
| } |
| |
| if (nid == NID_undef) { |
| OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_NON_NAMED_CURVE); |
| return NULL; |
| } |
| |
| ret = EC_GROUP_new_by_curve_name(nid); |
| if (ret == NULL) { |
| OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, |
| EC_R_EC_GROUP_NEW_BY_NAME_FAILURE); |
| return NULL; |
| } |
| |
| return ret; |
| } |
| |
| static EC_GROUP *d2i_ECPKParameters(EC_GROUP **groupp, const uint8_t **inp, |
| long len) { |
| EC_GROUP *group = NULL; |
| ECPKPARAMETERS *params = NULL; |
| |
| params = d2i_ECPKPARAMETERS(NULL, inp, len); |
| if (params == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPKParameters, EC_R_D2I_ECPKPARAMETERS_FAILURE); |
| ECPKPARAMETERS_free(params); |
| return NULL; |
| } |
| |
| group = ec_asn1_pkparameters2group(params); |
| if (group == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPKParameters, EC_R_PKPARAMETERS2GROUP_FAILURE); |
| ECPKPARAMETERS_free(params); |
| return NULL; |
| } |
| |
| if (groupp && *groupp) { |
| EC_GROUP_free(*groupp); |
| } |
| if (groupp) { |
| *groupp = group; |
| } |
| |
| ECPKPARAMETERS_free(params); |
| return group; |
| } |
| |
| static int i2d_ECPKParameters(const EC_GROUP *group, uint8_t **outp) { |
| int ret = 0; |
| ECPKPARAMETERS *tmp = ec_asn1_group2pkparameters(group, NULL); |
| if (tmp == NULL) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPKParameters, EC_R_GROUP2PKPARAMETERS_FAILURE); |
| return 0; |
| } |
| ret = i2d_ECPKPARAMETERS(tmp, outp); |
| if (ret == 0) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPKParameters, EC_R_I2D_ECPKPARAMETERS_FAILURE); |
| ECPKPARAMETERS_free(tmp); |
| return 0; |
| } |
| ECPKPARAMETERS_free(tmp); |
| return ret; |
| } |
| |
| EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const uint8_t **in, long len) { |
| int ok = 0; |
| EC_KEY *ret = NULL; |
| EC_PRIVATEKEY *priv_key = NULL; |
| |
| priv_key = EC_PRIVATEKEY_new(); |
| if (priv_key == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| |
| priv_key = d2i_EC_PRIVATEKEY(&priv_key, in, len); |
| if (priv_key == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB); |
| EC_PRIVATEKEY_free(priv_key); |
| return NULL; |
| } |
| |
| if (a == NULL || *a == NULL) { |
| ret = EC_KEY_new(); |
| if (ret == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_MALLOC_FAILURE); |
| goto err; |
| } |
| if (a) { |
| *a = ret; |
| } |
| } else { |
| ret = *a; |
| } |
| |
| if (priv_key->parameters) { |
| if (ret->group) { |
| EC_GROUP_free(ret->group); |
| } |
| ret->group = ec_asn1_pkparameters2group(priv_key->parameters); |
| } |
| |
| if (ret->group == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB); |
| goto err; |
| } |
| |
| ret->version = priv_key->version; |
| |
| if (priv_key->privateKey) { |
| ret->priv_key = |
| BN_bin2bn(M_ASN1_STRING_data(priv_key->privateKey), |
| M_ASN1_STRING_length(priv_key->privateKey), ret->priv_key); |
| if (ret->priv_key == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_BN_LIB); |
| goto err; |
| } |
| } else { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, EC_R_MISSING_PRIVATE_KEY); |
| goto err; |
| } |
| |
| /* TODO(fork): loading the public key is silly. Why not calculate it? */ |
| if (priv_key->publicKey) { |
| const uint8_t *pub_oct; |
| size_t pub_oct_len; |
| |
| if (ret->pub_key) { |
| EC_POINT_free(ret->pub_key); |
| } |
| ret->pub_key = EC_POINT_new(ret->group); |
| if (ret->pub_key == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB); |
| goto err; |
| } |
| pub_oct = M_ASN1_STRING_data(priv_key->publicKey); |
| pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey); |
| /* save the point conversion form */ |
| ret->conv_form = (point_conversion_form_t)(pub_oct[0] & ~0x01); |
| if (!EC_POINT_oct2point(ret->group, ret->pub_key, pub_oct, pub_oct_len, |
| NULL)) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB); |
| goto err; |
| } |
| } |
| |
| ok = 1; |
| |
| err: |
| if (!ok) { |
| if (ret) { |
| EC_KEY_free(ret); |
| } |
| ret = NULL; |
| } |
| |
| if (priv_key) { |
| EC_PRIVATEKEY_free(priv_key); |
| } |
| |
| return ret; |
| } |
| |
| int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp) { |
| int ret = 0, ok = 0; |
| uint8_t *buffer = NULL; |
| size_t buf_len = 0, tmp_len; |
| EC_PRIVATEKEY *priv_key = NULL; |
| |
| if (key == NULL || key->group == NULL || key->priv_key == NULL) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_PASSED_NULL_PARAMETER); |
| goto err; |
| } |
| |
| priv_key = EC_PRIVATEKEY_new(); |
| if (priv_key == NULL) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE); |
| goto err; |
| } |
| |
| priv_key->version = key->version; |
| |
| buf_len = BN_num_bytes(key->priv_key); |
| buffer = OPENSSL_malloc(buf_len); |
| if (buffer == NULL) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE); |
| goto err; |
| } |
| |
| if (!BN_bn2bin(key->priv_key, buffer)) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_BN_LIB); |
| goto err; |
| } |
| |
| if (!M_ASN1_OCTET_STRING_set(priv_key->privateKey, buffer, buf_len)) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_ASN1_LIB); |
| goto err; |
| } |
| |
| /* TODO(fork): replace this flexibility with key sensible default? */ |
| if (!(key->enc_flag & EC_PKEY_NO_PARAMETERS)) { |
| if ((priv_key->parameters = ec_asn1_group2pkparameters( |
| key->group, priv_key->parameters)) == NULL) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_EC_LIB); |
| goto err; |
| } |
| } |
| |
| /* TODO(fork): replace this flexibility with key sensible default? */ |
| if (!(key->enc_flag & EC_PKEY_NO_PUBKEY) && key->pub_key != NULL) { |
| priv_key->publicKey = M_ASN1_BIT_STRING_new(); |
| if (priv_key->publicKey == NULL) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE); |
| goto err; |
| } |
| |
| tmp_len = EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, NULL, |
| 0, NULL); |
| |
| if (tmp_len > buf_len) { |
| uint8_t *tmp_buffer = OPENSSL_realloc(buffer, tmp_len); |
| if (!tmp_buffer) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE); |
| goto err; |
| } |
| buffer = tmp_buffer; |
| buf_len = tmp_len; |
| } |
| |
| if (!EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, buffer, |
| buf_len, NULL)) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_EC_LIB); |
| goto err; |
| } |
| |
| priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); |
| priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT; |
| if (!M_ASN1_BIT_STRING_set(priv_key->publicKey, buffer, buf_len)) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_ASN1_LIB); |
| goto err; |
| } |
| } |
| |
| ret = i2d_EC_PRIVATEKEY(priv_key, outp); |
| if (ret == 0) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_EC_LIB); |
| goto err; |
| } |
| ok = 1; |
| |
| err: |
| if (buffer) { |
| OPENSSL_free(buffer); |
| } |
| if (priv_key) { |
| EC_PRIVATEKEY_free(priv_key); |
| } |
| return (ok ? ret : 0); |
| } |
| |
| int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) { |
| if (key == NULL) { |
| OPENSSL_PUT_ERROR(EC, i2d_ECParameters, ERR_R_PASSED_NULL_PARAMETER); |
| return 0; |
| } |
| return i2d_ECPKParameters(key->group, outp); |
| } |
| |
| EC_KEY *d2i_ECParameters(EC_KEY **key, const uint8_t **inp, long len) { |
| EC_KEY *ret; |
| |
| if (inp == NULL || *inp == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECParameters, ERR_R_PASSED_NULL_PARAMETER); |
| return NULL; |
| } |
| |
| if (key == NULL || *key == NULL) { |
| ret = EC_KEY_new(); |
| if (ret == NULL) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECParameters, ERR_R_MALLOC_FAILURE); |
| return NULL; |
| } |
| if (key) { |
| *key = ret; |
| } |
| } else { |
| ret = *key; |
| } |
| |
| if (!d2i_ECPKParameters(&ret->group, inp, len)) { |
| OPENSSL_PUT_ERROR(EC, d2i_ECParameters, ERR_R_EC_LIB); |
| return NULL; |
| } |
| |
| return ret; |
| } |
| |
| EC_KEY *o2i_ECPublicKey(EC_KEY **keyp, const uint8_t **inp, long len) { |
| EC_KEY *ret = NULL; |
| |
| if (keyp == NULL || *keyp == NULL || (*keyp)->group == NULL) { |
| OPENSSL_PUT_ERROR(EC, o2i_ECPublicKey, ERR_R_PASSED_NULL_PARAMETER); |
| return 0; |
| } |
| ret = *keyp; |
| if (ret->pub_key == NULL && |
| (ret->pub_key = EC_POINT_new(ret->group)) == NULL) { |
| OPENSSL_PUT_ERROR(EC, o2i_ECPublicKey, ERR_R_MALLOC_FAILURE); |
| return 0; |
| } |
| if (!EC_POINT_oct2point(ret->group, ret->pub_key, *inp, len, NULL)) { |
| OPENSSL_PUT_ERROR(EC, o2i_ECPublicKey, ERR_R_EC_LIB); |
| return 0; |
| } |
| /* save the point conversion form */ |
| ret->conv_form = (point_conversion_form_t)(*inp[0] & ~0x01); |
| *inp += len; |
| return ret; |
| } |
| |
| int i2o_ECPublicKey(const EC_KEY *key, uint8_t **outp) { |
| size_t buf_len = 0; |
| int new_buffer = 0; |
| |
| if (key == NULL) { |
| OPENSSL_PUT_ERROR(EC, i2o_ECPublicKey, ERR_R_PASSED_NULL_PARAMETER); |
| return 0; |
| } |
| |
| buf_len = EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, NULL, |
| 0, NULL); |
| |
| if (outp == NULL || buf_len == 0) { |
| /* out == NULL => just return the length of the octet string */ |
| return buf_len; |
| } |
| |
| if (*outp == NULL) { |
| *outp = OPENSSL_malloc(buf_len); |
| if (*outp == NULL) { |
| OPENSSL_PUT_ERROR(EC, i2o_ECPublicKey, ERR_R_MALLOC_FAILURE); |
| return 0; |
| } |
| new_buffer = 1; |
| } |
| if (!EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, *outp, |
| buf_len, NULL)) { |
| OPENSSL_PUT_ERROR(EC, i2o_ECPublicKey, ERR_R_EC_LIB); |
| if (new_buffer) { |
| OPENSSL_free(*outp); |
| *outp = NULL; |
| } |
| return 0; |
| } |
| |
| if (!new_buffer) { |
| *outp += buf_len; |
| } |
| return buf_len; |
| } |