/* 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 #include #include #include #include #include #include #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; 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); DECLARE_ASN1_ALLOC_FUNCTIONS(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; ASN1_CHOICE(ECPKPARAMETERS) = { ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT), ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS), } ASN1_CHOICE_END(ECPKPARAMETERS); DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS); DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS); IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS); 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); DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY); DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, 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 = 0; if (params == NULL) { OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_MISSING_PARAMETERS); return NULL; } if (params->type != 0) { OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_NON_NAMED_CURVE); return NULL; } nid = OBJ_obj2nid(params->value.named_curve); 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); OPENSSL_free(*outp); *outp = NULL; return 0; } if (!new_buffer) { *outp += buf_len; } return buf_len; }