409 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			409 lines
		
	
	
		
			11 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)
 | ||
|  |  */ | ||
|  | 
 | ||
|  | #if !defined(MBEDTLS_CONFIG_FILE)
 | ||
|  | #include "mbedtls/config.h"
 | ||
|  | #else
 | ||
|  | #include MBEDTLS_CONFIG_FILE
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_ECIES_C)
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_ECP_C)
 | ||
|  | #include "mbedtls/ecp.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_FAST_EC_C)
 | ||
|  | #include "mbedtls/fast_ec.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_ECDH_C)
 | ||
|  | #include "mbedtls/ecdh.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_MD_C)
 | ||
|  | #include "mbedtls/md.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_PK_C)
 | ||
|  | #include "mbedtls/pk.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_KDF_C)
 | ||
|  | #include "mbedtls/kdf.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_CIPHER_C)
 | ||
|  | #include "mbedtls/cipher.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_ASN1_PARSE_C)
 | ||
|  | #include "mbedtls/asn1.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_ASN1_WRITE_C)
 | ||
|  | #include "mbedtls/asn1write.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_PLATFORM_C)
 | ||
|  | #include "mbedtls/platform.h"
 | ||
|  | #else
 | ||
|  | #include <stdlib.h>
 | ||
|  | #define mbedtls_calloc    calloc
 | ||
|  | #define mbedtls_free      free
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #include "mbedtls/ecies_internal.h"
 | ||
|  | #include "mbedtls/ecies_envelope.h"
 | ||
|  | 
 | ||
|  | #define ECIES_OCTET_SIZE 8
 | ||
|  | #define ECIES_SIZE_TO_OCTETS(size) ((size + 7) / ECIES_OCTET_SIZE)
 | ||
|  | 
 | ||
|  | #define INVOKE_AND_CHECK(result,invocation) \
 | ||
|  |     if ((result = invocation) < 0) goto cleanup; | ||
|  | 
 | ||
|  | #define ACCUMULATE_AND_CHECK(result, len, invocation) \
 | ||
|  | do { \ | ||
|  |     if ((result = invocation) < 0) { \ | ||
|  |         goto cleanup; \ | ||
|  |     } else { \ | ||
|  |         len += result; \ | ||
|  |         result = 0; \ | ||
|  |     } \ | ||
|  | } while (0) | ||
|  | 
 | ||
|  | static int asn1_get_tag_len(unsigned char *p, const unsigned char *end, | ||
|  |         size_t *len) | ||
|  | { | ||
|  |     int result = 0; | ||
|  |     unsigned char *len_p = p + 1; | ||
|  |     INVOKE_AND_CHECK(result, | ||
|  |         mbedtls_asn1_get_len(&len_p, end, len) | ||
|  |     ); | ||
|  |     *len += len_p - p; | ||
|  | cleanup: | ||
|  |     return result; | ||
|  | } | ||
|  | 
 | ||
