361 lines
10 KiB
C
361 lines
10 KiB
C
/**
|
|
* Copyright (C) 2015-2016 Virgil Security Inc.
|
|
*
|
|
* Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
|
|
*
|
|
* 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) Neither the name of the copyright holder nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS 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 AUTHOR 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 file is part of extension to mbed TLS (https://tls.mbed.org)
|
|
*/
|
|
/**
|
|
* Implementation is based on the standard ISO 18033-2.
|
|
*/
|
|
|
|
#if !defined(MBEDTLS_CONFIG_FILE)
|
|
#include "mbedtls/config.h"
|
|
#else
|
|
#include MBEDTLS_CONFIG_FILE
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_ECIES_C)
|
|
|
|
#include "mbedtls/ecies.h"
|
|
#include "mbedtls/ecies_envelope.h"
|
|
|
|
#include "mbedtls/asn1.h"
|
|
#include "mbedtls/asn1write.h"
|
|
#include "mbedtls/cipher.h"
|
|
#include "mbedtls/md.h"
|
|
#include "mbedtls/kdf.h"
|
|
#include "mbedtls/pk.h"
|
|
#include "mbedtls/oid.h"
|
|
|
|
#define INVOKE_AND_CHECK(result, invocation) \
|
|
do { \
|
|
if ((result = invocation) < 0) \
|
|
{ \
|
|
return MBEDTLS_ERR_ECIES_MALFORMED_DATA | result; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define ACCUMULATE_AND_CHECK(result, len, invocation) \
|
|
do { \
|
|
if ((result = invocation) < 0) \
|
|
{ \
|
|
return MBEDTLS_ERR_ECIES_OUTPUT_TOO_SMALL | result; \
|
|
} \
|
|
else \
|
|
{ \
|
|
len += result; \
|
|
result = 0; \
|
|
} \
|
|
} while (0)
|
|
|
|
int mbedtls_ecies_read_envelope(unsigned char **p, const unsigned char *end,
|
|
size_t *len)
|
|
{
|
|
int result = 0;
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
|
|
);
|
|
return result;
|
|
}
|
|
|
|
int mbedtls_ecies_read_version(unsigned char **p, const unsigned char *end,
|
|
int *version)
|
|
{
|
|
int result = 0;
|
|
if (version == NULL)
|
|
{
|
|
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
|
|
}
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_int(p, end, version)
|
|
);
|
|
return result;
|
|
}
|
|
|
|
|
|
int mbedtls_ecies_read_kdf(unsigned char **p, const unsigned char *end,
|
|
mbedtls_kdf_type_t *kdf_type, mbedtls_md_type_t *md_type)
|
|
{
|
|
int result = 0;
|
|
size_t len = 0;
|
|
mbedtls_asn1_buf kdf_alg;
|
|
mbedtls_asn1_buf md_alg;
|
|
|
|
if (kdf_type == NULL || md_type == NULL)
|
|
{
|
|
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
|
|
}
|
|
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
|
|
);
|
|
|
|
if ((end - *p) < 1)
|
|
{
|
|
INVOKE_AND_CHECK(result, MBEDTLS_ERR_ASN1_OUT_OF_DATA);
|
|
}
|
|
kdf_alg.tag = **p;
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, &kdf_alg.len, MBEDTLS_ASN1_OID)
|
|
);
|
|
kdf_alg.p = *p;
|
|
*p += kdf_alg.len;
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_oid_get_kdf_alg(&kdf_alg, kdf_type)
|
|
);
|
|
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
|
|
);
|
|
md_alg.tag = **p;
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, &md_alg.len, MBEDTLS_ASN1_OID)
|
|
);
|
|
md_alg.p = *p;
|
|
*p += md_alg.len;
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_oid_get_md_alg(&md_alg, md_type)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_NULL)
|
|
);
|
|
|
|
return result;
|
|
}
|
|
|
|
int mbedtls_ecies_read_hmac(unsigned char **p, const unsigned char *end,
|
|
mbedtls_md_type_t *hmac_type, unsigned char **hmac, size_t *hmac_len)
|
|
{
|
|
|
|
int result = 0;
|
|
size_t len = 0;
|
|
mbedtls_asn1_buf hmac_alg;
|
|
|
|
if (hmac_type == NULL || hmac == NULL)
|
|
{
|
|
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
|
|
}
|
|
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_alg_null(p, end, &hmac_alg)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_oid_get_md_alg(&hmac_alg, hmac_type)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, hmac_len, MBEDTLS_ASN1_OCTET_STRING)
|
|
);
|
|
*hmac = *p;
|
|
*p += *hmac_len;
|
|
|
|
return result;
|
|
}
|
|
|
|
int mbedtls_ecies_read_content_info(unsigned char **p, const unsigned char *end,
|
|
mbedtls_cipher_type_t *cipher_type, unsigned char **iv, size_t *iv_len,
|
|
unsigned char **data, size_t *data_len)
|
|
{
|
|
int result = 0;
|
|
size_t len = 0;
|
|
mbedtls_asn1_buf cipher_alg;
|
|
mbedtls_asn1_buf cipher_params;
|
|
|
|
if (cipher_type == NULL || iv == NULL || iv_len == NULL || data == NULL || data_len == NULL)
|
|
{
|
|
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
|
|
}
|
|
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_alg(p, end, &cipher_alg, &cipher_params)
|
|
);
|
|
if (cipher_params.tag != MBEDTLS_ASN1_OCTET_STRING)
|
|
{
|
|
INVOKE_AND_CHECK(result, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
|
|
}
|
|
*iv = cipher_params.p;
|
|
*iv_len = cipher_params.len;
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_oid_get_cipher_alg(&cipher_alg, cipher_type)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_asn1_get_tag(p, end, data_len, MBEDTLS_ASN1_OCTET_STRING)
|
|
);
|
|
*data = *p;
|
|
*p += *data_len;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
int mbedtls_ecies_write_envelope(unsigned char **p, unsigned char *start, size_t len)
|
|
{
|
|
int result = 0;
|
|
size_t asn_len = 0;
|
|
ACCUMULATE_AND_CHECK(result, asn_len,
|
|
mbedtls_asn1_write_len(p, start, len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, asn_len,
|
|
mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
|
|
);
|
|
return (int)asn_len;
|
|
}
|
|
|
|
int mbedtls_ecies_write_version(unsigned char **p, unsigned char *start, int version)
|
|
{
|
|
int result = 0;
|
|
size_t asn_len = 0;
|
|
ACCUMULATE_AND_CHECK(result, asn_len,
|
|
mbedtls_asn1_write_int(p, start, version)
|
|
);
|
|
return (int)asn_len;
|
|
}
|
|
|
|
int mbedtls_ecies_write_kdf(unsigned char **p, unsigned char *start,
|
|
mbedtls_kdf_type_t kdf_type, mbedtls_md_type_t md_type)
|
|
{
|
|
int result = 0;
|
|
int len = 0;
|
|
size_t md_par_len = 0;
|
|
size_t kdf_par_len = 0;
|
|
const char *oid = NULL;
|
|
size_t oid_len = 0;
|
|
|
|
if (kdf_type == MBEDTLS_KDF_NONE || md_type == MBEDTLS_MD_NONE)
|
|
{
|
|
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
|
|
}
|
|
|
|
ACCUMULATE_AND_CHECK(result, md_par_len,
|
|
mbedtls_asn1_write_null(p, start)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_oid_get_oid_by_md(md_type, &oid, &oid_len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, kdf_par_len,
|
|
mbedtls_asn1_write_algorithm_identifier(p, start, oid, oid_len, md_par_len)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_oid_get_oid_by_kdf_alg(kdf_type, &oid, &oid_len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_algorithm_identifier(p, start, oid, oid_len, kdf_par_len)
|
|
);
|
|
|
|
return (int)len;
|
|
}
|
|
|
|
int mbedtls_ecies_write_hmac(unsigned char **p, unsigned char *start,
|
|
mbedtls_md_type_t hmac_type, const unsigned char *hmac, size_t hmac_len)
|
|
{
|
|
int result = 0;
|
|
size_t len = 0;
|
|
size_t par_len = 0;
|
|
const char *oid = NULL;
|
|
size_t oid_len = 0;
|
|
|
|
if (hmac_type == MBEDTLS_MD_NONE || hmac == NULL || hmac_len == 0)
|
|
{
|
|
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
|
|
}
|
|
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_octet_string(p, start, hmac, hmac_len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, par_len,
|
|
mbedtls_asn1_write_null(p, start)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_oid_get_oid_by_md(hmac_type, &oid, &oid_len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_algorithm_identifier(p, start, oid, oid_len, par_len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_len(p, start, len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
|
|
);
|
|
|
|
return (int)len;
|
|
}
|
|
|
|
int mbedtls_ecies_write_content_info(unsigned char **p, unsigned char *start,
|
|
mbedtls_cipher_type_t cipher_type, const unsigned char *iv, size_t iv_len,
|
|
size_t data_len)
|
|
{
|
|
int result = 0;
|
|
size_t len = data_len;
|
|
size_t par_len = 0;
|
|
const char *oid = NULL;
|
|
size_t oid_len = 0;
|
|
|
|
if (cipher_type == MBEDTLS_CIPHER_NONE || iv == NULL || iv_len == 0)
|
|
{
|
|
return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA;
|
|
}
|
|
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_len(p, start, data_len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_OCTET_STRING)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, par_len,
|
|
mbedtls_asn1_write_octet_string(p, start, iv, iv_len)
|
|
);
|
|
INVOKE_AND_CHECK(result,
|
|
mbedtls_oid_get_oid_by_cipher_alg(cipher_type, &oid, &oid_len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_algorithm_identifier(p, start, oid, oid_len, par_len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_len(p, start, len)
|
|
);
|
|
ACCUMULATE_AND_CHECK(result, len,
|
|
mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
|
|
);
|
|
|
|
return (int)len;
|
|
}
|
|
|
|
#endif /* defined(MBEDTLS_ECIES_C) */
|