diff options
Diffstat (limited to 'src/crypto/ec/ec_asn1.c')
-rw-r--r-- | src/crypto/ec/ec_asn1.c | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/src/crypto/ec/ec_asn1.c b/src/crypto/ec/ec_asn1.c new file mode 100644 index 0000000..ce9b3f4 --- /dev/null +++ b/src/crypto/ec/ec_asn1.c @@ -0,0 +1,599 @@ +/* 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 <string.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; + } + + 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; + } + + if (priv_key->publicKey) { + const uint8_t *pub_oct; + int pub_oct_len; + + pub_oct = M_ASN1_STRING_data(priv_key->publicKey); + pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey); + /* The first byte (the point conversion form) must be present. */ + if (pub_oct_len <= 0) { + OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, EC_R_BUFFER_TOO_SMALL); + goto err; + } + /* 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; + } + } else { + if (!EC_POINT_mul(ret->group, ret->pub_key, ret->priv_key, NULL, NULL, + NULL)) { + OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB); + goto err; + } + /* Remember the original private-key-only encoding. */ + ret->enc_flag |= EC_PKEY_NO_PUBKEY; + } + + ok = 1; + +err: + if (!ok) { + if (ret) { + EC_KEY_free(ret); + } + ret = NULL; + if (a) { + *a = ret; + } + } + + 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; +} |