|  | const mbedtls_ecies_info_t* mbedtls_ecies_info_from_type(mbedtls_ecies_type_t type) | ||
|  | { | ||
|  |     switch( type ) | ||
|  |     { | ||
|  | #if defined(MBEDTLS_ECP_C) && defined (MBEDTLS_ECDH_C)
 | ||
|  |         case MBEDTLS_ECIES_ECP: | ||
|  |             return( &mbedtls_ecies_ecp_info ); | ||
|  | #endif
 | ||
|  | #if defined(MBEDTLS_FAST_EC_C)
 | ||
|  |         case MBEDTLS_ECIES_FAST_EC: | ||
|  |             return( &mbedtls_ecies_fast_ec_info ); | ||
|  | #endif
 | ||
|  |         default: | ||
|  |             return( NULL ); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_ECP_C) && defined (MBEDTLS_ECDH_C)
 | ||
|  | 
 | ||
|  | static void * ecp_key_alloc_wrap( void ) | ||
|  | { | ||
|  |     mbedtls_ecp_keypair* key = mbedtls_calloc( 1, sizeof( mbedtls_ecp_keypair ) ); | ||
|  | 
 | ||
|  |     if( key != NULL ) { | ||
|  |         mbedtls_ecp_keypair_init( key ); | ||
|  |     } | ||
|  | 
 | ||
|  |     return key; | ||
|  | } | ||
|  | 
 | ||
|  | static void ecp_key_free_wrap( void *key ) | ||
|  | { | ||
|  |     mbedtls_ecp_keypair_free( (mbedtls_ecp_keypair *) key ); | ||
|  | } | ||
|  | 
 | ||
|  | static int ecp_key_gen_ephemeral_wrap( void *src_key, void *dst_key, | ||
|  |         int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) | ||
|  | { | ||
|  |     mbedtls_ecp_keypair* src = (mbedtls_ecp_keypair *) src_key; | ||
|  |     mbedtls_ecp_keypair* dst = (mbedtls_ecp_keypair *) dst_key; | ||
|  | 
 | ||
|  |     return( mbedtls_ecp_gen_key( src->grp.id, dst, f_rng, p_rng ) ); | ||
|  | } | ||
|  | 
 | ||
|  | static int ecp_key_compute_shared_wrap( void *pub, void* prv, | ||
|  |         unsigned char* shared, size_t shared_len, | ||
|  |         int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) | ||
|  | { | ||
|  |     int result = 0; | ||
|  |     mbedtls_mpi shared_mpi; | ||
|  | 
 | ||
|  |     mbedtls_ecp_keypair* public = (mbedtls_ecp_keypair *) pub; | ||
|  |     mbedtls_ecp_keypair* private = (mbedtls_ecp_keypair *) prv; | ||
|  | 
 | ||
|  |     if (public->grp.id != private->grp.id) | ||
|  |         return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA; | ||
|  | 
 | ||
|  |     mbedtls_mpi_init( &shared_mpi ); | ||
|  | 
 | ||
|  |     INVOKE_AND_CHECK(result, | ||
|  |         mbedtls_ecdh_compute_shared( &public->grp, &shared_mpi, &public->Q, &private->d, | ||
|  |                                          f_rng, p_rng ) | ||
|  |     ); | ||
|  | 
 | ||
|  |     INVOKE_AND_CHECK(result, | ||
|  |         mbedtls_mpi_write_binary(&shared_mpi, shared, shared_len) | ||
|  |     ); | ||
|  | 
 | ||
|  | cleanup: | ||
|  |     mbedtls_mpi_free( &shared_mpi ); | ||
|  | 
 | ||
|  |     return( result ); | ||
|  | } | ||
|  | 
 | ||
|  | static size_t ecp_key_get_shared_len_wrap( void* key ) | ||
|  | { | ||
|  |     mbedtls_ecp_keypair* ecp_key = (mbedtls_ecp_keypair *) key; | ||
|  |     return( ECIES_SIZE_TO_OCTETS( ecp_key->grp.pbits ) ); | ||
|  | } | ||
|  | 
 | ||
|  | static int ecp_key_write_pub_asn1_wrap( unsigned char** p, unsigned char* start, void *key ) | ||
|  | { | ||
|  |     int result = 0; | ||
|  |     size_t len = 0; | ||
|  | 
 | ||
|  |     mbedtls_pk_context pk; | ||
|  | 
 | ||
|  |     pk.pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY); | ||
|  |     pk.pk_ctx = key; | ||
|  |     ACCUMULATE_AND_CHECK(result, len, | ||
|  |         mbedtls_pk_write_pubkey_der(&pk, start , *p - start) | ||
|  |     ); | ||
|  |     *p -= len; | ||
|  | cleanup: | ||
|  |     if (result < 0) | ||
|  |         return result; | ||
|  |     else | ||
|  |         return (int)len; | ||
|  | } | ||
|  | 
 | ||
|  | static int ecp_key_read_pub_asn1_wrap( unsigned char** p, const unsigned char* end, void *key ) | ||
|  | { | ||
|  |     int result = 0; | ||
|  |     mbedtls_pk_context pk; | ||
|  |     size_t key_len = 0; | ||
|  | 
 | ||
|  |     mbedtls_ecp_keypair* ecp_key = (mbedtls_ecp_keypair *) key; | ||
|  | 
 | ||
|  |     mbedtls_pk_init(&pk); | ||
|  | 
 | ||
|  |     INVOKE_AND_CHECK(result, | ||
|  |         asn1_get_tag_len(*p, end, &key_len) | ||
|  |     ); | ||
|  | 
 | ||
|  |     INVOKE_AND_CHECK(result, | ||
|  |         mbedtls_pk_parse_public_key(&pk, *p, key_len) | ||
|  |     ); | ||
|  |     *p += key_len; | ||
|  | 
 | ||
|  |     if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_ECKEY) || | ||
|  |         mbedtls_pk_can_do(&pk, MBEDTLS_PK_ECKEY_DH) || | ||
|  |         mbedtls_pk_can_do(&pk, MBEDTLS_PK_ECDSA)) | ||
|  |     { | ||
|  |         INVOKE_AND_CHECK(result, | ||
|  |             mbedtls_ecp_group_copy( &ecp_key->grp, &mbedtls_pk_ec(pk)->grp ) | ||
|  |         ); | ||
|  |         INVOKE_AND_CHECK(result, | ||
|  |             mbedtls_mpi_copy( &ecp_key->d, &mbedtls_pk_ec(pk)->d ) | ||
|  |         ); | ||
|  |         INVOKE_AND_CHECK(result, | ||
|  |             mbedtls_ecp_copy( &ecp_key->Q, &mbedtls_pk_ec(pk)->Q ) | ||
|  |         ); | ||
|  |     } else { | ||
|  |         result = MBEDTLS_ERR_ECIES_MALFORMED_DATA; | ||
|  |     } | ||
|  | cleanup: | ||
|  |     mbedtls_pk_free(&pk); | ||
|  |     return result; | ||
|  | } | ||
|  | 
 | ||
|  | const mbedtls_ecies_info_t mbedtls_ecies_ecp_info = { | ||
|  |     MBEDTLS_ECIES_ECP, // type
 | ||
|  |     "ECIES_ECP", // name
 | ||
|  |     ecp_key_alloc_wrap, // key_alloc_func
 | ||
|  |     ecp_key_free_wrap, // key_free_func
 | ||
|  |     ecp_key_gen_ephemeral_wrap, // key_gen_ephemeral_func
 | ||
|  |     ecp_key_compute_shared_wrap, // key_make_shared_func
 | ||
|  |     ecp_key_get_shared_len_wrap, // key_get_shared_len_func
 | ||
|  |     ecp_key_write_pub_asn1_wrap, // key_write_pub_asn1_func
 | ||
|  |     ecp_key_read_pub_asn1_wrap, // key_read_pub_asn1_func
 | ||
|  | }; | ||
|  | 
 | ||
|  | #endif /* MBEDTLS_ECP_C &&  MBEDTLS_ECDH_C */
 | ||
|  | 
 | ||
|  | #if defined(MBEDTLS_FAST_EC_C)
 | ||
|  | 
 | ||
|  | static void * fast_ec_key_alloc_wrap( void ) | ||
|  | { | ||
|  |     mbedtls_fast_ec_keypair_t* key = mbedtls_calloc( 1, sizeof( mbedtls_fast_ec_keypair_t ) ); | ||
|  | 
 | ||
|  |     if( key != NULL ) { | ||
|  |         mbedtls_fast_ec_init( key ); | ||
|  |     } | ||
|  | 
 | ||
|  |     return key; | ||
|  | } | ||
|  | 
 | ||
|  | static void fast_ec_key_free_wrap( void *key ) | ||
|  | { | ||
|  |     mbedtls_fast_ec_free( (mbedtls_fast_ec_keypair_t *) key ); | ||
|  | } | ||
|  | 
 | ||
|  | static int fast_ec_key_gen_ephemeral_wrap( void *src_key, void *dst_key, | ||
|  |         int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) | ||
|  | { | ||
|  |     int result = 0; | ||
|  | 
 | ||
|  |     mbedtls_fast_ec_keypair_t* src = (mbedtls_fast_ec_keypair_t *) src_key; | ||
|  |     mbedtls_fast_ec_keypair_t* dst = (mbedtls_fast_ec_keypair_t *) dst_key; | ||
|  | 
 | ||
|  |     INVOKE_AND_CHECK(result, | ||
|  |         mbedtls_fast_ec_setup( dst, src->info ) | ||
|  |     ); | ||
|  | 
 | ||
|  |     INVOKE_AND_CHECK(result, | ||
|  |         mbedtls_fast_ec_gen_key( dst, f_rng, p_rng ) | ||
|  |     ); | ||
|  | 
 | ||
|  | cleanup: | ||
|  |     return( result ); | ||
|  | } | ||
|  | 
 | ||
|  | static int fast_ec_key_compute_shared_wrap( void *pub, void* prv, | ||
|  |         unsigned char* shared, size_t shared_len, | ||
|  |         int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) | ||
|  | { | ||
|  |     mbedtls_fast_ec_keypair_t* public = (mbedtls_fast_ec_keypair_t *) pub; | ||
|  |     mbedtls_fast_ec_keypair_t* private = (mbedtls_fast_ec_keypair_t *) prv; | ||
|  | 
 | ||
|  |     (void) f_rng; | ||
|  |     (void) p_rng; | ||
|  | 
 | ||
|  |     if( mbedtls_fast_ec_get_type( public->info ) != mbedtls_fast_ec_get_type( private->info ) ) | ||
|  |         return MBEDTLS_ERR_ECIES_BAD_INPUT_DATA; | ||
|  | 
 | ||
|  |     return( mbedtls_fast_ec_compute_shared( public, private, shared, shared_len ) ); | ||
|  | } | ||
|  | 
 | ||
|  | static size_t fast_ec_key_get_shared_len_wrap( void* key ) | ||
|  | { | ||
|  |     return( mbedtls_fast_ec_get_shared_len( ( (mbedtls_fast_ec_keypair_t *) key )->info ) ); | ||
|  | } | ||
|  | 
 | ||
|  | static int fast_ec_key_write_pub_asn1_wrap( unsigned char** p, unsigned char* start, void *key ) | ||
|  | { | ||
|  |     int result = 0; | ||
|  |     size_t len = 0; | ||
|  | 
 | ||
|  |     mbedtls_pk_context pk; | ||
|  | 
 | ||
|  |     pk.pk_info = mbedtls_pk_info_from_type( mbedtls_pk_from_fast_ec_type( | ||
|  |             mbedtls_fast_ec_get_type( ( (mbedtls_fast_ec_keypair_t *) key )->info ) ) ); | ||
|  | 
 | ||
|  |     if( pk.pk_info == NULL) | ||
|  |         INVOKE_AND_CHECK( result, MBEDTLS_ERR_ECIES_MALFORMED_DATA ); | ||
|  | 
 | ||
|  |     pk.pk_ctx = key; | ||
|  |     ACCUMULATE_AND_CHECK(result, len, | ||
|  |         mbedtls_pk_write_pubkey_der(&pk, start , *p - start) | ||
|  |     ); | ||
|  |     *p -= len; | ||
|  | cleanup: | ||
|  |     if (result < 0) | ||
|  |         return result; | ||
|  |     else | ||
|  |         return (int)len; | ||
|  | } | ||
|  | 
 | ||
|  | static int fast_ec_key_read_pub_asn1_wrap( unsigned char** p, const unsigned char* end, void *key ) | ||
|  | { | ||
|  |     int result = 0; | ||
|  |     mbedtls_pk_context pk; | ||
|  |     size_t key_len = 0; | ||
|  | 
 | ||
|  |     mbedtls_fast_ec_keypair_t* fast_ec_key = (mbedtls_fast_ec_keypair_t *) key; | ||
|  | 
 | ||
|  |     mbedtls_pk_init(&pk); | ||
|  | 
 | ||
|  |     INVOKE_AND_CHECK(result, | ||
|  |         asn1_get_tag_len(*p, end, &key_len) | ||
|  |     ); | ||
|  | 
 | ||
|  |     INVOKE_AND_CHECK(result, | ||
|  |         mbedtls_pk_parse_public_key(&pk, *p, key_len) | ||
|  |     ); | ||
|  |     *p += key_len; | ||
|  | 
 | ||
|  |     if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_X25519) || mbedtls_pk_can_do(&pk, MBEDTLS_PK_ED25519) ) | ||
|  |     { | ||
|  |         INVOKE_AND_CHECK(result, | ||
|  |             mbedtls_fast_ec_copy( fast_ec_key, mbedtls_pk_fast_ec(pk) ) | ||
|  |         ); | ||
|  |     } else { | ||
|  |         result = MBEDTLS_ERR_ECIES_MALFORMED_DATA; | ||
|  |     } | ||
|  | cleanup: | ||
|  |     mbedtls_pk_free(&pk); | ||
|  |     return result; | ||
|  | } | ||
|  | 
 | ||
|  | const mbedtls_ecies_info_t mbedtls_ecies_fast_ec_info = { | ||
|  |     MBEDTLS_ECIES_FAST_EC, // type
 | ||
|  |     "ECIES_FAST_EC", // name
 | ||
|  |     fast_ec_key_alloc_wrap, // key_alloc_func
 | ||
|  |     fast_ec_key_free_wrap, // key_free_func
 | ||
|  |     fast_ec_key_gen_ephemeral_wrap, // key_gen_ephemeral_func
 | ||
|  |     fast_ec_key_compute_shared_wrap, // key_make_shared_func
 | ||
|  |     fast_ec_key_get_shared_len_wrap, // key_get_shared_len_func
 | ||
|  |     fast_ec_key_write_pub_asn1_wrap, // key_write_pub_asn1_func
 | ||
|  |     fast_ec_key_read_pub_asn1_wrap, // key_read_pub_asn1_func
 | ||
|  | }; | ||
|  | 
 | ||
|  | #endif /* MBEDTLS_FAST_EC_C */
 | ||
|  | 
 | ||
|  | #endif /* MBEDTLS_ECIES_C */
 |