1
0
mirror of https://github.com/Mbed-TLS/mbedtls.git synced 2025-07-29 11:41:15 +03:00

Merge mbed-crypto into mbedtls: the merge commit

Merge `unremove-non-crypto` into `mbedtls/development`. The branch
`unremove-non-crypto` was obtained by starting from `mbed-crypto/development`,
then reverting many commits that removed X.509 and TLS functionality when Mbed
Crypto forked from Mbed TLS (the “unremoval”), then make a few tweaks to
facilitate the merge.

The unremoval step restored old versions of some tls files. If a file doesn't
exist in mbed-crypto, check out the mbedtls version, regardless of what
happened during the unremoval of tls files in the crypto tree. Also
unconditionally take the mbedtls version of a few files where the
modifications are completely project-specific and are not relevant in
mbed-crypto:

* `.github/issue_template.md`: completely different. We may want to reconcile
  them independently as a follow-up.
* `.travis.yml`: would only be reverted to an earlier tls version.
* `README.md`: completely different. We may want to reconcile them
  independently as a follow-up.
* `doxygen/input/doc_mainpage.h`: the changes in crypto were minimal and not
  relevant except as a stopgap as mbed-crypto did not have its own product
  versioning in the Doxygen documentation.
* `tests/.jenkins/Jenkinsfile`: completely different.
* `tests/data_files/Makefile`: there were no changes in mbed-crypto,
  but the unremoval step restored an old version.

Shell script for everything to do after the merge apart from the conflict
resolution:
```
tls_files=($(comm -23 <(git ls-tree -r --name-only HEAD) <(git ls-tree -r --name-only $(git merge-base upstream-crypto/development MERGE_HEAD))))
tls_files+=($tls_files .github/issue_template.md .travis.yml README.md doxygen/input/doc_mainpage.h tests/.jenkins/Jenkinsfile tests/data_files/Makefile)
git checkout --theirs HEAD -- $tls_files
git add -- $tls_files
```

Resolve the remaining conflicts:

* `library/CMakeLists.txt`:
    * Keep the TLS definition of `src_crypto`
    * `USE_SHARED_MBEDTLS_LIBRARY`: keep all three libraries, with both
      `include` and `crypto/include` in `target_include_directories`, all with
      version `2.21.0`.
* `programs/Makefile`:
    * Reconcile the APPS lists (add/add from a differently-formatted common
      ancestor): insert the `psa/*` from crypto into the tls list.
    * Keep the `fuzz` target defined only in tls version.
    * Keep the recipe (only in tls version) cleaning `ssl_pthread_server`
      stuff for the `clean` target.
* `scripts/config.py`:
    * `include_in_full`: add/add conflict. Keep both.
* `tests/scripts/all.sh`:
    * `component_test_no_use_psa_crypto_full_cmake_asan`: partially old
      version in crypto. Take the tls version.
    * `component_test_malloc_0_null` and more: take
      `component_test_malloc_0_null` from crypto (with `config.py` rather than
      `config.pl`, and with `$ASAN_FLAGS` rather than an explicit list), but
      add the call to `ssl-opt.sh` from tls. Take the other components from
      crypto.

With this commit, building and running the unit tests with both `make ` and
`cmake` work in the default configuration on Linux. Other platforms, build
systems and configurations are likely not to work, and there is some
regression in test coverage.

There is some loss of functionality because the unremoval step restored older
versions of tls content. This commit contains the latest tls version of
tls-only files, but some changes from the tls side in files that existed on
both sides have regressed. Most problematic changes are hunks that remove some
tls-specific feature and contain either a C preprocessor symbol identifying a
tls-specific module or option, or the name of a tls-specific file. Hunks
that remove a tls-specific preprocessor symbol can be identified with the
regular expression `^-.*MBEDTLS_(ERR_)?(PKCS11|X509|NET|SSL)_`.

Subsequent commits will revert a few parts of the patch from this merge commit
in order to restore the tls functionality that it removes, ensure that the
test coverage includes what was covered in either branch, and fix test
failures.
This commit is contained in:
Gilles Peskine
2020-03-19 15:38:54 +01:00
397 changed files with 168444 additions and 995 deletions

View File

@ -1,6 +1,14 @@
option(USE_STATIC_MBEDTLS_LIBRARY "Build mbed TLS static library." ON)
option(USE_SHARED_MBEDTLS_LIBRARY "Build mbed TLS shared library." OFF)
option(LINK_WITH_PTHREAD "Explicitly link mbed TLS library to pthread." OFF)
option(LINK_WITH_TRUSTED_STORAGE "Explicitly link mbed TLS library to trusted_storage." OFF)
# Set the project root directory if it's not already defined, as may happen if
# the library folder is included directly by a parent project, without
# including the top level CMakeLists.txt.
if(NOT DEFINED MBEDTLS_DIR)
set(MBEDTLS_DIR ${CMAKE_SOURCE_DIR})
endif()
set(src_crypto
aes.c
@ -38,7 +46,6 @@ set(src_crypto
md2.c
md4.c
md5.c
md_wrap.c
memory_buffer_alloc.c
nist_kw.c
oid.c
@ -53,6 +60,11 @@ set(src_crypto
platform.c
platform_util.c
poly1305.c
psa_crypto.c
psa_crypto_se.c
psa_crypto_slot_management.c
psa_crypto_storage.c
psa_its_file.c
ripemd160.c
rsa.c
rsa_internal.c
@ -134,6 +146,10 @@ if(LINK_WITH_PTHREAD)
set(libs ${libs} pthread)
endif()
if(LINK_WITH_TRUSTED_STORAGE)
set(libs ${libs} trusted_storage)
endif()
if (NOT USE_STATIC_MBEDTLS_LIBRARY AND NOT USE_SHARED_MBEDTLS_LIBRARY)
message(FATAL_ERROR "Need to choose static or shared mbedtls build!")
endif(NOT USE_STATIC_MBEDTLS_LIBRARY AND NOT USE_SHARED_MBEDTLS_LIBRARY)
@ -149,31 +165,41 @@ elseif(USE_STATIC_MBEDTLS_LIBRARY)
endif()
if(USE_STATIC_MBEDTLS_LIBRARY)
add_library(${mbedx509_static_target} STATIC ${src_x509})
set_target_properties(${mbedx509_static_target} PROPERTIES OUTPUT_NAME mbedx509)
target_link_libraries(${mbedx509_static_target} ${libs} ${mbedcrypto_static_target})
target_include_directories(${mbedx509_static_target}
add_library(${mbedcrypto_static_target} STATIC ${src_crypto})
set_target_properties(${mbedcrypto_static_target} PROPERTIES OUTPUT_NAME mbedcrypto)
target_link_libraries(${mbedcrypto_static_target} ${libs})
target_include_directories(${mbedcrypto_static_target}
PUBLIC ${MBEDTLS_DIR}/include/
PUBLIC ${MBEDTLS_DIR}/crypto/include/)
add_library(${mbedtls_static_target} STATIC ${src_tls})
set_target_properties(${mbedtls_static_target} PROPERTIES OUTPUT_NAME mbedtls)
target_link_libraries(${mbedtls_static_target} ${libs} ${mbedx509_static_target})
target_include_directories(${mbedtls_static_target}
PUBLIC ${MBEDTLS_DIR}/include/
PUBLIC ${MBEDTLS_DIR}/crypto/include/
)
if(USE_CRYPTO_SUBMODULE)
install(TARGETS ${mbedcrypto_static_target}
DESTINATION ${LIB_INSTALL_DIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
else()
add_library(${mbedx509_static_target} STATIC ${src_x509})
set_target_properties(${mbedx509_static_target} PROPERTIES OUTPUT_NAME mbedx509)
target_link_libraries(${mbedx509_static_target} ${libs} ${mbedcrypto_static_target})
add_library(${mbedtls_static_target} STATIC ${src_tls})
set_target_properties(${mbedtls_static_target} PROPERTIES OUTPUT_NAME mbedtls)
target_link_libraries(${mbedtls_static_target} ${libs} ${mbedx509_static_target})
install(TARGETS ${mbedtls_static_target} ${mbedx509_static_target}
DESTINATION ${LIB_INSTALL_DIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(TARGETS ${mbedtls_static_target} ${mbedx509_static_target} ${mbedcrypto_static_target}
DESTINATION ${LIB_INSTALL_DIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
endif()
endif(USE_STATIC_MBEDTLS_LIBRARY)
if(USE_SHARED_MBEDTLS_LIBRARY)
add_library(mbedcrypto SHARED ${src_crypto})
set_target_properties(mbedcrypto PROPERTIES VERSION 2.21.0 SOVERSION 4)
target_link_libraries(mbedcrypto ${libs})
target_include_directories(mbedcrypto
PUBLIC ${MBEDTLS_DIR}/include/
PUBLIC ${MBEDTLS_DIR}/crypto/include/)
add_library(mbedx509 SHARED ${src_x509})
set_target_properties(mbedx509 PROPERTIES VERSION 2.21.0 SOVERSION 1)
target_link_libraries(mbedx509 ${libs} mbedcrypto)
@ -188,13 +214,33 @@ if(USE_SHARED_MBEDTLS_LIBRARY)
PUBLIC ${MBEDTLS_DIR}/include/
PUBLIC ${MBEDTLS_DIR}/crypto/include/)
install(TARGETS mbedtls mbedx509
DESTINATION ${LIB_INSTALL_DIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
if(USE_CRYPTO_SUBMODULE)
install(TARGETS mbedcrypto
DESTINATION ${LIB_INSTALL_DIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
else()
add_library(mbedx509 SHARED ${src_x509})
set_target_properties(mbedx509 PROPERTIES VERSION 2.16.0 SOVERSION 0)
target_link_libraries(mbedx509 ${libs} mbedcrypto)
add_library(mbedtls SHARED ${src_tls})
set_target_properties(mbedtls PROPERTIES VERSION 2.16.0 SOVERSION 12)
target_link_libraries(mbedtls ${libs} mbedx509)
install(TARGETS mbedtls mbedx509 mbedcrypto
DESTINATION ${LIB_INSTALL_DIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
endif()
endif(USE_SHARED_MBEDTLS_LIBRARY)
add_custom_target(lib DEPENDS mbedx509 mbedtls)
if(USE_STATIC_MBEDTLS_LIBRARY AND USE_SHARED_MBEDTLS_LIBRARY)
add_dependencies(lib mbedx509_static mbedtls_static)
if(USE_CRYPTO_SUBMODULE)
add_custom_target(crypto_lib DEPENDS mbedcrypto)
if(USE_STATIC_MBEDTLS_LIBRARY AND USE_SHARED_MBEDTLS_LIBRARY)
add_dependencies(crypto_lib mbedcrypto_static)
endif()
else()
add_custom_target(lib DEPENDS mbedcrypto mbedx509 mbedtls)
if(USE_STATIC_MBEDTLS_LIBRARY AND USE_SHARED_MBEDTLS_LIBRARY)
add_dependencies(lib mbedcrypto_static mbedx509_static mbedtls_static)
endif()
endif()

View File

@ -5,7 +5,8 @@ CFLAGS ?= -O2
WARNING_CFLAGS ?= -Wall -Wextra
LDFLAGS ?=
LOCAL_CFLAGS = $(WARNING_CFLAGS) -I../include -D_FILE_OFFSET_BITS=64
CRYPTO_INCLUDES ?= -I../include
LOCAL_CFLAGS = $(WARNING_CFLAGS) $(CRYPTO_INCLUDES) -D_FILE_OFFSET_BITS=64
LOCAL_LDFLAGS =
ifdef DEBUG
@ -35,8 +36,8 @@ LOCAL_CFLAGS += -fPIC -fpic
endif
endif
SOEXT_TLS=so.13
SOEXT_X509=so.1
SOEXT_TLS=so.12
SOEXT_X509=so.0
SOEXT_CRYPTO=so.4
# Set AR_DASH= (empty string) to use an ar implementation that does not accept
@ -63,12 +64,48 @@ DLEXT = dylib
endif
endif
OBJS_CRYPTO= aes.o aesni.o arc4.o \
aria.o asn1parse.o asn1write.o \
base64.o bignum.o blowfish.o \
camellia.o ccm.o chacha20.o \
chachapoly.o cipher.o cipher_wrap.o \
cmac.o ctr_drbg.o des.o \
dhm.o ecdh.o ecdsa.o \
ecjpake.o ecp.o \
ecp_curves.o entropy.o entropy_poll.o \
gcm.o havege.o \
hkdf.o \
hmac_drbg.o md.o md2.o \
md4.o md5.o \
memory_buffer_alloc.o nist_kw.o \
oid.o padlock.o pem.o \
pk.o pk_wrap.o pkcs12.o \
pkcs5.o pkparse.o pkwrite.o \
platform.o platform_util.o poly1305.o \
psa_crypto.o psa_crypto_se.o \
psa_crypto_slot_management.o \
psa_crypto_storage.o \
psa_its_file.o \
ripemd160.o rsa_internal.o rsa.o \
sha1.o sha256.o sha512.o \
threading.o timing.o \
xtea.o
# For files generated by the parent project (Mbed TLS) when building Mbed
# Crypto as a submodule, ensure that the parent project instance is used.
ifeq ($(USE_CRYPTO_SUBMODULE), 1)
OBJS_CRYPTO += $(patsubst %.c,%.o, $(realpath ../../library/error.c))
OBJS_CRYPTO += $(patsubst %.c,%.o, $(realpath ../../library/version.c))
OBJS_CRYPTO += $(patsubst %.c,%.o, $(realpath ../../library/version_features.c))
else
OBJS_CRYPTO += error.o
OBJS_CRYPTO += version.o
OBJS_CRYPTO += version_features.o
endif
# Look in crypto for libmbedcrypto.
LOCAL_LDFLAGS += -L../crypto/library
LOCAL_CFLAGS += -I../crypto/include
CRYPTO := ../crypto/library/
include ../3rdparty/Makefile.inc
LOCAL_CFLAGS+=$(THIRDPARTY_INCLUDES)
OBJS_CRYPTO+=$(THIRDPARTY_CRYPTO_OBJECTS)
OBJS_X509= certs.o pkcs11.o x509.o \
x509_create.o x509_crl.o x509_crt.o \
@ -81,12 +118,6 @@ OBJS_TLS= debug.o net_sockets.o \
ssl_srv.o ssl_ticket.o \
ssl_tls.o
INCLUDING_FROM_MBEDTLS:=1
include ../crypto/3rdparty/Makefile.inc
LOCAL_CFLAGS += $(patsubst -I../3rdparty/%, -I../crypto/3rdparty/%, $(THIRDPARTY_INCLUDES))
OBJS_CRYPTO += $(patsubst ../3rdparty/%, ../crypto/3rdparty/%, $(THIRDPARTY_CRYPTO_OBJECTS))
.SILENT:
.PHONY: all static shared clean
@ -139,7 +170,7 @@ ifneq ($(APPLE_BUILD),0)
endif
endif
libmbedx509.$(SOEXT_X509): $(OBJS_X509) $(CRYPTO)libmbedcrypto.so
libmbedx509.$(SOEXT_X509): $(OBJS_X509) libmbedcrypto.so
echo " LD $@"
$(CC) -shared -Wl,-soname,$@ -L. -lmbedcrypto $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_X509)
@ -147,21 +178,42 @@ libmbedx509.so: libmbedx509.$(SOEXT_X509)
echo " LN $@ -> $<"
ln -sf $< $@
libmbedx509.dylib: $(OBJS_X509) $(CRYPTO)libmbedcrypto.dylib
libmbedx509.dylib: $(OBJS_X509) libmbedcrypto.dylib
echo " LD $@"
$(CC) -dynamiclib -L. -lmbedcrypto $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_X509)
libmbedx509.dll: $(OBJS_X509) $(CRYPTO)libmbedcrypto.dll
libmbedx509.dll: $(OBJS_X509) libmbedcrypto.dll
echo " LD $@"
$(CC) -shared -Wl,-soname,$@ -Wl,--out-implib,$@.a -o $@ $(OBJS_X509) -lws2_32 -lwinmm -lgdi32 -L. -lmbedcrypto -static-libgcc $(LOCAL_LDFLAGS) $(LDFLAGS)
libmbedcrypto.%:
$(MAKE) CRYPTO_INCLUDES:="-I../../include -I../include" -C ../crypto/library $@
# crypto
libmbedcrypto.a: $(OBJS_CRYPTO)
echo " AR $@"
$(AR) $(ARFLAGS) $@ $(OBJS_CRYPTO)
ifdef APPLE_BUILD
ifneq ($(APPLE_BUILD),0)
echo " RL $@"
$(RL) $(RLFLAGS) $@
endif
endif
libmbedcrypto.$(DLEXT): $(CRYPTO)libmbedcrypto.$(DLEXT)
libmbedcrypto.$(SOEXT_CRYPTO): $(OBJS_CRYPTO)
echo " LD $@"
$(CC) -shared -Wl,-soname,$@ $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_CRYPTO)
$(CRYPTO)libmbedcrypto.$(DLEXT): | libmbedcrypto.a
$(MAKE) CRYPTO_INCLUDES:="-I../../include -I../include" -C ../crypto/library libmbedcrypto.$(DLEXT)
libmbedcrypto.so: libmbedcrypto.$(SOEXT_CRYPTO)
echo " LN $@ -> $<"
ln -sf $< $@
libmbedcrypto.dylib: $(OBJS_CRYPTO)
echo " LD $@"
$(CC) -dynamiclib $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ $(OBJS_CRYPTO)
libmbedcrypto.dll: $(OBJS_CRYPTO)
echo " LD $@"
$(CC) -shared -Wl,-soname,$@ -Wl,--out-implib,$@.a -o $@ $(OBJS_CRYPTO) -lws2_32 -lwinmm -lgdi32 -static-libgcc $(LOCAL_LDFLAGS) $(LDFLAGS)
libmbedcrypto.$(DLEXT): | libmbedcrypto.a
.c.o:
echo " CC $<"

2234
library/aes.c Normal file

File diff suppressed because it is too large Load Diff

470
library/aesni.c Normal file
View File

@ -0,0 +1,470 @@
/*
* AES-NI support functions
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* [AES-WP] http://software.intel.com/en-us/articles/intel-advanced-encryption-standard-aes-instructions-set
* [CLMUL-WP] http://software.intel.com/en-us/articles/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode/
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_AESNI_C)
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
#warning "MBEDTLS_AESNI_C is known to cause spurious error reports with some memory sanitizers as they do not understand the assembly code."
#endif
#endif
#include "mbedtls/aesni.h"
#include <string.h>
#ifndef asm
#define asm __asm
#endif
#if defined(MBEDTLS_HAVE_X86_64)
/*
* AES-NI support detection routine
*/
int mbedtls_aesni_has_support( unsigned int what )
{
static int done = 0;
static unsigned int c = 0;
if( ! done )
{
asm( "movl $1, %%eax \n\t"
"cpuid \n\t"
: "=c" (c)
:
: "eax", "ebx", "edx" );
done = 1;
}
return( ( c & what ) != 0 );
}
/*
* Binutils needs to be at least 2.19 to support AES-NI instructions.
* Unfortunately, a lot of users have a lower version now (2014-04).
* Emit bytecode directly in order to support "old" version of gas.
*
* Opcodes from the Intel architecture reference manual, vol. 3.
* We always use registers, so we don't need prefixes for memory operands.
* Operand macros are in gas order (src, dst) as opposed to Intel order
* (dst, src) in order to blend better into the surrounding assembly code.
*/
#define AESDEC ".byte 0x66,0x0F,0x38,0xDE,"
#define AESDECLAST ".byte 0x66,0x0F,0x38,0xDF,"
#define AESENC ".byte 0x66,0x0F,0x38,0xDC,"
#define AESENCLAST ".byte 0x66,0x0F,0x38,0xDD,"
#define AESIMC ".byte 0x66,0x0F,0x38,0xDB,"
#define AESKEYGENA ".byte 0x66,0x0F,0x3A,0xDF,"
#define PCLMULQDQ ".byte 0x66,0x0F,0x3A,0x44,"
#define xmm0_xmm0 "0xC0"
#define xmm0_xmm1 "0xC8"
#define xmm0_xmm2 "0xD0"
#define xmm0_xmm3 "0xD8"
#define xmm0_xmm4 "0xE0"
#define xmm1_xmm0 "0xC1"
#define xmm1_xmm2 "0xD1"
/*
* AES-NI AES-ECB block en(de)cryption
*/
int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] )
{
asm( "movdqu (%3), %%xmm0 \n\t" // load input
"movdqu (%1), %%xmm1 \n\t" // load round key 0
"pxor %%xmm1, %%xmm0 \n\t" // round 0
"add $16, %1 \n\t" // point to next round key
"subl $1, %0 \n\t" // normal rounds = nr - 1
"test %2, %2 \n\t" // mode?
"jz 2f \n\t" // 0 = decrypt
"1: \n\t" // encryption loop
"movdqu (%1), %%xmm1 \n\t" // load round key
AESENC xmm1_xmm0 "\n\t" // do round
"add $16, %1 \n\t" // point to next round key
"subl $1, %0 \n\t" // loop
"jnz 1b \n\t"
"movdqu (%1), %%xmm1 \n\t" // load round key
AESENCLAST xmm1_xmm0 "\n\t" // last round
"jmp 3f \n\t"
"2: \n\t" // decryption loop
"movdqu (%1), %%xmm1 \n\t"
AESDEC xmm1_xmm0 "\n\t" // do round
"add $16, %1 \n\t"
"subl $1, %0 \n\t"
"jnz 2b \n\t"
"movdqu (%1), %%xmm1 \n\t" // load round key
AESDECLAST xmm1_xmm0 "\n\t" // last round
"3: \n\t"
"movdqu %%xmm0, (%4) \n\t" // export output
:
: "r" (ctx->nr), "r" (ctx->rk), "r" (mode), "r" (input), "r" (output)
: "memory", "cc", "xmm0", "xmm1" );
return( 0 );
}
/*
* GCM multiplication: c = a times b in GF(2^128)
* Based on [CLMUL-WP] algorithms 1 (with equation 27) and 5.
*/
void mbedtls_aesni_gcm_mult( unsigned char c[16],
const unsigned char a[16],
const unsigned char b[16] )
{
unsigned char aa[16], bb[16], cc[16];
size_t i;
/* The inputs are in big-endian order, so byte-reverse them */
for( i = 0; i < 16; i++ )
{
aa[i] = a[15 - i];
bb[i] = b[15 - i];
}
asm( "movdqu (%0), %%xmm0 \n\t" // a1:a0
"movdqu (%1), %%xmm1 \n\t" // b1:b0
/*
* Caryless multiplication xmm2:xmm1 = xmm0 * xmm1
* using [CLMUL-WP] algorithm 1 (p. 13).
*/
"movdqa %%xmm1, %%xmm2 \n\t" // copy of b1:b0
"movdqa %%xmm1, %%xmm3 \n\t" // same
"movdqa %%xmm1, %%xmm4 \n\t" // same
PCLMULQDQ xmm0_xmm1 ",0x00 \n\t" // a0*b0 = c1:c0
PCLMULQDQ xmm0_xmm2 ",0x11 \n\t" // a1*b1 = d1:d0
PCLMULQDQ xmm0_xmm3 ",0x10 \n\t" // a0*b1 = e1:e0
PCLMULQDQ xmm0_xmm4 ",0x01 \n\t" // a1*b0 = f1:f0
"pxor %%xmm3, %%xmm4 \n\t" // e1+f1:e0+f0
"movdqa %%xmm4, %%xmm3 \n\t" // same
"psrldq $8, %%xmm4 \n\t" // 0:e1+f1
"pslldq $8, %%xmm3 \n\t" // e0+f0:0
"pxor %%xmm4, %%xmm2 \n\t" // d1:d0+e1+f1
"pxor %%xmm3, %%xmm1 \n\t" // c1+e0+f1:c0
/*
* Now shift the result one bit to the left,
* taking advantage of [CLMUL-WP] eq 27 (p. 20)
*/
"movdqa %%xmm1, %%xmm3 \n\t" // r1:r0
"movdqa %%xmm2, %%xmm4 \n\t" // r3:r2
"psllq $1, %%xmm1 \n\t" // r1<<1:r0<<1
"psllq $1, %%xmm2 \n\t" // r3<<1:r2<<1
"psrlq $63, %%xmm3 \n\t" // r1>>63:r0>>63
"psrlq $63, %%xmm4 \n\t" // r3>>63:r2>>63
"movdqa %%xmm3, %%xmm5 \n\t" // r1>>63:r0>>63
"pslldq $8, %%xmm3 \n\t" // r0>>63:0
"pslldq $8, %%xmm4 \n\t" // r2>>63:0
"psrldq $8, %%xmm5 \n\t" // 0:r1>>63
"por %%xmm3, %%xmm1 \n\t" // r1<<1|r0>>63:r0<<1
"por %%xmm4, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1
"por %%xmm5, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1|r1>>63
/*
* Now reduce modulo the GCM polynomial x^128 + x^7 + x^2 + x + 1
* using [CLMUL-WP] algorithm 5 (p. 20).
* Currently xmm2:xmm1 holds x3:x2:x1:x0 (already shifted).
*/
/* Step 2 (1) */
"movdqa %%xmm1, %%xmm3 \n\t" // x1:x0
"movdqa %%xmm1, %%xmm4 \n\t" // same
"movdqa %%xmm1, %%xmm5 \n\t" // same
"psllq $63, %%xmm3 \n\t" // x1<<63:x0<<63 = stuff:a
"psllq $62, %%xmm4 \n\t" // x1<<62:x0<<62 = stuff:b
"psllq $57, %%xmm5 \n\t" // x1<<57:x0<<57 = stuff:c
/* Step 2 (2) */
"pxor %%xmm4, %%xmm3 \n\t" // stuff:a+b
"pxor %%xmm5, %%xmm3 \n\t" // stuff:a+b+c
"pslldq $8, %%xmm3 \n\t" // a+b+c:0
"pxor %%xmm3, %%xmm1 \n\t" // x1+a+b+c:x0 = d:x0
/* Steps 3 and 4 */
"movdqa %%xmm1,%%xmm0 \n\t" // d:x0
"movdqa %%xmm1,%%xmm4 \n\t" // same
"movdqa %%xmm1,%%xmm5 \n\t" // same
"psrlq $1, %%xmm0 \n\t" // e1:x0>>1 = e1:e0'
"psrlq $2, %%xmm4 \n\t" // f1:x0>>2 = f1:f0'
"psrlq $7, %%xmm5 \n\t" // g1:x0>>7 = g1:g0'
"pxor %%xmm4, %%xmm0 \n\t" // e1+f1:e0'+f0'
"pxor %%xmm5, %%xmm0 \n\t" // e1+f1+g1:e0'+f0'+g0'
// e0'+f0'+g0' is almost e0+f0+g0, ex\tcept for some missing
// bits carried from d. Now get those\t bits back in.
"movdqa %%xmm1,%%xmm3 \n\t" // d:x0
"movdqa %%xmm1,%%xmm4 \n\t" // same
"movdqa %%xmm1,%%xmm5 \n\t" // same
"psllq $63, %%xmm3 \n\t" // d<<63:stuff
"psllq $62, %%xmm4 \n\t" // d<<62:stuff
"psllq $57, %%xmm5 \n\t" // d<<57:stuff
"pxor %%xmm4, %%xmm3 \n\t" // d<<63+d<<62:stuff
"pxor %%xmm5, %%xmm3 \n\t" // missing bits of d:stuff
"psrldq $8, %%xmm3 \n\t" // 0:missing bits of d
"pxor %%xmm3, %%xmm0 \n\t" // e1+f1+g1:e0+f0+g0
"pxor %%xmm1, %%xmm0 \n\t" // h1:h0
"pxor %%xmm2, %%xmm0 \n\t" // x3+h1:x2+h0
"movdqu %%xmm0, (%2) \n\t" // done
:
: "r" (aa), "r" (bb), "r" (cc)
: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" );
/* Now byte-reverse the outputs */
for( i = 0; i < 16; i++ )
c[i] = cc[15 - i];
return;
}
/*
* Compute decryption round keys from encryption round keys
*/
void mbedtls_aesni_inverse_key( unsigned char *invkey,
const unsigned char *fwdkey, int nr )
{
unsigned char *ik = invkey;
const unsigned char *fk = fwdkey + 16 * nr;
memcpy( ik, fk, 16 );
for( fk -= 16, ik += 16; fk > fwdkey; fk -= 16, ik += 16 )
asm( "movdqu (%0), %%xmm0 \n\t"
AESIMC xmm0_xmm0 "\n\t"
"movdqu %%xmm0, (%1) \n\t"
:
: "r" (fk), "r" (ik)
: "memory", "xmm0" );
memcpy( ik, fk, 16 );
}
/*
* Key expansion, 128-bit case
*/
static void aesni_setkey_enc_128( unsigned char *rk,
const unsigned char *key )
{
asm( "movdqu (%1), %%xmm0 \n\t" // copy the original key
"movdqu %%xmm0, (%0) \n\t" // as round key 0
"jmp 2f \n\t" // skip auxiliary routine
/*
* Finish generating the next round key.
*
* On entry xmm0 is r3:r2:r1:r0 and xmm1 is X:stuff:stuff:stuff
* with X = rot( sub( r3 ) ) ^ RCON.
*
* On exit, xmm0 is r7:r6:r5:r4
* with r4 = X + r0, r5 = r4 + r1, r6 = r5 + r2, r7 = r6 + r3
* and those are written to the round key buffer.
*/
"1: \n\t"
"pshufd $0xff, %%xmm1, %%xmm1 \n\t" // X:X:X:X
"pxor %%xmm0, %%xmm1 \n\t" // X+r3:X+r2:X+r1:r4
"pslldq $4, %%xmm0 \n\t" // r2:r1:r0:0
"pxor %%xmm0, %%xmm1 \n\t" // X+r3+r2:X+r2+r1:r5:r4
"pslldq $4, %%xmm0 \n\t" // etc
"pxor %%xmm0, %%xmm1 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm1, %%xmm0 \n\t" // update xmm0 for next time!
"add $16, %0 \n\t" // point to next round key
"movdqu %%xmm0, (%0) \n\t" // write it
"ret \n\t"
/* Main "loop" */
"2: \n\t"
AESKEYGENA xmm0_xmm1 ",0x01 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x02 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x04 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x08 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x10 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x20 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x40 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x80 \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x1B \n\tcall 1b \n\t"
AESKEYGENA xmm0_xmm1 ",0x36 \n\tcall 1b \n\t"
:
: "r" (rk), "r" (key)
: "memory", "cc", "0" );
}
/*
* Key expansion, 192-bit case
*/
static void aesni_setkey_enc_192( unsigned char *rk,
const unsigned char *key )
{
asm( "movdqu (%1), %%xmm0 \n\t" // copy original round key
"movdqu %%xmm0, (%0) \n\t"
"add $16, %0 \n\t"
"movq 16(%1), %%xmm1 \n\t"
"movq %%xmm1, (%0) \n\t"
"add $8, %0 \n\t"
"jmp 2f \n\t" // skip auxiliary routine
/*
* Finish generating the next 6 quarter-keys.
*
* On entry xmm0 is r3:r2:r1:r0, xmm1 is stuff:stuff:r5:r4
* and xmm2 is stuff:stuff:X:stuff with X = rot( sub( r3 ) ) ^ RCON.
*
* On exit, xmm0 is r9:r8:r7:r6 and xmm1 is stuff:stuff:r11:r10
* and those are written to the round key buffer.
*/
"1: \n\t"
"pshufd $0x55, %%xmm2, %%xmm2 \n\t" // X:X:X:X
"pxor %%xmm0, %%xmm2 \n\t" // X+r3:X+r2:X+r1:r4
"pslldq $4, %%xmm0 \n\t" // etc
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm2, %%xmm0 \n\t" // update xmm0 = r9:r8:r7:r6
"movdqu %%xmm0, (%0) \n\t"
"add $16, %0 \n\t"
"pshufd $0xff, %%xmm0, %%xmm2 \n\t" // r9:r9:r9:r9
"pxor %%xmm1, %%xmm2 \n\t" // stuff:stuff:r9+r5:r10
"pslldq $4, %%xmm1 \n\t" // r2:r1:r0:0
"pxor %%xmm2, %%xmm1 \n\t" // xmm1 = stuff:stuff:r11:r10
"movq %%xmm1, (%0) \n\t"
"add $8, %0 \n\t"
"ret \n\t"
"2: \n\t"
AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x80 \n\tcall 1b \n\t"
:
: "r" (rk), "r" (key)
: "memory", "cc", "0" );
}
/*
* Key expansion, 256-bit case
*/
static void aesni_setkey_enc_256( unsigned char *rk,
const unsigned char *key )
{
asm( "movdqu (%1), %%xmm0 \n\t"
"movdqu %%xmm0, (%0) \n\t"
"add $16, %0 \n\t"
"movdqu 16(%1), %%xmm1 \n\t"
"movdqu %%xmm1, (%0) \n\t"
"jmp 2f \n\t" // skip auxiliary routine
/*
* Finish generating the next two round keys.
*
* On entry xmm0 is r3:r2:r1:r0, xmm1 is r7:r6:r5:r4 and
* xmm2 is X:stuff:stuff:stuff with X = rot( sub( r7 )) ^ RCON
*
* On exit, xmm0 is r11:r10:r9:r8 and xmm1 is r15:r14:r13:r12
* and those have been written to the output buffer.
*/
"1: \n\t"
"pshufd $0xff, %%xmm2, %%xmm2 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm0, %%xmm2 \n\t"
"pslldq $4, %%xmm0 \n\t"
"pxor %%xmm2, %%xmm0 \n\t"
"add $16, %0 \n\t"
"movdqu %%xmm0, (%0) \n\t"
/* Set xmm2 to stuff:Y:stuff:stuff with Y = subword( r11 )
* and proceed to generate next round key from there */
AESKEYGENA xmm0_xmm2 ",0x00 \n\t"
"pshufd $0xaa, %%xmm2, %%xmm2 \n\t"
"pxor %%xmm1, %%xmm2 \n\t"
"pslldq $4, %%xmm1 \n\t"
"pxor %%xmm1, %%xmm2 \n\t"
"pslldq $4, %%xmm1 \n\t"
"pxor %%xmm1, %%xmm2 \n\t"
"pslldq $4, %%xmm1 \n\t"
"pxor %%xmm2, %%xmm1 \n\t"
"add $16, %0 \n\t"
"movdqu %%xmm1, (%0) \n\t"
"ret \n\t"
/*
* Main "loop" - Generating one more key than necessary,
* see definition of mbedtls_aes_context.buf
*/
"2: \n\t"
AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t"
AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t"
:
: "r" (rk), "r" (key)
: "memory", "cc", "0" );
}
/*
* Key expansion, wrapper
*/
int mbedtls_aesni_setkey_enc( unsigned char *rk,
const unsigned char *key,
size_t bits )
{
switch( bits )
{
case 128: aesni_setkey_enc_128( rk, key ); break;
case 192: aesni_setkey_enc_192( rk, key ); break;
case 256: aesni_setkey_enc_256( rk, key ); break;
default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH );
}
return( 0 );
}
#endif /* MBEDTLS_HAVE_X86_64 */
#endif /* MBEDTLS_AESNI_C */

201
library/arc4.c Normal file
View File

@ -0,0 +1,201 @@
/*
* An implementation of the ARCFOUR algorithm
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The ARCFOUR algorithm was publicly disclosed on 94/09.
*
* http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ARC4_C)
#include "mbedtls/arc4.h"
#include "mbedtls/platform_util.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_ARC4_ALT)
void mbedtls_arc4_init( mbedtls_arc4_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_arc4_context ) );
}
void mbedtls_arc4_free( mbedtls_arc4_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_arc4_context ) );
}
/*
* ARC4 key schedule
*/
void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key,
unsigned int keylen )
{
int i, j, a;
unsigned int k;
unsigned char *m;
ctx->x = 0;
ctx->y = 0;
m = ctx->m;
for( i = 0; i < 256; i++ )
m[i] = (unsigned char) i;
j = k = 0;
for( i = 0; i < 256; i++, k++ )
{
if( k >= keylen ) k = 0;
a = m[i];
j = ( j + a + key[k] ) & 0xFF;
m[i] = m[j];
m[j] = (unsigned char) a;
}
}
/*
* ARC4 cipher function
*/
int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input,
unsigned char *output )
{
int x, y, a, b;
size_t i;
unsigned char *m;
x = ctx->x;
y = ctx->y;
m = ctx->m;
for( i = 0; i < length; i++ )
{
x = ( x + 1 ) & 0xFF; a = m[x];
y = ( y + a ) & 0xFF; b = m[y];
m[x] = (unsigned char) b;
m[y] = (unsigned char) a;
output[i] = (unsigned char)
( input[i] ^ m[(unsigned char)( a + b )] );
}
ctx->x = x;
ctx->y = y;
return( 0 );
}
#endif /* !MBEDTLS_ARC4_ALT */
#if defined(MBEDTLS_SELF_TEST)
/*
* ARC4 tests vectors as posted by Eric Rescorla in sep. 1994:
*
* http://groups.google.com/group/comp.security.misc/msg/10a300c9d21afca0
*/
static const unsigned char arc4_test_key[3][8] =
{
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
static const unsigned char arc4_test_pt[3][8] =
{
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
static const unsigned char arc4_test_ct[3][8] =
{
{ 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 },
{ 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 },
{ 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A }
};
/*
* Checkup routine
*/
int mbedtls_arc4_self_test( int verbose )
{
int i, ret = 0;
unsigned char ibuf[8];
unsigned char obuf[8];
mbedtls_arc4_context ctx;
mbedtls_arc4_init( &ctx );
for( i = 0; i < 3; i++ )
{
if( verbose != 0 )
mbedtls_printf( " ARC4 test #%d: ", i + 1 );
memcpy( ibuf, arc4_test_pt[i], 8 );
mbedtls_arc4_setup( &ctx, arc4_test_key[i], 8 );
mbedtls_arc4_crypt( &ctx, 8, ibuf, obuf );
if( memcmp( obuf, arc4_test_ct[i], 8 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
exit:
mbedtls_arc4_free( &ctx );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_ARC4_C */

1079
library/aria.c Normal file

File diff suppressed because it is too large Load Diff

487
library/asn1parse.c Normal file
View File

@ -0,0 +1,487 @@
/*
* Generic ASN.1 parsing
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ASN1_PARSE_C)
#include "mbedtls/asn1.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
/*
* ASN.1 DER decoding routines
*/
int mbedtls_asn1_get_len( unsigned char **p,
const unsigned char *end,
size_t *len )
{
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
if( ( **p & 0x80 ) == 0 )
*len = *(*p)++;
else
{
switch( **p & 0x7F )
{
case 1:
if( ( end - *p ) < 2 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = (*p)[1];
(*p) += 2;
break;
case 2:
if( ( end - *p ) < 3 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 8 ) | (*p)[2];
(*p) += 3;
break;
case 3:
if( ( end - *p ) < 4 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 16 ) |
( (size_t)(*p)[2] << 8 ) | (*p)[3];
(*p) += 4;
break;
case 4:
if( ( end - *p ) < 5 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) |
( (size_t)(*p)[3] << 8 ) | (*p)[4];
(*p) += 5;
break;
default:
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
}
}
if( *len > (size_t) ( end - *p ) )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
return( 0 );
}
int mbedtls_asn1_get_tag( unsigned char **p,
const unsigned char *end,
size_t *len, int tag )
{
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
if( **p != tag )
return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
(*p)++;
return( mbedtls_asn1_get_len( p, end, len ) );
}
int mbedtls_asn1_get_bool( unsigned char **p,
const unsigned char *end,
int *val )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_BOOLEAN ) ) != 0 )
return( ret );
if( len != 1 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
*val = ( **p != 0 ) ? 1 : 0;
(*p)++;
return( 0 );
}
static int asn1_get_tagged_int( unsigned char **p,
const unsigned char *end,
int tag, int *val )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, tag ) ) != 0 )
return( ret );
/*
* len==0 is malformed (0 must be represented as 020100 for INTEGER,
* or 0A0100 for ENUMERATED tags
*/
if( len == 0 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
/* This is a cryptography library. Reject negative integers. */
if( ( **p & 0x80 ) != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
/* Skip leading zeros. */
while( len > 0 && **p == 0 )
{
++( *p );
--len;
}
/* Reject integers that don't fit in an int. This code assumes that
* the int type has no padding bit. */
if( len > sizeof( int ) )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
if( len == sizeof( int ) && ( **p & 0x80 ) != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
*val = 0;
while( len-- > 0 )
{
*val = ( *val << 8 ) | **p;
(*p)++;
}
return( 0 );
}
int mbedtls_asn1_get_int( unsigned char **p,
const unsigned char *end,
int *val )
{
return( asn1_get_tagged_int( p, end, MBEDTLS_ASN1_INTEGER, val) );
}
int mbedtls_asn1_get_enum( unsigned char **p,
const unsigned char *end,
int *val )
{
return( asn1_get_tagged_int( p, end, MBEDTLS_ASN1_ENUMERATED, val) );
}
#if defined(MBEDTLS_BIGNUM_C)
int mbedtls_asn1_get_mpi( unsigned char **p,
const unsigned char *end,
mbedtls_mpi *X )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
return( ret );
ret = mbedtls_mpi_read_binary( X, *p, len );
*p += len;
return( ret );
}
#endif /* MBEDTLS_BIGNUM_C */
int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end,
mbedtls_asn1_bitstring *bs)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* Certificate type is a single byte bitstring */
if( ( ret = mbedtls_asn1_get_tag( p, end, &bs->len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 )
return( ret );
/* Check length, subtract one for actual bit string length */
if( bs->len < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
bs->len -= 1;
/* Get number of unused bits, ensure unused bits <= 7 */
bs->unused_bits = **p;
if( bs->unused_bits > 7 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
(*p)++;
/* Get actual bitstring */
bs->p = *p;
*p += bs->len;
if( *p != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
/*
* Traverse an ASN.1 "SEQUENCE OF <tag>"
* and call a callback for each entry found.
*/
int mbedtls_asn1_traverse_sequence_of(
unsigned char **p,
const unsigned char *end,
unsigned char tag_must_mask, unsigned char tag_must_val,
unsigned char tag_may_mask, unsigned char tag_may_val,
int (*cb)( void *ctx, int tag,
unsigned char *start, size_t len ),
void *ctx )
{
int ret;
size_t len;
/* Get main sequence tag */
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
{
return( ret );
}
if( *p + len != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
while( *p < end )
{
unsigned char const tag = *(*p)++;
if( ( tag & tag_must_mask ) != tag_must_val )
return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
if( ( ret = mbedtls_asn1_get_len( p, end, &len ) ) != 0 )
return( ret );
if( ( tag & tag_may_mask ) == tag_may_val )
{
if( cb != NULL )
{
ret = cb( ctx, tag, *p, len );
if( ret != 0 )
return( ret );
}
}
*p += len;
}
return( 0 );
}
/*
* Get a bit string without unused bits
*/
int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end,
size_t *len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 )
return( ret );
if( *len == 0 )
return( MBEDTLS_ERR_ASN1_INVALID_DATA );
--( *len );
if( **p != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_DATA );
++( *p );
return( 0 );
}
void mbedtls_asn1_sequence_free( mbedtls_asn1_sequence *seq )
{
while( seq != NULL )
{
mbedtls_asn1_sequence *next = seq->next;
mbedtls_platform_zeroize( seq, sizeof( *seq ) );
mbedtls_free( seq );
seq = next;
}
}
typedef struct
{
int tag;
mbedtls_asn1_sequence *cur;
} asn1_get_sequence_of_cb_ctx_t;
static int asn1_get_sequence_of_cb( void *ctx,
int tag,
unsigned char *start,
size_t len )
{
asn1_get_sequence_of_cb_ctx_t *cb_ctx =
(asn1_get_sequence_of_cb_ctx_t *) ctx;
mbedtls_asn1_sequence *cur =
cb_ctx->cur;
if( cur->buf.p != NULL )
{
cur->next =
mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) );
if( cur->next == NULL )
return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
cur = cur->next;
}
cur->buf.p = start;
cur->buf.len = len;
cur->buf.tag = tag;
cb_ctx->cur = cur;
return( 0 );
}
/*
* Parses and splits an ASN.1 "SEQUENCE OF <tag>"
*/
int mbedtls_asn1_get_sequence_of( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_sequence *cur,
int tag)
{
asn1_get_sequence_of_cb_ctx_t cb_ctx = { tag, cur };
memset( cur, 0, sizeof( mbedtls_asn1_sequence ) );
return( mbedtls_asn1_traverse_sequence_of(
p, end, 0xFF, tag, 0, 0,
asn1_get_sequence_of_cb, &cb_ctx ) );
}
int mbedtls_asn1_get_alg( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
return( ret );
if( ( end - *p ) < 1 )
return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
alg->tag = **p;
end = *p + len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 )
return( ret );
alg->p = *p;
*p += alg->len;
if( *p == end )
{
mbedtls_platform_zeroize( params, sizeof(mbedtls_asn1_buf) );
return( 0 );
}
params->tag = **p;
(*p)++;
if( ( ret = mbedtls_asn1_get_len( p, end, &params->len ) ) != 0 )
return( ret );
params->p = *p;
*p += params->len;
if( *p != end )
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
int mbedtls_asn1_get_alg_null( unsigned char **p,
const unsigned char *end,
mbedtls_asn1_buf *alg )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_asn1_buf params;
memset( &params, 0, sizeof(mbedtls_asn1_buf) );
if( ( ret = mbedtls_asn1_get_alg( p, end, alg, &params ) ) != 0 )
return( ret );
if( ( params.tag != MBEDTLS_ASN1_NULL && params.tag != 0 ) || params.len != 0 )
return( MBEDTLS_ERR_ASN1_INVALID_DATA );
return( 0 );
}
void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur )
{
if( cur == NULL )
return;
mbedtls_free( cur->oid.p );
mbedtls_free( cur->val.p );
mbedtls_platform_zeroize( cur, sizeof( mbedtls_asn1_named_data ) );
}
void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head )
{
mbedtls_asn1_named_data *cur;
while( ( cur = *head ) != NULL )
{
*head = cur->next;
mbedtls_asn1_free_named_data( cur );
mbedtls_free( cur );
}
}
mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list,
const char *oid, size_t len )
{
while( list != NULL )
{
if( list->oid.len == len &&
memcmp( list->oid.p, oid, len ) == 0 )
{
break;
}
list = list->next;
}
return( list );
}
#endif /* MBEDTLS_ASN1_PARSE_C */

486
library/asn1write.c Normal file
View File

@ -0,0 +1,486 @@
/*
* ASN.1 buffer writing functionality
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ASN1_WRITE_C)
#include "mbedtls/asn1write.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len )
{
if( len < 0x80 )
{
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = (unsigned char) len;
return( 1 );
}
if( len <= 0xFF )
{
if( *p - start < 2 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = (unsigned char) len;
*--(*p) = 0x81;
return( 2 );
}
if( len <= 0xFFFF )
{
if( *p - start < 3 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = ( len ) & 0xFF;
*--(*p) = ( len >> 8 ) & 0xFF;
*--(*p) = 0x82;
return( 3 );
}
if( len <= 0xFFFFFF )
{
if( *p - start < 4 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = ( len ) & 0xFF;
*--(*p) = ( len >> 8 ) & 0xFF;
*--(*p) = ( len >> 16 ) & 0xFF;
*--(*p) = 0x83;
return( 4 );
}
#if SIZE_MAX > 0xFFFFFFFF
if( len <= 0xFFFFFFFF )
#endif
{
if( *p - start < 5 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = ( len ) & 0xFF;
*--(*p) = ( len >> 8 ) & 0xFF;
*--(*p) = ( len >> 16 ) & 0xFF;
*--(*p) = ( len >> 24 ) & 0xFF;
*--(*p) = 0x84;
return( 5 );
}
#if SIZE_MAX > 0xFFFFFFFF
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
#endif
}
int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag )
{
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = tag;
return( 1 );
}
int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
const unsigned char *buf, size_t size )
{
size_t len = 0;
if( *p < start || (size_t)( *p - start ) < size )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
len = size;
(*p) -= len;
memcpy( *p, buf, len );
return( (int) len );
}
#if defined(MBEDTLS_BIGNUM_C)
int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
// Write the MPI
//
len = mbedtls_mpi_size( X );
if( *p < start || (size_t)( *p - start ) < len )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
(*p) -= len;
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) );
// DER format assumes 2s complement for numbers, so the leftmost bit
// should be 0 for positive numbers and 1 for negative numbers.
//
if( X->s ==1 && **p & 0x80 )
{
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = 0x00;
len += 1;
}
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) );
ret = (int) len;
cleanup:
return( ret );
}
#endif /* MBEDTLS_BIGNUM_C */
int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
// Write NULL
//
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) );
return( (int) len );
}
int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start,
const char *oid, size_t oid_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
(const unsigned char *) oid, oid_len ) );
MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) );
return( (int) len );
}
int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
const char *oid, size_t oid_len,
size_t par_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
if( par_len == 0 )
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) );
else
len += par_len;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
return( (int) len );
}
int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = (boolean) ? 255 : 0;
len++;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BOOLEAN ) );
return( (int) len );
}
static int asn1_write_tagged_int( unsigned char **p, unsigned char *start, int val, int tag )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
do
{
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
len += 1;
*--(*p) = val & 0xff;
val >>= 8;
}
while( val > 0 );
if( **p & 0x80 )
{
if( *p - start < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--(*p) = 0x00;
len += 1;
}
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) );
return( (int) len );
}
int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val )
{
return( asn1_write_tagged_int( p, start, val, MBEDTLS_ASN1_INTEGER ) );
}
int mbedtls_asn1_write_enum( unsigned char **p, unsigned char *start, int val )
{
return( asn1_write_tagged_int( p, start, val, MBEDTLS_ASN1_ENUMERATED ) );
}
int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start, int tag,
const char *text, size_t text_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
(const unsigned char *) text, text_len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) );
return( (int) len );
}
int mbedtls_asn1_write_utf8_string( unsigned char **p, unsigned char *start,
const char *text, size_t text_len )
{
return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_UTF8_STRING, text, text_len) );
}
int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start,
const char *text, size_t text_len )
{
return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_PRINTABLE_STRING, text, text_len) );
}
int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
const char *text, size_t text_len )
{
return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len) );
}
int mbedtls_asn1_write_named_bitstring( unsigned char **p,
unsigned char *start,
const unsigned char *buf,
size_t bits )
{
size_t unused_bits, byte_len;
const unsigned char *cur_byte;
unsigned char cur_byte_shifted;
unsigned char bit;
byte_len = ( bits + 7 ) / 8;
unused_bits = ( byte_len * 8 ) - bits;
/*
* Named bitstrings require that trailing 0s are excluded in the encoding
* of the bitstring. Trailing 0s are considered part of the 'unused' bits
* when encoding this value in the first content octet
*/
if( bits != 0 )
{
cur_byte = buf + byte_len - 1;
cur_byte_shifted = *cur_byte >> unused_bits;
for( ; ; )
{
bit = cur_byte_shifted & 0x1;
cur_byte_shifted >>= 1;
if( bit != 0 )
break;
bits--;
if( bits == 0 )
break;
if( bits % 8 == 0 )
cur_byte_shifted = *--cur_byte;
}
}
return( mbedtls_asn1_write_bitstring( p, start, buf, bits ) );
}
int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
const unsigned char *buf, size_t bits )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
size_t unused_bits, byte_len;
byte_len = ( bits + 7 ) / 8;
unused_bits = ( byte_len * 8 ) - bits;
if( *p < start || (size_t)( *p - start ) < byte_len + 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
len = byte_len + 1;
/* Write the bitstring. Ensure the unused bits are zeroed */
if( byte_len > 0 )
{
byte_len--;
*--( *p ) = buf[byte_len] & ~( ( 0x1 << unused_bits ) - 1 );
( *p ) -= byte_len;
memcpy( *p, buf, byte_len );
}
/* Write unused bits */
*--( *p ) = (unsigned char)unused_bits;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) );
return( (int) len );
}
int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start,
const unsigned char *buf, size_t size )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) );
return( (int) len );
}
/* This is a copy of the ASN.1 parsing function mbedtls_asn1_find_named_data(),
* which is replicated to avoid a dependency ASN1_WRITE_C on ASN1_PARSE_C. */
static mbedtls_asn1_named_data *asn1_find_named_data(
mbedtls_asn1_named_data *list,
const char *oid, size_t len )
{
while( list != NULL )
{
if( list->oid.len == len &&
memcmp( list->oid.p, oid, len ) == 0 )
{
break;
}
list = list->next;
}
return( list );
}
mbedtls_asn1_named_data *mbedtls_asn1_store_named_data(
mbedtls_asn1_named_data **head,
const char *oid, size_t oid_len,
const unsigned char *val,
size_t val_len )
{
mbedtls_asn1_named_data *cur;
if( ( cur = asn1_find_named_data( *head, oid, oid_len ) ) == NULL )
{
// Add new entry if not present yet based on OID
//
cur = (mbedtls_asn1_named_data*)mbedtls_calloc( 1,
sizeof(mbedtls_asn1_named_data) );
if( cur == NULL )
return( NULL );
cur->oid.len = oid_len;
cur->oid.p = mbedtls_calloc( 1, oid_len );
if( cur->oid.p == NULL )
{
mbedtls_free( cur );
return( NULL );
}
memcpy( cur->oid.p, oid, oid_len );
cur->val.len = val_len;
if( val_len != 0 )
{
cur->val.p = mbedtls_calloc( 1, val_len );
if( cur->val.p == NULL )
{
mbedtls_free( cur->oid.p );
mbedtls_free( cur );
return( NULL );
}
}
cur->next = *head;
*head = cur;
}
else if( val_len == 0 )
{
mbedtls_free( cur->val.p );
cur->val.p = NULL;
}
else if( cur->val.len != val_len )
{
/*
* Enlarge existing value buffer if needed
* Preserve old data until the allocation succeeded, to leave list in
* a consistent state in case allocation fails.
*/
void *p = mbedtls_calloc( 1, val_len );
if( p == NULL )
return( NULL );
mbedtls_free( cur->val.p );
cur->val.p = p;
cur->val.len = val_len;
}
if( val != NULL )
memcpy( cur->val.p, val, val_len );
return( cur );
}
#endif /* MBEDTLS_ASN1_WRITE_C */

293
library/base64.c Normal file
View File

@ -0,0 +1,293 @@
/*
* RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_BASE64_C)
#include "mbedtls/base64.h"
#include <stdint.h>
#if defined(MBEDTLS_SELF_TEST)
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
static const unsigned char base64_enc_map[64] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/'
};
static const unsigned char base64_dec_map[128] =
{
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 127, 127, 127, 127, 127
};
#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
/*
* Encode a buffer into base64 format
*/
int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
const unsigned char *src, size_t slen )
{
size_t i, n;
int C1, C2, C3;
unsigned char *p;
if( slen == 0 )
{
*olen = 0;
return( 0 );
}
n = slen / 3 + ( slen % 3 != 0 );
if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
{
*olen = BASE64_SIZE_T_MAX;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
n *= 4;
if( ( dlen < n + 1 ) || ( NULL == dst ) )
{
*olen = n + 1;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
n = ( slen / 3 ) * 3;
for( i = 0, p = dst; i < n; i += 3 )
{
C1 = *src++;
C2 = *src++;
C3 = *src++;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
*p++ = base64_enc_map[C3 & 0x3F];
}
if( i < slen )
{
C1 = *src++;
C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
if( ( i + 1 ) < slen )
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
else *p++ = '=';
*p++ = '=';
}
*olen = p - dst;
*p = 0;
return( 0 );
}
/*
* Decode a base64-formatted buffer
*/
int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
const unsigned char *src, size_t slen )
{
size_t i, n;
uint32_t j, x;
unsigned char *p;
/* First pass: check for validity and get output length */
for( i = n = j = 0; i < slen; i++ )
{
/* Skip spaces before checking for EOL */
x = 0;
while( i < slen && src[i] == ' ' )
{
++i;
++x;
}
/* Spaces at end of buffer are OK */
if( i == slen )
break;
if( ( slen - i ) >= 2 &&
src[i] == '\r' && src[i + 1] == '\n' )
continue;
if( src[i] == '\n' )
continue;
/* Space inside a line is an error */
if( x != 0 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
if( src[i] == '=' && ++j > 2 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
if( base64_dec_map[src[i]] < 64 && j != 0 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
n++;
}
if( n == 0 )
{
*olen = 0;
return( 0 );
}
/* The following expression is to calculate the following formula without
* risk of integer overflow in n:
* n = ( ( n * 6 ) + 7 ) >> 3;
*/
n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
n -= j;
if( dst == NULL || dlen < n )
{
*olen = n;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
{
if( *src == '\r' || *src == '\n' || *src == ' ' )
continue;
j -= ( base64_dec_map[*src] == 64 );
x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
if( ++n == 4 )
{
n = 0;
if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
if( j > 2 ) *p++ = (unsigned char)( x );
}
}
*olen = p - dst;
return( 0 );
}
#if defined(MBEDTLS_SELF_TEST)
static const unsigned char base64_test_dec[64] =
{
0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
};
static const unsigned char base64_test_enc[] =
"JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
"swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
/*
* Checkup routine
*/
int mbedtls_base64_self_test( int verbose )
{
size_t len;
const unsigned char *src;
unsigned char buffer[128];
if( verbose != 0 )
mbedtls_printf( " Base64 encoding test: " );
src = base64_test_dec;
if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
memcmp( base64_test_enc, buffer, 88 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
mbedtls_printf( "passed\n Base64 decoding test: " );
src = base64_test_enc;
if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
memcmp( base64_test_dec, buffer, 64 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
mbedtls_printf( "passed\n\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_BASE64_C */

2954
library/bignum.c Normal file

File diff suppressed because it is too large Load Diff

696
library/blowfish.c Normal file
View File

@ -0,0 +1,696 @@
/*
* Blowfish implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The Blowfish block cipher was designed by Bruce Schneier in 1993.
* http://www.schneier.com/blowfish.html
* http://en.wikipedia.org/wiki/Blowfish_%28cipher%29
*
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_BLOWFISH_C)
#include "mbedtls/blowfish.h"
#include "mbedtls/platform_util.h"
#include <string.h>
#if !defined(MBEDTLS_BLOWFISH_ALT)
/* Parameter validation macros */
#define BLOWFISH_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA )
#define BLOWFISH_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
}
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
static const uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2] = {
0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L,
0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L,
0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL,
0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L,
0x9216D5D9L, 0x8979FB1BL
};
/* declarations of data at the end of this file */
static const uint32_t S[4][256];
static uint32_t F( mbedtls_blowfish_context *ctx, uint32_t x )
{
unsigned short a, b, c, d;
uint32_t y;
d = (unsigned short)(x & 0xFF);
x >>= 8;
c = (unsigned short)(x & 0xFF);
x >>= 8;
b = (unsigned short)(x & 0xFF);
x >>= 8;
a = (unsigned short)(x & 0xFF);
y = ctx->S[0][a] + ctx->S[1][b];
y = y ^ ctx->S[2][c];
y = y + ctx->S[3][d];
return( y );
}
static void blowfish_enc( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr )
{
uint32_t Xl, Xr, temp;
short i;
Xl = *xl;
Xr = *xr;
for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS; ++i )
{
Xl = Xl ^ ctx->P[i];
Xr = F( ctx, Xl ) ^ Xr;
temp = Xl;
Xl = Xr;
Xr = temp;
}
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS];
Xl = Xl ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS + 1];
*xl = Xl;
*xr = Xr;
}
static void blowfish_dec( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr )
{
uint32_t Xl, Xr, temp;
short i;
Xl = *xl;
Xr = *xr;
for( i = MBEDTLS_BLOWFISH_ROUNDS + 1; i > 1; --i )
{
Xl = Xl ^ ctx->P[i];
Xr = F( ctx, Xl ) ^ Xr;
temp = Xl;
Xl = Xr;
Xr = temp;
}
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ ctx->P[1];
Xl = Xl ^ ctx->P[0];
*xl = Xl;
*xr = Xr;
}
void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx )
{
BLOWFISH_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_blowfish_context ) );
}
void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_blowfish_context ) );
}
/*
* Blowfish key schedule
*/
int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx,
const unsigned char *key,
unsigned int keybits )
{
unsigned int i, j, k;
uint32_t data, datal, datar;
BLOWFISH_VALIDATE_RET( ctx != NULL );
BLOWFISH_VALIDATE_RET( key != NULL );
if( keybits < MBEDTLS_BLOWFISH_MIN_KEY_BITS ||
keybits > MBEDTLS_BLOWFISH_MAX_KEY_BITS ||
keybits % 8 != 0 )
{
return( MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA );
}
keybits >>= 3;
for( i = 0; i < 4; i++ )
{
for( j = 0; j < 256; j++ )
ctx->S[i][j] = S[i][j];
}
j = 0;
for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; ++i )
{
data = 0x00000000;
for( k = 0; k < 4; ++k )
{
data = ( data << 8 ) | key[j++];
if( j >= keybits )
j = 0;
}
ctx->P[i] = P[i] ^ data;
}
datal = 0x00000000;
datar = 0x00000000;
for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; i += 2 )
{
blowfish_enc( ctx, &datal, &datar );
ctx->P[i] = datal;
ctx->P[i + 1] = datar;
}
for( i = 0; i < 4; i++ )
{
for( j = 0; j < 256; j += 2 )
{
blowfish_enc( ctx, &datal, &datar );
ctx->S[i][j] = datal;
ctx->S[i][j + 1] = datar;
}
}
return( 0 );
}
/*
* Blowfish-ECB block encryption/decryption
*/
int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx,
int mode,
const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE],
unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] )
{
uint32_t X0, X1;
BLOWFISH_VALIDATE_RET( ctx != NULL );
BLOWFISH_VALIDATE_RET( mode == MBEDTLS_BLOWFISH_ENCRYPT ||
mode == MBEDTLS_BLOWFISH_DECRYPT );
BLOWFISH_VALIDATE_RET( input != NULL );
BLOWFISH_VALIDATE_RET( output != NULL );
GET_UINT32_BE( X0, input, 0 );
GET_UINT32_BE( X1, input, 4 );
if( mode == MBEDTLS_BLOWFISH_DECRYPT )
{
blowfish_dec( ctx, &X0, &X1 );
}
else /* MBEDTLS_BLOWFISH_ENCRYPT */
{
blowfish_enc( ctx, &X0, &X1 );
}
PUT_UINT32_BE( X0, output, 0 );
PUT_UINT32_BE( X1, output, 4 );
return( 0 );
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/*
* Blowfish-CBC buffer encryption/decryption
*/
int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx,
int mode,
size_t length,
unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE],
const unsigned char *input,
unsigned char *output )
{
int i;
unsigned char temp[MBEDTLS_BLOWFISH_BLOCKSIZE];
BLOWFISH_VALIDATE_RET( ctx != NULL );
BLOWFISH_VALIDATE_RET( mode == MBEDTLS_BLOWFISH_ENCRYPT ||
mode == MBEDTLS_BLOWFISH_DECRYPT );
BLOWFISH_VALIDATE_RET( iv != NULL );
BLOWFISH_VALIDATE_RET( length == 0 || input != NULL );
BLOWFISH_VALIDATE_RET( length == 0 || output != NULL );
if( length % MBEDTLS_BLOWFISH_BLOCKSIZE )
return( MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH );
if( mode == MBEDTLS_BLOWFISH_DECRYPT )
{
while( length > 0 )
{
memcpy( temp, input, MBEDTLS_BLOWFISH_BLOCKSIZE );
mbedtls_blowfish_crypt_ecb( ctx, mode, input, output );
for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE;i++ )
output[i] = (unsigned char)( output[i] ^ iv[i] );
memcpy( iv, temp, MBEDTLS_BLOWFISH_BLOCKSIZE );
input += MBEDTLS_BLOWFISH_BLOCKSIZE;
output += MBEDTLS_BLOWFISH_BLOCKSIZE;
length -= MBEDTLS_BLOWFISH_BLOCKSIZE;
}
}
else
{
while( length > 0 )
{
for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE; i++ )
output[i] = (unsigned char)( input[i] ^ iv[i] );
mbedtls_blowfish_crypt_ecb( ctx, mode, output, output );
memcpy( iv, output, MBEDTLS_BLOWFISH_BLOCKSIZE );
input += MBEDTLS_BLOWFISH_BLOCKSIZE;
output += MBEDTLS_BLOWFISH_BLOCKSIZE;
length -= MBEDTLS_BLOWFISH_BLOCKSIZE;
}
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/*
* Blowfish CFB buffer encryption/decryption
*/
int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE],
const unsigned char *input,
unsigned char *output )
{
int c;
size_t n;
BLOWFISH_VALIDATE_RET( ctx != NULL );
BLOWFISH_VALIDATE_RET( mode == MBEDTLS_BLOWFISH_ENCRYPT ||
mode == MBEDTLS_BLOWFISH_DECRYPT );
BLOWFISH_VALIDATE_RET( iv != NULL );
BLOWFISH_VALIDATE_RET( iv_off != NULL );
BLOWFISH_VALIDATE_RET( length == 0 || input != NULL );
BLOWFISH_VALIDATE_RET( length == 0 || output != NULL );
n = *iv_off;
if( n >= 8 )
return( MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA );
if( mode == MBEDTLS_BLOWFISH_DECRYPT )
{
while( length-- )
{
if( n == 0 )
mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv );
c = *input++;
*output++ = (unsigned char)( c ^ iv[n] );
iv[n] = (unsigned char) c;
n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE;
}
}
else
{
while( length-- )
{
if( n == 0 )
mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv );
iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE;
}
}
*iv_off = n;
return( 0 );
}
#endif /*MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/*
* Blowfish CTR buffer encryption/decryption
*/
int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE],
unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE],
const unsigned char *input,
unsigned char *output )
{
int c, i;
size_t n;
BLOWFISH_VALIDATE_RET( ctx != NULL );
BLOWFISH_VALIDATE_RET( nonce_counter != NULL );
BLOWFISH_VALIDATE_RET( stream_block != NULL );
BLOWFISH_VALIDATE_RET( nc_off != NULL );
BLOWFISH_VALIDATE_RET( length == 0 || input != NULL );
BLOWFISH_VALIDATE_RET( length == 0 || output != NULL );
n = *nc_off;
if( n >= 8 )
return( MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA );
while( length-- )
{
if( n == 0 ) {
mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, nonce_counter,
stream_block );
for( i = MBEDTLS_BLOWFISH_BLOCKSIZE; i > 0; i-- )
if( ++nonce_counter[i - 1] != 0 )
break;
}
c = *input++;
*output++ = (unsigned char)( c ^ stream_block[n] );
n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE;
}
*nc_off = n;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CTR */
static const uint32_t S[4][256] = {
{ 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L,
0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L,
0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L,
0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL,
0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL,
0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L,
0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL,
0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL,
0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L,
0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L,
0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL,
0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL,
0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL,
0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L,
0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L,
0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L,
0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L,
0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L,
0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL,
0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L,
0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L,
0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L,
0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L,
0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL,
0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L,
0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL,
0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL,
0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L,
0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL,
0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L,
0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL,
0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L,
0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L,
0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL,
0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L,
0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L,
0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL,
0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L,
0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL,
0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L,
0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L,
0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL,
0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L,
0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L,
0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L,
0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L,
0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L,
0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL,
0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL,
0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L,
0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L,
0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L,
0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L,
0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL,
0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L,
0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL,
0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL,
0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L,
0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L,
0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L,
0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L,
0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L,
0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L,
0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL },
{ 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L,
0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L,
0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L,
0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL,
0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L,
0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L,
0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL,
0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L,
0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L,
0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L,
0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL,
0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL,
0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L,
0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L,
0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L,
0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L,
0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL,
0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL,
0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL,
0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L,
0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL,
0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L,
0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L,
0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL,
0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL,
0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L,
0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL,
0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L,
0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL,
0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL,
0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L,
0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L,
0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L,
0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L,
0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L,
0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L,
0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L,
0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL,
0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L,
0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL,
0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L,
0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L,
0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L,
0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L,
0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L,
0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L,
0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L,
0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L,
0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L,
0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L,
0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L,
0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L,
0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L,
0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L,
0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L,
0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L,
0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL,
0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL,
0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L,
0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL,
0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L,
0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L,
0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L,
0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L },
{ 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L,
0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L,
0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL,
0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L,
0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L,
0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L,
0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL,
0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL,
0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL,
0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L,
0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L,
0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL,
0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L,
0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL,
0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L,
0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL,
0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L,
0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL,
0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L,
0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL,
0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L,
0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L,
0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL,
0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L,
0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L,
0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L,
0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L,
0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL,
0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L,
0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL,
0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L,
0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL,
0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L,
0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL,
0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL,
0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL,
0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L,
0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L,
0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL,
0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL,
0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL,
0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL,
0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL,
0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L,
0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L,
0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L,
0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L,
0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL,
0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL,
0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L,
0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L,
0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L,
0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L,
0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L,
0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L,
0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L,
0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L,
0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L,
0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L,
0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL,
0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L,
0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL,
0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L,
0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L },
{ 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL,
0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL,
0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL,
0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L,
0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L,
0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L,
0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L,
0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L,
0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L,
0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L,
0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L,
0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L,
0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L,
0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L,
0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L,
0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL,
0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL,
0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L,
0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL,
0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL,
0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL,
0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L,
0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL,
0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL,
0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L,
0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L,
0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L,
0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L,
0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL,
0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL,
0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L,
0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L,
0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L,
0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL,
0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L,
0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L,
0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L,
0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL,
0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L,
0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L,
0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L,
0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL,
0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL,
0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L,
0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L,
0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L,
0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L,
0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL,
0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L,
0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL,
0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL,
0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L,
0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L,
0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL,
0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L,
0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL,
0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L,
0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL,
0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L,
0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L,
0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL,
0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L,
0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL,
0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L }
};
#endif /* !MBEDTLS_BLOWFISH_ALT */
#endif /* MBEDTLS_BLOWFISH_C */

1114
library/camellia.c Normal file

File diff suppressed because it is too large Load Diff

553
library/ccm.c Normal file
View File

@ -0,0 +1,553 @@
/*
* NIST SP800-38C compliant CCM implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Definition of CCM:
* http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
* RFC 3610 "Counter with CBC-MAC (CCM)"
*
* Related:
* RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CCM_C)
#include "mbedtls/ccm.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#if !defined(MBEDTLS_CCM_ALT)
#define CCM_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CCM_BAD_INPUT )
#define CCM_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#define CCM_ENCRYPT 0
#define CCM_DECRYPT 1
/*
* Initialize context
*/
void mbedtls_ccm_init( mbedtls_ccm_context *ctx )
{
CCM_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_ccm_context ) );
}
int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
const mbedtls_cipher_info_t *cipher_info;
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( key != NULL );
cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
MBEDTLS_MODE_ECB );
if( cipher_info == NULL )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
if( cipher_info->block_size != 16 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
mbedtls_cipher_free( &ctx->cipher_ctx );
if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
MBEDTLS_ENCRYPT ) ) != 0 )
{
return( ret );
}
return( 0 );
}
/*
* Free context
*/
void mbedtls_ccm_free( mbedtls_ccm_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_cipher_free( &ctx->cipher_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ccm_context ) );
}
/*
* Macros for common operations.
* Results in smaller compiled code than static inline functions.
*/
/*
* Update the CBC-MAC state in y using a block in b
* (Always using b as the source helps the compiler optimise a bit better.)
*/
#define UPDATE_CBC_MAC \
for( i = 0; i < 16; i++ ) \
y[i] ^= b[i]; \
\
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
return( ret );
/*
* Encrypt or decrypt a partial block with CTR
* Warning: using b for temporary storage! src and dst must not be b!
* This avoids allocating one more 16 bytes buffer while allowing src == dst.
*/
#define CTR_CRYPT( dst, src, len ) \
do \
{ \
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, \
16, b, &olen ) ) != 0 ) \
{ \
return( ret ); \
} \
\
for( i = 0; i < (len); i++ ) \
(dst)[i] = (src)[i] ^ b[i]; \
} while( 0 )
/*
* Authenticated encryption or decryption
*/
static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char i;
unsigned char q;
size_t len_left, olen;
unsigned char b[16];
unsigned char y[16];
unsigned char ctr[16];
const unsigned char *src;
unsigned char *dst;
/*
* Check length requirements: SP800-38C A.1
* Additional requirement: a < 2^16 - 2^8 to simplify the code.
* 'length' checked later (when writing it to the first block)
*
* Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
*/
if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
/* Also implies q is within bounds */
if( iv_len < 7 || iv_len > 13 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
if( add_len > 0xFF00 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
q = 16 - 1 - (unsigned char) iv_len;
/*
* First block B_0:
* 0 .. 0 flags
* 1 .. iv_len nonce (aka iv)
* iv_len+1 .. 15 length
*
* With flags as (bits):
* 7 0
* 6 add present?
* 5 .. 3 (t - 2) / 2
* 2 .. 0 q - 1
*/
b[0] = 0;
b[0] |= ( add_len > 0 ) << 6;
b[0] |= ( ( tag_len - 2 ) / 2 ) << 3;
b[0] |= q - 1;
memcpy( b + 1, iv, iv_len );
for( i = 0, len_left = length; i < q; i++, len_left >>= 8 )
b[15-i] = (unsigned char)( len_left & 0xFF );
if( len_left > 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
/* Start CBC-MAC with first block */
memset( y, 0, 16 );
UPDATE_CBC_MAC;
/*
* If there is additional data, update CBC-MAC with
* add_len, add, 0 (padding to a block boundary)
*/
if( add_len > 0 )
{
size_t use_len;
len_left = add_len;
src = add;
memset( b, 0, 16 );
b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF );
b[1] = (unsigned char)( ( add_len ) & 0xFF );
use_len = len_left < 16 - 2 ? len_left : 16 - 2;
memcpy( b + 2, src, use_len );
len_left -= use_len;
src += use_len;
UPDATE_CBC_MAC;
while( len_left > 0 )
{
use_len = len_left > 16 ? 16 : len_left;
memset( b, 0, 16 );
memcpy( b, src, use_len );
UPDATE_CBC_MAC;
len_left -= use_len;
src += use_len;
}
}
/*
* Prepare counter block for encryption:
* 0 .. 0 flags
* 1 .. iv_len nonce (aka iv)
* iv_len+1 .. 15 counter (initially 1)
*
* With flags as (bits):
* 7 .. 3 0
* 2 .. 0 q - 1
*/
ctr[0] = q - 1;
memcpy( ctr + 1, iv, iv_len );
memset( ctr + 1 + iv_len, 0, q );
ctr[15] = 1;
/*
* Authenticate and {en,de}crypt the message.
*
* The only difference between encryption and decryption is
* the respective order of authentication and {en,de}cryption.
*/
len_left = length;
src = input;
dst = output;
while( len_left > 0 )
{
size_t use_len = len_left > 16 ? 16 : len_left;
if( mode == CCM_ENCRYPT )
{
memset( b, 0, 16 );
memcpy( b, src, use_len );
UPDATE_CBC_MAC;
}
CTR_CRYPT( dst, src, use_len );
if( mode == CCM_DECRYPT )
{
memset( b, 0, 16 );
memcpy( b, dst, use_len );
UPDATE_CBC_MAC;
}
dst += use_len;
src += use_len;
len_left -= use_len;
/*
* Increment counter.
* No need to check for overflow thanks to the length check above.
*/
for( i = 0; i < q; i++ )
if( ++ctr[15-i] != 0 )
break;
}
/*
* Authentication: reset counter and crypt/mask internal tag
*/
for( i = 0; i < q; i++ )
ctr[15-i] = 0;
CTR_CRYPT( y, y, 16 );
memcpy( tag, y, tag_len );
return( 0 );
}
/*
* Authenticated encryption
*/
int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( iv != NULL );
CCM_VALIDATE_RET( add_len == 0 || add != NULL );
CCM_VALIDATE_RET( length == 0 || input != NULL );
CCM_VALIDATE_RET( length == 0 || output != NULL );
CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len,
add, add_len, input, output, tag, tag_len ) );
}
int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( iv != NULL );
CCM_VALIDATE_RET( add_len == 0 || add != NULL );
CCM_VALIDATE_RET( length == 0 || input != NULL );
CCM_VALIDATE_RET( length == 0 || output != NULL );
CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
if( tag_len == 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
return( mbedtls_ccm_star_encrypt_and_tag( ctx, length, iv, iv_len, add,
add_len, input, output, tag, tag_len ) );
}
/*
* Authenticated decryption
*/
int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char check_tag[16];
unsigned char i;
int diff;
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( iv != NULL );
CCM_VALIDATE_RET( add_len == 0 || add != NULL );
CCM_VALIDATE_RET( length == 0 || input != NULL );
CCM_VALIDATE_RET( length == 0 || output != NULL );
CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length,
iv, iv_len, add, add_len,
input, output, check_tag, tag_len ) ) != 0 )
{
return( ret );
}
/* Check tag in "constant-time" */
for( diff = 0, i = 0; i < tag_len; i++ )
diff |= tag[i] ^ check_tag[i];
if( diff != 0 )
{
mbedtls_platform_zeroize( output, length );
return( MBEDTLS_ERR_CCM_AUTH_FAILED );
}
return( 0 );
}
int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len )
{
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( iv != NULL );
CCM_VALIDATE_RET( add_len == 0 || add != NULL );
CCM_VALIDATE_RET( length == 0 || input != NULL );
CCM_VALIDATE_RET( length == 0 || output != NULL );
CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
if( tag_len == 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
return( mbedtls_ccm_star_auth_decrypt( ctx, length, iv, iv_len, add,
add_len, input, output, tag, tag_len ) );
}
#endif /* !MBEDTLS_CCM_ALT */
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
/*
* Examples 1 to 3 from SP800-38C Appendix C
*/
#define NB_TESTS 3
#define CCM_SELFTEST_PT_MAX_LEN 24
#define CCM_SELFTEST_CT_MAX_LEN 32
/*
* The data is the same for all tests, only the used length changes
*/
static const unsigned char key_test_data[] = {
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
};
static const unsigned char iv_test_data[] = {
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b
};
static const unsigned char ad_test_data[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13
};
static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
};
static const size_t iv_len_test_data [NB_TESTS] = { 7, 8, 12 };
static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 };
static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
{ 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
{ 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
{ 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
};
int mbedtls_ccm_self_test( int verbose )
{
mbedtls_ccm_context ctx;
/*
* Some hardware accelerators require the input and output buffers
* would be in RAM, because the flash is not accessible.
* Use buffers on the stack to hold the test vectors data.
*/
unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
size_t i;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ccm_init( &ctx );
if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
8 * sizeof key_test_data ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( " CCM: setup failed" );
return( 1 );
}
for( i = 0; i < NB_TESTS; i++ )
{
if( verbose != 0 )
mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 );
memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
memset( ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN );
memcpy( plaintext, msg_test_data, msg_len_test_data[i] );
ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len_test_data[i],
iv_test_data, iv_len_test_data[i],
ad_test_data, add_len_test_data[i],
plaintext, ciphertext,
ciphertext + msg_len_test_data[i],
tag_len_test_data[i] );
if( ret != 0 ||
memcmp( ciphertext, res_test_data[i],
msg_len_test_data[i] + tag_len_test_data[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len_test_data[i],
iv_test_data, iv_len_test_data[i],
ad_test_data, add_len_test_data[i],
ciphertext, plaintext,
ciphertext + msg_len_test_data[i],
tag_len_test_data[i] );
if( ret != 0 ||
memcmp( plaintext, msg_test_data, msg_len_test_data[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
mbedtls_ccm_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#endif /* MBEDTLS_CCM_C */

571
library/chacha20.c Normal file
View File

@ -0,0 +1,571 @@
/**
* \file chacha20.c
*
* \brief ChaCha20 cipher.
*
* \author Daniel King <damaki.gh@gmail.com>
*
* Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CHACHA20_C)
#include "mbedtls/chacha20.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <stddef.h>
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_CHACHA20_ALT)
#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
!defined(inline) && !defined(__cplusplus)
#define inline __inline
#endif
/* Parameter validation macros */
#define CHACHA20_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA )
#define CHACHA20_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#define BYTES_TO_U32_LE( data, offset ) \
( (uint32_t) (data)[offset] \
| (uint32_t) ( (uint32_t) (data)[( offset ) + 1] << 8 ) \
| (uint32_t) ( (uint32_t) (data)[( offset ) + 2] << 16 ) \
| (uint32_t) ( (uint32_t) (data)[( offset ) + 3] << 24 ) \
)
#define ROTL32( value, amount ) \
( (uint32_t) ( (value) << (amount) ) | ( (value) >> ( 32 - (amount) ) ) )
#define CHACHA20_CTR_INDEX ( 12U )
#define CHACHA20_BLOCK_SIZE_BYTES ( 4U * 16U )
/**
* \brief ChaCha20 quarter round operation.
*
* The quarter round is defined as follows (from RFC 7539):
* 1. a += b; d ^= a; d <<<= 16;
* 2. c += d; b ^= c; b <<<= 12;
* 3. a += b; d ^= a; d <<<= 8;
* 4. c += d; b ^= c; b <<<= 7;
*
* \param state ChaCha20 state to modify.
* \param a The index of 'a' in the state.
* \param b The index of 'b' in the state.
* \param c The index of 'c' in the state.
* \param d The index of 'd' in the state.
*/
static inline void chacha20_quarter_round( uint32_t state[16],
size_t a,
size_t b,
size_t c,
size_t d )
{
/* a += b; d ^= a; d <<<= 16; */
state[a] += state[b];
state[d] ^= state[a];
state[d] = ROTL32( state[d], 16 );
/* c += d; b ^= c; b <<<= 12 */
state[c] += state[d];
state[b] ^= state[c];
state[b] = ROTL32( state[b], 12 );
/* a += b; d ^= a; d <<<= 8; */
state[a] += state[b];
state[d] ^= state[a];
state[d] = ROTL32( state[d], 8 );
/* c += d; b ^= c; b <<<= 7; */
state[c] += state[d];
state[b] ^= state[c];
state[b] = ROTL32( state[b], 7 );
}
/**
* \brief Perform the ChaCha20 inner block operation.
*
* This function performs two rounds: the column round and the
* diagonal round.
*
* \param state The ChaCha20 state to update.
*/
static void chacha20_inner_block( uint32_t state[16] )
{
chacha20_quarter_round( state, 0, 4, 8, 12 );
chacha20_quarter_round( state, 1, 5, 9, 13 );
chacha20_quarter_round( state, 2, 6, 10, 14 );
chacha20_quarter_round( state, 3, 7, 11, 15 );
chacha20_quarter_round( state, 0, 5, 10, 15 );
chacha20_quarter_round( state, 1, 6, 11, 12 );
chacha20_quarter_round( state, 2, 7, 8, 13 );
chacha20_quarter_round( state, 3, 4, 9, 14 );
}
/**
* \brief Generates a keystream block.
*
* \param initial_state The initial ChaCha20 state (key, nonce, counter).
* \param keystream Generated keystream bytes are written to this buffer.
*/
static void chacha20_block( const uint32_t initial_state[16],
unsigned char keystream[64] )
{
uint32_t working_state[16];
size_t i;
memcpy( working_state,
initial_state,
CHACHA20_BLOCK_SIZE_BYTES );
for( i = 0U; i < 10U; i++ )
chacha20_inner_block( working_state );
working_state[ 0] += initial_state[ 0];
working_state[ 1] += initial_state[ 1];
working_state[ 2] += initial_state[ 2];
working_state[ 3] += initial_state[ 3];
working_state[ 4] += initial_state[ 4];
working_state[ 5] += initial_state[ 5];
working_state[ 6] += initial_state[ 6];
working_state[ 7] += initial_state[ 7];
working_state[ 8] += initial_state[ 8];
working_state[ 9] += initial_state[ 9];
working_state[10] += initial_state[10];
working_state[11] += initial_state[11];
working_state[12] += initial_state[12];
working_state[13] += initial_state[13];
working_state[14] += initial_state[14];
working_state[15] += initial_state[15];
for( i = 0U; i < 16; i++ )
{
size_t offset = i * 4U;
keystream[offset ] = (unsigned char)( working_state[i] );
keystream[offset + 1U] = (unsigned char)( working_state[i] >> 8 );
keystream[offset + 2U] = (unsigned char)( working_state[i] >> 16 );
keystream[offset + 3U] = (unsigned char)( working_state[i] >> 24 );
}
mbedtls_platform_zeroize( working_state, sizeof( working_state ) );
}
void mbedtls_chacha20_init( mbedtls_chacha20_context *ctx )
{
CHACHA20_VALIDATE( ctx != NULL );
mbedtls_platform_zeroize( ctx->state, sizeof( ctx->state ) );
mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) );
/* Initially, there's no keystream bytes available */
ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES;
}
void mbedtls_chacha20_free( mbedtls_chacha20_context *ctx )
{
if( ctx != NULL )
{
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_chacha20_context ) );
}
}
int mbedtls_chacha20_setkey( mbedtls_chacha20_context *ctx,
const unsigned char key[32] )
{
CHACHA20_VALIDATE_RET( ctx != NULL );
CHACHA20_VALIDATE_RET( key != NULL );
/* ChaCha20 constants - the string "expand 32-byte k" */
ctx->state[0] = 0x61707865;
ctx->state[1] = 0x3320646e;
ctx->state[2] = 0x79622d32;
ctx->state[3] = 0x6b206574;
/* Set key */
ctx->state[4] = BYTES_TO_U32_LE( key, 0 );
ctx->state[5] = BYTES_TO_U32_LE( key, 4 );
ctx->state[6] = BYTES_TO_U32_LE( key, 8 );
ctx->state[7] = BYTES_TO_U32_LE( key, 12 );
ctx->state[8] = BYTES_TO_U32_LE( key, 16 );
ctx->state[9] = BYTES_TO_U32_LE( key, 20 );
ctx->state[10] = BYTES_TO_U32_LE( key, 24 );
ctx->state[11] = BYTES_TO_U32_LE( key, 28 );
return( 0 );
}
int mbedtls_chacha20_starts( mbedtls_chacha20_context* ctx,
const unsigned char nonce[12],
uint32_t counter )
{
CHACHA20_VALIDATE_RET( ctx != NULL );
CHACHA20_VALIDATE_RET( nonce != NULL );
/* Counter */
ctx->state[12] = counter;
/* Nonce */
ctx->state[13] = BYTES_TO_U32_LE( nonce, 0 );
ctx->state[14] = BYTES_TO_U32_LE( nonce, 4 );
ctx->state[15] = BYTES_TO_U32_LE( nonce, 8 );
mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) );
/* Initially, there's no keystream bytes available */
ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES;
return( 0 );
}
int mbedtls_chacha20_update( mbedtls_chacha20_context *ctx,
size_t size,
const unsigned char *input,
unsigned char *output )
{
size_t offset = 0U;
size_t i;
CHACHA20_VALIDATE_RET( ctx != NULL );
CHACHA20_VALIDATE_RET( size == 0 || input != NULL );
CHACHA20_VALIDATE_RET( size == 0 || output != NULL );
/* Use leftover keystream bytes, if available */
while( size > 0U && ctx->keystream_bytes_used < CHACHA20_BLOCK_SIZE_BYTES )
{
output[offset] = input[offset]
^ ctx->keystream8[ctx->keystream_bytes_used];
ctx->keystream_bytes_used++;
offset++;
size--;
}
/* Process full blocks */
while( size >= CHACHA20_BLOCK_SIZE_BYTES )
{
/* Generate new keystream block and increment counter */
chacha20_block( ctx->state, ctx->keystream8 );
ctx->state[CHACHA20_CTR_INDEX]++;
for( i = 0U; i < 64U; i += 8U )
{
output[offset + i ] = input[offset + i ] ^ ctx->keystream8[i ];
output[offset + i+1] = input[offset + i+1] ^ ctx->keystream8[i+1];
output[offset + i+2] = input[offset + i+2] ^ ctx->keystream8[i+2];
output[offset + i+3] = input[offset + i+3] ^ ctx->keystream8[i+3];
output[offset + i+4] = input[offset + i+4] ^ ctx->keystream8[i+4];
output[offset + i+5] = input[offset + i+5] ^ ctx->keystream8[i+5];
output[offset + i+6] = input[offset + i+6] ^ ctx->keystream8[i+6];
output[offset + i+7] = input[offset + i+7] ^ ctx->keystream8[i+7];
}
offset += CHACHA20_BLOCK_SIZE_BYTES;
size -= CHACHA20_BLOCK_SIZE_BYTES;
}
/* Last (partial) block */
if( size > 0U )
{
/* Generate new keystream block and increment counter */
chacha20_block( ctx->state, ctx->keystream8 );
ctx->state[CHACHA20_CTR_INDEX]++;
for( i = 0U; i < size; i++)
{
output[offset + i] = input[offset + i] ^ ctx->keystream8[i];
}
ctx->keystream_bytes_used = size;
}
return( 0 );
}
int mbedtls_chacha20_crypt( const unsigned char key[32],
const unsigned char nonce[12],
uint32_t counter,
size_t data_len,
const unsigned char* input,
unsigned char* output )
{
mbedtls_chacha20_context ctx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
CHACHA20_VALIDATE_RET( key != NULL );
CHACHA20_VALIDATE_RET( nonce != NULL );
CHACHA20_VALIDATE_RET( data_len == 0 || input != NULL );
CHACHA20_VALIDATE_RET( data_len == 0 || output != NULL );
mbedtls_chacha20_init( &ctx );
ret = mbedtls_chacha20_setkey( &ctx, key );
if( ret != 0 )
goto cleanup;
ret = mbedtls_chacha20_starts( &ctx, nonce, counter );
if( ret != 0 )
goto cleanup;
ret = mbedtls_chacha20_update( &ctx, data_len, input, output );
cleanup:
mbedtls_chacha20_free( &ctx );
return( ret );
}
#endif /* !MBEDTLS_CHACHA20_ALT */
#if defined(MBEDTLS_SELF_TEST)
static const unsigned char test_keys[2][32] =
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
}
};
static const unsigned char test_nonces[2][12] =
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02
}
};
static const uint32_t test_counters[2] =
{
0U,
1U
};
static const unsigned char test_input[2][375] =
{
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d,
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74,
0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45,
0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e,
0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74,
0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72,
0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66,
0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61,
0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72,
0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66,
0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46,
0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20,
0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73,
0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69,
0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49,
0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69,
0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20,
0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72,
0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49,
0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e,
0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20,
0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75,
0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20,
0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45,
0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20,
0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20,
0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20,
0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63,
0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63,
0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61,
0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e,
0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f,
0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c,
0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61,
0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f
}
};
static const unsigned char test_output[2][375] =
{
{
0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86
},
{
0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde,
0x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70,
0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd,
0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec,
0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15,
0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05,
0x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f,
0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d,
0x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa,
0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e,
0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7,
0xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50,
0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05,
0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c,
0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05,
0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a,
0xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0,
0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66,
0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4,
0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d,
0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91,
0x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28,
0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87,
0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b,
0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2,
0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f,
0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76,
0x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c,
0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b,
0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84,
0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd,
0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b,
0xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe,
0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0,
0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80,
0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f,
0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3,
0x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62,
0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91,
0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6,
0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64,
0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85,
0x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41,
0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab,
0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba,
0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd,
0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21
}
};
static const size_t test_lengths[2] =
{
64U,
375U
};
#define ASSERT( cond, args ) \
do \
{ \
if( ! ( cond ) ) \
{ \
if( verbose != 0 ) \
mbedtls_printf args; \
\
return( -1 ); \
} \
} \
while( 0 )
int mbedtls_chacha20_self_test( int verbose )
{
unsigned char output[381];
unsigned i;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
for( i = 0U; i < 2U; i++ )
{
if( verbose != 0 )
mbedtls_printf( " ChaCha20 test %u ", i );
ret = mbedtls_chacha20_crypt( test_keys[i],
test_nonces[i],
test_counters[i],
test_lengths[i],
test_input[i],
output );
ASSERT( 0 == ret, ( "error code: %i\n", ret ) );
ASSERT( 0 == memcmp( output, test_output[i], test_lengths[i] ),
( "failed (output)\n" ) );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* !MBEDTLS_CHACHA20_C */

541
library/chachapoly.c Normal file
View File

@ -0,0 +1,541 @@
/**
* \file chachapoly.c
*
* \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
*
* Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CHACHAPOLY_C)
#include "mbedtls/chachapoly.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_CHACHAPOLY_ALT)
/* Parameter validation macros */
#define CHACHAPOLY_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA )
#define CHACHAPOLY_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#define CHACHAPOLY_STATE_INIT ( 0 )
#define CHACHAPOLY_STATE_AAD ( 1 )
#define CHACHAPOLY_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */
#define CHACHAPOLY_STATE_FINISHED ( 3 )
/**
* \brief Adds nul bytes to pad the AAD for Poly1305.
*
* \param ctx The ChaCha20-Poly1305 context.
*/
static int chachapoly_pad_aad( mbedtls_chachapoly_context *ctx )
{
uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U );
unsigned char zeroes[15];
if( partial_block_len == 0U )
return( 0 );
memset( zeroes, 0, sizeof( zeroes ) );
return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
zeroes,
16U - partial_block_len ) );
}
/**
* \brief Adds nul bytes to pad the ciphertext for Poly1305.
*
* \param ctx The ChaCha20-Poly1305 context.
*/
static int chachapoly_pad_ciphertext( mbedtls_chachapoly_context *ctx )
{
uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U );
unsigned char zeroes[15];
if( partial_block_len == 0U )
return( 0 );
memset( zeroes, 0, sizeof( zeroes ) );
return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
zeroes,
16U - partial_block_len ) );
}
void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx )
{
CHACHAPOLY_VALIDATE( ctx != NULL );
mbedtls_chacha20_init( &ctx->chacha20_ctx );
mbedtls_poly1305_init( &ctx->poly1305_ctx );
ctx->aad_len = 0U;
ctx->ciphertext_len = 0U;
ctx->state = CHACHAPOLY_STATE_INIT;
ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;
}
void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_chacha20_free( &ctx->chacha20_ctx );
mbedtls_poly1305_free( &ctx->poly1305_ctx );
ctx->aad_len = 0U;
ctx->ciphertext_len = 0U;
ctx->state = CHACHAPOLY_STATE_INIT;
ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;
}
int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx,
const unsigned char key[32] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
CHACHAPOLY_VALIDATE_RET( ctx != NULL );
CHACHAPOLY_VALIDATE_RET( key != NULL );
ret = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key );
return( ret );
}
int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx,
const unsigned char nonce[12],
mbedtls_chachapoly_mode_t mode )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char poly1305_key[64];
CHACHAPOLY_VALIDATE_RET( ctx != NULL );
CHACHAPOLY_VALIDATE_RET( nonce != NULL );
/* Set counter = 0, will be update to 1 when generating Poly1305 key */
ret = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 0U );
if( ret != 0 )
goto cleanup;
/* Generate the Poly1305 key by getting the ChaCha20 keystream output with
* counter = 0. This is the same as encrypting a buffer of zeroes.
* Only the first 256-bits (32 bytes) of the key is used for Poly1305.
* The other 256 bits are discarded.
*/
memset( poly1305_key, 0, sizeof( poly1305_key ) );
ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, sizeof( poly1305_key ),
poly1305_key, poly1305_key );
if( ret != 0 )
goto cleanup;
ret = mbedtls_poly1305_starts( &ctx->poly1305_ctx, poly1305_key );
if( ret == 0 )
{
ctx->aad_len = 0U;
ctx->ciphertext_len = 0U;
ctx->state = CHACHAPOLY_STATE_AAD;
ctx->mode = mode;
}
cleanup:
mbedtls_platform_zeroize( poly1305_key, 64U );
return( ret );
}
int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx,
const unsigned char *aad,
size_t aad_len )
{
CHACHAPOLY_VALIDATE_RET( ctx != NULL );
CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
if( ctx->state != CHACHAPOLY_STATE_AAD )
return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
ctx->aad_len += aad_len;
return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad, aad_len ) );
}
int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx,
size_t len,
const unsigned char *input,
unsigned char *output )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
CHACHAPOLY_VALIDATE_RET( ctx != NULL );
CHACHAPOLY_VALIDATE_RET( len == 0 || input != NULL );
CHACHAPOLY_VALIDATE_RET( len == 0 || output != NULL );
if( ( ctx->state != CHACHAPOLY_STATE_AAD ) &&
( ctx->state != CHACHAPOLY_STATE_CIPHERTEXT ) )
{
return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
}
if( ctx->state == CHACHAPOLY_STATE_AAD )
{
ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
ret = chachapoly_pad_aad( ctx );
if( ret != 0 )
return( ret );
}
ctx->ciphertext_len += len;
if( ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT )
{
ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
if( ret != 0 )
return( ret );
ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, output, len );
if( ret != 0 )
return( ret );
}
else /* DECRYPT */
{
ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, input, len );
if( ret != 0 )
return( ret );
ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
if( ret != 0 )
return( ret );
}
return( 0 );
}
int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx,
unsigned char mac[16] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char len_block[16];
CHACHAPOLY_VALIDATE_RET( ctx != NULL );
CHACHAPOLY_VALIDATE_RET( mac != NULL );
if( ctx->state == CHACHAPOLY_STATE_INIT )
{
return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
}
if( ctx->state == CHACHAPOLY_STATE_AAD )
{
ret = chachapoly_pad_aad( ctx );
if( ret != 0 )
return( ret );
}
else if( ctx->state == CHACHAPOLY_STATE_CIPHERTEXT )
{
ret = chachapoly_pad_ciphertext( ctx );
if( ret != 0 )
return( ret );
}
ctx->state = CHACHAPOLY_STATE_FINISHED;
/* The lengths of the AAD and ciphertext are processed by
* Poly1305 as the final 128-bit block, encoded as little-endian integers.
*/
len_block[ 0] = (unsigned char)( ctx->aad_len );
len_block[ 1] = (unsigned char)( ctx->aad_len >> 8 );
len_block[ 2] = (unsigned char)( ctx->aad_len >> 16 );
len_block[ 3] = (unsigned char)( ctx->aad_len >> 24 );
len_block[ 4] = (unsigned char)( ctx->aad_len >> 32 );
len_block[ 5] = (unsigned char)( ctx->aad_len >> 40 );
len_block[ 6] = (unsigned char)( ctx->aad_len >> 48 );
len_block[ 7] = (unsigned char)( ctx->aad_len >> 56 );
len_block[ 8] = (unsigned char)( ctx->ciphertext_len );
len_block[ 9] = (unsigned char)( ctx->ciphertext_len >> 8 );
len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 );
len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 );
len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 );
len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 );
len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 );
len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 );
ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U );
if( ret != 0 )
return( ret );
ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac );
return( ret );
}
static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx,
mbedtls_chachapoly_mode_t mode,
size_t length,
const unsigned char nonce[12],
const unsigned char *aad,
size_t aad_len,
const unsigned char *input,
unsigned char *output,
unsigned char tag[16] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ret = mbedtls_chachapoly_starts( ctx, nonce, mode );
if( ret != 0 )
goto cleanup;
ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len );
if( ret != 0 )
goto cleanup;
ret = mbedtls_chachapoly_update( ctx, length, input, output );
if( ret != 0 )
goto cleanup;
ret = mbedtls_chachapoly_finish( ctx, tag );
cleanup:
return( ret );
}
int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx,
size_t length,
const unsigned char nonce[12],
const unsigned char *aad,
size_t aad_len,
const unsigned char *input,
unsigned char *output,
unsigned char tag[16] )
{
CHACHAPOLY_VALIDATE_RET( ctx != NULL );
CHACHAPOLY_VALIDATE_RET( nonce != NULL );
CHACHAPOLY_VALIDATE_RET( tag != NULL );
CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL );
CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL );
return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
length, nonce, aad, aad_len,
input, output, tag ) );
}
int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx,
size_t length,
const unsigned char nonce[12],
const unsigned char *aad,
size_t aad_len,
const unsigned char tag[16],
const unsigned char *input,
unsigned char *output )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char check_tag[16];
size_t i;
int diff;
CHACHAPOLY_VALIDATE_RET( ctx != NULL );
CHACHAPOLY_VALIDATE_RET( nonce != NULL );
CHACHAPOLY_VALIDATE_RET( tag != NULL );
CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL );
CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL );
if( ( ret = chachapoly_crypt_and_tag( ctx,
MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
aad, aad_len, input, output, check_tag ) ) != 0 )
{
return( ret );
}
/* Check tag in "constant-time" */
for( diff = 0, i = 0; i < sizeof( check_tag ); i++ )
diff |= tag[i] ^ check_tag[i];
if( diff != 0 )
{
mbedtls_platform_zeroize( output, length );
return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED );
}
return( 0 );
}
#endif /* MBEDTLS_CHACHAPOLY_ALT */
#if defined(MBEDTLS_SELF_TEST)
static const unsigned char test_key[1][32] =
{
{
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
}
};
static const unsigned char test_nonce[1][12] =
{
{
0x07, 0x00, 0x00, 0x00, /* 32-bit common part */
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */
}
};
static const unsigned char test_aad[1][12] =
{
{
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7
}
};
static const size_t test_aad_len[1] =
{
12U
};
static const unsigned char test_input[1][114] =
{
{
0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
0x74, 0x2e
}
};
static const unsigned char test_output[1][114] =
{
{
0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
0x61, 0x16
}
};
static const size_t test_input_len[1] =
{
114U
};
static const unsigned char test_mac[1][16] =
{
{
0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
}
};
#define ASSERT( cond, args ) \
do \
{ \
if( ! ( cond ) ) \
{ \
if( verbose != 0 ) \
mbedtls_printf args; \
\
return( -1 ); \
} \
} \
while( 0 )
int mbedtls_chachapoly_self_test( int verbose )
{
mbedtls_chachapoly_context ctx;
unsigned i;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char output[200];
unsigned char mac[16];
for( i = 0U; i < 1U; i++ )
{
if( verbose != 0 )
mbedtls_printf( " ChaCha20-Poly1305 test %u ", i );
mbedtls_chachapoly_init( &ctx );
ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] );
ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) );
ret = mbedtls_chachapoly_encrypt_and_tag( &ctx,
test_input_len[i],
test_nonce[i],
test_aad[i],
test_aad_len[i],
test_input[i],
output,
mac );
ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) );
ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ),
( "failure (wrong output)\n" ) );
ASSERT( 0 == memcmp( mac, test_mac[i], 16U ),
( "failure (wrong MAC)\n" ) );
mbedtls_chachapoly_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_CHACHAPOLY_C */

1525
library/cipher.c Normal file

File diff suppressed because it is too large Load Diff

2412
library/cipher_wrap.c Normal file

File diff suppressed because it is too large Load Diff

1079
library/cmac.c Normal file

File diff suppressed because it is too large Load Diff

816
library/ctr_drbg.c Normal file
View File

@ -0,0 +1,816 @@
/*
* CTR_DRBG implementation based on AES-256 (NIST SP 800-90)
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The NIST SP 800-90 DRBGs are described in the following publication.
*
* http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CTR_DRBG_C)
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_FS_IO)
#include <stdio.h>
#endif
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
/*
* CTR_DRBG context initialization
*/
void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
/* Indicate that the entropy nonce length is not set explicitly.
* See mbedtls_ctr_drbg_set_nonce_len(). */
ctx->reseed_counter = -1;
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_init( &ctx->mutex );
#endif
}
void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
{
if( ctx == NULL )
return;
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_free( &ctx->mutex );
#endif
mbedtls_aes_free( &ctx->aes_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
}
void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
int resistance )
{
ctx->prediction_resistance = resistance;
}
void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
size_t len )
{
ctx->entropy_len = len;
}
int mbedtls_ctr_drbg_set_nonce_len( mbedtls_ctr_drbg_context *ctx,
size_t len )
{
/* If mbedtls_ctr_drbg_seed() has already been called, it's
* too late. Return the error code that's closest to making sense. */
if( ctx->f_entropy != NULL )
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
#if SIZE_MAX > INT_MAX
/* This shouldn't be an issue because
* MBEDTLS_CTR_DRBG_MAX_SEED_INPUT < INT_MAX in any sensible
* configuration, but make sure anyway. */
if( len > INT_MAX )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
#endif
/* For backward compatibility with Mbed TLS <= 2.19, store the
* entropy nonce length in a field that already exists, but isn't
* used until after the initial seeding. */
/* Due to the capping of len above, the value fits in an int. */
ctx->reseed_counter = (int) len;
return( 0 );
}
void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
int interval )
{
ctx->reseed_interval = interval;
}
static int block_cipher_df( unsigned char *output,
const unsigned char *data, size_t data_len )
{
unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE];
unsigned char *p, *iv;
mbedtls_aes_context aes_ctx;
int ret = 0;
int i, j;
size_t buf_len, use_len;
if( data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 );
mbedtls_aes_init( &aes_ctx );
/*
* Construct IV (16 bytes) and S in buffer
* IV = Counter (in 32-bits) padded to 16 with zeroes
* S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
* data || 0x80
* (Total is padded to a multiple of 16-bytes with zeroes)
*/
p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE;
*p++ = ( data_len >> 24 ) & 0xff;
*p++ = ( data_len >> 16 ) & 0xff;
*p++ = ( data_len >> 8 ) & 0xff;
*p++ = ( data_len ) & 0xff;
p += 3;
*p++ = MBEDTLS_CTR_DRBG_SEEDLEN;
memcpy( p, data, data_len );
p[data_len] = 0x80;
buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
for( i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++ )
key[i] = i;
if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, key,
MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
{
goto exit;
}
/*
* Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data
*/
for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
{
p = buf;
memset( chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE );
use_len = buf_len;
while( use_len > 0 )
{
for( i = 0; i < MBEDTLS_CTR_DRBG_BLOCKSIZE; i++ )
chain[i] ^= p[i];
p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ?
MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT,
chain, chain ) ) != 0 )
{
goto exit;
}
}
memcpy( tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE );
/*
* Update IV
*/
buf[3]++;
}
/*
* Do final encryption with reduced data
*/
if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, tmp,
MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
{
goto exit;
}
iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE;
p = output;
for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
{
if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT,
iv, iv ) ) != 0 )
{
goto exit;
}
memcpy( p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE );
p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
}
exit:
mbedtls_aes_free( &aes_ctx );
/*
* tidy up the stack
*/
mbedtls_platform_zeroize( buf, sizeof( buf ) );
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
mbedtls_platform_zeroize( key, sizeof( key ) );
mbedtls_platform_zeroize( chain, sizeof( chain ) );
if( 0 != ret )
{
/*
* wipe partial seed from memory
*/
mbedtls_platform_zeroize( output, MBEDTLS_CTR_DRBG_SEEDLEN );
}
return( ret );
}
/* CTR_DRBG_Update (SP 800-90A &sect;10.2.1.2)
* ctr_drbg_update_internal(ctx, provided_data)
* implements
* CTR_DRBG_Update(provided_data, Key, V)
* with inputs and outputs
* ctx->aes_ctx = Key
* ctx->counter = V
*/
static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx,
const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] )
{
unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
unsigned char *p = tmp;
int i, j;
int ret = 0;
memset( tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN );
for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
{
/*
* Increase counter
*/
for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
if( ++ctx->counter[i - 1] != 0 )
break;
/*
* Crypt counter block
*/
if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
ctx->counter, p ) ) != 0 )
{
goto exit;
}
p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
}
for( i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++ )
tmp[i] ^= data[i];
/*
* Update key and counter
*/
if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp,
MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
{
goto exit;
}
memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE,
MBEDTLS_CTR_DRBG_BLOCKSIZE );
exit:
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
return( ret );
}
/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
* mbedtls_ctr_drbg_update(ctx, additional, add_len)
* implements
* CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
* security_strength) -> initial_working_state
* with inputs
* ctx->counter = all-bits-0
* ctx->aes_ctx = context from all-bits-0 key
* additional[:add_len] = entropy_input || nonce || personalization_string
* and with outputs
* ctx = initial_working_state
*/
int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional,
size_t add_len )
{
unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( add_len == 0 )
return( 0 );
if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
goto exit;
if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
goto exit;
exit:
mbedtls_platform_zeroize( add_input, sizeof( add_input ) );
return( ret );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional,
size_t add_len )
{
/* MAX_INPUT would be more logical here, but we have to match
* block_cipher_df()'s limits since we can't propagate errors */
if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT;
(void) mbedtls_ctr_drbg_update_ret( ctx, additional, add_len );
}
#endif /* MBEDTLS_DEPRECATED_REMOVED */
/* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
* mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len)
* implements
* CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
* -> new_working_state
* with inputs
* ctx contains working_state
* additional[:len] = additional_input
* and entropy_input comes from calling ctx->f_entropy
* for (ctx->entropy_len + nonce_len) bytes
* and with output
* ctx contains new_working_state
*/
static int mbedtls_ctr_drbg_reseed_internal( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional,
size_t len,
size_t nonce_len )
{
unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
size_t seedlen = 0;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
if( nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT );
/* Gather entropy_len bytes of entropy to seed state. */
if( 0 != ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) )
{
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
}
seedlen += ctx->entropy_len;
/* Gather entropy for a nonce if requested. */
if( nonce_len != 0 )
{
if( 0 != ctx->f_entropy( ctx->p_entropy, seed, nonce_len ) )
{
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
}
seedlen += nonce_len;
}
/* Add additional data if provided. */
if( additional != NULL && len != 0 )
{
memcpy( seed + seedlen, additional, len );
seedlen += len;
}
/* Reduce to 384 bits. */
if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 )
goto exit;
/* Update state. */
if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 )
goto exit;
ctx->reseed_counter = 1;
exit:
mbedtls_platform_zeroize( seed, sizeof( seed ) );
return( ret );
}
int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional, size_t len )
{
return( mbedtls_ctr_drbg_reseed_internal( ctx, additional, len, 0 ) );
}
/* Return a "good" nonce length for CTR_DRBG. The chosen nonce length
* is sufficient to achieve the maximum security strength given the key
* size and entropy length. If there is enough entropy in the initial
* call to the entropy function to serve as both the entropy input and
* the nonce, don't make a second call to get a nonce. */
static size_t good_nonce_len( size_t entropy_len )
{
if( entropy_len >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2 )
return( 0 );
else
return( ( entropy_len + 1 ) / 2 );
}
/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
* mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len)
* implements
* CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
* security_strength) -> initial_working_state
* with inputs
* custom[:len] = nonce || personalization_string
* where entropy_input comes from f_entropy for ctx->entropy_len bytes
* and with outputs
* ctx = initial_working_state
*/
int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
int (*f_entropy)(void *, unsigned char *, size_t),
void *p_entropy,
const unsigned char *custom,
size_t len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
size_t nonce_len;
memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
mbedtls_aes_init( &ctx->aes_ctx );
ctx->f_entropy = f_entropy;
ctx->p_entropy = p_entropy;
if( ctx->entropy_len == 0 )
ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
/* ctx->reseed_counter contains the desired amount of entropy to
* grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()).
* If it's -1, indicating that the entropy nonce length was not set
* explicitly, use a sufficiently large nonce for security. */
nonce_len = ( ctx->reseed_counter >= 0 ?
(size_t) ctx->reseed_counter :
good_nonce_len( ctx->entropy_len ) );
ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
/* Initialize with an empty key. */
if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key,
MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
{
return( ret );
}
/* Do the initial seeding. */
if( ( ret = mbedtls_ctr_drbg_reseed_internal( ctx, custom, len,
nonce_len ) ) != 0 )
{
return( ret );
}
return( 0 );
}
/* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
* mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
* implements
* CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len])
* -> working_state_after_reseed
* if required, then
* CTR_DRBG_Generate(working_state_after_reseed,
* requested_number_of_bits, additional_input)
* -> status, returned_bits, new_working_state
* with inputs
* ctx contains working_state
* requested_number_of_bits = 8 * output_len
* additional[:add_len] = additional_input
* and entropy_input comes from calling ctx->f_entropy
* and with outputs
* status = SUCCESS (this function does the reseed internally)
* returned_bits = output[:output_len]
* ctx contains new_working_state
*/
int mbedtls_ctr_drbg_random_with_add( void *p_rng,
unsigned char *output, size_t output_len,
const unsigned char *additional, size_t add_len )
{
int ret = 0;
mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
unsigned char *p = output;
unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE];
int i;
size_t use_len;
if( output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST )
return( MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG );
if( add_len > MBEDTLS_CTR_DRBG_MAX_INPUT )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
memset( add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN );
if( ctx->reseed_counter > ctx->reseed_interval ||
ctx->prediction_resistance )
{
if( ( ret = mbedtls_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 )
{
return( ret );
}
add_len = 0;
}
if( add_len > 0 )
{
if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
goto exit;
if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
goto exit;
}
while( output_len > 0 )
{
/*
* Increase counter
*/
for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
if( ++ctx->counter[i - 1] != 0 )
break;
/*
* Crypt counter block
*/
if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
ctx->counter, tmp ) ) != 0 )
{
goto exit;
}
use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE )
? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len;
/*
* Copy random block to destination
*/
memcpy( p, tmp, use_len );
p += use_len;
output_len -= use_len;
}
if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
goto exit;
ctx->reseed_counter++;
exit:
mbedtls_platform_zeroize( add_input, sizeof( add_input ) );
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
return( ret );
}
int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output,
size_t output_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
#if defined(MBEDTLS_THREADING_C)
if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
return( ret );
#endif
ret = mbedtls_ctr_drbg_random_with_add( ctx, output, output_len, NULL, 0 );
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif
return( ret );
}
#if defined(MBEDTLS_FS_IO)
int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx,
const char *path )
{
int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
FILE *f;
unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ];
if( ( f = fopen( path, "wb" ) ) == NULL )
return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
if( ( ret = mbedtls_ctr_drbg_random( ctx, buf,
MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 )
goto exit;
if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) !=
MBEDTLS_CTR_DRBG_MAX_INPUT )
{
ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
}
else
{
ret = 0;
}
exit:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
fclose( f );
return( ret );
}
int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx,
const char *path )
{
int ret = 0;
FILE *f = NULL;
size_t n;
unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ];
unsigned char c;
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
n = fread( buf, 1, sizeof( buf ), f );
if( fread( &c, 1, 1, f ) != 0 )
{
ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
goto exit;
}
if( n == 0 || ferror( f ) )
{
ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
goto exit;
}
fclose( f );
f = NULL;
ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n );
exit:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
if( f != NULL )
fclose( f );
if( ret != 0 )
return( ret );
return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) );
}
#endif /* MBEDTLS_FS_IO */
#if defined(MBEDTLS_SELF_TEST)
static const unsigned char entropy_source_pr[96] =
{ 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16,
0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02,
0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b,
0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb,
0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9,
0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95,
0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63,
0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3,
0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31,
0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4,
0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56,
0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 };
static const unsigned char entropy_source_nopr[64] =
{ 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14,
0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe,
0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d,
0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20,
0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9,
0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46,
0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e,
0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e };
static const unsigned char nonce_pers_pr[16] =
{ 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2,
0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c };
static const unsigned char nonce_pers_nopr[16] =
{ 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5,
0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f };
#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
static const unsigned char result_pr[16] =
{ 0x95, 0x3c, 0xa5, 0xbd, 0x44, 0x1, 0x34, 0xb7,
0x13, 0x58, 0x3e, 0x6a, 0x6c, 0x7e, 0x88, 0x8a };
static const unsigned char result_nopr[16] =
{ 0x6c, 0x25, 0x27, 0x95, 0xa3, 0x62, 0xd6, 0xdb,
0x90, 0xfd, 0x69, 0xb5, 0x42, 0x9, 0x4b, 0x84 };
#else /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
static const unsigned char result_pr[16] =
{ 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f,
0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 };
static const unsigned char result_nopr[16] =
{ 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88,
0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f };
#endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
static size_t test_offset;
static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf,
size_t len )
{
const unsigned char *p = data;
memcpy( buf, p + test_offset, len );
test_offset += len;
return( 0 );
}
#define CHK( c ) if( (c) != 0 ) \
{ \
if( verbose != 0 ) \
mbedtls_printf( "failed\n" ); \
return( 1 ); \
}
/*
* Checkup routine
*/
int mbedtls_ctr_drbg_self_test( int verbose )
{
mbedtls_ctr_drbg_context ctx;
unsigned char buf[16];
mbedtls_ctr_drbg_init( &ctx );
/*
* Based on a NIST CTR_DRBG test vector (PR = True)
*/
if( verbose != 0 )
mbedtls_printf( " CTR_DRBG (PR = TRUE) : " );
test_offset = 0;
mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 );
mbedtls_ctr_drbg_set_nonce_len( &ctx, 0 );
CHK( mbedtls_ctr_drbg_seed( &ctx,
ctr_drbg_self_test_entropy,
(void *) entropy_source_pr,
nonce_pers_pr, 16 ) );
mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
CHK( memcmp( buf, result_pr, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
mbedtls_ctr_drbg_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
/*
* Based on a NIST CTR_DRBG test vector (PR = FALSE)
*/
if( verbose != 0 )
mbedtls_printf( " CTR_DRBG (PR = FALSE): " );
mbedtls_ctr_drbg_init( &ctx );
test_offset = 0;
mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 );
mbedtls_ctr_drbg_set_nonce_len( &ctx, 0 );
CHK( mbedtls_ctr_drbg_seed( &ctx,
ctr_drbg_self_test_entropy,
(void *) entropy_source_nopr,
nonce_pers_nopr, 16 ) );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
CHK( memcmp( buf, result_nopr, 16 ) );
mbedtls_ctr_drbg_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_CTR_DRBG_C */

1064
library/des.c Normal file

File diff suppressed because it is too large Load Diff

713
library/dhm.c Normal file
View File

@ -0,0 +1,713 @@
/*
* Diffie-Hellman-Merkle key exchange
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The following sources were referenced in the design of this implementation
* of the Diffie-Hellman-Merkle algorithm:
*
* [1] Handbook of Applied Cryptography - 1997, Chapter 12
* Menezes, van Oorschot and Vanstone
*
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_DHM_C)
#include "mbedtls/dhm.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_PEM_PARSE_C)
#include "mbedtls/pem.h"
#endif
#if defined(MBEDTLS_ASN1_PARSE_C)
#include "mbedtls/asn1.h"
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#include <stdio.h>
#define mbedtls_printf printf
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
#if !defined(MBEDTLS_DHM_ALT)
#define DHM_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA )
#define DHM_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
/*
* helper to validate the mbedtls_mpi size and import it
*/
static int dhm_read_bignum( mbedtls_mpi *X,
unsigned char **p,
const unsigned char *end )
{
int ret, n;
if( end - *p < 2 )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
n = ( (*p)[0] << 8 ) | (*p)[1];
(*p) += 2;
if( (int)( end - *p ) < n )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 )
return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret );
(*p) += n;
return( 0 );
}
/*
* Verify sanity of parameter with regards to P
*
* Parameter should be: 2 <= public_param <= P - 2
*
* This means that we need to return an error if
* public_param < 2 or public_param > P-2
*
* For more information on the attack, see:
* http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
* http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
*/
static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P )
{
mbedtls_mpi L, U;
int ret = 0;
mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) );
if( mbedtls_mpi_cmp_mpi( param, &L ) < 0 ||
mbedtls_mpi_cmp_mpi( param, &U ) > 0 )
{
ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
}
cleanup:
mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U );
return( ret );
}
void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
{
DHM_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
}
/*
* Parse the ServerKeyExchange parameters
*/
int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
unsigned char **p,
const unsigned char *end )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( p != NULL && *p != NULL );
DHM_VALIDATE_RET( end != NULL );
if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 ||
( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 ||
( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
return( ret );
if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
return( ret );
ctx->len = mbedtls_mpi_size( &ctx->P );
return( 0 );
}
/*
* Setup and write the ServerKeyExchange parameters
*/
int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size,
unsigned char *output, size_t *olen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret, count = 0;
size_t n1, n2, n3;
unsigned char *p;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( output != NULL );
DHM_VALIDATE_RET( olen != NULL );
DHM_VALIDATE_RET( f_rng != NULL );
if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
/*
* Generate X as large as possible ( < P )
*/
do
{
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
if( count++ > 10 )
return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED );
}
while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
/*
* Calculate GX = G^X mod P
*/
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
&ctx->P , &ctx->RP ) );
if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
return( ret );
/*
* export P, G, GX
*/
#define DHM_MPI_EXPORT( X, n ) \
do { \
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( ( X ), \
p + 2, \
( n ) ) ); \
*p++ = (unsigned char)( ( n ) >> 8 ); \
*p++ = (unsigned char)( ( n ) ); \
p += ( n ); \
} while( 0 )
n1 = mbedtls_mpi_size( &ctx->P );
n2 = mbedtls_mpi_size( &ctx->G );
n3 = mbedtls_mpi_size( &ctx->GX );
p = output;
DHM_MPI_EXPORT( &ctx->P , n1 );
DHM_MPI_EXPORT( &ctx->G , n2 );
DHM_MPI_EXPORT( &ctx->GX, n3 );
*olen = p - output;
ctx->len = n1;
cleanup:
if( ret != 0 )
return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret );
return( 0 );
}
/*
* Set prime modulus and generator
*/
int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx,
const mbedtls_mpi *P,
const mbedtls_mpi *G )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( P != NULL );
DHM_VALIDATE_RET( G != NULL );
if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ||
( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 )
{
return( MBEDTLS_ERR_DHM_SET_GROUP_FAILED + ret );
}
ctx->len = mbedtls_mpi_size( &ctx->P );
return( 0 );
}
/*
* Import the peer's public value G^Y
*/
int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
const unsigned char *input, size_t ilen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( input != NULL );
if( ilen < 1 || ilen > ctx->len )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret );
return( 0 );
}
/*
* Create own private value X and export G^X
*/
int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,
unsigned char *output, size_t olen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret, count = 0;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( output != NULL );
DHM_VALIDATE_RET( f_rng != NULL );
if( olen < 1 || olen > ctx->len )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
/*
* generate X and calculate GX = G^X mod P
*/
do
{
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
if( count++ > 10 )
return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED );
}
while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
&ctx->P , &ctx->RP ) );
if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
return( ret );
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) );
cleanup:
if( ret != 0 )
return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret );
return( 0 );
}
/*
* Use the blinding method and optimisation suggested in section 10 of:
* KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
* DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
* Berlin Heidelberg, 1996. p. 104-113.
*/
static int dhm_update_blinding( mbedtls_dhm_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{
int ret, count;
/*
* Don't use any blinding the first time a particular X is used,
* but remember it to use blinding next time.
*/
if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) );
return( 0 );
}
/*
* Ok, we need blinding. Can we re-use existing values?
* If yes, just update them by squaring them.
*/
if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
return( 0 );
}
/*
* We need to generate blinding values from scratch
*/
/* Vi = random( 2, P-1 ) */
count = 0;
do
{
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ) );
while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 )
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) );
if( count++ > 10 )
return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
}
while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 );
/* Vf = Vi^-X mod P */
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) );
cleanup:
return( ret );
}
/*
* Derive and export the shared secret (G^Y)^X mod P
*/
int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,
unsigned char *output, size_t output_size, size_t *olen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_mpi GYb;
DHM_VALIDATE_RET( ctx != NULL );
DHM_VALIDATE_RET( output != NULL );
DHM_VALIDATE_RET( olen != NULL );
if( output_size < ctx->len )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
return( ret );
mbedtls_mpi_init( &GYb );
/* Blind peer's value */
if( f_rng != NULL )
{
MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) );
}
else
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) );
/* Do modular exponentiation */
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X,
&ctx->P, &ctx->RP ) );
/* Unblind secret value */
if( f_rng != NULL )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) );
}
*olen = mbedtls_mpi_size( &ctx->K );
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) );
cleanup:
mbedtls_mpi_free( &GYb );
if( ret != 0 )
return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret );
return( 0 );
}
/*
* Free the components of a DHM key
*/
void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_mpi_free( &ctx->pX );
mbedtls_mpi_free( &ctx->Vf );
mbedtls_mpi_free( &ctx->Vi );
mbedtls_mpi_free( &ctx->RP );
mbedtls_mpi_free( &ctx->K );
mbedtls_mpi_free( &ctx->GY );
mbedtls_mpi_free( &ctx->GX );
mbedtls_mpi_free( &ctx->X );
mbedtls_mpi_free( &ctx->G );
mbedtls_mpi_free( &ctx->P );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_dhm_context ) );
}
#if defined(MBEDTLS_ASN1_PARSE_C)
/*
* Parse DHM parameters
*/
int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
size_t dhminlen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len;
unsigned char *p, *end;
#if defined(MBEDTLS_PEM_PARSE_C)
mbedtls_pem_context pem;
#endif /* MBEDTLS_PEM_PARSE_C */
DHM_VALIDATE_RET( dhm != NULL );
DHM_VALIDATE_RET( dhmin != NULL );
#if defined(MBEDTLS_PEM_PARSE_C)
mbedtls_pem_init( &pem );
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' )
ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
else
ret = mbedtls_pem_read_buffer( &pem,
"-----BEGIN DH PARAMETERS-----",
"-----END DH PARAMETERS-----",
dhmin, NULL, 0, &dhminlen );
if( ret == 0 )
{
/*
* Was PEM encoded
*/
dhminlen = pem.buflen;
}
else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
goto exit;
p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin;
#else
p = (unsigned char *) dhmin;
#endif /* MBEDTLS_PEM_PARSE_C */
end = p + dhminlen;
/*
* DHParams ::= SEQUENCE {
* prime INTEGER, -- P
* generator INTEGER, -- g
* privateValueLength INTEGER OPTIONAL
* }
*/
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
{
ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
goto exit;
}
end = p + len;
if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P ) ) != 0 ||
( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 )
{
ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
goto exit;
}
if( p != end )
{
/* This might be the optional privateValueLength.
* If so, we can cleanly discard it */
mbedtls_mpi rec;
mbedtls_mpi_init( &rec );
ret = mbedtls_asn1_get_mpi( &p, end, &rec );
mbedtls_mpi_free( &rec );
if ( ret != 0 )
{
ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
goto exit;
}
if ( p != end )
{
ret = MBEDTLS_ERR_DHM_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
goto exit;
}
}
ret = 0;
dhm->len = mbedtls_mpi_size( &dhm->P );
exit:
#if defined(MBEDTLS_PEM_PARSE_C)
mbedtls_pem_free( &pem );
#endif
if( ret != 0 )
mbedtls_dhm_free( dhm );
return( ret );
}
#if defined(MBEDTLS_FS_IO)
/*
* Load all data from a file into a given buffer.
*
* The file is expected to contain either PEM or DER encoded data.
* A terminating null byte is always appended. It is included in the announced
* length only if the data looks like it is PEM encoded.
*/
static int load_file( const char *path, unsigned char **buf, size_t *n )
{
FILE *f;
long size;
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
fseek( f, 0, SEEK_END );
if( ( size = ftell( f ) ) == -1 )
{
fclose( f );
return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
}
fseek( f, 0, SEEK_SET );
*n = (size_t) size;
if( *n + 1 == 0 ||
( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
{
fclose( f );
return( MBEDTLS_ERR_DHM_ALLOC_FAILED );
}
if( fread( *buf, 1, *n, f ) != *n )
{
fclose( f );
mbedtls_platform_zeroize( *buf, *n + 1 );
mbedtls_free( *buf );
return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
}
fclose( f );
(*buf)[*n] = '\0';
if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
++*n;
return( 0 );
}
/*
* Load and parse DHM parameters
*/
int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t n;
unsigned char *buf;
DHM_VALIDATE_RET( dhm != NULL );
DHM_VALIDATE_RET( path != NULL );
if( ( ret = load_file( path, &buf, &n ) ) != 0 )
return( ret );
ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
mbedtls_platform_zeroize( buf, n );
mbedtls_free( buf );
return( ret );
}
#endif /* MBEDTLS_FS_IO */
#endif /* MBEDTLS_ASN1_PARSE_C */
#endif /* MBEDTLS_DHM_ALT */
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PEM_PARSE_C)
static const char mbedtls_test_dhm_params[] =
"-----BEGIN DH PARAMETERS-----\r\n"
"MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n"
"1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n"
"9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n"
"-----END DH PARAMETERS-----\r\n";
#else /* MBEDTLS_PEM_PARSE_C */
static const char mbedtls_test_dhm_params[] = {
0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44,
0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d,
0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3,
0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1,
0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18,
0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a,
0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1,
0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6,
0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64,
0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8,
0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f,
0x49, 0x75, 0xb3, 0x02, 0x01, 0x02 };
#endif /* MBEDTLS_PEM_PARSE_C */
static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params );
/*
* Checkup routine
*/
int mbedtls_dhm_self_test( int verbose )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_dhm_context dhm;
mbedtls_dhm_init( &dhm );
if( verbose != 0 )
mbedtls_printf( " DHM parameter load: " );
if( ( ret = mbedtls_dhm_parse_dhm( &dhm,
(const unsigned char *) mbedtls_test_dhm_params,
mbedtls_test_dhm_params_len ) ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
if( verbose != 0 )
mbedtls_printf( "passed\n\n" );
exit:
mbedtls_dhm_free( &dhm );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_DHM_C */

735
library/ecdh.c Normal file
View File

@ -0,0 +1,735 @@
/*
* Elliptic curve Diffie-Hellman
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* References:
*
* SEC1 http://www.secg.org/index.php?action=secg,docs_secg
* RFC 4492
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ECDH_C)
#include "mbedtls/ecdh.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
/* Parameter validation macros based on platform_util.h */
#define ECDH_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
#define ECDH_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed;
#endif
static mbedtls_ecp_group_id mbedtls_ecdh_grp_id(
const mbedtls_ecdh_context *ctx )
{
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ctx->grp.id );
#else
return( ctx->grp_id );
#endif
}
int mbedtls_ecdh_can_do( mbedtls_ecp_group_id gid )
{
/* At this time, all groups support ECDH. */
(void) gid;
return( 1 );
}
#if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
/*
* Generate public key (restartable version)
*
* Note: this internal function relies on its caller preserving the value of
* the output parameter 'd' across continuation calls. This would not be
* acceptable for a public function but is OK here as we control call sites.
*/
static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp,
mbedtls_mpi *d, mbedtls_ecp_point *Q,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* If multiplication is in progress, we already generated a privkey */
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( rs_ctx == NULL || rs_ctx->rsm == NULL )
#endif
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G,
f_rng, p_rng, rs_ctx ) );
cleanup:
return( ret );
}
/*
* Generate public key
*/
int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
ECDH_VALIDATE_RET( grp != NULL );
ECDH_VALIDATE_RET( d != NULL );
ECDH_VALIDATE_RET( Q != NULL );
ECDH_VALIDATE_RET( f_rng != NULL );
return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) );
}
#endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */
#if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT)
/*
* Compute shared secret (SEC1 3.3.1)
*/
static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp,
mbedtls_mpi *z,
const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ecp_point P;
mbedtls_ecp_point_init( &P );
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q,
f_rng, p_rng, rs_ctx ) );
if( mbedtls_ecp_is_zero( &P ) )
{
ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
goto cleanup;
}
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) );
cleanup:
mbedtls_ecp_point_free( &P );
return( ret );
}
/*
* Compute shared secret (SEC1 3.3.1)
*/
int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
ECDH_VALIDATE_RET( grp != NULL );
ECDH_VALIDATE_RET( Q != NULL );
ECDH_VALIDATE_RET( d != NULL );
ECDH_VALIDATE_RET( z != NULL );
return( ecdh_compute_shared_restartable( grp, z, Q, d,
f_rng, p_rng, NULL ) );
}
#endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
static void ecdh_init_internal( mbedtls_ecdh_context_mbed *ctx )
{
mbedtls_ecp_group_init( &ctx->grp );
mbedtls_mpi_init( &ctx->d );
mbedtls_ecp_point_init( &ctx->Q );
mbedtls_ecp_point_init( &ctx->Qp );
mbedtls_mpi_init( &ctx->z );
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_init( &ctx->rs );
#endif
}
/*
* Initialize context
*/
void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx )
{
ECDH_VALIDATE( ctx != NULL );
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
ecdh_init_internal( ctx );
mbedtls_ecp_point_init( &ctx->Vi );
mbedtls_ecp_point_init( &ctx->Vf );
mbedtls_mpi_init( &ctx->_d );
#else
memset( ctx, 0, sizeof( mbedtls_ecdh_context ) );
ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
#endif
ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
#if defined(MBEDTLS_ECP_RESTARTABLE)
ctx->restart_enabled = 0;
#endif
}
static int ecdh_setup_internal( mbedtls_ecdh_context_mbed *ctx,
mbedtls_ecp_group_id grp_id )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ret = mbedtls_ecp_group_load( &ctx->grp, grp_id );
if( ret != 0 )
{
return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
}
return( 0 );
}
/*
* Setup context
*/
int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id )
{
ECDH_VALIDATE_RET( ctx != NULL );
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_setup_internal( ctx, grp_id ) );
#else
switch( grp_id )
{
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
case MBEDTLS_ECP_DP_CURVE25519:
ctx->point_format = MBEDTLS_ECP_PF_COMPRESSED;
ctx->var = MBEDTLS_ECDH_VARIANT_EVEREST;
ctx->grp_id = grp_id;
return( mbedtls_everest_setup( &ctx->ctx.everest_ecdh, grp_id ) );
#endif
default:
ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0;
ctx->grp_id = grp_id;
ecdh_init_internal( &ctx->ctx.mbed_ecdh );
return( ecdh_setup_internal( &ctx->ctx.mbed_ecdh, grp_id ) );
}
#endif
}
static void ecdh_free_internal( mbedtls_ecdh_context_mbed *ctx )
{
mbedtls_ecp_group_free( &ctx->grp );
mbedtls_mpi_free( &ctx->d );
mbedtls_ecp_point_free( &ctx->Q );
mbedtls_ecp_point_free( &ctx->Qp );
mbedtls_mpi_free( &ctx->z );
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_free( &ctx->rs );
#endif
}
#if defined(MBEDTLS_ECP_RESTARTABLE)
/*
* Enable restartable operations for context
*/
void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx )
{
ECDH_VALIDATE( ctx != NULL );
ctx->restart_enabled = 1;
}
#endif
/*
* Free context
*/
void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx )
{
if( ctx == NULL )
return;
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
mbedtls_ecp_point_free( &ctx->Vi );
mbedtls_ecp_point_free( &ctx->Vf );
mbedtls_mpi_free( &ctx->_d );
ecdh_free_internal( ctx );
#else
switch( ctx->var )
{
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
case MBEDTLS_ECDH_VARIANT_EVEREST:
mbedtls_everest_free( &ctx->ctx.everest_ecdh );
break;
#endif
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
ecdh_free_internal( &ctx->ctx.mbed_ecdh );
break;
default:
break;
}
ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
ctx->var = MBEDTLS_ECDH_VARIANT_NONE;
ctx->grp_id = MBEDTLS_ECP_DP_NONE;
#endif
}
static int ecdh_make_params_internal( mbedtls_ecdh_context_mbed *ctx,
size_t *olen, int point_format,
unsigned char *buf, size_t blen,
int (*f_rng)(void *,
unsigned char *,
size_t),
void *p_rng,
int restart_enabled )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t grp_len, pt_len;
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_ctx *rs_ctx = NULL;
#endif
if( ctx->grp.pbits == 0 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( restart_enabled )
rs_ctx = &ctx->rs;
#else
(void) restart_enabled;
#endif
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
f_rng, p_rng, rs_ctx ) ) != 0 )
return( ret );
#else
if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
f_rng, p_rng ) ) != 0 )
return( ret );
#endif /* MBEDTLS_ECP_RESTARTABLE */
if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf,
blen ) ) != 0 )
return( ret );
buf += grp_len;
blen -= grp_len;
if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format,
&pt_len, buf, blen ) ) != 0 )
return( ret );
*olen = grp_len + pt_len;
return( 0 );
}
/*
* Setup and write the ServerKeyExchange parameters (RFC 4492)
* struct {
* ECParameters curve_params;
* ECPoint public;
* } ServerECDHParams;
*/
int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int restart_enabled = 0;
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( olen != NULL );
ECDH_VALIDATE_RET( buf != NULL );
ECDH_VALIDATE_RET( f_rng != NULL );
#if defined(MBEDTLS_ECP_RESTARTABLE)
restart_enabled = ctx->restart_enabled;
#else
(void) restart_enabled;
#endif
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_make_params_internal( ctx, olen, ctx->point_format, buf, blen,
f_rng, p_rng, restart_enabled ) );
#else
switch( ctx->var )
{
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
case MBEDTLS_ECDH_VARIANT_EVEREST:
return( mbedtls_everest_make_params( &ctx->ctx.everest_ecdh, olen,
buf, blen, f_rng, p_rng ) );
#endif
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen,
ctx->point_format, buf, blen,
f_rng, p_rng,
restart_enabled ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
}
static int ecdh_read_params_internal( mbedtls_ecdh_context_mbed *ctx,
const unsigned char **buf,
const unsigned char *end )
{
return( mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf,
end - *buf ) );
}
/*
* Read the ServerKeyExhange parameters (RFC 4492)
* struct {
* ECParameters curve_params;
* ECPoint public;
* } ServerECDHParams;
*/
int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx,
const unsigned char **buf,
const unsigned char *end )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ecp_group_id grp_id;
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( buf != NULL );
ECDH_VALIDATE_RET( *buf != NULL );
ECDH_VALIDATE_RET( end != NULL );
if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, end - *buf ) )
!= 0 )
return( ret );
if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 )
return( ret );
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_read_params_internal( ctx, buf, end ) );
#else
switch( ctx->var )
{
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
case MBEDTLS_ECDH_VARIANT_EVEREST:
return( mbedtls_everest_read_params( &ctx->ctx.everest_ecdh,
buf, end) );
#endif
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh,
buf, end ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
}
static int ecdh_get_params_internal( mbedtls_ecdh_context_mbed *ctx,
const mbedtls_ecp_keypair *key,
mbedtls_ecdh_side side )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* If it's not our key, just import the public part as Qp */
if( side == MBEDTLS_ECDH_THEIRS )
return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) );
/* Our key: import public (as Q) and private parts */
if( side != MBEDTLS_ECDH_OURS )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 ||
( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 )
return( ret );
return( 0 );
}
/*
* Get parameters from a keypair
*/
int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx,
const mbedtls_ecp_keypair *key,
mbedtls_ecdh_side side )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( key != NULL );
ECDH_VALIDATE_RET( side == MBEDTLS_ECDH_OURS ||
side == MBEDTLS_ECDH_THEIRS );
if( mbedtls_ecdh_grp_id( ctx ) == MBEDTLS_ECP_DP_NONE )
{
/* This is the first call to get_params(). Set up the context
* for use with the group. */
if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 )
return( ret );
}
else
{
/* This is not the first call to get_params(). Check that the
* current key's group is the same as the context's, which was set
* from the first key's group. */
if( mbedtls_ecdh_grp_id( ctx ) != key->grp.id )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
}
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_get_params_internal( ctx, key, side ) );
#else
switch( ctx->var )
{
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
case MBEDTLS_ECDH_VARIANT_EVEREST:
{
mbedtls_everest_ecdh_side s = side == MBEDTLS_ECDH_OURS ?
MBEDTLS_EVEREST_ECDH_OURS :
MBEDTLS_EVEREST_ECDH_THEIRS;
return( mbedtls_everest_get_params( &ctx->ctx.everest_ecdh,
key, s) );
}
#endif
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_get_params_internal( &ctx->ctx.mbed_ecdh,
key, side ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
}
static int ecdh_make_public_internal( mbedtls_ecdh_context_mbed *ctx,
size_t *olen, int point_format,
unsigned char *buf, size_t blen,
int (*f_rng)(void *,
unsigned char *,
size_t),
void *p_rng,
int restart_enabled )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_ctx *rs_ctx = NULL;
#endif
if( ctx->grp.pbits == 0 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( restart_enabled )
rs_ctx = &ctx->rs;
#else
(void) restart_enabled;
#endif
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
f_rng, p_rng, rs_ctx ) ) != 0 )
return( ret );
#else
if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q,
f_rng, p_rng ) ) != 0 )
return( ret );
#endif /* MBEDTLS_ECP_RESTARTABLE */
return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, olen,
buf, blen );
}
/*
* Setup and export the client public value
*/
int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int restart_enabled = 0;
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( olen != NULL );
ECDH_VALIDATE_RET( buf != NULL );
ECDH_VALIDATE_RET( f_rng != NULL );
#if defined(MBEDTLS_ECP_RESTARTABLE)
restart_enabled = ctx->restart_enabled;
#endif
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_make_public_internal( ctx, olen, ctx->point_format, buf, blen,
f_rng, p_rng, restart_enabled ) );
#else
switch( ctx->var )
{
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
case MBEDTLS_ECDH_VARIANT_EVEREST:
return( mbedtls_everest_make_public( &ctx->ctx.everest_ecdh, olen,
buf, blen, f_rng, p_rng ) );
#endif
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen,
ctx->point_format, buf, blen,
f_rng, p_rng,
restart_enabled ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
}
static int ecdh_read_public_internal( mbedtls_ecdh_context_mbed *ctx,
const unsigned char *buf, size_t blen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
const unsigned char *p = buf;
if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p,
blen ) ) != 0 )
return( ret );
if( (size_t)( p - buf ) != blen )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
return( 0 );
}
/*
* Parse and import the client's public value
*/
int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx,
const unsigned char *buf, size_t blen )
{
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( buf != NULL );
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_read_public_internal( ctx, buf, blen ) );
#else
switch( ctx->var )
{
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
case MBEDTLS_ECDH_VARIANT_EVEREST:
return( mbedtls_everest_read_public( &ctx->ctx.everest_ecdh,
buf, blen ) );
#endif
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh,
buf, blen ) );
default:
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
#endif
}
static int ecdh_calc_secret_internal( mbedtls_ecdh_context_mbed *ctx,
size_t *olen, unsigned char *buf,
size_t blen,
int (*f_rng)(void *,
unsigned char *,
size_t),
void *p_rng,
int restart_enabled )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_ECP_RESTARTABLE)
mbedtls_ecp_restart_ctx *rs_ctx = NULL;
#endif
if( ctx == NULL || ctx->grp.pbits == 0 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( restart_enabled )
rs_ctx = &ctx->rs;
#else
(void) restart_enabled;
#endif
#if defined(MBEDTLS_ECP_RESTARTABLE)
if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, &ctx->z, &ctx->Qp,
&ctx->d, f_rng, p_rng,
rs_ctx ) ) != 0 )
{
return( ret );
}
#else
if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp,
&ctx->d, f_rng, p_rng ) ) != 0 )
{
return( ret );
}
#endif /* MBEDTLS_ECP_RESTARTABLE */
if( mbedtls_mpi_size( &ctx->z ) > blen )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
*olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 );
if( mbedtls_ecp_get_type( &ctx->grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
return mbedtls_mpi_write_binary_le( &ctx->z, buf, *olen );
return mbedtls_mpi_write_binary( &ctx->z, buf, *olen );
}
/*
* Derive and export the shared secret
*/
int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int restart_enabled = 0;
ECDH_VALIDATE_RET( ctx != NULL );
ECDH_VALIDATE_RET( olen != NULL );
ECDH_VALIDATE_RET( buf != NULL );
#if defined(MBEDTLS_ECP_RESTARTABLE)
restart_enabled = ctx->restart_enabled;
#endif
#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
return( ecdh_calc_secret_internal( ctx, olen, buf, blen, f_rng, p_rng,
restart_enabled ) );
#else
switch( ctx->var )
{
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
case MBEDTLS_ECDH_VARIANT_EVEREST:
return( mbedtls_everest_calc_secret( &ctx->ctx.everest_ecdh, olen,
buf, blen, f_rng, p_rng ) );
#endif
case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0:
return( ecdh_calc_secret_internal( &ctx->ctx.mbed_ecdh, olen, buf,
blen, f_rng, p_rng,
restart_enabled ) );
default:
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
}
#endif
}
#endif /* MBEDTLS_ECDH_C */

1008
library/ecdsa.c Normal file

File diff suppressed because it is too large Load Diff

1141
library/ecjpake.c Normal file

File diff suppressed because it is too large Load Diff

3148
library/ecp.c Normal file

File diff suppressed because it is too large Load Diff

1471
library/ecp_curves.c Normal file

File diff suppressed because it is too large Load Diff

730
library/entropy.c Normal file
View File

@ -0,0 +1,730 @@
/*
* Entropy accumulator implementation
*
* Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ENTROPY_C)
#if defined(MBEDTLS_TEST_NULL_ENTROPY)
#warning "**** WARNING! MBEDTLS_TEST_NULL_ENTROPY defined! "
#warning "**** THIS BUILD HAS NO DEFINED ENTROPY SOURCES "
#warning "**** THIS BUILD IS *NOT* SUITABLE FOR PRODUCTION USE "
#endif
#include "mbedtls/entropy.h"
#include "mbedtls/entropy_poll.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_FS_IO)
#include <stdio.h>
#endif
#if defined(MBEDTLS_ENTROPY_NV_SEED)
#include "mbedtls/platform.h"
#endif
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if defined(MBEDTLS_HAVEGE_C)
#include "mbedtls/havege.h"
#endif
#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */
void mbedtls_entropy_init( mbedtls_entropy_context *ctx )
{
ctx->source_count = 0;
memset( ctx->source, 0, sizeof( ctx->source ) );
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_init( &ctx->mutex );
#endif
ctx->accumulator_started = 0;
#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
mbedtls_sha512_init( &ctx->accumulator );
#else
mbedtls_sha256_init( &ctx->accumulator );
#endif
#if defined(MBEDTLS_HAVEGE_C)
mbedtls_havege_init( &ctx->havege_data );
#endif
/* Reminder: Update ENTROPY_HAVE_STRONG in the test files
* when adding more strong entropy sources here. */
#if defined(MBEDTLS_TEST_NULL_ENTROPY)
mbedtls_entropy_add_source( ctx, mbedtls_null_entropy_poll, NULL,
1, MBEDTLS_ENTROPY_SOURCE_STRONG );
#endif
#if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL,
MBEDTLS_ENTROPY_MIN_PLATFORM,
MBEDTLS_ENTROPY_SOURCE_STRONG );
#endif
#if defined(MBEDTLS_TIMING_C)
mbedtls_entropy_add_source( ctx, mbedtls_hardclock_poll, NULL,
MBEDTLS_ENTROPY_MIN_HARDCLOCK,
MBEDTLS_ENTROPY_SOURCE_WEAK );
#endif
#if defined(MBEDTLS_HAVEGE_C)
mbedtls_entropy_add_source( ctx, mbedtls_havege_poll, &ctx->havege_data,
MBEDTLS_ENTROPY_MIN_HAVEGE,
MBEDTLS_ENTROPY_SOURCE_STRONG );
#endif
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
mbedtls_entropy_add_source( ctx, mbedtls_hardware_poll, NULL,
MBEDTLS_ENTROPY_MIN_HARDWARE,
MBEDTLS_ENTROPY_SOURCE_STRONG );
#endif
#if defined(MBEDTLS_ENTROPY_NV_SEED)
mbedtls_entropy_add_source( ctx, mbedtls_nv_seed_poll, NULL,
MBEDTLS_ENTROPY_BLOCK_SIZE,
MBEDTLS_ENTROPY_SOURCE_STRONG );
ctx->initial_entropy_run = 0;
#endif
#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */
}
void mbedtls_entropy_free( mbedtls_entropy_context *ctx )
{
#if defined(MBEDTLS_HAVEGE_C)
mbedtls_havege_free( &ctx->havege_data );
#endif
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_free( &ctx->mutex );
#endif
#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
mbedtls_sha512_free( &ctx->accumulator );
#else
mbedtls_sha256_free( &ctx->accumulator );
#endif
#if defined(MBEDTLS_ENTROPY_NV_SEED)
ctx->initial_entropy_run = 0;
#endif
ctx->source_count = 0;
mbedtls_platform_zeroize( ctx->source, sizeof( ctx->source ) );
ctx->accumulator_started = 0;
}
int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx,
mbedtls_entropy_f_source_ptr f_source, void *p_source,
size_t threshold, int strong )
{
int idx, ret = 0;
#if defined(MBEDTLS_THREADING_C)
if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
return( ret );
#endif
idx = ctx->source_count;
if( idx >= MBEDTLS_ENTROPY_MAX_SOURCES )
{
ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES;
goto exit;
}
ctx->source[idx].f_source = f_source;
ctx->source[idx].p_source = p_source;
ctx->source[idx].threshold = threshold;
ctx->source[idx].strong = strong;
ctx->source_count++;
exit:
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif
return( ret );
}
/*
* Entropy accumulator update
*/
static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id,
const unsigned char *data, size_t len )
{
unsigned char header[2];
unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE];
size_t use_len = len;
const unsigned char *p = data;
int ret = 0;
if( use_len > MBEDTLS_ENTROPY_BLOCK_SIZE )
{
#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
if( ( ret = mbedtls_sha512_ret( data, len, tmp, 0 ) ) != 0 )
goto cleanup;
#else
if( ( ret = mbedtls_sha256_ret( data, len, tmp, 0 ) ) != 0 )
goto cleanup;
#endif
p = tmp;
use_len = MBEDTLS_ENTROPY_BLOCK_SIZE;
}
header[0] = source_id;
header[1] = use_len & 0xFF;
/*
* Start the accumulator if this has not already happened. Note that
* it is sufficient to start the accumulator here only because all calls to
* gather entropy eventually execute this code.
*/
#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
if( ctx->accumulator_started == 0 &&
( ret = mbedtls_sha512_starts_ret( &ctx->accumulator, 0 ) ) != 0 )
goto cleanup;
else
ctx->accumulator_started = 1;
if( ( ret = mbedtls_sha512_update_ret( &ctx->accumulator, header, 2 ) ) != 0 )
goto cleanup;
ret = mbedtls_sha512_update_ret( &ctx->accumulator, p, use_len );
#else
if( ctx->accumulator_started == 0 &&
( ret = mbedtls_sha256_starts_ret( &ctx->accumulator, 0 ) ) != 0 )
goto cleanup;
else
ctx->accumulator_started = 1;
if( ( ret = mbedtls_sha256_update_ret( &ctx->accumulator, header, 2 ) ) != 0 )
goto cleanup;
ret = mbedtls_sha256_update_ret( &ctx->accumulator, p, use_len );
#endif
cleanup:
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
return( ret );
}
int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx,
const unsigned char *data, size_t len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_THREADING_C)
if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
return( ret );
#endif
ret = entropy_update( ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len );
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif
return( ret );
}
/*
* Run through the different sources to add entropy to our accumulator
*/
static int entropy_gather_internal( mbedtls_entropy_context *ctx )
{
int ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
int i;
int have_one_strong = 0;
unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER];
size_t olen;
if( ctx->source_count == 0 )
return( MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED );
/*
* Run through our entropy sources
*/
for( i = 0; i < ctx->source_count; i++ )
{
if( ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG )
have_one_strong = 1;
olen = 0;
if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source,
buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen ) ) != 0 )
{
goto cleanup;
}
/*
* Add if we actually gathered something
*/
if( olen > 0 )
{
if( ( ret = entropy_update( ctx, (unsigned char) i,
buf, olen ) ) != 0 )
return( ret );
ctx->source[i].size += olen;
}
}
if( have_one_strong == 0 )
ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE;
cleanup:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
return( ret );
}
/*
* Thread-safe wrapper for entropy_gather_internal()
*/
int mbedtls_entropy_gather( mbedtls_entropy_context *ctx )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_THREADING_C)
if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
return( ret );
#endif
ret = entropy_gather_internal( ctx );
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif
return( ret );
}
int mbedtls_entropy_func( void *data, unsigned char *output, size_t len )
{
int ret, count = 0, i, thresholds_reached;
size_t strong_size;
mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data;
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
if( len > MBEDTLS_ENTROPY_BLOCK_SIZE )
return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
#if defined(MBEDTLS_ENTROPY_NV_SEED)
/* Update the NV entropy seed before generating any entropy for outside
* use.
*/
if( ctx->initial_entropy_run == 0 )
{
ctx->initial_entropy_run = 1;
if( ( ret = mbedtls_entropy_update_nv_seed( ctx ) ) != 0 )
return( ret );
}
#endif
#if defined(MBEDTLS_THREADING_C)
if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
return( ret );
#endif
/*
* Always gather extra entropy before a call
*/
do
{
if( count++ > ENTROPY_MAX_LOOP )
{
ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
goto exit;
}
if( ( ret = entropy_gather_internal( ctx ) ) != 0 )
goto exit;
thresholds_reached = 1;
strong_size = 0;
for( i = 0; i < ctx->source_count; i++ )
{
if( ctx->source[i].size < ctx->source[i].threshold )
thresholds_reached = 0;
if( ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG )
strong_size += ctx->source[i].size;
}
}
while( ! thresholds_reached || strong_size < MBEDTLS_ENTROPY_BLOCK_SIZE );
memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
/*
* Note that at this stage it is assumed that the accumulator was started
* in a previous call to entropy_update(). If this is not guaranteed, the
* code below will fail.
*/
if( ( ret = mbedtls_sha512_finish_ret( &ctx->accumulator, buf ) ) != 0 )
goto exit;
/*
* Reset accumulator and counters and recycle existing entropy
*/
mbedtls_sha512_free( &ctx->accumulator );
mbedtls_sha512_init( &ctx->accumulator );
if( ( ret = mbedtls_sha512_starts_ret( &ctx->accumulator, 0 ) ) != 0 )
goto exit;
if( ( ret = mbedtls_sha512_update_ret( &ctx->accumulator, buf,
MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 )
goto exit;
/*
* Perform second SHA-512 on entropy
*/
if( ( ret = mbedtls_sha512_ret( buf, MBEDTLS_ENTROPY_BLOCK_SIZE,
buf, 0 ) ) != 0 )
goto exit;
#else /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */
if( ( ret = mbedtls_sha256_finish_ret( &ctx->accumulator, buf ) ) != 0 )
goto exit;
/*
* Reset accumulator and counters and recycle existing entropy
*/
mbedtls_sha256_free( &ctx->accumulator );
mbedtls_sha256_init( &ctx->accumulator );
if( ( ret = mbedtls_sha256_starts_ret( &ctx->accumulator, 0 ) ) != 0 )
goto exit;
if( ( ret = mbedtls_sha256_update_ret( &ctx->accumulator, buf,
MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 )
goto exit;
/*
* Perform second SHA-256 on entropy
*/
if( ( ret = mbedtls_sha256_ret( buf, MBEDTLS_ENTROPY_BLOCK_SIZE,
buf, 0 ) ) != 0 )
goto exit;
#endif /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */
for( i = 0; i < ctx->source_count; i++ )
ctx->source[i].size = 0;
memcpy( output, buf, len );
ret = 0;
exit:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif
return( ret );
}
#if defined(MBEDTLS_ENTROPY_NV_SEED)
int mbedtls_entropy_update_nv_seed( mbedtls_entropy_context *ctx )
{
int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
/* Read new seed and write it to NV */
if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 )
return( ret );
if( mbedtls_nv_seed_write( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 )
return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR );
/* Manually update the remaining stream with a separator value to diverge */
memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
ret = mbedtls_entropy_update_manual( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE );
return( ret );
}
#endif /* MBEDTLS_ENTROPY_NV_SEED */
#if defined(MBEDTLS_FS_IO)
int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path )
{
int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
FILE *f;
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
if( ( f = fopen( path, "wb" ) ) == NULL )
return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR );
if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 )
goto exit;
if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != MBEDTLS_ENTROPY_BLOCK_SIZE )
{
ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
goto exit;
}
ret = 0;
exit:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
fclose( f );
return( ret );
}
int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path )
{
int ret = 0;
FILE *f;
size_t n;
unsigned char buf[ MBEDTLS_ENTROPY_MAX_SEED_SIZE ];
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR );
fseek( f, 0, SEEK_END );
n = (size_t) ftell( f );
fseek( f, 0, SEEK_SET );
if( n > MBEDTLS_ENTROPY_MAX_SEED_SIZE )
n = MBEDTLS_ENTROPY_MAX_SEED_SIZE;
if( fread( buf, 1, n, f ) != n )
ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
else
ret = mbedtls_entropy_update_manual( ctx, buf, n );
fclose( f );
mbedtls_platform_zeroize( buf, sizeof( buf ) );
if( ret != 0 )
return( ret );
return( mbedtls_entropy_write_seed_file( ctx, path ) );
}
#endif /* MBEDTLS_FS_IO */
#if defined(MBEDTLS_SELF_TEST)
#if !defined(MBEDTLS_TEST_NULL_ENTROPY)
/*
* Dummy source function
*/
static int entropy_dummy_source( void *data, unsigned char *output,
size_t len, size_t *olen )
{
((void) data);
memset( output, 0x2a, len );
*olen = len;
return( 0 );
}
#endif /* !MBEDTLS_TEST_NULL_ENTROPY */
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
static int mbedtls_entropy_source_self_test_gather( unsigned char *buf, size_t buf_len )
{
int ret = 0;
size_t entropy_len = 0;
size_t olen = 0;
size_t attempts = buf_len;
while( attempts > 0 && entropy_len < buf_len )
{
if( ( ret = mbedtls_hardware_poll( NULL, buf + entropy_len,
buf_len - entropy_len, &olen ) ) != 0 )
return( ret );
entropy_len += olen;
attempts--;
}
if( entropy_len < buf_len )
{
ret = 1;
}
return( ret );
}
static int mbedtls_entropy_source_self_test_check_bits( const unsigned char *buf,
size_t buf_len )
{
unsigned char set= 0xFF;
unsigned char unset = 0x00;
size_t i;
for( i = 0; i < buf_len; i++ )
{
set &= buf[i];
unset |= buf[i];
}
return( set == 0xFF || unset == 0x00 );
}
/*
* A test to ensure hat the entropy sources are functioning correctly
* and there is no obvious failure. The test performs the following checks:
* - The entropy source is not providing only 0s (all bits unset) or 1s (all
* bits set).
* - The entropy source is not providing values in a pattern. Because the
* hardware could be providing data in an arbitrary length, this check polls
* the hardware entropy source twice and compares the result to ensure they
* are not equal.
* - The error code returned by the entropy source is not an error.
*/
int mbedtls_entropy_source_self_test( int verbose )
{
int ret = 0;
unsigned char buf0[2 * sizeof( unsigned long long int )];
unsigned char buf1[2 * sizeof( unsigned long long int )];
if( verbose != 0 )
mbedtls_printf( " ENTROPY_BIAS test: " );
memset( buf0, 0x00, sizeof( buf0 ) );
memset( buf1, 0x00, sizeof( buf1 ) );
if( ( ret = mbedtls_entropy_source_self_test_gather( buf0, sizeof( buf0 ) ) ) != 0 )
goto cleanup;
if( ( ret = mbedtls_entropy_source_self_test_gather( buf1, sizeof( buf1 ) ) ) != 0 )
goto cleanup;
/* Make sure that the returned values are not all 0 or 1 */
if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf0, sizeof( buf0 ) ) ) != 0 )
goto cleanup;
if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf1, sizeof( buf1 ) ) ) != 0 )
goto cleanup;
/* Make sure that the entropy source is not returning values in a
* pattern */
ret = memcmp( buf0, buf1, sizeof( buf0 ) ) == 0;
cleanup:
if( verbose != 0 )
{
if( ret != 0 )
mbedtls_printf( "failed\n" );
else
mbedtls_printf( "passed\n" );
mbedtls_printf( "\n" );
}
return( ret != 0 );
}
#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */
/*
* The actual entropy quality is hard to test, but we can at least
* test that the functions don't cause errors and write the correct
* amount of data to buffers.
*/
int mbedtls_entropy_self_test( int verbose )
{
int ret = 1;
#if !defined(MBEDTLS_TEST_NULL_ENTROPY)
mbedtls_entropy_context ctx;
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
size_t i, j;
#endif /* !MBEDTLS_TEST_NULL_ENTROPY */
if( verbose != 0 )
mbedtls_printf( " ENTROPY test: " );
#if !defined(MBEDTLS_TEST_NULL_ENTROPY)
mbedtls_entropy_init( &ctx );
/* First do a gather to make sure we have default sources */
if( ( ret = mbedtls_entropy_gather( &ctx ) ) != 0 )
goto cleanup;
ret = mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL, 16,
MBEDTLS_ENTROPY_SOURCE_WEAK );
if( ret != 0 )
goto cleanup;
if( ( ret = mbedtls_entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 )
goto cleanup;
/*
* To test that mbedtls_entropy_func writes correct number of bytes:
* - use the whole buffer and rely on ASan to detect overruns
* - collect entropy 8 times and OR the result in an accumulator:
* any byte should then be 0 with probably 2^(-64), so requiring
* each of the 32 or 64 bytes to be non-zero has a false failure rate
* of at most 2^(-58) which is acceptable.
*/
for( i = 0; i < 8; i++ )
{
if( ( ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 )
goto cleanup;
for( j = 0; j < sizeof( buf ); j++ )
acc[j] |= buf[j];
}
for( j = 0; j < sizeof( buf ); j++ )
{
if( acc[j] == 0 )
{
ret = 1;
goto cleanup;
}
}
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
if( ( ret = mbedtls_entropy_source_self_test( 0 ) ) != 0 )
goto cleanup;
#endif
cleanup:
mbedtls_entropy_free( &ctx );
#endif /* !MBEDTLS_TEST_NULL_ENTROPY */
if( verbose != 0 )
{
if( ret != 0 )
mbedtls_printf( "failed\n" );
else
mbedtls_printf( "passed\n" );
mbedtls_printf( "\n" );
}
return( ret != 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_ENTROPY_C */

237
library/entropy_poll.c Normal file
View File

@ -0,0 +1,237 @@
/*
* Platform-specific and custom entropy polling functions
*
* Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if defined(__linux__)
/* Ensure that syscall() is available even when compiling with -std=c99 */
#define _GNU_SOURCE
#endif
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <string.h>
#if defined(MBEDTLS_ENTROPY_C)
#include "mbedtls/entropy.h"
#include "mbedtls/entropy_poll.h"
#include "mbedtls/error.h"
#if defined(MBEDTLS_TIMING_C)
#include "mbedtls/timing.h"
#endif
#if defined(MBEDTLS_HAVEGE_C)
#include "mbedtls/havege.h"
#endif
#if defined(MBEDTLS_ENTROPY_NV_SEED)
#include "mbedtls/platform.h"
#endif
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
!defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
!defined(__HAIKU__)
#error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h"
#endif
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
#if !defined(_WIN32_WINNT)
#define _WIN32_WINNT 0x0400
#endif
#include <windows.h>
#include <wincrypt.h>
int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len,
size_t *olen )
{
HCRYPTPROV provider;
((void) data);
*olen = 0;
if( CryptAcquireContext( &provider, NULL, NULL,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE )
{
return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
}
if( CryptGenRandom( provider, (DWORD) len, output ) == FALSE )
{
CryptReleaseContext( provider, 0 );
return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
}
CryptReleaseContext( provider, 0 );
*olen = len;
return( 0 );
}
#else /* _WIN32 && !EFIX64 && !EFI32 */
/*
* Test for Linux getrandom() support.
* Since there is no wrapper in the libc yet, use the generic syscall wrapper
* available in GNU libc and compatible libc's (eg uClibc).
*/
#if defined(__linux__) && defined(__GLIBC__)
#include <unistd.h>
#include <sys/syscall.h>
#if defined(SYS_getrandom)
#define HAVE_GETRANDOM
#include <errno.h>
static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags )
{
/* MemSan cannot understand that the syscall writes to the buffer */
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
memset( buf, 0, buflen );
#endif
#endif
return( syscall( SYS_getrandom, buf, buflen, flags ) );
}
#endif /* SYS_getrandom */
#endif /* __linux__ */
#include <stdio.h>
int mbedtls_platform_entropy_poll( void *data,
unsigned char *output, size_t len, size_t *olen )
{
FILE *file;
size_t read_len;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
((void) data);
#if defined(HAVE_GETRANDOM)
ret = getrandom_wrapper( output, len, 0 );
if( ret >= 0 )
{
*olen = ret;
return( 0 );
}
else if( errno != ENOSYS )
return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
/* Fall through if the system call isn't known. */
#else
((void) ret);
#endif /* HAVE_GETRANDOM */
*olen = 0;
file = fopen( "/dev/urandom", "rb" );
if( file == NULL )
return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
read_len = fread( output, 1, len, file );
if( read_len != len )
{
fclose( file );
return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
}
fclose( file );
*olen = len;
return( 0 );
}
#endif /* _WIN32 && !EFIX64 && !EFI32 */
#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */
#if defined(MBEDTLS_TEST_NULL_ENTROPY)
int mbedtls_null_entropy_poll( void *data,
unsigned char *output, size_t len, size_t *olen )
{
((void) data);
((void) output);
*olen = 0;
if( len < sizeof(unsigned char) )
return( 0 );
*olen = sizeof(unsigned char);
return( 0 );
}
#endif
#if defined(MBEDTLS_TIMING_C)
int mbedtls_hardclock_poll( void *data,
unsigned char *output, size_t len, size_t *olen )
{
unsigned long timer = mbedtls_timing_hardclock();
((void) data);
*olen = 0;
if( len < sizeof(unsigned long) )
return( 0 );
memcpy( output, &timer, sizeof(unsigned long) );
*olen = sizeof(unsigned long);
return( 0 );
}
#endif /* MBEDTLS_TIMING_C */
#if defined(MBEDTLS_HAVEGE_C)
int mbedtls_havege_poll( void *data,
unsigned char *output, size_t len, size_t *olen )
{
mbedtls_havege_state *hs = (mbedtls_havege_state *) data;
*olen = 0;
if( mbedtls_havege_random( hs, output, len ) != 0 )
return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
*olen = len;
return( 0 );
}
#endif /* MBEDTLS_HAVEGE_C */
#if defined(MBEDTLS_ENTROPY_NV_SEED)
int mbedtls_nv_seed_poll( void *data,
unsigned char *output, size_t len, size_t *olen )
{
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE;
((void) data);
memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
if( mbedtls_nv_seed_read( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 )
return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
if( len < use_len )
use_len = len;
memcpy( output, buf, use_len );
*olen = use_len;
return( 0 );
}
#endif /* MBEDTLS_ENTROPY_NV_SEED */
#endif /* MBEDTLS_ENTROPY_C */

View File

@ -140,6 +140,10 @@
#include "mbedtls/md5.h"
#endif
#if defined(MBEDTLS_NET_C)
#include "mbedtls/net_sockets.h"
#endif
#if defined(MBEDTLS_OID_C)
#include "mbedtls/oid.h"
#endif
@ -192,26 +196,22 @@
#include "mbedtls/sha512.h"
#endif
#if defined(MBEDTLS_THREADING_C)
#include "mbedtls/threading.h"
#endif
#if defined(MBEDTLS_XTEA_C)
#include "mbedtls/xtea.h"
#endif
#if defined(MBEDTLS_NET_C)
#include "mbedtls/net_sockets.h"
#endif
#if defined(MBEDTLS_SSL_TLS_C)
#include "mbedtls/ssl.h"
#endif
#if defined(MBEDTLS_THREADING_C)
#include "mbedtls/threading.h"
#endif
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
#include "mbedtls/x509.h"
#endif
#if defined(MBEDTLS_XTEA_C)
#include "mbedtls/xtea.h"
#endif
void mbedtls_strerror( int ret, char *buf, size_t buflen )
{
@ -526,10 +526,6 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "SSL - The asynchronous operation is not completed yet" );
if( use_ret == -(MBEDTLS_ERR_SSL_EARLY_MESSAGE) )
mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that a message arrived early" );
if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_CID) )
mbedtls_snprintf( buf, buflen, "SSL - An encrypted DTLS-frame with an unexpected CID was received" );
if( use_ret == -(MBEDTLS_ERR_SSL_VERSION_MISMATCH) )
mbedtls_snprintf( buf, buflen, "SSL - An operation failed due to an unexpected version or configuration" );
if( use_ret == -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) )
mbedtls_snprintf( buf, buflen, "SSL - A cryptographic operation is in progress. Try again later" );
#endif /* MBEDTLS_SSL_TLS_C */
@ -804,6 +800,35 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
mbedtls_snprintf( buf, buflen, "MD5 - MD5 hardware accelerator failed" );
#endif /* MBEDTLS_MD5_C */
#if defined(MBEDTLS_NET_C)
if( use_ret == -(MBEDTLS_ERR_NET_SOCKET_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Failed to open a socket" );
if( use_ret == -(MBEDTLS_ERR_NET_CONNECT_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - The connection to the given server / port failed" );
if( use_ret == -(MBEDTLS_ERR_NET_BIND_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Binding of the socket failed" );
if( use_ret == -(MBEDTLS_ERR_NET_LISTEN_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Could not listen on the socket" );
if( use_ret == -(MBEDTLS_ERR_NET_ACCEPT_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Could not accept the incoming connection" );
if( use_ret == -(MBEDTLS_ERR_NET_RECV_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Reading information from the socket failed" );
if( use_ret == -(MBEDTLS_ERR_NET_SEND_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Sending information through the socket failed" );
if( use_ret == -(MBEDTLS_ERR_NET_CONN_RESET) )
mbedtls_snprintf( buf, buflen, "NET - Connection was reset by peer" );
if( use_ret == -(MBEDTLS_ERR_NET_UNKNOWN_HOST) )
mbedtls_snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" );
if( use_ret == -(MBEDTLS_ERR_NET_BUFFER_TOO_SMALL) )
mbedtls_snprintf( buf, buflen, "NET - Buffer is too small to hold the data" );
if( use_ret == -(MBEDTLS_ERR_NET_INVALID_CONTEXT) )
mbedtls_snprintf( buf, buflen, "NET - The context is invalid, eg because it was free()ed" );
if( use_ret == -(MBEDTLS_ERR_NET_POLL_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Polling the net context failed" );
if( use_ret == -(MBEDTLS_ERR_NET_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "NET - Input invalid" );
#endif /* MBEDTLS_NET_C */
#if defined(MBEDTLS_OID_C)
if( use_ret == -(MBEDTLS_ERR_OID_NOT_FOUND) )
mbedtls_snprintf( buf, buflen, "OID - OID is not found" );
@ -873,35 +898,6 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
if( use_ret == -(MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED) )
mbedtls_snprintf( buf, buflen, "XTEA - XTEA hardware accelerator failed" );
#endif /* MBEDTLS_XTEA_C */
#if defined(MBEDTLS_NET_C)
if( use_ret == -(MBEDTLS_ERR_NET_SOCKET_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Failed to open a socket" );
if( use_ret == -(MBEDTLS_ERR_NET_CONNECT_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - The connection to the given server / port failed" );
if( use_ret == -(MBEDTLS_ERR_NET_BIND_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Binding of the socket failed" );
if( use_ret == -(MBEDTLS_ERR_NET_LISTEN_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Could not listen on the socket" );
if( use_ret == -(MBEDTLS_ERR_NET_ACCEPT_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Could not accept the incoming connection" );
if( use_ret == -(MBEDTLS_ERR_NET_RECV_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Reading information from the socket failed" );
if( use_ret == -(MBEDTLS_ERR_NET_SEND_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Sending information through the socket failed" );
if( use_ret == -(MBEDTLS_ERR_NET_CONN_RESET) )
mbedtls_snprintf( buf, buflen, "NET - Connection was reset by peer" );
if( use_ret == -(MBEDTLS_ERR_NET_UNKNOWN_HOST) )
mbedtls_snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" );
if( use_ret == -(MBEDTLS_ERR_NET_BUFFER_TOO_SMALL) )
mbedtls_snprintf( buf, buflen, "NET - Buffer is too small to hold the data" );
if( use_ret == -(MBEDTLS_ERR_NET_INVALID_CONTEXT) )
mbedtls_snprintf( buf, buflen, "NET - The context is invalid, eg because it was free()ed" );
if( use_ret == -(MBEDTLS_ERR_NET_POLL_FAILED) )
mbedtls_snprintf( buf, buflen, "NET - Polling the net context failed" );
if( use_ret == -(MBEDTLS_ERR_NET_BAD_INPUT_DATA) )
mbedtls_snprintf( buf, buflen, "NET - Input invalid" );
#endif /* MBEDTLS_NET_C */
// END generated code
if( strlen( buf ) != 0 )

1021
library/gcm.c Normal file

File diff suppressed because it is too large Load Diff

243
library/havege.c Normal file
View File

@ -0,0 +1,243 @@
/**
* \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The HAVEGE RNG was designed by Andre Seznec in 2002.
*
* http://www.irisa.fr/caps/projects/hipsor/publi.php
*
* Contact: seznec(at)irisa_dot_fr - orocheco(at)irisa_dot_fr
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_HAVEGE_C)
#include "mbedtls/havege.h"
#include "mbedtls/timing.h"
#include "mbedtls/platform_util.h"
#include <stdint.h>
#include <string.h>
/* ------------------------------------------------------------------------
* On average, one iteration accesses two 8-word blocks in the havege WALK
* table, and generates 16 words in the RES array.
*
* The data read in the WALK table is updated and permuted after each use.
* The result of the hardware clock counter read is used for this update.
*
* 25 conditional tests are present. The conditional tests are grouped in
* two nested groups of 12 conditional tests and 1 test that controls the
* permutation; on average, there should be 6 tests executed and 3 of them
* should be mispredicted.
* ------------------------------------------------------------------------
*/
#define SWAP(X,Y) { uint32_t *T = (X); (X) = (Y); (Y) = T; }
#define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
#define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
#define TST1_LEAVE U1++; }
#define TST2_LEAVE U2++; }
#define ONE_ITERATION \
\
PTEST = PT1 >> 20; \
\
TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \
TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \
TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \
\
TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \
TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \
TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \
\
PTX = (PT1 >> 18) & 7; \
PT1 &= 0x1FFF; \
PT2 &= 0x1FFF; \
CLK = (uint32_t) mbedtls_timing_hardclock(); \
\
i = 0; \
A = &WALK[PT1 ]; RES[i++] ^= *A; \
B = &WALK[PT2 ]; RES[i++] ^= *B; \
C = &WALK[PT1 ^ 1]; RES[i++] ^= *C; \
D = &WALK[PT2 ^ 4]; RES[i++] ^= *D; \
\
IN = (*A >> (1)) ^ (*A << (31)) ^ CLK; \
*A = (*B >> (2)) ^ (*B << (30)) ^ CLK; \
*B = IN ^ U1; \
*C = (*C >> (3)) ^ (*C << (29)) ^ CLK; \
*D = (*D >> (4)) ^ (*D << (28)) ^ CLK; \
\
A = &WALK[PT1 ^ 2]; RES[i++] ^= *A; \
B = &WALK[PT2 ^ 2]; RES[i++] ^= *B; \
C = &WALK[PT1 ^ 3]; RES[i++] ^= *C; \
D = &WALK[PT2 ^ 6]; RES[i++] ^= *D; \
\
if( PTEST & 1 ) SWAP( A, C ); \
\
IN = (*A >> (5)) ^ (*A << (27)) ^ CLK; \
*A = (*B >> (6)) ^ (*B << (26)) ^ CLK; \
*B = IN; CLK = (uint32_t) mbedtls_timing_hardclock(); \
*C = (*C >> (7)) ^ (*C << (25)) ^ CLK; \
*D = (*D >> (8)) ^ (*D << (24)) ^ CLK; \
\
A = &WALK[PT1 ^ 4]; \
B = &WALK[PT2 ^ 1]; \
\
PTEST = PT2 >> 1; \
\
PT2 = (RES[(i - 8) ^ PTY] ^ WALK[PT2 ^ PTY ^ 7]); \
PT2 = ((PT2 & 0x1FFF) & (~8)) ^ ((PT1 ^ 8) & 0x8); \
PTY = (PT2 >> 10) & 7; \
\
TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \
TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \
TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \
\
TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \
TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \
TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \
\
C = &WALK[PT1 ^ 5]; \
D = &WALK[PT2 ^ 5]; \
\
RES[i++] ^= *A; \
RES[i++] ^= *B; \
RES[i++] ^= *C; \
RES[i++] ^= *D; \
\
IN = (*A >> ( 9)) ^ (*A << (23)) ^ CLK; \
*A = (*B >> (10)) ^ (*B << (22)) ^ CLK; \
*B = IN ^ U2; \
*C = (*C >> (11)) ^ (*C << (21)) ^ CLK; \
*D = (*D >> (12)) ^ (*D << (20)) ^ CLK; \
\
A = &WALK[PT1 ^ 6]; RES[i++] ^= *A; \
B = &WALK[PT2 ^ 3]; RES[i++] ^= *B; \
C = &WALK[PT1 ^ 7]; RES[i++] ^= *C; \
D = &WALK[PT2 ^ 7]; RES[i++] ^= *D; \
\
IN = (*A >> (13)) ^ (*A << (19)) ^ CLK; \
*A = (*B >> (14)) ^ (*B << (18)) ^ CLK; \
*B = IN; \
*C = (*C >> (15)) ^ (*C << (17)) ^ CLK; \
*D = (*D >> (16)) ^ (*D << (16)) ^ CLK; \
\
PT1 = ( RES[( i - 8 ) ^ PTX] ^ \
WALK[PT1 ^ PTX ^ 7] ) & (~1); \
PT1 ^= (PT2 ^ 0x10) & 0x10; \
\
for( n++, i = 0; i < 16; i++ ) \
hs->pool[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i];
/*
* Entropy gathering function
*/
static void havege_fill( mbedtls_havege_state *hs )
{
size_t n = 0;
size_t i;
uint32_t U1, U2, *A, *B, *C, *D;
uint32_t PT1, PT2, *WALK, RES[16];
uint32_t PTX, PTY, CLK, PTEST, IN;
WALK = hs->WALK;
PT1 = hs->PT1;
PT2 = hs->PT2;
PTX = U1 = 0;
PTY = U2 = 0;
(void)PTX;
memset( RES, 0, sizeof( RES ) );
while( n < MBEDTLS_HAVEGE_COLLECT_SIZE * 4 )
{
ONE_ITERATION
ONE_ITERATION
ONE_ITERATION
ONE_ITERATION
}
hs->PT1 = PT1;
hs->PT2 = PT2;
hs->offset[0] = 0;
hs->offset[1] = MBEDTLS_HAVEGE_COLLECT_SIZE / 2;
}
/*
* HAVEGE initialization
*/
void mbedtls_havege_init( mbedtls_havege_state *hs )
{
memset( hs, 0, sizeof( mbedtls_havege_state ) );
havege_fill( hs );
}
void mbedtls_havege_free( mbedtls_havege_state *hs )
{
if( hs == NULL )
return;
mbedtls_platform_zeroize( hs, sizeof( mbedtls_havege_state ) );
}
/*
* HAVEGE rand function
*/
int mbedtls_havege_random( void *p_rng, unsigned char *buf, size_t len )
{
uint32_t val;
size_t use_len;
mbedtls_havege_state *hs = (mbedtls_havege_state *) p_rng;
unsigned char *p = buf;
while( len > 0 )
{
use_len = len;
if( use_len > sizeof( val ) )
use_len = sizeof( val );
if( hs->offset[1] >= MBEDTLS_HAVEGE_COLLECT_SIZE )
havege_fill( hs );
val = hs->pool[hs->offset[0]++];
val ^= hs->pool[hs->offset[1]++];
memcpy( p, &val, use_len );
len -= use_len;
p += use_len;
}
return( 0 );
}
#endif /* MBEDTLS_HAVEGE_C */

193
library/hkdf.c Normal file
View File

@ -0,0 +1,193 @@
/*
* HKDF implementation -- RFC 5869
*
* Copyright (C) 2016-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_HKDF_C)
#include <string.h>
#include "mbedtls/hkdf.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt,
size_t salt_len, const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
unsigned char *okm, size_t okm_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char prk[MBEDTLS_MD_MAX_SIZE];
ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk );
if( ret == 0 )
{
ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size( md ),
info, info_len, okm, okm_len );
}
mbedtls_platform_zeroize( prk, sizeof( prk ) );
return( ret );
}
int mbedtls_hkdf_extract( const mbedtls_md_info_t *md,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
unsigned char *prk )
{
unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
if( salt == NULL )
{
size_t hash_len;
if( salt_len != 0 )
{
return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
}
hash_len = mbedtls_md_get_size( md );
if( hash_len == 0 )
{
return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
}
salt = null_salt;
salt_len = hash_len;
}
return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) );
}
int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk,
size_t prk_len, const unsigned char *info,
size_t info_len, unsigned char *okm, size_t okm_len )
{
size_t hash_len;
size_t where = 0;
size_t n;
size_t t_len = 0;
size_t i;
int ret = 0;
mbedtls_md_context_t ctx;
unsigned char t[MBEDTLS_MD_MAX_SIZE];
if( okm == NULL )
{
return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
}
hash_len = mbedtls_md_get_size( md );
if( prk_len < hash_len || hash_len == 0 )
{
return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
}
if( info == NULL )
{
info = (const unsigned char *) "";
info_len = 0;
}
n = okm_len / hash_len;
if( (okm_len % hash_len) != 0 )
{
n++;
}
/*
* Per RFC 5869 Section 2.3, okm_len must not exceed
* 255 times the hash length
*/
if( n > 255 )
{
return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
}
mbedtls_md_init( &ctx );
if( (ret = mbedtls_md_setup( &ctx, md, 1) ) != 0 )
{
goto exit;
}
/*
* Compute T = T(1) | T(2) | T(3) | ... | T(N)
* Where T(N) is defined in RFC 5869 Section 2.3
*/
for( i = 1; i <= n; i++ )
{
size_t num_to_copy;
unsigned char c = i & 0xff;
ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len );
if( ret != 0 )
{
goto exit;
}
ret = mbedtls_md_hmac_update( &ctx, t, t_len );
if( ret != 0 )
{
goto exit;
}
ret = mbedtls_md_hmac_update( &ctx, info, info_len );
if( ret != 0 )
{
goto exit;
}
/* The constant concatenated to the end of each T(n) is a single octet.
* */
ret = mbedtls_md_hmac_update( &ctx, &c, 1 );
if( ret != 0 )
{
goto exit;
}
ret = mbedtls_md_hmac_finish( &ctx, t );
if( ret != 0 )
{
goto exit;
}
num_to_copy = i != n ? hash_len : okm_len - where;
memcpy( okm + where, t, num_to_copy );
where += hash_len;
t_len = hash_len;
}
exit:
mbedtls_md_free( &ctx );
mbedtls_platform_zeroize( t, sizeof( t ) );
return( ret );
}
#endif /* MBEDTLS_HKDF_C */

626
library/hmac_drbg.c Normal file
View File

@ -0,0 +1,626 @@
/*
* HMAC_DRBG implementation (NIST SP 800-90)
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The NIST SP 800-90A DRBGs are described in the following publication.
* http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
* References below are based on rev. 1 (January 2012).
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_HMAC_DRBG_C)
#include "mbedtls/hmac_drbg.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_FS_IO)
#include <stdio.h>
#endif
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_PLATFORM_C */
/*
* HMAC_DRBG context initialization
*/
void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) );
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_init( &ctx->mutex );
#endif
}
/*
* HMAC_DRBG update, using optional additional data (10.1.2.2)
*/
int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx,
const unsigned char *additional,
size_t add_len )
{
size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info );
unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1;
unsigned char sep[1];
unsigned char K[MBEDTLS_MD_MAX_SIZE];
int ret = MBEDTLS_ERR_MD_BAD_INPUT_DATA;
for( sep[0] = 0; sep[0] < rounds; sep[0]++ )
{
/* Step 1 or 4 */
if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
ctx->V, md_len ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
sep, 1 ) ) != 0 )
goto exit;
if( rounds == 2 )
{
if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
additional, add_len ) ) != 0 )
goto exit;
}
if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, K ) ) != 0 )
goto exit;
/* Step 2 or 5 */
if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
ctx->V, md_len ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 )
goto exit;
}
exit:
mbedtls_platform_zeroize( K, sizeof( K ) );
return( ret );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx,
const unsigned char *additional,
size_t add_len )
{
(void) mbedtls_hmac_drbg_update_ret( ctx, additional, add_len );
}
#endif /* MBEDTLS_DEPRECATED_REMOVED */
/*
* Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA)
*/
int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx,
const mbedtls_md_info_t * md_info,
const unsigned char *data, size_t data_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
return( ret );
/*
* Set initial working state.
* Use the V memory location, which is currently all 0, to initialize the
* MD context with an all-zero key. Then set V to its initial value.
*/
if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V,
mbedtls_md_get_size( md_info ) ) ) != 0 )
return( ret );
memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) );
if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, data, data_len ) ) != 0 )
return( ret );
return( 0 );
}
/*
* Internal function used both for seeding and reseeding the DRBG.
* Comments starting with arabic numbers refer to section 10.1.2.4
* of SP800-90A, while roman numbers refer to section 9.2.
*/
static int hmac_drbg_reseed_core( mbedtls_hmac_drbg_context *ctx,
const unsigned char *additional, size_t len,
int use_nonce )
{
unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT];
size_t seedlen = 0;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
{
size_t total_entropy_len;
if( use_nonce == 0 )
total_entropy_len = ctx->entropy_len;
else
total_entropy_len = ctx->entropy_len * 3 / 2;
/* III. Check input length */
if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT ||
total_entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT )
{
return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG );
}
}
memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT );
/* IV. Gather entropy_len bytes of entropy for the seed */
if( ( ret = ctx->f_entropy( ctx->p_entropy,
seed, ctx->entropy_len ) ) != 0 )
{
return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED );
}
seedlen += ctx->entropy_len;
/* For initial seeding, allow adding of nonce generated
* from the entropy source. See Sect 8.6.7 in SP800-90A. */
if( use_nonce )
{
/* Note: We don't merge the two calls to f_entropy() in order
* to avoid requesting too much entropy from f_entropy()
* at once. Specifically, if the underlying digest is not
* SHA-1, 3 / 2 * entropy_len is at least 36 Bytes, which
* is larger than the maximum of 32 Bytes that our own
* entropy source implementation can emit in a single
* call in configurations disabling SHA-512. */
if( ( ret = ctx->f_entropy( ctx->p_entropy,
seed + seedlen,
ctx->entropy_len / 2 ) ) != 0 )
{
return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED );
}
seedlen += ctx->entropy_len / 2;
}
/* 1. Concatenate entropy and additional data if any */
if( additional != NULL && len != 0 )
{
memcpy( seed + seedlen, additional, len );
seedlen += len;
}
/* 2. Update state */
if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, seed, seedlen ) ) != 0 )
goto exit;
/* 3. Reset reseed_counter */
ctx->reseed_counter = 1;
exit:
/* 4. Done */
mbedtls_platform_zeroize( seed, seedlen );
return( ret );
}
/*
* HMAC_DRBG reseeding: 10.1.2.4 + 9.2
*/
int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
const unsigned char *additional, size_t len )
{
return( hmac_drbg_reseed_core( ctx, additional, len, 0 ) );
}
/*
* HMAC_DRBG initialisation (10.1.2.3 + 9.1)
*
* The nonce is not passed as a separate parameter but extracted
* from the entropy source as suggested in 8.6.7.
*/
int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
const mbedtls_md_info_t * md_info,
int (*f_entropy)(void *, unsigned char *, size_t),
void *p_entropy,
const unsigned char *custom,
size_t len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t md_size;
if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
return( ret );
md_size = mbedtls_md_get_size( md_info );
/*
* Set initial working state.
* Use the V memory location, which is currently all 0, to initialize the
* MD context with an all-zero key. Then set V to its initial value.
*/
if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ) ) != 0 )
return( ret );
memset( ctx->V, 0x01, md_size );
ctx->f_entropy = f_entropy;
ctx->p_entropy = p_entropy;
ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
if( ctx->entropy_len == 0 )
{
/*
* See SP800-57 5.6.1 (p. 65-66) for the security strength provided by
* each hash function, then according to SP800-90A rev1 10.1 table 2,
* min_entropy_len (in bits) is security_strength.
*
* (This also matches the sizes used in the NIST test vectors.)
*/
ctx->entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */
md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */
32; /* better (256+) -> 256 bits */
}
if( ( ret = hmac_drbg_reseed_core( ctx, custom, len,
1 /* add nonce */ ) ) != 0 )
{
return( ret );
}
return( 0 );
}
/*
* Set prediction resistance
*/
void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx,
int resistance )
{
ctx->prediction_resistance = resistance;
}
/*
* Set entropy length grabbed for seeding
*/
void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len )
{
ctx->entropy_len = len;
}
/*
* Set reseed interval
*/
void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, int interval )
{
ctx->reseed_interval = interval;
}
/*
* HMAC_DRBG random function with optional additional data:
* 10.1.2.5 (arabic) + 9.3 (Roman)
*/
int mbedtls_hmac_drbg_random_with_add( void *p_rng,
unsigned char *output, size_t out_len,
const unsigned char *additional, size_t add_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng;
size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info );
size_t left = out_len;
unsigned char *out = output;
/* II. Check request length */
if( out_len > MBEDTLS_HMAC_DRBG_MAX_REQUEST )
return( MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG );
/* III. Check input length */
if( add_len > MBEDTLS_HMAC_DRBG_MAX_INPUT )
return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG );
/* 1. (aka VII and IX) Check reseed counter and PR */
if( ctx->f_entropy != NULL && /* For no-reseeding instances */
( ctx->prediction_resistance == MBEDTLS_HMAC_DRBG_PR_ON ||
ctx->reseed_counter > ctx->reseed_interval ) )
{
if( ( ret = mbedtls_hmac_drbg_reseed( ctx, additional, add_len ) ) != 0 )
return( ret );
add_len = 0; /* VII.4 */
}
/* 2. Use additional data if any */
if( additional != NULL && add_len != 0 )
{
if( ( ret = mbedtls_hmac_drbg_update_ret( ctx,
additional, add_len ) ) != 0 )
goto exit;
}
/* 3, 4, 5. Generate bytes */
while( left != 0 )
{
size_t use_len = left > md_len ? md_len : left;
if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
ctx->V, md_len ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 )
goto exit;
memcpy( out, ctx->V, use_len );
out += use_len;
left -= use_len;
}
/* 6. Update */
if( ( ret = mbedtls_hmac_drbg_update_ret( ctx,
additional, add_len ) ) != 0 )
goto exit;
/* 7. Update reseed counter */
ctx->reseed_counter++;
exit:
/* 8. Done */
return( ret );
}
/*
* HMAC_DRBG random function
*/
int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng;
#if defined(MBEDTLS_THREADING_C)
if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
return( ret );
#endif
ret = mbedtls_hmac_drbg_random_with_add( ctx, output, out_len, NULL, 0 );
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
#endif
return( ret );
}
/*
* Free an HMAC_DRBG context
*/
void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx )
{
if( ctx == NULL )
return;
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_free( &ctx->mutex );
#endif
mbedtls_md_free( &ctx->md_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) );
}
#if defined(MBEDTLS_FS_IO)
int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
FILE *f;
unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ];
if( ( f = fopen( path, "wb" ) ) == NULL )
return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
if( ( ret = mbedtls_hmac_drbg_random( ctx, buf, sizeof( buf ) ) ) != 0 )
goto exit;
if( fwrite( buf, 1, sizeof( buf ), f ) != sizeof( buf ) )
{
ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR;
goto exit;
}
ret = 0;
exit:
fclose( f );
mbedtls_platform_zeroize( buf, sizeof( buf ) );
return( ret );
}
int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path )
{
int ret = 0;
FILE *f = NULL;
size_t n;
unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ];
unsigned char c;
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
n = fread( buf, 1, sizeof( buf ), f );
if( fread( &c, 1, 1, f ) != 0 )
{
ret = MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG;
goto exit;
}
if( n == 0 || ferror( f ) )
{
ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR;
goto exit;
}
fclose( f );
f = NULL;
ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n );
exit:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
if( f != NULL )
fclose( f );
if( ret != 0 )
return( ret );
return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) );
}
#endif /* MBEDTLS_FS_IO */
#if defined(MBEDTLS_SELF_TEST)
#if !defined(MBEDTLS_SHA1_C)
/* Dummy checkup routine */
int mbedtls_hmac_drbg_self_test( int verbose )
{
(void) verbose;
return( 0 );
}
#else
#define OUTPUT_LEN 80
/* From a NIST PR=true test vector */
static const unsigned char entropy_pr[] = {
0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f,
0xf7, 0x3e, 0x9c, 0x5b, 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11,
0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42,
0x17, 0x60, 0x99, 0xd4, 0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3,
0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4 };
static const unsigned char result_pr[OUTPUT_LEN] = {
0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec, 0xb1, 0x39,
0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25, 0x0d, 0x3c, 0x1e, 0x94,
0x10, 0x10, 0x98, 0x12, 0x93, 0x25, 0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54,
0x73, 0x19, 0x70, 0xc0, 0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e,
0x4b, 0xc6, 0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab,
0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40, 0xee, 0xf3,
0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44 };
/* From a NIST PR=false test vector */
static const unsigned char entropy_nopr[] = {
0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 0x86, 0x66,
0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 0xbf, 0x8c, 0x35, 0xc8,
0xc7, 0x21, 0x5b, 0x5b, 0x96, 0xc4, 0x8e, 0x9b, 0x33, 0x8c, 0x74, 0xe3,
0xe9, 0x9d, 0xfe, 0xdf };
static const unsigned char result_nopr[OUTPUT_LEN] = {
0xc6, 0xa1, 0x6a, 0xb8, 0xd4, 0x20, 0x70, 0x6f, 0x0f, 0x34, 0xab, 0x7f,
0xec, 0x5a, 0xdc, 0xa9, 0xd8, 0xca, 0x3a, 0x13, 0x3e, 0x15, 0x9c, 0xa6,
0xac, 0x43, 0xc6, 0xf8, 0xa2, 0xbe, 0x22, 0x83, 0x4a, 0x4c, 0x0a, 0x0a,
0xff, 0xb1, 0x0d, 0x71, 0x94, 0xf1, 0xc1, 0xa5, 0xcf, 0x73, 0x22, 0xec,
0x1a, 0xe0, 0x96, 0x4e, 0xd4, 0xbf, 0x12, 0x27, 0x46, 0xe0, 0x87, 0xfd,
0xb5, 0xb3, 0xe9, 0x1b, 0x34, 0x93, 0xd5, 0xbb, 0x98, 0xfa, 0xed, 0x49,
0xe8, 0x5f, 0x13, 0x0f, 0xc8, 0xa4, 0x59, 0xb7 };
/* "Entropy" from buffer */
static size_t test_offset;
static int hmac_drbg_self_test_entropy( void *data,
unsigned char *buf, size_t len )
{
const unsigned char *p = data;
memcpy( buf, p + test_offset, len );
test_offset += len;
return( 0 );
}
#define CHK( c ) if( (c) != 0 ) \
{ \
if( verbose != 0 ) \
mbedtls_printf( "failed\n" ); \
return( 1 ); \
}
/*
* Checkup routine for HMAC_DRBG with SHA-1
*/
int mbedtls_hmac_drbg_self_test( int verbose )
{
mbedtls_hmac_drbg_context ctx;
unsigned char buf[OUTPUT_LEN];
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 );
mbedtls_hmac_drbg_init( &ctx );
/*
* PR = True
*/
if( verbose != 0 )
mbedtls_printf( " HMAC_DRBG (PR = True) : " );
test_offset = 0;
CHK( mbedtls_hmac_drbg_seed( &ctx, md_info,
hmac_drbg_self_test_entropy, (void *) entropy_pr,
NULL, 0 ) );
mbedtls_hmac_drbg_set_prediction_resistance( &ctx, MBEDTLS_HMAC_DRBG_PR_ON );
CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
CHK( memcmp( buf, result_pr, OUTPUT_LEN ) );
mbedtls_hmac_drbg_free( &ctx );
mbedtls_hmac_drbg_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
/*
* PR = False
*/
if( verbose != 0 )
mbedtls_printf( " HMAC_DRBG (PR = False) : " );
mbedtls_hmac_drbg_init( &ctx );
test_offset = 0;
CHK( mbedtls_hmac_drbg_seed( &ctx, md_info,
hmac_drbg_self_test_entropy, (void *) entropy_nopr,
NULL, 0 ) );
CHK( mbedtls_hmac_drbg_reseed( &ctx, NULL, 0 ) );
CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
CHK( memcmp( buf, result_nopr, OUTPUT_LEN ) );
mbedtls_hmac_drbg_free( &ctx );
mbedtls_hmac_drbg_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SHA1_C */
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_HMAC_DRBG_C */

900
library/md.c Normal file
View File

@ -0,0 +1,900 @@
/**
* \file mbedtls_md.c
*
* \brief Generic message digest wrapper for mbed TLS
*
* \author Adriaan de Jong <dejong@fox-it.com>
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_MD_C)
#include "mbedtls/md.h"
#include "mbedtls/md_internal.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include "mbedtls/md2.h"
#include "mbedtls/md4.h"
#include "mbedtls/md5.h"
#include "mbedtls/ripemd160.h"
#include "mbedtls/sha1.h"
#include "mbedtls/sha256.h"
#include "mbedtls/sha512.h"
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
#include <string.h>
#if defined(MBEDTLS_FS_IO)
#include <stdio.h>
#endif
#if defined(MBEDTLS_MD2_C)
const mbedtls_md_info_t mbedtls_md2_info = {
"MD2",
MBEDTLS_MD_MD2,
16,
16,
};
#endif
#if defined(MBEDTLS_MD4_C)
const mbedtls_md_info_t mbedtls_md4_info = {
"MD4",
MBEDTLS_MD_MD4,
16,
64,
};
#endif
#if defined(MBEDTLS_MD5_C)
const mbedtls_md_info_t mbedtls_md5_info = {
"MD5",
MBEDTLS_MD_MD5,
16,
64,
};
#endif
#if defined(MBEDTLS_RIPEMD160_C)
const mbedtls_md_info_t mbedtls_ripemd160_info = {
"RIPEMD160",
MBEDTLS_MD_RIPEMD160,
20,
64,
};
#endif
#if defined(MBEDTLS_SHA1_C)
const mbedtls_md_info_t mbedtls_sha1_info = {
"SHA1",
MBEDTLS_MD_SHA1,
20,
64,
};
#endif
#if defined(MBEDTLS_SHA256_C)
const mbedtls_md_info_t mbedtls_sha224_info = {
"SHA224",
MBEDTLS_MD_SHA224,
28,
64,
};
const mbedtls_md_info_t mbedtls_sha256_info = {
"SHA256",
MBEDTLS_MD_SHA256,
32,
64,
};
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
const mbedtls_md_info_t mbedtls_sha384_info = {
"SHA384",
MBEDTLS_MD_SHA384,
48,
128,
};
#endif
const mbedtls_md_info_t mbedtls_sha512_info = {
"SHA512",
MBEDTLS_MD_SHA512,
64,
128,
};
#endif
/*
* Reminder: update profiles in x509_crt.c when adding a new hash!
*/
static const int supported_digests[] = {
#if defined(MBEDTLS_SHA512_C)
MBEDTLS_MD_SHA512,
#if !defined(MBEDTLS_SHA512_NO_SHA384)
MBEDTLS_MD_SHA384,
#endif
#endif
#if defined(MBEDTLS_SHA256_C)
MBEDTLS_MD_SHA256,
MBEDTLS_MD_SHA224,
#endif
#if defined(MBEDTLS_SHA1_C)
MBEDTLS_MD_SHA1,
#endif
#if defined(MBEDTLS_RIPEMD160_C)
MBEDTLS_MD_RIPEMD160,
#endif
#if defined(MBEDTLS_MD5_C)
MBEDTLS_MD_MD5,
#endif
#if defined(MBEDTLS_MD4_C)
MBEDTLS_MD_MD4,
#endif
#if defined(MBEDTLS_MD2_C)
MBEDTLS_MD_MD2,
#endif
MBEDTLS_MD_NONE
};
const int *mbedtls_md_list( void )
{
return( supported_digests );
}
const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name )
{
if( NULL == md_name )
return( NULL );
/* Get the appropriate digest information */
#if defined(MBEDTLS_MD2_C)
if( !strcmp( "MD2", md_name ) )
return mbedtls_md_info_from_type( MBEDTLS_MD_MD2 );
#endif
#if defined(MBEDTLS_MD4_C)
if( !strcmp( "MD4", md_name ) )
return mbedtls_md_info_from_type( MBEDTLS_MD_MD4 );
#endif
#if defined(MBEDTLS_MD5_C)
if( !strcmp( "MD5", md_name ) )
return mbedtls_md_info_from_type( MBEDTLS_MD_MD5 );
#endif
#if defined(MBEDTLS_RIPEMD160_C)
if( !strcmp( "RIPEMD160", md_name ) )
return mbedtls_md_info_from_type( MBEDTLS_MD_RIPEMD160 );
#endif
#if defined(MBEDTLS_SHA1_C)
if( !strcmp( "SHA1", md_name ) || !strcmp( "SHA", md_name ) )
return mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 );
#endif
#if defined(MBEDTLS_SHA256_C)
if( !strcmp( "SHA224", md_name ) )
return mbedtls_md_info_from_type( MBEDTLS_MD_SHA224 );
if( !strcmp( "SHA256", md_name ) )
return mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
if( !strcmp( "SHA384", md_name ) )
return mbedtls_md_info_from_type( MBEDTLS_MD_SHA384 );
#endif
if( !strcmp( "SHA512", md_name ) )
return mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 );
#endif
return( NULL );
}
const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type )
{
switch( md_type )
{
#if defined(MBEDTLS_MD2_C)
case MBEDTLS_MD_MD2:
return( &mbedtls_md2_info );
#endif
#if defined(MBEDTLS_MD4_C)
case MBEDTLS_MD_MD4:
return( &mbedtls_md4_info );
#endif
#if defined(MBEDTLS_MD5_C)
case MBEDTLS_MD_MD5:
return( &mbedtls_md5_info );
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case MBEDTLS_MD_RIPEMD160:
return( &mbedtls_ripemd160_info );
#endif
#if defined(MBEDTLS_SHA1_C)
case MBEDTLS_MD_SHA1:
return( &mbedtls_sha1_info );
#endif
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_MD_SHA224:
return( &mbedtls_sha224_info );
case MBEDTLS_MD_SHA256:
return( &mbedtls_sha256_info );
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case MBEDTLS_MD_SHA384:
return( &mbedtls_sha384_info );
#endif
case MBEDTLS_MD_SHA512:
return( &mbedtls_sha512_info );
#endif
default:
return( NULL );
}
}
void mbedtls_md_init( mbedtls_md_context_t *ctx )
{
memset( ctx, 0, sizeof( mbedtls_md_context_t ) );
}
void mbedtls_md_free( mbedtls_md_context_t *ctx )
{
if( ctx == NULL || ctx->md_info == NULL )
return;
if( ctx->md_ctx != NULL )
{
switch( ctx->md_info->type )
{
#if defined(MBEDTLS_MD2_C)
case MBEDTLS_MD_MD2:
mbedtls_md2_free( ctx->md_ctx );
break;
#endif
#if defined(MBEDTLS_MD4_C)
case MBEDTLS_MD_MD4:
mbedtls_md4_free( ctx->md_ctx );
break;
#endif
#if defined(MBEDTLS_MD5_C)
case MBEDTLS_MD_MD5:
mbedtls_md5_free( ctx->md_ctx );
break;
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case MBEDTLS_MD_RIPEMD160:
mbedtls_ripemd160_free( ctx->md_ctx );
break;
#endif
#if defined(MBEDTLS_SHA1_C)
case MBEDTLS_MD_SHA1:
mbedtls_sha1_free( ctx->md_ctx );
break;
#endif
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_MD_SHA224:
case MBEDTLS_MD_SHA256:
mbedtls_sha256_free( ctx->md_ctx );
break;
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case MBEDTLS_MD_SHA384:
#endif
case MBEDTLS_MD_SHA512:
mbedtls_sha512_free( ctx->md_ctx );
break;
#endif
default:
/* Shouldn't happen */
break;
}
mbedtls_free( ctx->md_ctx );
}
if( ctx->hmac_ctx != NULL )
{
mbedtls_platform_zeroize( ctx->hmac_ctx,
2 * ctx->md_info->block_size );
mbedtls_free( ctx->hmac_ctx );
}
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md_context_t ) );
}
int mbedtls_md_clone( mbedtls_md_context_t *dst,
const mbedtls_md_context_t *src )
{
if( dst == NULL || dst->md_info == NULL ||
src == NULL || src->md_info == NULL ||
dst->md_info != src->md_info )
{
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
}
switch( src->md_info->type )
{
#if defined(MBEDTLS_MD2_C)
case MBEDTLS_MD_MD2:
mbedtls_md2_clone( dst->md_ctx, src->md_ctx );
break;
#endif
#if defined(MBEDTLS_MD4_C)
case MBEDTLS_MD_MD4:
mbedtls_md4_clone( dst->md_ctx, src->md_ctx );
break;
#endif
#if defined(MBEDTLS_MD5_C)
case MBEDTLS_MD_MD5:
mbedtls_md5_clone( dst->md_ctx, src->md_ctx );
break;
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case MBEDTLS_MD_RIPEMD160:
mbedtls_ripemd160_clone( dst->md_ctx, src->md_ctx );
break;
#endif
#if defined(MBEDTLS_SHA1_C)
case MBEDTLS_MD_SHA1:
mbedtls_sha1_clone( dst->md_ctx, src->md_ctx );
break;
#endif
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_MD_SHA224:
case MBEDTLS_MD_SHA256:
mbedtls_sha256_clone( dst->md_ctx, src->md_ctx );
break;
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case MBEDTLS_MD_SHA384:
#endif
case MBEDTLS_MD_SHA512:
mbedtls_sha512_clone( dst->md_ctx, src->md_ctx );
break;
#endif
default:
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
}
return( 0 );
}
#if ! defined(MBEDTLS_DEPRECATED_REMOVED)
int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info )
{
return mbedtls_md_setup( ctx, md_info, 1 );
}
#endif
#define ALLOC( type ) \
do { \
ctx->md_ctx = mbedtls_calloc( 1, sizeof( mbedtls_##type##_context ) ); \
if( ctx->md_ctx == NULL ) \
return( MBEDTLS_ERR_MD_ALLOC_FAILED ); \
mbedtls_##type##_init( ctx->md_ctx ); \
} \
while( 0 )
int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac )
{
if( md_info == NULL || ctx == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
switch( md_info->type )
{
#if defined(MBEDTLS_MD2_C)
case MBEDTLS_MD_MD2:
ALLOC( md2 );
break;
#endif
#if defined(MBEDTLS_MD4_C)
case MBEDTLS_MD_MD4:
ALLOC( md4 );
break;
#endif
#if defined(MBEDTLS_MD5_C)
case MBEDTLS_MD_MD5:
ALLOC( md5 );
break;
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case MBEDTLS_MD_RIPEMD160:
ALLOC( ripemd160 );
break;
#endif
#if defined(MBEDTLS_SHA1_C)
case MBEDTLS_MD_SHA1:
ALLOC( sha1 );
break;
#endif
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_MD_SHA224:
case MBEDTLS_MD_SHA256:
ALLOC( sha256 );
break;
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case MBEDTLS_MD_SHA384:
#endif
case MBEDTLS_MD_SHA512:
ALLOC( sha512 );
break;
#endif
default:
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
}
if( hmac != 0 )
{
ctx->hmac_ctx = mbedtls_calloc( 2, md_info->block_size );
if( ctx->hmac_ctx == NULL )
{
mbedtls_md_free( ctx );
return( MBEDTLS_ERR_MD_ALLOC_FAILED );
}
}
ctx->md_info = md_info;
return( 0 );
}
#undef ALLOC
int mbedtls_md_starts( mbedtls_md_context_t *ctx )
{
if( ctx == NULL || ctx->md_info == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
switch( ctx->md_info->type )
{
#if defined(MBEDTLS_MD2_C)
case MBEDTLS_MD_MD2:
return( mbedtls_md2_starts_ret( ctx->md_ctx ) );
#endif
#if defined(MBEDTLS_MD4_C)
case MBEDTLS_MD_MD4:
return( mbedtls_md4_starts_ret( ctx->md_ctx ) );
#endif
#if defined(MBEDTLS_MD5_C)
case MBEDTLS_MD_MD5:
return( mbedtls_md5_starts_ret( ctx->md_ctx ) );
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case MBEDTLS_MD_RIPEMD160:
return( mbedtls_ripemd160_starts_ret( ctx->md_ctx ) );
#endif
#if defined(MBEDTLS_SHA1_C)
case MBEDTLS_MD_SHA1:
return( mbedtls_sha1_starts_ret( ctx->md_ctx ) );
#endif
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_MD_SHA224:
return( mbedtls_sha256_starts_ret( ctx->md_ctx, 1 ) );
case MBEDTLS_MD_SHA256:
return( mbedtls_sha256_starts_ret( ctx->md_ctx, 0 ) );
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case MBEDTLS_MD_SHA384:
return( mbedtls_sha512_starts_ret( ctx->md_ctx, 1 ) );
#endif
case MBEDTLS_MD_SHA512:
return( mbedtls_sha512_starts_ret( ctx->md_ctx, 0 ) );
#endif
default:
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
}
}
int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen )
{
if( ctx == NULL || ctx->md_info == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
switch( ctx->md_info->type )
{
#if defined(MBEDTLS_MD2_C)
case MBEDTLS_MD_MD2:
return( mbedtls_md2_update_ret( ctx->md_ctx, input, ilen ) );
#endif
#if defined(MBEDTLS_MD4_C)
case MBEDTLS_MD_MD4:
return( mbedtls_md4_update_ret( ctx->md_ctx, input, ilen ) );
#endif
#if defined(MBEDTLS_MD5_C)
case MBEDTLS_MD_MD5:
return( mbedtls_md5_update_ret( ctx->md_ctx, input, ilen ) );
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case MBEDTLS_MD_RIPEMD160:
return( mbedtls_ripemd160_update_ret( ctx->md_ctx, input, ilen ) );
#endif
#if defined(MBEDTLS_SHA1_C)
case MBEDTLS_MD_SHA1:
return( mbedtls_sha1_update_ret( ctx->md_ctx, input, ilen ) );
#endif
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_MD_SHA224:
return( mbedtls_sha256_update_ret( ctx->md_ctx, input, ilen ) );
case MBEDTLS_MD_SHA256:
return( mbedtls_sha256_update_ret( ctx->md_ctx, input, ilen ) );
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case MBEDTLS_MD_SHA384:
return( mbedtls_sha512_update_ret( ctx->md_ctx, input, ilen ) );
#endif
case MBEDTLS_MD_SHA512:
return( mbedtls_sha512_update_ret( ctx->md_ctx, input, ilen ) );
#endif
default:
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
}
}
int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output )
{
if( ctx == NULL || ctx->md_info == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
switch( ctx->md_info->type )
{
#if defined(MBEDTLS_MD2_C)
case MBEDTLS_MD_MD2:
return( mbedtls_md2_finish_ret( ctx->md_ctx, output ) );
#endif
#if defined(MBEDTLS_MD4_C)
case MBEDTLS_MD_MD4:
return( mbedtls_md4_finish_ret( ctx->md_ctx, output ) );
#endif
#if defined(MBEDTLS_MD5_C)
case MBEDTLS_MD_MD5:
return( mbedtls_md5_finish_ret( ctx->md_ctx, output ) );
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case MBEDTLS_MD_RIPEMD160:
return( mbedtls_ripemd160_finish_ret( ctx->md_ctx, output ) );
#endif
#if defined(MBEDTLS_SHA1_C)
case MBEDTLS_MD_SHA1:
return( mbedtls_sha1_finish_ret( ctx->md_ctx, output ) );
#endif
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_MD_SHA224:
return( mbedtls_sha256_finish_ret( ctx->md_ctx, output ) );
case MBEDTLS_MD_SHA256:
return( mbedtls_sha256_finish_ret( ctx->md_ctx, output ) );
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case MBEDTLS_MD_SHA384:
return( mbedtls_sha512_finish_ret( ctx->md_ctx, output ) );
#endif
case MBEDTLS_MD_SHA512:
return( mbedtls_sha512_finish_ret( ctx->md_ctx, output ) );
#endif
default:
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
}
}
int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen,
unsigned char *output )
{
if( md_info == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
switch( md_info->type )
{
#if defined(MBEDTLS_MD2_C)
case MBEDTLS_MD_MD2:
return( mbedtls_md2_ret( input, ilen, output ) );
#endif
#if defined(MBEDTLS_MD4_C)
case MBEDTLS_MD_MD4:
return( mbedtls_md4_ret( input, ilen, output ) );
#endif
#if defined(MBEDTLS_MD5_C)
case MBEDTLS_MD_MD5:
return( mbedtls_md5_ret( input, ilen, output ) );
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case MBEDTLS_MD_RIPEMD160:
return( mbedtls_ripemd160_ret( input, ilen, output ) );
#endif
#if defined(MBEDTLS_SHA1_C)
case MBEDTLS_MD_SHA1:
return( mbedtls_sha1_ret( input, ilen, output ) );
#endif
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_MD_SHA224:
return( mbedtls_sha256_ret( input, ilen, output, 1 ) );
case MBEDTLS_MD_SHA256:
return( mbedtls_sha256_ret( input, ilen, output, 0 ) );
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case MBEDTLS_MD_SHA384:
return( mbedtls_sha512_ret( input, ilen, output, 1 ) );
#endif
case MBEDTLS_MD_SHA512:
return( mbedtls_sha512_ret( input, ilen, output, 0 ) );
#endif
default:
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
}
}
#if defined(MBEDTLS_FS_IO)
int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigned char *output )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
FILE *f;
size_t n;
mbedtls_md_context_t ctx;
unsigned char buf[1024];
if( md_info == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_MD_FILE_IO_ERROR );
mbedtls_md_init( &ctx );
if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 )
goto cleanup;
if( ( ret = mbedtls_md_starts( &ctx ) ) != 0 )
goto cleanup;
while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
if( ( ret = mbedtls_md_update( &ctx, buf, n ) ) != 0 )
goto cleanup;
if( ferror( f ) != 0 )
ret = MBEDTLS_ERR_MD_FILE_IO_ERROR;
else
ret = mbedtls_md_finish( &ctx, output );
cleanup:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
fclose( f );
mbedtls_md_free( &ctx );
return( ret );
}
#endif /* MBEDTLS_FS_IO */
int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char sum[MBEDTLS_MD_MAX_SIZE];
unsigned char *ipad, *opad;
size_t i;
if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
if( keylen > (size_t) ctx->md_info->block_size )
{
if( ( ret = mbedtls_md_starts( ctx ) ) != 0 )
goto cleanup;
if( ( ret = mbedtls_md_update( ctx, key, keylen ) ) != 0 )
goto cleanup;
if( ( ret = mbedtls_md_finish( ctx, sum ) ) != 0 )
goto cleanup;
keylen = ctx->md_info->size;
key = sum;
}
ipad = (unsigned char *) ctx->hmac_ctx;
opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size;
memset( ipad, 0x36, ctx->md_info->block_size );
memset( opad, 0x5C, ctx->md_info->block_size );
for( i = 0; i < keylen; i++ )
{
ipad[i] = (unsigned char)( ipad[i] ^ key[i] );
opad[i] = (unsigned char)( opad[i] ^ key[i] );
}
if( ( ret = mbedtls_md_starts( ctx ) ) != 0 )
goto cleanup;
if( ( ret = mbedtls_md_update( ctx, ipad,
ctx->md_info->block_size ) ) != 0 )
goto cleanup;
cleanup:
mbedtls_platform_zeroize( sum, sizeof( sum ) );
return( ret );
}
int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen )
{
if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
return( mbedtls_md_update( ctx, input, ilen ) );
}
int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char tmp[MBEDTLS_MD_MAX_SIZE];
unsigned char *opad;
if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size;
if( ( ret = mbedtls_md_finish( ctx, tmp ) ) != 0 )
return( ret );
if( ( ret = mbedtls_md_starts( ctx ) ) != 0 )
return( ret );
if( ( ret = mbedtls_md_update( ctx, opad,
ctx->md_info->block_size ) ) != 0 )
return( ret );
if( ( ret = mbedtls_md_update( ctx, tmp,
ctx->md_info->size ) ) != 0 )
return( ret );
return( mbedtls_md_finish( ctx, output ) );
}
int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char *ipad;
if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
ipad = (unsigned char *) ctx->hmac_ctx;
if( ( ret = mbedtls_md_starts( ctx ) ) != 0 )
return( ret );
return( mbedtls_md_update( ctx, ipad, ctx->md_info->block_size ) );
}
int mbedtls_md_hmac( const mbedtls_md_info_t *md_info,
const unsigned char *key, size_t keylen,
const unsigned char *input, size_t ilen,
unsigned char *output )
{
mbedtls_md_context_t ctx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( md_info == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
mbedtls_md_init( &ctx );
if( ( ret = mbedtls_md_setup( &ctx, md_info, 1 ) ) != 0 )
goto cleanup;
if( ( ret = mbedtls_md_hmac_starts( &ctx, key, keylen ) ) != 0 )
goto cleanup;
if( ( ret = mbedtls_md_hmac_update( &ctx, input, ilen ) ) != 0 )
goto cleanup;
if( ( ret = mbedtls_md_hmac_finish( &ctx, output ) ) != 0 )
goto cleanup;
cleanup:
mbedtls_md_free( &ctx );
return( ret );
}
int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data )
{
if( ctx == NULL || ctx->md_info == NULL )
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
switch( ctx->md_info->type )
{
#if defined(MBEDTLS_MD2_C)
case MBEDTLS_MD_MD2:
return( mbedtls_internal_md2_process( ctx->md_ctx ) );
#endif
#if defined(MBEDTLS_MD4_C)
case MBEDTLS_MD_MD4:
return( mbedtls_internal_md4_process( ctx->md_ctx, data ) );
#endif
#if defined(MBEDTLS_MD5_C)
case MBEDTLS_MD_MD5:
return( mbedtls_internal_md5_process( ctx->md_ctx, data ) );
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case MBEDTLS_MD_RIPEMD160:
return( mbedtls_internal_ripemd160_process( ctx->md_ctx, data ) );
#endif
#if defined(MBEDTLS_SHA1_C)
case MBEDTLS_MD_SHA1:
return( mbedtls_internal_sha1_process( ctx->md_ctx, data ) );
#endif
#if defined(MBEDTLS_SHA256_C)
case MBEDTLS_MD_SHA224:
return( mbedtls_internal_sha256_process( ctx->md_ctx, data ) );
case MBEDTLS_MD_SHA256:
return( mbedtls_internal_sha256_process( ctx->md_ctx, data ) );
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case MBEDTLS_MD_SHA384:
return( mbedtls_internal_sha512_process( ctx->md_ctx, data ) );
#endif
case MBEDTLS_MD_SHA512:
return( mbedtls_internal_sha512_process( ctx->md_ctx, data ) );
#endif
default:
return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
}
}
unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info )
{
if( md_info == NULL )
return( 0 );
return md_info->size;
}
mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info )
{
if( md_info == NULL )
return( MBEDTLS_MD_NONE );
return md_info->type;
}
const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info )
{
if( md_info == NULL )
return( NULL );
return md_info->name;
}
#endif /* MBEDTLS_MD_C */

364
library/md2.c Normal file
View File

@ -0,0 +1,364 @@
/*
* RFC 1115/1319 compliant MD2 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The MD2 algorithm was designed by Ron Rivest in 1989.
*
* http://www.ietf.org/rfc/rfc1115.txt
* http://www.ietf.org/rfc/rfc1319.txt
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_MD2_C)
#include "mbedtls/md2.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_MD2_ALT)
static const unsigned char PI_SUBST[256] =
{
0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36,
0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3,
0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C,
0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16,
0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E,
0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E,
0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2,
0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E,
0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3,
0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56,
0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6,
0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D,
0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65,
0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0,
0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C,
0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E,
0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81,
0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA,
0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88,
0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE,
0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58,
0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99,
0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
};
void mbedtls_md2_init( mbedtls_md2_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_md2_context ) );
}
void mbedtls_md2_free( mbedtls_md2_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md2_context ) );
}
void mbedtls_md2_clone( mbedtls_md2_context *dst,
const mbedtls_md2_context *src )
{
*dst = *src;
}
/*
* MD2 context setup
*/
int mbedtls_md2_starts_ret( mbedtls_md2_context *ctx )
{
memset( ctx->cksum, 0, 16 );
memset( ctx->state, 0, 46 );
memset( ctx->buffer, 0, 16 );
ctx->left = 0;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md2_starts( mbedtls_md2_context *ctx )
{
mbedtls_md2_starts_ret( ctx );
}
#endif
#if !defined(MBEDTLS_MD2_PROCESS_ALT)
int mbedtls_internal_md2_process( mbedtls_md2_context *ctx )
{
int i, j;
unsigned char t = 0;
for( i = 0; i < 16; i++ )
{
ctx->state[i + 16] = ctx->buffer[i];
ctx->state[i + 32] =
(unsigned char)( ctx->buffer[i] ^ ctx->state[i]);
}
for( i = 0; i < 18; i++ )
{
for( j = 0; j < 48; j++ )
{
ctx->state[j] = (unsigned char)
( ctx->state[j] ^ PI_SUBST[t] );
t = ctx->state[j];
}
t = (unsigned char)( t + i );
}
t = ctx->cksum[15];
for( i = 0; i < 16; i++ )
{
ctx->cksum[i] = (unsigned char)
( ctx->cksum[i] ^ PI_SUBST[ctx->buffer[i] ^ t] );
t = ctx->cksum[i];
}
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md2_process( mbedtls_md2_context *ctx )
{
mbedtls_internal_md2_process( ctx );
}
#endif
#endif /* !MBEDTLS_MD2_PROCESS_ALT */
/*
* MD2 process buffer
*/
int mbedtls_md2_update_ret( mbedtls_md2_context *ctx,
const unsigned char *input,
size_t ilen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t fill;
while( ilen > 0 )
{
if( ilen > 16 - ctx->left )
fill = 16 - ctx->left;
else
fill = ilen;
memcpy( ctx->buffer + ctx->left, input, fill );
ctx->left += fill;
input += fill;
ilen -= fill;
if( ctx->left == 16 )
{
ctx->left = 0;
if( ( ret = mbedtls_internal_md2_process( ctx ) ) != 0 )
return( ret );
}
}
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md2_update( mbedtls_md2_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_md2_update_ret( ctx, input, ilen );
}
#endif
/*
* MD2 final digest
*/
int mbedtls_md2_finish_ret( mbedtls_md2_context *ctx,
unsigned char output[16] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t i;
unsigned char x;
x = (unsigned char)( 16 - ctx->left );
for( i = ctx->left; i < 16; i++ )
ctx->buffer[i] = x;
if( ( ret = mbedtls_internal_md2_process( ctx ) ) != 0 )
return( ret );
memcpy( ctx->buffer, ctx->cksum, 16 );
if( ( ret = mbedtls_internal_md2_process( ctx ) ) != 0 )
return( ret );
memcpy( output, ctx->state, 16 );
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md2_finish( mbedtls_md2_context *ctx,
unsigned char output[16] )
{
mbedtls_md2_finish_ret( ctx, output );
}
#endif
#endif /* !MBEDTLS_MD2_ALT */
/*
* output = MD2( input buffer )
*/
int mbedtls_md2_ret( const unsigned char *input,
size_t ilen,
unsigned char output[16] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_md2_context ctx;
mbedtls_md2_init( &ctx );
if( ( ret = mbedtls_md2_starts_ret( &ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md2_update_ret( &ctx, input, ilen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md2_finish_ret( &ctx, output ) ) != 0 )
goto exit;
exit:
mbedtls_md2_free( &ctx );
return( ret );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md2( const unsigned char *input,
size_t ilen,
unsigned char output[16] )
{
mbedtls_md2_ret( input, ilen, output );
}
#endif
#if defined(MBEDTLS_SELF_TEST)
/*
* RFC 1319 test vectors
*/
static const unsigned char md2_test_str[7][81] =
{
{ "" },
{ "a" },
{ "abc" },
{ "message digest" },
{ "abcdefghijklmnopqrstuvwxyz" },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
{ "12345678901234567890123456789012345678901234567890123456789012"
"345678901234567890" }
};
static const size_t md2_test_strlen[7] =
{
0, 1, 3, 14, 26, 62, 80
};
static const unsigned char md2_test_sum[7][16] =
{
{ 0x83, 0x50, 0xE5, 0xA3, 0xE2, 0x4C, 0x15, 0x3D,
0xF2, 0x27, 0x5C, 0x9F, 0x80, 0x69, 0x27, 0x73 },
{ 0x32, 0xEC, 0x01, 0xEC, 0x4A, 0x6D, 0xAC, 0x72,
0xC0, 0xAB, 0x96, 0xFB, 0x34, 0xC0, 0xB5, 0xD1 },
{ 0xDA, 0x85, 0x3B, 0x0D, 0x3F, 0x88, 0xD9, 0x9B,
0x30, 0x28, 0x3A, 0x69, 0xE6, 0xDE, 0xD6, 0xBB },
{ 0xAB, 0x4F, 0x49, 0x6B, 0xFB, 0x2A, 0x53, 0x0B,
0x21, 0x9F, 0xF3, 0x30, 0x31, 0xFE, 0x06, 0xB0 },
{ 0x4E, 0x8D, 0xDF, 0xF3, 0x65, 0x02, 0x92, 0xAB,
0x5A, 0x41, 0x08, 0xC3, 0xAA, 0x47, 0x94, 0x0B },
{ 0xDA, 0x33, 0xDE, 0xF2, 0xA4, 0x2D, 0xF1, 0x39,
0x75, 0x35, 0x28, 0x46, 0xC3, 0x03, 0x38, 0xCD },
{ 0xD5, 0x97, 0x6F, 0x79, 0xD8, 0x3D, 0x3A, 0x0D,
0xC9, 0x80, 0x6C, 0x3C, 0x66, 0xF3, 0xEF, 0xD8 }
};
/*
* Checkup routine
*/
int mbedtls_md2_self_test( int verbose )
{
int i, ret = 0;
unsigned char md2sum[16];
for( i = 0; i < 7; i++ )
{
if( verbose != 0 )
mbedtls_printf( " MD2 test #%d: ", i + 1 );
ret = mbedtls_md2_ret( md2_test_str[i], md2_test_strlen[i], md2sum );
if( ret != 0 )
goto fail;
if( memcmp( md2sum, md2_test_sum[i], 16 ) != 0 )
{
ret = 1;
goto fail;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
fail:
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_MD2_C */

485
library/md4.c Normal file
View File

@ -0,0 +1,485 @@
/*
* RFC 1186/1320 compliant MD4 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The MD4 algorithm was designed by Ron Rivest in 1990.
*
* http://www.ietf.org/rfc/rfc1186.txt
* http://www.ietf.org/rfc/rfc1320.txt
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_MD4_C)
#include "mbedtls/md4.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_MD4_ALT)
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_UINT32_LE
#define GET_UINT32_LE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] ) \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
| ( (uint32_t) (b)[(i) + 3] << 24 ); \
}
#endif
#ifndef PUT_UINT32_LE
#define PUT_UINT32_LE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
(b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
(b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
}
#endif
void mbedtls_md4_init( mbedtls_md4_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_md4_context ) );
}
void mbedtls_md4_free( mbedtls_md4_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md4_context ) );
}
void mbedtls_md4_clone( mbedtls_md4_context *dst,
const mbedtls_md4_context *src )
{
*dst = *src;
}
/*
* MD4 context setup
*/
int mbedtls_md4_starts_ret( mbedtls_md4_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md4_starts( mbedtls_md4_context *ctx )
{
mbedtls_md4_starts_ret( ctx );
}
#endif
#if !defined(MBEDTLS_MD4_PROCESS_ALT)
int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
const unsigned char data[64] )
{
uint32_t X[16], A, B, C, D;
GET_UINT32_LE( X[ 0], data, 0 );
GET_UINT32_LE( X[ 1], data, 4 );
GET_UINT32_LE( X[ 2], data, 8 );
GET_UINT32_LE( X[ 3], data, 12 );
GET_UINT32_LE( X[ 4], data, 16 );
GET_UINT32_LE( X[ 5], data, 20 );
GET_UINT32_LE( X[ 6], data, 24 );
GET_UINT32_LE( X[ 7], data, 28 );
GET_UINT32_LE( X[ 8], data, 32 );
GET_UINT32_LE( X[ 9], data, 36 );
GET_UINT32_LE( X[10], data, 40 );
GET_UINT32_LE( X[11], data, 44 );
GET_UINT32_LE( X[12], data, 48 );
GET_UINT32_LE( X[13], data, 52 );
GET_UINT32_LE( X[14], data, 56 );
GET_UINT32_LE( X[15], data, 60 );
#define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n))))
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
#define P(a,b,c,d,x,s) \
do \
{ \
(a) += F((b),(c),(d)) + (x); \
(a) = S((a),(s)); \
} while( 0 )
P( A, B, C, D, X[ 0], 3 );
P( D, A, B, C, X[ 1], 7 );
P( C, D, A, B, X[ 2], 11 );
P( B, C, D, A, X[ 3], 19 );
P( A, B, C, D, X[ 4], 3 );
P( D, A, B, C, X[ 5], 7 );
P( C, D, A, B, X[ 6], 11 );
P( B, C, D, A, X[ 7], 19 );
P( A, B, C, D, X[ 8], 3 );
P( D, A, B, C, X[ 9], 7 );
P( C, D, A, B, X[10], 11 );
P( B, C, D, A, X[11], 19 );
P( A, B, C, D, X[12], 3 );
P( D, A, B, C, X[13], 7 );
P( C, D, A, B, X[14], 11 );
P( B, C, D, A, X[15], 19 );
#undef P
#undef F
#define F(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define P(a,b,c,d,x,s) \
do \
{ \
(a) += F((b),(c),(d)) + (x) + 0x5A827999; \
(a) = S((a),(s)); \
} while( 0 )
P( A, B, C, D, X[ 0], 3 );
P( D, A, B, C, X[ 4], 5 );
P( C, D, A, B, X[ 8], 9 );
P( B, C, D, A, X[12], 13 );
P( A, B, C, D, X[ 1], 3 );
P( D, A, B, C, X[ 5], 5 );
P( C, D, A, B, X[ 9], 9 );
P( B, C, D, A, X[13], 13 );
P( A, B, C, D, X[ 2], 3 );
P( D, A, B, C, X[ 6], 5 );
P( C, D, A, B, X[10], 9 );
P( B, C, D, A, X[14], 13 );
P( A, B, C, D, X[ 3], 3 );
P( D, A, B, C, X[ 7], 5 );
P( C, D, A, B, X[11], 9 );
P( B, C, D, A, X[15], 13 );
#undef P
#undef F
#define F(x,y,z) ((x) ^ (y) ^ (z))
#define P(a,b,c,d,x,s) \
do \
{ \
(a) += F((b),(c),(d)) + (x) + 0x6ED9EBA1; \
(a) = S((a),(s)); \
} while( 0 )
P( A, B, C, D, X[ 0], 3 );
P( D, A, B, C, X[ 8], 9 );
P( C, D, A, B, X[ 4], 11 );
P( B, C, D, A, X[12], 15 );
P( A, B, C, D, X[ 2], 3 );
P( D, A, B, C, X[10], 9 );
P( C, D, A, B, X[ 6], 11 );
P( B, C, D, A, X[14], 15 );
P( A, B, C, D, X[ 1], 3 );
P( D, A, B, C, X[ 9], 9 );
P( C, D, A, B, X[ 5], 11 );
P( B, C, D, A, X[13], 15 );
P( A, B, C, D, X[ 3], 3 );
P( D, A, B, C, X[11], 9 );
P( C, D, A, B, X[ 7], 11 );
P( B, C, D, A, X[15], 15 );
#undef F
#undef P
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md4_process( mbedtls_md4_context *ctx,
const unsigned char data[64] )
{
mbedtls_internal_md4_process( ctx, data );
}
#endif
#endif /* !MBEDTLS_MD4_PROCESS_ALT */
/*
* MD4 process buffer
*/
int mbedtls_md4_update_ret( mbedtls_md4_context *ctx,
const unsigned char *input,
size_t ilen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t fill;
uint32_t left;
if( ilen == 0 )
return( 0 );
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (uint32_t) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, fill );
if( ( ret = mbedtls_internal_md4_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
if( ( ret = mbedtls_internal_md4_process( ctx, input ) ) != 0 )
return( ret );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, ilen );
}
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md4_update( mbedtls_md4_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_md4_update_ret( ctx, input, ilen );
}
#endif
static const unsigned char md4_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* MD4 final digest
*/
int mbedtls_md4_finish_ret( mbedtls_md4_context *ctx,
unsigned char output[16] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_LE( low, msglen, 0 );
PUT_UINT32_LE( high, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
ret = mbedtls_md4_update_ret( ctx, (unsigned char *)md4_padding, padn );
if( ret != 0 )
return( ret );
if( ( ret = mbedtls_md4_update_ret( ctx, msglen, 8 ) ) != 0 )
return( ret );
PUT_UINT32_LE( ctx->state[0], output, 0 );
PUT_UINT32_LE( ctx->state[1], output, 4 );
PUT_UINT32_LE( ctx->state[2], output, 8 );
PUT_UINT32_LE( ctx->state[3], output, 12 );
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md4_finish( mbedtls_md4_context *ctx,
unsigned char output[16] )
{
mbedtls_md4_finish_ret( ctx, output );
}
#endif
#endif /* !MBEDTLS_MD4_ALT */
/*
* output = MD4( input buffer )
*/
int mbedtls_md4_ret( const unsigned char *input,
size_t ilen,
unsigned char output[16] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_md4_context ctx;
mbedtls_md4_init( &ctx );
if( ( ret = mbedtls_md4_starts_ret( &ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md4_update_ret( &ctx, input, ilen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md4_finish_ret( &ctx, output ) ) != 0 )
goto exit;
exit:
mbedtls_md4_free( &ctx );
return( ret );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md4( const unsigned char *input,
size_t ilen,
unsigned char output[16] )
{
mbedtls_md4_ret( input, ilen, output );
}
#endif
#if defined(MBEDTLS_SELF_TEST)
/*
* RFC 1320 test vectors
*/
static const unsigned char md4_test_str[7][81] =
{
{ "" },
{ "a" },
{ "abc" },
{ "message digest" },
{ "abcdefghijklmnopqrstuvwxyz" },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
{ "12345678901234567890123456789012345678901234567890123456789012"
"345678901234567890" }
};
static const size_t md4_test_strlen[7] =
{
0, 1, 3, 14, 26, 62, 80
};
static const unsigned char md4_test_sum[7][16] =
{
{ 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31,
0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 },
{ 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46,
0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 },
{ 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52,
0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D },
{ 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8,
0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B },
{ 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD,
0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 },
{ 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35,
0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 },
{ 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19,
0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 }
};
/*
* Checkup routine
*/
int mbedtls_md4_self_test( int verbose )
{
int i, ret = 0;
unsigned char md4sum[16];
for( i = 0; i < 7; i++ )
{
if( verbose != 0 )
mbedtls_printf( " MD4 test #%d: ", i + 1 );
ret = mbedtls_md4_ret( md4_test_str[i], md4_test_strlen[i], md4sum );
if( ret != 0 )
goto fail;
if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 )
{
ret = 1;
goto fail;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
fail:
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_MD4_C */

499
library/md5.c Normal file
View File

@ -0,0 +1,499 @@
/*
* RFC 1321 compliant MD5 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The MD5 algorithm was designed by Ron Rivest in 1991.
*
* http://www.ietf.org/rfc/rfc1321.txt
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_MD5_C)
#include "mbedtls/md5.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_MD5_ALT)
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_UINT32_LE
#define GET_UINT32_LE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] ) \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
| ( (uint32_t) (b)[(i) + 3] << 24 ); \
}
#endif
#ifndef PUT_UINT32_LE
#define PUT_UINT32_LE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
(b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
(b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
}
#endif
void mbedtls_md5_init( mbedtls_md5_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_md5_context ) );
}
void mbedtls_md5_free( mbedtls_md5_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md5_context ) );
}
void mbedtls_md5_clone( mbedtls_md5_context *dst,
const mbedtls_md5_context *src )
{
*dst = *src;
}
/*
* MD5 context setup
*/
int mbedtls_md5_starts_ret( mbedtls_md5_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5_starts( mbedtls_md5_context *ctx )
{
mbedtls_md5_starts_ret( ctx );
}
#endif
#if !defined(MBEDTLS_MD5_PROCESS_ALT)
int mbedtls_internal_md5_process( mbedtls_md5_context *ctx,
const unsigned char data[64] )
{
uint32_t X[16], A, B, C, D;
GET_UINT32_LE( X[ 0], data, 0 );
GET_UINT32_LE( X[ 1], data, 4 );
GET_UINT32_LE( X[ 2], data, 8 );
GET_UINT32_LE( X[ 3], data, 12 );
GET_UINT32_LE( X[ 4], data, 16 );
GET_UINT32_LE( X[ 5], data, 20 );
GET_UINT32_LE( X[ 6], data, 24 );
GET_UINT32_LE( X[ 7], data, 28 );
GET_UINT32_LE( X[ 8], data, 32 );
GET_UINT32_LE( X[ 9], data, 36 );
GET_UINT32_LE( X[10], data, 40 );
GET_UINT32_LE( X[11], data, 44 );
GET_UINT32_LE( X[12], data, 48 );
GET_UINT32_LE( X[13], data, 52 );
GET_UINT32_LE( X[14], data, 56 );
GET_UINT32_LE( X[15], data, 60 );
#define S(x,n) \
( ( (x) << (n) ) | ( ( (x) & 0xFFFFFFFF) >> ( 32 - (n) ) ) )
#define P(a,b,c,d,k,s,t) \
do \
{ \
(a) += F((b),(c),(d)) + X[(k)] + (t); \
(a) = S((a),(s)) + (b); \
} while( 0 )
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
P( A, B, C, D, 0, 7, 0xD76AA478 );
P( D, A, B, C, 1, 12, 0xE8C7B756 );
P( C, D, A, B, 2, 17, 0x242070DB );
P( B, C, D, A, 3, 22, 0xC1BDCEEE );
P( A, B, C, D, 4, 7, 0xF57C0FAF );
P( D, A, B, C, 5, 12, 0x4787C62A );
P( C, D, A, B, 6, 17, 0xA8304613 );
P( B, C, D, A, 7, 22, 0xFD469501 );
P( A, B, C, D, 8, 7, 0x698098D8 );
P( D, A, B, C, 9, 12, 0x8B44F7AF );
P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
P( B, C, D, A, 11, 22, 0x895CD7BE );
P( A, B, C, D, 12, 7, 0x6B901122 );
P( D, A, B, C, 13, 12, 0xFD987193 );
P( C, D, A, B, 14, 17, 0xA679438E );
P( B, C, D, A, 15, 22, 0x49B40821 );
#undef F
#define F(x,y,z) ((y) ^ ((z) & ((x) ^ (y))))
P( A, B, C, D, 1, 5, 0xF61E2562 );
P( D, A, B, C, 6, 9, 0xC040B340 );
P( C, D, A, B, 11, 14, 0x265E5A51 );
P( B, C, D, A, 0, 20, 0xE9B6C7AA );
P( A, B, C, D, 5, 5, 0xD62F105D );
P( D, A, B, C, 10, 9, 0x02441453 );
P( C, D, A, B, 15, 14, 0xD8A1E681 );
P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
P( A, B, C, D, 9, 5, 0x21E1CDE6 );
P( D, A, B, C, 14, 9, 0xC33707D6 );
P( C, D, A, B, 3, 14, 0xF4D50D87 );
P( B, C, D, A, 8, 20, 0x455A14ED );
P( A, B, C, D, 13, 5, 0xA9E3E905 );
P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
P( C, D, A, B, 7, 14, 0x676F02D9 );
P( B, C, D, A, 12, 20, 0x8D2A4C8A );
#undef F
#define F(x,y,z) ((x) ^ (y) ^ (z))
P( A, B, C, D, 5, 4, 0xFFFA3942 );
P( D, A, B, C, 8, 11, 0x8771F681 );
P( C, D, A, B, 11, 16, 0x6D9D6122 );
P( B, C, D, A, 14, 23, 0xFDE5380C );
P( A, B, C, D, 1, 4, 0xA4BEEA44 );
P( D, A, B, C, 4, 11, 0x4BDECFA9 );
P( C, D, A, B, 7, 16, 0xF6BB4B60 );
P( B, C, D, A, 10, 23, 0xBEBFBC70 );
P( A, B, C, D, 13, 4, 0x289B7EC6 );
P( D, A, B, C, 0, 11, 0xEAA127FA );
P( C, D, A, B, 3, 16, 0xD4EF3085 );
P( B, C, D, A, 6, 23, 0x04881D05 );
P( A, B, C, D, 9, 4, 0xD9D4D039 );
P( D, A, B, C, 12, 11, 0xE6DB99E5 );
P( C, D, A, B, 15, 16, 0x1FA27CF8 );
P( B, C, D, A, 2, 23, 0xC4AC5665 );
#undef F
#define F(x,y,z) ((y) ^ ((x) | ~(z)))
P( A, B, C, D, 0, 6, 0xF4292244 );
P( D, A, B, C, 7, 10, 0x432AFF97 );
P( C, D, A, B, 14, 15, 0xAB9423A7 );
P( B, C, D, A, 5, 21, 0xFC93A039 );
P( A, B, C, D, 12, 6, 0x655B59C3 );
P( D, A, B, C, 3, 10, 0x8F0CCC92 );
P( C, D, A, B, 10, 15, 0xFFEFF47D );
P( B, C, D, A, 1, 21, 0x85845DD1 );
P( A, B, C, D, 8, 6, 0x6FA87E4F );
P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
P( C, D, A, B, 6, 15, 0xA3014314 );
P( B, C, D, A, 13, 21, 0x4E0811A1 );
P( A, B, C, D, 4, 6, 0xF7537E82 );
P( D, A, B, C, 11, 10, 0xBD3AF235 );
P( C, D, A, B, 2, 15, 0x2AD7D2BB );
P( B, C, D, A, 9, 21, 0xEB86D391 );
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5_process( mbedtls_md5_context *ctx,
const unsigned char data[64] )
{
mbedtls_internal_md5_process( ctx, data );
}
#endif
#endif /* !MBEDTLS_MD5_PROCESS_ALT */
/*
* MD5 process buffer
*/
int mbedtls_md5_update_ret( mbedtls_md5_context *ctx,
const unsigned char *input,
size_t ilen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t fill;
uint32_t left;
if( ilen == 0 )
return( 0 );
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (uint32_t) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
memcpy( (void *) (ctx->buffer + left), input, fill );
if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
if( ( ret = mbedtls_internal_md5_process( ctx, input ) ) != 0 )
return( ret );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
{
memcpy( (void *) (ctx->buffer + left), input, ilen );
}
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5_update( mbedtls_md5_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_md5_update_ret( ctx, input, ilen );
}
#endif
/*
* MD5 final digest
*/
int mbedtls_md5_finish_ret( mbedtls_md5_context *ctx,
unsigned char output[16] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
uint32_t used;
uint32_t high, low;
/*
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
*/
used = ctx->total[0] & 0x3F;
ctx->buffer[used++] = 0x80;
if( used <= 56 )
{
/* Enough room for padding + length in current block */
memset( ctx->buffer + used, 0, 56 - used );
}
else
{
/* We'll need an extra block */
memset( ctx->buffer + used, 0, 64 - used );
if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
memset( ctx->buffer, 0, 56 );
}
/*
* Add message length
*/
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_LE( low, ctx->buffer, 56 );
PUT_UINT32_LE( high, ctx->buffer, 60 );
if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
/*
* Output final state
*/
PUT_UINT32_LE( ctx->state[0], output, 0 );
PUT_UINT32_LE( ctx->state[1], output, 4 );
PUT_UINT32_LE( ctx->state[2], output, 8 );
PUT_UINT32_LE( ctx->state[3], output, 12 );
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5_finish( mbedtls_md5_context *ctx,
unsigned char output[16] )
{
mbedtls_md5_finish_ret( ctx, output );
}
#endif
#endif /* !MBEDTLS_MD5_ALT */
/*
* output = MD5( input buffer )
*/
int mbedtls_md5_ret( const unsigned char *input,
size_t ilen,
unsigned char output[16] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_md5_context ctx;
mbedtls_md5_init( &ctx );
if( ( ret = mbedtls_md5_starts_ret( &ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md5_update_ret( &ctx, input, ilen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md5_finish_ret( &ctx, output ) ) != 0 )
goto exit;
exit:
mbedtls_md5_free( &ctx );
return( ret );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5( const unsigned char *input,
size_t ilen,
unsigned char output[16] )
{
mbedtls_md5_ret( input, ilen, output );
}
#endif
#if defined(MBEDTLS_SELF_TEST)
/*
* RFC 1321 test vectors
*/
static const unsigned char md5_test_buf[7][81] =
{
{ "" },
{ "a" },
{ "abc" },
{ "message digest" },
{ "abcdefghijklmnopqrstuvwxyz" },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
{ "12345678901234567890123456789012345678901234567890123456789012"
"345678901234567890" }
};
static const size_t md5_test_buflen[7] =
{
0, 1, 3, 14, 26, 62, 80
};
static const unsigned char md5_test_sum[7][16] =
{
{ 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E },
{ 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 },
{ 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 },
{ 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 },
{ 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B },
{ 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F },
{ 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A }
};
/*
* Checkup routine
*/
int mbedtls_md5_self_test( int verbose )
{
int i, ret = 0;
unsigned char md5sum[16];
for( i = 0; i < 7; i++ )
{
if( verbose != 0 )
mbedtls_printf( " MD5 test #%d: ", i + 1 );
ret = mbedtls_md5_ret( md5_test_buf[i], md5_test_buflen[i], md5sum );
if( ret != 0 )
goto fail;
if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 )
{
ret = 1;
goto fail;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
fail:
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_MD5_C */

View File

@ -0,0 +1,750 @@
/*
* Buffer-based memory allocator
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
#include "mbedtls/memory_buffer_alloc.h"
/* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C
is dependent upon MBEDTLS_PLATFORM_C */
#include "mbedtls/platform.h"
#include "mbedtls/platform_util.h"
#include <string.h>
#if defined(MBEDTLS_MEMORY_BACKTRACE)
#include <execinfo.h>
#endif
#if defined(MBEDTLS_THREADING_C)
#include "mbedtls/threading.h"
#endif
#define MAGIC1 0xFF00AA55
#define MAGIC2 0xEE119966
#define MAX_BT 20
typedef struct _memory_header memory_header;
struct _memory_header
{
size_t magic1;
size_t size;
size_t alloc;
memory_header *prev;
memory_header *next;
memory_header *prev_free;
memory_header *next_free;
#if defined(MBEDTLS_MEMORY_BACKTRACE)
char **trace;
size_t trace_count;
#endif
size_t magic2;
};
typedef struct
{
unsigned char *buf;
size_t len;
memory_header *first;
memory_header *first_free;
int verify;
#if defined(MBEDTLS_MEMORY_DEBUG)
size_t alloc_count;
size_t free_count;
size_t total_used;
size_t maximum_used;
size_t header_count;
size_t maximum_header_count;
#endif
#if defined(MBEDTLS_THREADING_C)
mbedtls_threading_mutex_t mutex;
#endif
}
buffer_alloc_ctx;
static buffer_alloc_ctx heap;
#if defined(MBEDTLS_MEMORY_DEBUG)
static void debug_header( memory_header *hdr )
{
#if defined(MBEDTLS_MEMORY_BACKTRACE)
size_t i;
#endif
mbedtls_fprintf( stderr, "HDR: PTR(%10zu), PREV(%10zu), NEXT(%10zu), "
"ALLOC(%zu), SIZE(%10zu)\n",
(size_t) hdr, (size_t) hdr->prev, (size_t) hdr->next,
hdr->alloc, hdr->size );
mbedtls_fprintf( stderr, " FPREV(%10zu), FNEXT(%10zu)\n",
(size_t) hdr->prev_free, (size_t) hdr->next_free );
#if defined(MBEDTLS_MEMORY_BACKTRACE)
mbedtls_fprintf( stderr, "TRACE: \n" );
for( i = 0; i < hdr->trace_count; i++ )
mbedtls_fprintf( stderr, "%s\n", hdr->trace[i] );
mbedtls_fprintf( stderr, "\n" );
#endif
}
static void debug_chain( void )
{
memory_header *cur = heap.first;
mbedtls_fprintf( stderr, "\nBlock list\n" );
while( cur != NULL )
{
debug_header( cur );
cur = cur->next;
}
mbedtls_fprintf( stderr, "Free list\n" );
cur = heap.first_free;
while( cur != NULL )
{
debug_header( cur );
cur = cur->next_free;
}
}
#endif /* MBEDTLS_MEMORY_DEBUG */
static int verify_header( memory_header *hdr )
{
if( hdr->magic1 != MAGIC1 )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: MAGIC1 mismatch\n" );
#endif
return( 1 );
}
if( hdr->magic2 != MAGIC2 )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: MAGIC2 mismatch\n" );
#endif
return( 1 );
}
if( hdr->alloc > 1 )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: alloc has illegal value\n" );
#endif
return( 1 );
}
if( hdr->prev != NULL && hdr->prev == hdr->next )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: prev == next\n" );
#endif
return( 1 );
}
if( hdr->prev_free != NULL && hdr->prev_free == hdr->next_free )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: prev_free == next_free\n" );
#endif
return( 1 );
}
return( 0 );
}
static int verify_chain( void )
{
memory_header *prv = heap.first, *cur;
if( prv == NULL || verify_header( prv ) != 0 )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: verification of first header "
"failed\n" );
#endif
return( 1 );
}
if( heap.first->prev != NULL )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: verification failed: "
"first->prev != NULL\n" );
#endif
return( 1 );
}
cur = heap.first->next;
while( cur != NULL )
{
if( verify_header( cur ) != 0 )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: verification of header "
"failed\n" );
#endif
return( 1 );
}
if( cur->prev != prv )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: verification failed: "
"cur->prev != prv\n" );
#endif
return( 1 );
}
prv = cur;
cur = cur->next;
}
return( 0 );
}
static void *buffer_alloc_calloc( size_t n, size_t size )
{
memory_header *new, *cur = heap.first_free;
unsigned char *p;
void *ret;
size_t original_len, len;
#if defined(MBEDTLS_MEMORY_BACKTRACE)
void *trace_buffer[MAX_BT];
size_t trace_cnt;
#endif
if( heap.buf == NULL || heap.first == NULL )
return( NULL );
original_len = len = n * size;
if( n == 0 || size == 0 || len / n != size )
return( NULL );
else if( len > (size_t)-MBEDTLS_MEMORY_ALIGN_MULTIPLE )
return( NULL );
if( len % MBEDTLS_MEMORY_ALIGN_MULTIPLE )
{
len -= len % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
len += MBEDTLS_MEMORY_ALIGN_MULTIPLE;
}
// Find block that fits
//
while( cur != NULL )
{
if( cur->size >= len )
break;
cur = cur->next_free;
}
if( cur == NULL )
return( NULL );
if( cur->alloc != 0 )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: block in free_list but allocated "
"data\n" );
#endif
mbedtls_exit( 1 );
}
#if defined(MBEDTLS_MEMORY_DEBUG)
heap.alloc_count++;
#endif
// Found location, split block if > memory_header + 4 room left
//
if( cur->size - len < sizeof(memory_header) +
MBEDTLS_MEMORY_ALIGN_MULTIPLE )
{
cur->alloc = 1;
// Remove from free_list
//
if( cur->prev_free != NULL )
cur->prev_free->next_free = cur->next_free;
else
heap.first_free = cur->next_free;
if( cur->next_free != NULL )
cur->next_free->prev_free = cur->prev_free;
cur->prev_free = NULL;
cur->next_free = NULL;
#if defined(MBEDTLS_MEMORY_DEBUG)
heap.total_used += cur->size;
if( heap.total_used > heap.maximum_used )
heap.maximum_used = heap.total_used;
#endif
#if defined(MBEDTLS_MEMORY_BACKTRACE)
trace_cnt = backtrace( trace_buffer, MAX_BT );
cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
cur->trace_count = trace_cnt;
#endif
if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
mbedtls_exit( 1 );
ret = (unsigned char *) cur + sizeof( memory_header );
memset( ret, 0, original_len );
return( ret );
}
p = ( (unsigned char *) cur ) + sizeof(memory_header) + len;
new = (memory_header *) p;
new->size = cur->size - len - sizeof(memory_header);
new->alloc = 0;
new->prev = cur;
new->next = cur->next;
#if defined(MBEDTLS_MEMORY_BACKTRACE)
new->trace = NULL;
new->trace_count = 0;
#endif
new->magic1 = MAGIC1;
new->magic2 = MAGIC2;
if( new->next != NULL )
new->next->prev = new;
// Replace cur with new in free_list
//
new->prev_free = cur->prev_free;
new->next_free = cur->next_free;
if( new->prev_free != NULL )
new->prev_free->next_free = new;
else
heap.first_free = new;
if( new->next_free != NULL )
new->next_free->prev_free = new;
cur->alloc = 1;
cur->size = len;
cur->next = new;
cur->prev_free = NULL;
cur->next_free = NULL;
#if defined(MBEDTLS_MEMORY_DEBUG)
heap.header_count++;
if( heap.header_count > heap.maximum_header_count )
heap.maximum_header_count = heap.header_count;
heap.total_used += cur->size;
if( heap.total_used > heap.maximum_used )
heap.maximum_used = heap.total_used;
#endif
#if defined(MBEDTLS_MEMORY_BACKTRACE)
trace_cnt = backtrace( trace_buffer, MAX_BT );
cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
cur->trace_count = trace_cnt;
#endif
if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
mbedtls_exit( 1 );
ret = (unsigned char *) cur + sizeof( memory_header );
memset( ret, 0, original_len );
return( ret );
}
static void buffer_alloc_free( void *ptr )
{
memory_header *hdr, *old = NULL;
unsigned char *p = (unsigned char *) ptr;
if( ptr == NULL || heap.buf == NULL || heap.first == NULL )
return;
if( p < heap.buf || p >= heap.buf + heap.len )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: mbedtls_free() outside of managed "
"space\n" );
#endif
mbedtls_exit( 1 );
}
p -= sizeof(memory_header);
hdr = (memory_header *) p;
if( verify_header( hdr ) != 0 )
mbedtls_exit( 1 );
if( hdr->alloc != 1 )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_fprintf( stderr, "FATAL: mbedtls_free() on unallocated "
"data\n" );
#endif
mbedtls_exit( 1 );
}
hdr->alloc = 0;
#if defined(MBEDTLS_MEMORY_DEBUG)
heap.free_count++;
heap.total_used -= hdr->size;
#endif
#if defined(MBEDTLS_MEMORY_BACKTRACE)
free( hdr->trace );
hdr->trace = NULL;
hdr->trace_count = 0;
#endif
// Regroup with block before
//
if( hdr->prev != NULL && hdr->prev->alloc == 0 )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
heap.header_count--;
#endif
hdr->prev->size += sizeof(memory_header) + hdr->size;
hdr->prev->next = hdr->next;
old = hdr;
hdr = hdr->prev;
if( hdr->next != NULL )
hdr->next->prev = hdr;
memset( old, 0, sizeof(memory_header) );
}
// Regroup with block after
//
if( hdr->next != NULL && hdr->next->alloc == 0 )
{
#if defined(MBEDTLS_MEMORY_DEBUG)
heap.header_count--;
#endif
hdr->size += sizeof(memory_header) + hdr->next->size;
old = hdr->next;
hdr->next = hdr->next->next;
if( hdr->prev_free != NULL || hdr->next_free != NULL )
{
if( hdr->prev_free != NULL )
hdr->prev_free->next_free = hdr->next_free;
else
heap.first_free = hdr->next_free;
if( hdr->next_free != NULL )
hdr->next_free->prev_free = hdr->prev_free;
}
hdr->prev_free = old->prev_free;
hdr->next_free = old->next_free;
if( hdr->prev_free != NULL )
hdr->prev_free->next_free = hdr;
else
heap.first_free = hdr;
if( hdr->next_free != NULL )
hdr->next_free->prev_free = hdr;
if( hdr->next != NULL )
hdr->next->prev = hdr;
memset( old, 0, sizeof(memory_header) );
}
// Prepend to free_list if we have not merged
// (Does not have to stay in same order as prev / next list)
//
if( old == NULL )
{
hdr->next_free = heap.first_free;
if( heap.first_free != NULL )
heap.first_free->prev_free = hdr;
heap.first_free = hdr;
}
if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_FREE ) && verify_chain() != 0 )
mbedtls_exit( 1 );
}
void mbedtls_memory_buffer_set_verify( int verify )
{
heap.verify = verify;
}
int mbedtls_memory_buffer_alloc_verify( void )
{
return verify_chain();
}
#if defined(MBEDTLS_MEMORY_DEBUG)
void mbedtls_memory_buffer_alloc_status( void )
{
mbedtls_fprintf( stderr,
"Current use: %zu blocks / %zu bytes, max: %zu blocks / "
"%zu bytes (total %zu bytes), alloc / free: %zu / %zu\n",
heap.header_count, heap.total_used,
heap.maximum_header_count, heap.maximum_used,
heap.maximum_header_count * sizeof( memory_header )
+ heap.maximum_used,
heap.alloc_count, heap.free_count );
if( heap.first->next == NULL )
{
mbedtls_fprintf( stderr, "All memory de-allocated in stack buffer\n" );
}
else
{
mbedtls_fprintf( stderr, "Memory currently allocated:\n" );
debug_chain();
}
}
void mbedtls_memory_buffer_alloc_max_get( size_t *max_used, size_t *max_blocks )
{
*max_used = heap.maximum_used;
*max_blocks = heap.maximum_header_count;
}
void mbedtls_memory_buffer_alloc_max_reset( void )
{
heap.maximum_used = 0;
heap.maximum_header_count = 0;
}
void mbedtls_memory_buffer_alloc_cur_get( size_t *cur_used, size_t *cur_blocks )
{
*cur_used = heap.total_used;
*cur_blocks = heap.header_count;
}
#endif /* MBEDTLS_MEMORY_DEBUG */
#if defined(MBEDTLS_THREADING_C)
static void *buffer_alloc_calloc_mutexed( size_t n, size_t size )
{
void *buf;
if( mbedtls_mutex_lock( &heap.mutex ) != 0 )
return( NULL );
buf = buffer_alloc_calloc( n, size );
if( mbedtls_mutex_unlock( &heap.mutex ) )
return( NULL );
return( buf );
}
static void buffer_alloc_free_mutexed( void *ptr )
{
/* We have to good option here, but corrupting the heap seems
* worse than loosing memory. */
if( mbedtls_mutex_lock( &heap.mutex ) )
return;
buffer_alloc_free( ptr );
(void) mbedtls_mutex_unlock( &heap.mutex );
}
#endif /* MBEDTLS_THREADING_C */
void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len )
{
memset( &heap, 0, sizeof( buffer_alloc_ctx ) );
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_init( &heap.mutex );
mbedtls_platform_set_calloc_free( buffer_alloc_calloc_mutexed,
buffer_alloc_free_mutexed );
#else
mbedtls_platform_set_calloc_free( buffer_alloc_calloc, buffer_alloc_free );
#endif
if( len < sizeof( memory_header ) + MBEDTLS_MEMORY_ALIGN_MULTIPLE )
return;
else if( (size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE )
{
/* Adjust len first since buf is used in the computation */
len -= MBEDTLS_MEMORY_ALIGN_MULTIPLE
- (size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
buf += MBEDTLS_MEMORY_ALIGN_MULTIPLE
- (size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
}
memset( buf, 0, len );
heap.buf = buf;
heap.len = len;
heap.first = (memory_header *)buf;
heap.first->size = len - sizeof( memory_header );
heap.first->magic1 = MAGIC1;
heap.first->magic2 = MAGIC2;
heap.first_free = heap.first;
}
void mbedtls_memory_buffer_alloc_free( void )
{
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_free( &heap.mutex );
#endif
mbedtls_platform_zeroize( &heap, sizeof(buffer_alloc_ctx) );
}
#if defined(MBEDTLS_SELF_TEST)
static int check_pointer( void *p )
{
if( p == NULL )
return( -1 );
if( (size_t) p % MBEDTLS_MEMORY_ALIGN_MULTIPLE != 0 )
return( -1 );
return( 0 );
}
static int check_all_free( void )
{
if(
#if defined(MBEDTLS_MEMORY_DEBUG)
heap.total_used != 0 ||
#endif
heap.first != heap.first_free ||
(void *) heap.first != (void *) heap.buf )
{
return( -1 );
}
return( 0 );
}
#define TEST_ASSERT( condition ) \
if( ! (condition) ) \
{ \
if( verbose != 0 ) \
mbedtls_printf( "failed\n" ); \
\
ret = 1; \
goto cleanup; \
}
int mbedtls_memory_buffer_alloc_self_test( int verbose )
{
unsigned char buf[1024];
unsigned char *p, *q, *r, *end;
int ret = 0;
if( verbose != 0 )
mbedtls_printf( " MBA test #1 (basic alloc-free cycle): " );
mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) );
p = mbedtls_calloc( 1, 1 );
q = mbedtls_calloc( 1, 128 );
r = mbedtls_calloc( 1, 16 );
TEST_ASSERT( check_pointer( p ) == 0 &&
check_pointer( q ) == 0 &&
check_pointer( r ) == 0 );
mbedtls_free( r );
mbedtls_free( q );
mbedtls_free( p );
TEST_ASSERT( check_all_free( ) == 0 );
/* Memorize end to compare with the next test */
end = heap.buf + heap.len;
mbedtls_memory_buffer_alloc_free( );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
if( verbose != 0 )
mbedtls_printf( " MBA test #2 (buf not aligned): " );
mbedtls_memory_buffer_alloc_init( buf + 1, sizeof( buf ) - 1 );
TEST_ASSERT( heap.buf + heap.len == end );
p = mbedtls_calloc( 1, 1 );
q = mbedtls_calloc( 1, 128 );
r = mbedtls_calloc( 1, 16 );
TEST_ASSERT( check_pointer( p ) == 0 &&
check_pointer( q ) == 0 &&
check_pointer( r ) == 0 );
mbedtls_free( r );
mbedtls_free( q );
mbedtls_free( p );
TEST_ASSERT( check_all_free( ) == 0 );
mbedtls_memory_buffer_alloc_free( );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
if( verbose != 0 )
mbedtls_printf( " MBA test #3 (full): " );
mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) );
p = mbedtls_calloc( 1, sizeof( buf ) - sizeof( memory_header ) );
TEST_ASSERT( check_pointer( p ) == 0 );
TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL );
mbedtls_free( p );
p = mbedtls_calloc( 1, sizeof( buf ) - 2 * sizeof( memory_header ) - 16 );
q = mbedtls_calloc( 1, 16 );
TEST_ASSERT( check_pointer( p ) == 0 && check_pointer( q ) == 0 );
TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL );
mbedtls_free( q );
TEST_ASSERT( mbedtls_calloc( 1, 17 ) == NULL );
mbedtls_free( p );
TEST_ASSERT( check_all_free( ) == 0 );
mbedtls_memory_buffer_alloc_free( );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
cleanup:
mbedtls_memory_buffer_alloc_free( );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */

756
library/nist_kw.c Normal file
View File

@ -0,0 +1,756 @@
/*
* Implementation of NIST SP 800-38F key wrapping, supporting KW and KWP modes
* only
*
* Copyright (C) 2018, Arm Limited (or its affiliates), All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
/*
* Definition of Key Wrapping:
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf
* RFC 3394 "Advanced Encryption Standard (AES) Key Wrap Algorithm"
* RFC 5649 "Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm"
*
* Note: RFC 3394 defines different methodology for intermediate operations for
* the wrapping and unwrapping operation than the definition in NIST SP 800-38F.
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_NIST_KW_C)
#include "mbedtls/nist_kw.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <stdint.h>
#include <string.h>
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#if !defined(MBEDTLS_NIST_KW_ALT)
#define KW_SEMIBLOCK_LENGTH 8
#define MIN_SEMIBLOCKS_COUNT 3
/* constant-time buffer comparison */
static inline unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n )
{
size_t i;
volatile const unsigned char *A = (volatile const unsigned char *) a;
volatile const unsigned char *B = (volatile const unsigned char *) b;
volatile unsigned char diff = 0;
for( i = 0; i < n; i++ )
{
/* Read volatile data in order before computing diff.
* This avoids IAR compiler warning:
* 'the order of volatile accesses is undefined ..' */
unsigned char x = A[i], y = B[i];
diff |= x ^ y;
}
return( diff );
}
/*! The 64-bit default integrity check value (ICV) for KW mode. */
static const unsigned char NIST_KW_ICV1[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
/*! The 32-bit default integrity check value (ICV) for KWP mode. */
static const unsigned char NIST_KW_ICV2[] = {0xA6, 0x59, 0x59, 0xA6};
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
do { \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
} while( 0 )
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
do { \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
} while( 0 )
#endif
/*
* Initialize context
*/
void mbedtls_nist_kw_init( mbedtls_nist_kw_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_nist_kw_context ) );
}
int mbedtls_nist_kw_setkey( mbedtls_nist_kw_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits,
const int is_wrap )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
const mbedtls_cipher_info_t *cipher_info;
cipher_info = mbedtls_cipher_info_from_values( cipher,
keybits,
MBEDTLS_MODE_ECB );
if( cipher_info == NULL )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( cipher_info->block_size != 16 )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
/*
* SP 800-38F currently defines AES cipher as the only block cipher allowed:
* "For KW and KWP, the underlying block cipher shall be approved, and the
* block size shall be 128 bits. Currently, the AES block cipher, with key
* lengths of 128, 192, or 256 bits, is the only block cipher that fits
* this profile."
* Currently we don't support other 128 bit block ciphers for key wrapping,
* such as Camellia and Aria.
*/
if( cipher != MBEDTLS_CIPHER_ID_AES )
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
mbedtls_cipher_free( &ctx->cipher_ctx );
if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
is_wrap ? MBEDTLS_ENCRYPT :
MBEDTLS_DECRYPT )
) != 0 )
{
return( ret );
}
return( 0 );
}
/*
* Free context
*/
void mbedtls_nist_kw_free( mbedtls_nist_kw_context *ctx )
{
mbedtls_cipher_free( &ctx->cipher_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_nist_kw_context ) );
}
/*
* Helper function for Xoring the uint64_t "t" with the encrypted A.
* Defined in NIST SP 800-38F section 6.1
*/
static void calc_a_xor_t( unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t )
{
size_t i = 0;
for( i = 0; i < sizeof( t ); i++ )
{
A[i] ^= ( t >> ( ( sizeof( t ) - 1 - i ) * 8 ) ) & 0xff;
}
}
/*
* KW-AE as defined in SP 800-38F section 6.2
* KWP-AE as defined in SP 800-38F section 6.3
*/
int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx,
mbedtls_nist_kw_mode_t mode,
const unsigned char *input, size_t in_len,
unsigned char *output, size_t *out_len, size_t out_size )
{
int ret = 0;
size_t semiblocks = 0;
size_t s;
size_t olen, padlen = 0;
uint64_t t = 0;
unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
unsigned char *A = output;
*out_len = 0;
/*
* Generate the String to work on
*/
if( mode == MBEDTLS_KW_MODE_KW )
{
if( out_size < in_len + KW_SEMIBLOCK_LENGTH )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
/*
* According to SP 800-38F Table 1, the plaintext length for KW
* must be between 2 to 2^54-1 semiblocks inclusive.
*/
if( in_len < 16 ||
#if SIZE_MAX > 0x1FFFFFFFFFFFFF8
in_len > 0x1FFFFFFFFFFFFF8 ||
#endif
in_len % KW_SEMIBLOCK_LENGTH != 0 )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
memcpy( output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH );
memmove( output + KW_SEMIBLOCK_LENGTH, input, in_len );
}
else
{
if( in_len % 8 != 0 )
{
padlen = ( 8 - ( in_len % 8 ) );
}
if( out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
/*
* According to SP 800-38F Table 1, the plaintext length for KWP
* must be between 1 and 2^32-1 octets inclusive.
*/
if( in_len < 1
#if SIZE_MAX > 0xFFFFFFFF
|| in_len > 0xFFFFFFFF
#endif
)
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
memcpy( output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2 );
PUT_UINT32_BE( ( in_len & 0xffffffff ), output,
KW_SEMIBLOCK_LENGTH / 2 );
memcpy( output + KW_SEMIBLOCK_LENGTH, input, in_len );
memset( output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen );
}
semiblocks = ( ( in_len + padlen ) / KW_SEMIBLOCK_LENGTH ) + 1;
s = 6 * ( semiblocks - 1 );
if( mode == MBEDTLS_KW_MODE_KWP
&& in_len <= KW_SEMIBLOCK_LENGTH )
{
memcpy( inbuff, output, 16 );
ret = mbedtls_cipher_update( &ctx->cipher_ctx,
inbuff, 16, output, &olen );
if( ret != 0 )
goto cleanup;
}
else
{
/*
* Do the wrapping function W, as defined in RFC 3394 section 2.2.1
*/
if( semiblocks < MIN_SEMIBLOCKS_COUNT )
{
ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
goto cleanup;
}
/* Calculate intermediate values */
for( t = 1; t <= s; t++ )
{
memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH );
memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH );
ret = mbedtls_cipher_update( &ctx->cipher_ctx,
inbuff, 16, outbuff, &olen );
if( ret != 0 )
goto cleanup;
memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
calc_a_xor_t( A, t );
memcpy( R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
R2 += KW_SEMIBLOCK_LENGTH;
if( R2 >= output + ( semiblocks * KW_SEMIBLOCK_LENGTH ) )
R2 = output + KW_SEMIBLOCK_LENGTH;
}
}
*out_len = semiblocks * KW_SEMIBLOCK_LENGTH;
cleanup:
if( ret != 0)
{
memset( output, 0, semiblocks * KW_SEMIBLOCK_LENGTH );
}
mbedtls_platform_zeroize( inbuff, KW_SEMIBLOCK_LENGTH * 2 );
mbedtls_platform_zeroize( outbuff, KW_SEMIBLOCK_LENGTH * 2 );
return( ret );
}
/*
* W-1 function as defined in RFC 3394 section 2.2.2
* This function assumes the following:
* 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH.
* 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH.
* 3. Minimal number of semiblocks is 3.
* 4. A is a buffer to hold the first semiblock of the input buffer.
*/
static int unwrap( mbedtls_nist_kw_context *ctx,
const unsigned char *input, size_t semiblocks,
unsigned char A[KW_SEMIBLOCK_LENGTH],
unsigned char *output, size_t* out_len )
{
int ret = 0;
const size_t s = 6 * ( semiblocks - 1 );
size_t olen;
uint64_t t = 0;
unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
unsigned char *R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH;
*out_len = 0;
if( semiblocks < MIN_SEMIBLOCKS_COUNT )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
memcpy( A, input, KW_SEMIBLOCK_LENGTH );
memmove( output, input + KW_SEMIBLOCK_LENGTH, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH );
/* Calculate intermediate values */
for( t = s; t >= 1; t-- )
{
calc_a_xor_t( A, t );
memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH );
memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH );
ret = mbedtls_cipher_update( &ctx->cipher_ctx,
inbuff, 16, outbuff, &olen );
if( ret != 0 )
goto cleanup;
memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
/* Set R as LSB64 of outbuff */
memcpy( R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
if( R == output )
R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH;
else
R -= KW_SEMIBLOCK_LENGTH;
}
*out_len = ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH;
cleanup:
if( ret != 0)
memset( output, 0, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH );
mbedtls_platform_zeroize( inbuff, sizeof( inbuff ) );
mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) );
return( ret );
}
/*
* KW-AD as defined in SP 800-38F section 6.2
* KWP-AD as defined in SP 800-38F section 6.3
*/
int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx,
mbedtls_nist_kw_mode_t mode,
const unsigned char *input, size_t in_len,
unsigned char *output, size_t *out_len, size_t out_size )
{
int ret = 0;
size_t i, olen;
unsigned char A[KW_SEMIBLOCK_LENGTH];
unsigned char diff, bad_padding = 0;
*out_len = 0;
if( out_size < in_len - KW_SEMIBLOCK_LENGTH )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
if( mode == MBEDTLS_KW_MODE_KW )
{
/*
* According to SP 800-38F Table 1, the ciphertext length for KW
* must be between 3 to 2^54 semiblocks inclusive.
*/
if( in_len < 24 ||
#if SIZE_MAX > 0x200000000000000
in_len > 0x200000000000000 ||
#endif
in_len % KW_SEMIBLOCK_LENGTH != 0 )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
A, output, out_len );
if( ret != 0 )
goto cleanup;
/* Check ICV in "constant-time" */
diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH );
if( diff != 0 )
{
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
goto cleanup;
}
}
else if( mode == MBEDTLS_KW_MODE_KWP )
{
size_t padlen = 0;
uint32_t Plen;
/*
* According to SP 800-38F Table 1, the ciphertext length for KWP
* must be between 2 to 2^29 semiblocks inclusive.
*/
if( in_len < KW_SEMIBLOCK_LENGTH * 2 ||
#if SIZE_MAX > 0x100000000
in_len > 0x100000000 ||
#endif
in_len % KW_SEMIBLOCK_LENGTH != 0 )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
if( in_len == KW_SEMIBLOCK_LENGTH * 2 )
{
unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
ret = mbedtls_cipher_update( &ctx->cipher_ctx,
input, 16, outbuff, &olen );
if( ret != 0 )
goto cleanup;
memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
memcpy( output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) );
*out_len = KW_SEMIBLOCK_LENGTH;
}
else
{
/* in_len >= KW_SEMIBLOCK_LENGTH * 3 */
ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
A, output, out_len );
if( ret != 0 )
goto cleanup;
}
/* Check ICV in "constant-time" */
diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 );
if( diff != 0 )
{
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
}
GET_UINT32_BE( Plen, A, KW_SEMIBLOCK_LENGTH / 2 );
/*
* Plen is the length of the plaintext, when the input is valid.
* If Plen is larger than the plaintext and padding, padlen will be
* larger than 8, because of the type wrap around.
*/
padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen;
if ( padlen > 7 )
{
padlen &= 7;
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
}
/* Check padding in "constant-time" */
for( diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++ )
{
if( i >= KW_SEMIBLOCK_LENGTH - padlen )
diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
else
bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
}
if( diff != 0 )
{
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
}
if( ret != 0 )
{
goto cleanup;
}
memset( output + Plen, 0, padlen );
*out_len = Plen;
}
else
{
ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
goto cleanup;
}
cleanup:
if( ret != 0 )
{
memset( output, 0, *out_len );
*out_len = 0;
}
mbedtls_platform_zeroize( &bad_padding, sizeof( bad_padding) );
mbedtls_platform_zeroize( &diff, sizeof( diff ) );
mbedtls_platform_zeroize( A, sizeof( A ) );
return( ret );
}
#endif /* !MBEDTLS_NIST_KW_ALT */
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
#define KW_TESTS 3
/*
* Test vectors taken from NIST
* https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#KW
*/
static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 };
static const unsigned char kw_key[KW_TESTS][32] = {
{ 0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2,
0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6 },
{ 0x2d, 0x85, 0x26, 0x08, 0x1d, 0x02, 0xfb, 0x5b,
0x85, 0xf6, 0x9a, 0xc2, 0x86, 0xec, 0xd5, 0x7d,
0x40, 0xdf, 0x5d, 0xf3, 0x49, 0x47, 0x44, 0xd3 },
{ 0x11, 0x2a, 0xd4, 0x1b, 0x48, 0x56, 0xc7, 0x25,
0x4a, 0x98, 0x48, 0xd3, 0x0f, 0xdd, 0x78, 0x33,
0x5b, 0x03, 0x9a, 0x48, 0xa8, 0x96, 0x2c, 0x4d,
0x1c, 0xb7, 0x8e, 0xab, 0xd5, 0xda, 0xd7, 0x88 }
};
static const unsigned char kw_msg[KW_TESTS][40] = {
{ 0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea,
0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f },
{ 0x95, 0xc1, 0x1b, 0xf5, 0x35, 0x3a, 0xfe, 0xdb,
0x98, 0xfd, 0xd6, 0xc8, 0xca, 0x6f, 0xdb, 0x6d,
0xa5, 0x4b, 0x74, 0xb4, 0x99, 0x0f, 0xdc, 0x45,
0xc0, 0x9d, 0x15, 0x8f, 0x51, 0xce, 0x62, 0x9d,
0xe2, 0xaf, 0x26, 0xe3, 0x25, 0x0e, 0x6b, 0x4c },
{ 0x1b, 0x20, 0xbf, 0x19, 0x90, 0xb0, 0x65, 0xd7,
0x98, 0xe1, 0xb3, 0x22, 0x64, 0xad, 0x50, 0xa8,
0x74, 0x74, 0x92, 0xba, 0x09, 0xa0, 0x4d, 0xd1 }
};
static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 };
static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 };
static const unsigned char kw_res[KW_TESTS][48] = {
{ 0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d,
0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3,
0xf5, 0x6f, 0xab, 0xea, 0x25, 0x48, 0xf5, 0xfb },
{ 0x44, 0x3c, 0x6f, 0x15, 0x09, 0x83, 0x71, 0x91,
0x3e, 0x5c, 0x81, 0x4c, 0xa1, 0xa0, 0x42, 0xec,
0x68, 0x2f, 0x7b, 0x13, 0x6d, 0x24, 0x3a, 0x4d,
0x6c, 0x42, 0x6f, 0xc6, 0x97, 0x15, 0x63, 0xe8,
0xa1, 0x4a, 0x55, 0x8e, 0x09, 0x64, 0x16, 0x19,
0xbf, 0x03, 0xfc, 0xaf, 0x90, 0xb1, 0xfc, 0x2d },
{ 0xba, 0x8a, 0x25, 0x9a, 0x47, 0x1b, 0x78, 0x7d,
0xd5, 0xd5, 0x40, 0xec, 0x25, 0xd4, 0x3d, 0x87,
0x20, 0x0f, 0xda, 0xdc, 0x6d, 0x1f, 0x05, 0xd9,
0x16, 0x58, 0x4f, 0xa9, 0xf6, 0xcb, 0xf5, 0x12 }
};
static const unsigned char kwp_key[KW_TESTS][32] = {
{ 0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a,
0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4 },
{ 0xf5, 0xf8, 0x96, 0xa3, 0xbd, 0x2f, 0x4a, 0x98,
0x23, 0xef, 0x16, 0x2b, 0x00, 0xb8, 0x05, 0xd7,
0xde, 0x1e, 0xa4, 0x66, 0x26, 0x96, 0xa2, 0x58 },
{ 0x95, 0xda, 0x27, 0x00, 0xca, 0x6f, 0xd9, 0xa5,
0x25, 0x54, 0xee, 0x2a, 0x8d, 0xf1, 0x38, 0x6f,
0x5b, 0x94, 0xa1, 0xa6, 0x0e, 0xd8, 0xa4, 0xae,
0xf6, 0x0a, 0x8d, 0x61, 0xab, 0x5f, 0x22, 0x5a }
};
static const unsigned char kwp_msg[KW_TESTS][31] = {
{ 0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8,
0x96 },
{ 0x6c, 0xcd, 0xd5, 0x85, 0x18, 0x40, 0x97, 0xeb,
0xd5, 0xc3, 0xaf, 0x3e, 0x47, 0xd0, 0x2c, 0x19,
0x14, 0x7b, 0x4d, 0x99, 0x5f, 0x96, 0x43, 0x66,
0x91, 0x56, 0x75, 0x8c, 0x13, 0x16, 0x8f },
{ 0xd1 }
};
static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 };
static const unsigned char kwp_res[KW_TESTS][48] = {
{ 0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e,
0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7,
0x4d, 0xb6, 0xf8, 0xc5, 0x64, 0xe2, 0x35, 0x00 },
{ 0x4e, 0x9b, 0xc2, 0xbc, 0xbc, 0x6c, 0x1e, 0x13,
0xd3, 0x35, 0xbc, 0xc0, 0xf7, 0x73, 0x6a, 0x88,
0xfa, 0x87, 0x53, 0x66, 0x15, 0xbb, 0x8e, 0x63,
0x8b, 0xcc, 0x81, 0x66, 0x84, 0x68, 0x17, 0x90,
0x67, 0xcf, 0xa9, 0x8a, 0x9d, 0x0e, 0x33, 0x26 },
{ 0x06, 0xba, 0x7a, 0xe6, 0xf3, 0x24, 0x8c, 0xfd,
0xcf, 0x26, 0x75, 0x07, 0xfa, 0x00, 0x1b, 0xc4 }
};
static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 };
int mbedtls_nist_kw_self_test( int verbose )
{
mbedtls_nist_kw_context ctx;
unsigned char out[48];
size_t olen;
int i;
int ret = 0;
mbedtls_nist_kw_init( &ctx );
for( i = 0; i < KW_TESTS; i++ )
{
if( verbose != 0 )
mbedtls_printf( " KW-AES-%u ", (unsigned int) key_len[i] * 8 );
ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
kw_key[i], key_len[i] * 8, 1 );
if( ret != 0 )
{
if( verbose != 0 )
mbedtls_printf( " KW: setup failed " );
goto end;
}
ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KW, kw_msg[i],
kw_msg_len[i], out, &olen, sizeof( out ) );
if( ret != 0 || kw_out_len[i] != olen ||
memcmp( out, kw_res[i], kw_out_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed. ");
ret = 1;
goto end;
}
if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
kw_key[i], key_len[i] * 8, 0 ) )
!= 0 )
{
if( verbose != 0 )
mbedtls_printf( " KW: setup failed ");
goto end;
}
ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KW,
out, olen, out, &olen, sizeof( out ) );
if( ret != 0 || olen != kw_msg_len[i] ||
memcmp( out, kw_msg[i], kw_msg_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto end;
}
if( verbose != 0 )
mbedtls_printf( " passed\n" );
}
for( i = 0; i < KW_TESTS; i++ )
{
olen = sizeof( out );
if( verbose != 0 )
mbedtls_printf( " KWP-AES-%u ", (unsigned int) key_len[i] * 8 );
ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, kwp_key[i],
key_len[i] * 8, 1 );
if( ret != 0 )
{
if( verbose != 0 )
mbedtls_printf( " KWP: setup failed " );
goto end;
}
ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i],
kwp_msg_len[i], out, &olen, sizeof( out ) );
if( ret != 0 || kwp_out_len[i] != olen ||
memcmp( out, kwp_res[i], kwp_out_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed. ");
ret = 1;
goto end;
}
if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
kwp_key[i], key_len[i] * 8, 0 ) )
!= 0 )
{
if( verbose != 0 )
mbedtls_printf( " KWP: setup failed ");
goto end;
}
ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KWP, out,
olen, out, &olen, sizeof( out ) );
if( ret != 0 || olen != kwp_msg_len[i] ||
memcmp( out, kwp_msg[i], kwp_msg_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed. ");
ret = 1;
goto end;
}
if( verbose != 0 )
mbedtls_printf( " passed\n" );
}
end:
mbedtls_nist_kw_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "\n" );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#endif /* MBEDTLS_NIST_KW_C */

773
library/oid.c Normal file
View File

@ -0,0 +1,773 @@
/**
* \file oid.c
*
* \brief Object Identifier (OID) database
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_OID_C)
#include "mbedtls/oid.h"
#include "mbedtls/rsa.h"
#include "mbedtls/error.h"
#include <stdio.h>
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#define mbedtls_snprintf snprintf
#endif
/*
* Macro to automatically add the size of #define'd OIDs
*/
#define ADD_LEN(s) s, MBEDTLS_OID_SIZE(s)
/*
* Macro to generate an internal function for oid_XXX_from_asn1() (used by
* the other functions)
*/
#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \
static const TYPE_T * oid_ ## NAME ## _from_asn1( \
const mbedtls_asn1_buf *oid ) \
{ \
const TYPE_T *p = (LIST); \
const mbedtls_oid_descriptor_t *cur = \
(const mbedtls_oid_descriptor_t *) p; \
if( p == NULL || oid == NULL ) return( NULL ); \
while( cur->asn1 != NULL ) { \
if( cur->asn1_len == oid->len && \
memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \
return( p ); \
} \
p++; \
cur = (const mbedtls_oid_descriptor_t *) p; \
} \
return( NULL ); \
}
/*
* Macro to generate a function for retrieving a single attribute from the
* descriptor of an mbedtls_oid_descriptor_t wrapper.
*/
#define FN_OID_GET_DESCRIPTOR_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \
int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \
{ \
const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \
*ATTR1 = data->descriptor.ATTR1; \
return( 0 ); \
}
/*
* Macro to generate a function for retrieving a single attribute from an
* mbedtls_oid_descriptor_t wrapper.
*/
#define FN_OID_GET_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \
int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \
{ \
const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \
*ATTR1 = data->ATTR1; \
return( 0 ); \
}
/*
* Macro to generate a function for retrieving two attributes from an
* mbedtls_oid_descriptor_t wrapper.
*/
#define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \
ATTR2_TYPE, ATTR2) \
int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, \
ATTR2_TYPE * ATTR2 ) \
{ \
const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \
*(ATTR1) = data->ATTR1; \
*(ATTR2) = data->ATTR2; \
return( 0 ); \
}
/*
* Macro to generate a function for retrieving the OID based on a single
* attribute from a mbedtls_oid_descriptor_t wrapper.
*/
#define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \
int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \
{ \
const TYPE_T *cur = (LIST); \
while( cur->descriptor.asn1 != NULL ) { \
if( cur->ATTR1 == (ATTR1) ) { \
*oid = cur->descriptor.asn1; \
*olen = cur->descriptor.asn1_len; \
return( 0 ); \
} \
cur++; \
} \
return( MBEDTLS_ERR_OID_NOT_FOUND ); \
}
/*
* Macro to generate a function for retrieving the OID based on two
* attributes from a mbedtls_oid_descriptor_t wrapper.
*/
#define FN_OID_GET_OID_BY_ATTR2(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1, \
ATTR2_TYPE, ATTR2) \
int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \
size_t *olen ) \
{ \
const TYPE_T *cur = (LIST); \
while( cur->descriptor.asn1 != NULL ) { \
if( cur->ATTR1 == (ATTR1) && cur->ATTR2 == (ATTR2) ) { \
*oid = cur->descriptor.asn1; \
*olen = cur->descriptor.asn1_len; \
return( 0 ); \
} \
cur++; \
} \
return( MBEDTLS_ERR_OID_NOT_FOUND ); \
}
/*
* For X520 attribute types
*/
typedef struct {
mbedtls_oid_descriptor_t descriptor;
const char *short_name;
} oid_x520_attr_t;
static const oid_x520_attr_t oid_x520_attr_type[] =
{
{
{ ADD_LEN( MBEDTLS_OID_AT_CN ), "id-at-commonName", "Common Name" },
"CN",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_COUNTRY ), "id-at-countryName", "Country" },
"C",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_LOCALITY ), "id-at-locality", "Locality" },
"L",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_STATE ), "id-at-state", "State" },
"ST",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_ORGANIZATION ),"id-at-organizationName", "Organization" },
"O",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_ORG_UNIT ), "id-at-organizationalUnitName", "Org Unit" },
"OU",
},
{
{ ADD_LEN( MBEDTLS_OID_PKCS9_EMAIL ), "emailAddress", "E-mail address" },
"emailAddress",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_SERIAL_NUMBER ),"id-at-serialNumber", "Serial number" },
"serialNumber",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_POSTAL_ADDRESS ),"id-at-postalAddress", "Postal address" },
"postalAddress",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_POSTAL_CODE ), "id-at-postalCode", "Postal code" },
"postalCode",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_SUR_NAME ), "id-at-surName", "Surname" },
"SN",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_GIVEN_NAME ), "id-at-givenName", "Given name" },
"GN",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_INITIALS ), "id-at-initials", "Initials" },
"initials",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_GENERATION_QUALIFIER ), "id-at-generationQualifier", "Generation qualifier" },
"generationQualifier",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_TITLE ), "id-at-title", "Title" },
"title",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_DN_QUALIFIER ),"id-at-dnQualifier", "Distinguished Name qualifier" },
"dnQualifier",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_PSEUDONYM ), "id-at-pseudonym", "Pseudonym" },
"pseudonym",
},
{
{ ADD_LEN( MBEDTLS_OID_DOMAIN_COMPONENT ), "id-domainComponent", "Domain component" },
"DC",
},
{
{ ADD_LEN( MBEDTLS_OID_AT_UNIQUE_IDENTIFIER ), "id-at-uniqueIdentifier", "Unique Identifier" },
"uniqueIdentifier",
},
{
{ NULL, 0, NULL, NULL },
NULL,
}
};
FN_OID_TYPED_FROM_ASN1(oid_x520_attr_t, x520_attr, oid_x520_attr_type)
FN_OID_GET_ATTR1(mbedtls_oid_get_attr_short_name, oid_x520_attr_t, x520_attr, const char *, short_name)
/*
* For X509 extensions
*/
typedef struct {
mbedtls_oid_descriptor_t descriptor;
int ext_type;
} oid_x509_ext_t;
static const oid_x509_ext_t oid_x509_ext[] =
{
{
{ ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" },
MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS,
},
{
{ ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" },
MBEDTLS_OID_X509_EXT_KEY_USAGE,
},
{
{ ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" },
MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE,
},
{
{ ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" },
MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME,
},
{
{ ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" },
MBEDTLS_OID_X509_EXT_NS_CERT_TYPE,
},
{
{ ADD_LEN( MBEDTLS_OID_CERTIFICATE_POLICIES ), "id-ce-certificatePolicies", "Certificate Policies" },
MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES,
},
{
{ NULL, 0, NULL, NULL },
0,
},
};
FN_OID_TYPED_FROM_ASN1(oid_x509_ext_t, x509_ext, oid_x509_ext)
FN_OID_GET_ATTR1(mbedtls_oid_get_x509_ext_type, oid_x509_ext_t, x509_ext, int, ext_type)
static const mbedtls_oid_descriptor_t oid_ext_key_usage[] =
{
{ ADD_LEN( MBEDTLS_OID_SERVER_AUTH ), "id-kp-serverAuth", "TLS Web Server Authentication" },
{ ADD_LEN( MBEDTLS_OID_CLIENT_AUTH ), "id-kp-clientAuth", "TLS Web Client Authentication" },
{ ADD_LEN( MBEDTLS_OID_CODE_SIGNING ), "id-kp-codeSigning", "Code Signing" },
{ ADD_LEN( MBEDTLS_OID_EMAIL_PROTECTION ), "id-kp-emailProtection", "E-mail Protection" },
{ ADD_LEN( MBEDTLS_OID_TIME_STAMPING ), "id-kp-timeStamping", "Time Stamping" },
{ ADD_LEN( MBEDTLS_OID_OCSP_SIGNING ), "id-kp-OCSPSigning", "OCSP Signing" },
{ ADD_LEN( MBEDTLS_OID_WISUN_FAN ), "id-kp-wisun-fan-device", "Wi-SUN Alliance Field Area Network (FAN)" },
{ NULL, 0, NULL, NULL },
};
FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, ext_key_usage, oid_ext_key_usage)
FN_OID_GET_ATTR1(mbedtls_oid_get_extended_key_usage, mbedtls_oid_descriptor_t, ext_key_usage, const char *, description)
static const mbedtls_oid_descriptor_t oid_certificate_policies[] =
{
{ ADD_LEN( MBEDTLS_OID_ANY_POLICY ), "anyPolicy", "Any Policy" },
{ NULL, 0, NULL, NULL },
};
FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, certificate_policies, oid_certificate_policies)
FN_OID_GET_ATTR1(mbedtls_oid_get_certificate_policies, mbedtls_oid_descriptor_t, certificate_policies, const char *, description)
#if defined(MBEDTLS_MD_C)
/*
* For SignatureAlgorithmIdentifier
*/
typedef struct {
mbedtls_oid_descriptor_t descriptor;
mbedtls_md_type_t md_alg;
mbedtls_pk_type_t pk_alg;
} oid_sig_alg_t;
static const oid_sig_alg_t oid_sig_alg[] =
{
#if defined(MBEDTLS_RSA_C)
#if defined(MBEDTLS_MD2_C)
{
{ ADD_LEN( MBEDTLS_OID_PKCS1_MD2 ), "md2WithRSAEncryption", "RSA with MD2" },
MBEDTLS_MD_MD2, MBEDTLS_PK_RSA,
},
#endif /* MBEDTLS_MD2_C */
#if defined(MBEDTLS_MD4_C)
{
{ ADD_LEN( MBEDTLS_OID_PKCS1_MD4 ), "md4WithRSAEncryption", "RSA with MD4" },
MBEDTLS_MD_MD4, MBEDTLS_PK_RSA,
},
#endif /* MBEDTLS_MD4_C */
#if defined(MBEDTLS_MD5_C)
{
{ ADD_LEN( MBEDTLS_OID_PKCS1_MD5 ), "md5WithRSAEncryption", "RSA with MD5" },
MBEDTLS_MD_MD5, MBEDTLS_PK_RSA,
},
#endif /* MBEDTLS_MD5_C */
#if defined(MBEDTLS_SHA1_C)
{
{ ADD_LEN( MBEDTLS_OID_PKCS1_SHA1 ), "sha-1WithRSAEncryption", "RSA with SHA1" },
MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA,
},
#endif /* MBEDTLS_SHA1_C */
#if defined(MBEDTLS_SHA256_C)
{
{ ADD_LEN( MBEDTLS_OID_PKCS1_SHA224 ), "sha224WithRSAEncryption", "RSA with SHA-224" },
MBEDTLS_MD_SHA224, MBEDTLS_PK_RSA,
},
{
{ ADD_LEN( MBEDTLS_OID_PKCS1_SHA256 ), "sha256WithRSAEncryption", "RSA with SHA-256" },
MBEDTLS_MD_SHA256, MBEDTLS_PK_RSA,
},
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
{
{ ADD_LEN( MBEDTLS_OID_PKCS1_SHA384 ), "sha384WithRSAEncryption", "RSA with SHA-384" },
MBEDTLS_MD_SHA384, MBEDTLS_PK_RSA,
},
{
{ ADD_LEN( MBEDTLS_OID_PKCS1_SHA512 ), "sha512WithRSAEncryption", "RSA with SHA-512" },
MBEDTLS_MD_SHA512, MBEDTLS_PK_RSA,
},
#endif /* MBEDTLS_SHA512_C */
#if defined(MBEDTLS_SHA1_C)
{
{ ADD_LEN( MBEDTLS_OID_RSA_SHA_OBS ), "sha-1WithRSAEncryption", "RSA with SHA1" },
MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA,
},
#endif /* MBEDTLS_SHA1_C */
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_ECDSA_C)
#if defined(MBEDTLS_SHA1_C)
{
{ ADD_LEN( MBEDTLS_OID_ECDSA_SHA1 ), "ecdsa-with-SHA1", "ECDSA with SHA1" },
MBEDTLS_MD_SHA1, MBEDTLS_PK_ECDSA,
},
#endif /* MBEDTLS_SHA1_C */
#if defined(MBEDTLS_SHA256_C)
{
{ ADD_LEN( MBEDTLS_OID_ECDSA_SHA224 ), "ecdsa-with-SHA224", "ECDSA with SHA224" },
MBEDTLS_MD_SHA224, MBEDTLS_PK_ECDSA,
},
{
{ ADD_LEN( MBEDTLS_OID_ECDSA_SHA256 ), "ecdsa-with-SHA256", "ECDSA with SHA256" },
MBEDTLS_MD_SHA256, MBEDTLS_PK_ECDSA,
},
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
{
{ ADD_LEN( MBEDTLS_OID_ECDSA_SHA384 ), "ecdsa-with-SHA384", "ECDSA with SHA384" },
MBEDTLS_MD_SHA384, MBEDTLS_PK_ECDSA,
},
{
{ ADD_LEN( MBEDTLS_OID_ECDSA_SHA512 ), "ecdsa-with-SHA512", "ECDSA with SHA512" },
MBEDTLS_MD_SHA512, MBEDTLS_PK_ECDSA,
},
#endif /* MBEDTLS_SHA512_C */
#endif /* MBEDTLS_ECDSA_C */
#if defined(MBEDTLS_RSA_C)
{
{ ADD_LEN( MBEDTLS_OID_RSASSA_PSS ), "RSASSA-PSS", "RSASSA-PSS" },
MBEDTLS_MD_NONE, MBEDTLS_PK_RSASSA_PSS,
},
#endif /* MBEDTLS_RSA_C */
{
{ NULL, 0, NULL, NULL },
MBEDTLS_MD_NONE, MBEDTLS_PK_NONE,
},
};
FN_OID_TYPED_FROM_ASN1(oid_sig_alg_t, sig_alg, oid_sig_alg)
FN_OID_GET_DESCRIPTOR_ATTR1(mbedtls_oid_get_sig_alg_desc, oid_sig_alg_t, sig_alg, const char *, description)
FN_OID_GET_ATTR2(mbedtls_oid_get_sig_alg, oid_sig_alg_t, sig_alg, mbedtls_md_type_t, md_alg, mbedtls_pk_type_t, pk_alg)
FN_OID_GET_OID_BY_ATTR2(mbedtls_oid_get_oid_by_sig_alg, oid_sig_alg_t, oid_sig_alg, mbedtls_pk_type_t, pk_alg, mbedtls_md_type_t, md_alg)
#endif /* MBEDTLS_MD_C */
/*
* For PublicKeyInfo (PKCS1, RFC 5480)
*/
typedef struct {
mbedtls_oid_descriptor_t descriptor;
mbedtls_pk_type_t pk_alg;
} oid_pk_alg_t;
static const oid_pk_alg_t oid_pk_alg[] =
{
{
{ ADD_LEN( MBEDTLS_OID_PKCS1_RSA ), "rsaEncryption", "RSA" },
MBEDTLS_PK_RSA,
},
{
{ ADD_LEN( MBEDTLS_OID_EC_ALG_UNRESTRICTED ), "id-ecPublicKey", "Generic EC key" },
MBEDTLS_PK_ECKEY,
},
{
{ ADD_LEN( MBEDTLS_OID_EC_ALG_ECDH ), "id-ecDH", "EC key for ECDH" },
MBEDTLS_PK_ECKEY_DH,
},
{
{ NULL, 0, NULL, NULL },
MBEDTLS_PK_NONE,
},
};
FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg)
FN_OID_GET_ATTR1(mbedtls_oid_get_pk_alg, oid_pk_alg_t, pk_alg, mbedtls_pk_type_t, pk_alg)
FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, mbedtls_pk_type_t, pk_alg)
#if defined(MBEDTLS_ECP_C)
/*
* For namedCurve (RFC 5480)
*/
typedef struct {
mbedtls_oid_descriptor_t descriptor;
mbedtls_ecp_group_id grp_id;
} oid_ecp_grp_t;
static const oid_ecp_grp_t oid_ecp_grp[] =
{
#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192R1 ), "secp192r1", "secp192r1" },
MBEDTLS_ECP_DP_SECP192R1,
},
#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224R1 ), "secp224r1", "secp224r1" },
MBEDTLS_ECP_DP_SECP224R1,
},
#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */
#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256R1 ), "secp256r1", "secp256r1" },
MBEDTLS_ECP_DP_SECP256R1,
},
#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */
#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_SECP384R1 ), "secp384r1", "secp384r1" },
MBEDTLS_ECP_DP_SECP384R1,
},
#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */
#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_SECP521R1 ), "secp521r1", "secp521r1" },
MBEDTLS_ECP_DP_SECP521R1,
},
#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */
#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192K1 ), "secp192k1", "secp192k1" },
MBEDTLS_ECP_DP_SECP192K1,
},
#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */
#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224K1 ), "secp224k1", "secp224k1" },
MBEDTLS_ECP_DP_SECP224K1,
},
#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */
#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256K1 ), "secp256k1", "secp256k1" },
MBEDTLS_ECP_DP_SECP256K1,
},
#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */
#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_BP256R1 ), "brainpoolP256r1","brainpool256r1" },
MBEDTLS_ECP_DP_BP256R1,
},
#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */
#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_BP384R1 ), "brainpoolP384r1","brainpool384r1" },
MBEDTLS_ECP_DP_BP384R1,
},
#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */
#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)
{
{ ADD_LEN( MBEDTLS_OID_EC_GRP_BP512R1 ), "brainpoolP512r1","brainpool512r1" },
MBEDTLS_ECP_DP_BP512R1,
},
#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */
{
{ NULL, 0, NULL, NULL },
MBEDTLS_ECP_DP_NONE,
},
};
FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp)
FN_OID_GET_ATTR1(mbedtls_oid_get_ec_grp, oid_ecp_grp_t, grp_id, mbedtls_ecp_group_id, grp_id)
FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, mbedtls_ecp_group_id, grp_id)
#endif /* MBEDTLS_ECP_C */
#if defined(MBEDTLS_CIPHER_C)
/*
* For PKCS#5 PBES2 encryption algorithm
*/
typedef struct {
mbedtls_oid_descriptor_t descriptor;
mbedtls_cipher_type_t cipher_alg;
} oid_cipher_alg_t;
static const oid_cipher_alg_t oid_cipher_alg[] =
{
{
{ ADD_LEN( MBEDTLS_OID_DES_CBC ), "desCBC", "DES-CBC" },
MBEDTLS_CIPHER_DES_CBC,
},
{
{ ADD_LEN( MBEDTLS_OID_DES_EDE3_CBC ), "des-ede3-cbc", "DES-EDE3-CBC" },
MBEDTLS_CIPHER_DES_EDE3_CBC,
},
{
{ NULL, 0, NULL, NULL },
MBEDTLS_CIPHER_NONE,
},
};
FN_OID_TYPED_FROM_ASN1(oid_cipher_alg_t, cipher_alg, oid_cipher_alg)
FN_OID_GET_ATTR1(mbedtls_oid_get_cipher_alg, oid_cipher_alg_t, cipher_alg, mbedtls_cipher_type_t, cipher_alg)
#endif /* MBEDTLS_CIPHER_C */
#if defined(MBEDTLS_MD_C)
/*
* For digestAlgorithm
*/
typedef struct {
mbedtls_oid_descriptor_t descriptor;
mbedtls_md_type_t md_alg;
} oid_md_alg_t;
static const oid_md_alg_t oid_md_alg[] =
{
#if defined(MBEDTLS_MD2_C)
{
{ ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD2 ), "id-md2", "MD2" },
MBEDTLS_MD_MD2,
},
#endif /* MBEDTLS_MD2_C */
#if defined(MBEDTLS_MD4_C)
{
{ ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD4 ), "id-md4", "MD4" },
MBEDTLS_MD_MD4,
},
#endif /* MBEDTLS_MD4_C */
#if defined(MBEDTLS_MD5_C)
{
{ ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD5 ), "id-md5", "MD5" },
MBEDTLS_MD_MD5,
},
#endif /* MBEDTLS_MD5_C */
#if defined(MBEDTLS_SHA1_C)
{
{ ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA1 ), "id-sha1", "SHA-1" },
MBEDTLS_MD_SHA1,
},
#endif /* MBEDTLS_SHA1_C */
#if defined(MBEDTLS_SHA256_C)
{
{ ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA224 ), "id-sha224", "SHA-224" },
MBEDTLS_MD_SHA224,
},
{
{ ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA256 ), "id-sha256", "SHA-256" },
MBEDTLS_MD_SHA256,
},
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
{
{ ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA384 ), "id-sha384", "SHA-384" },
MBEDTLS_MD_SHA384,
},
{
{ ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA512 ), "id-sha512", "SHA-512" },
MBEDTLS_MD_SHA512,
},
#endif /* MBEDTLS_SHA512_C */
#if defined(MBEDTLS_RIPEMD160_C)
{
{ ADD_LEN( MBEDTLS_OID_DIGEST_ALG_RIPEMD160 ), "id-ripemd160", "RIPEMD-160" },
MBEDTLS_MD_RIPEMD160,
},
#endif /* MBEDTLS_RIPEMD160_C */
{
{ NULL, 0, NULL, NULL },
MBEDTLS_MD_NONE,
},
};
FN_OID_TYPED_FROM_ASN1(oid_md_alg_t, md_alg, oid_md_alg)
FN_OID_GET_ATTR1(mbedtls_oid_get_md_alg, oid_md_alg_t, md_alg, mbedtls_md_type_t, md_alg)
FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_md, oid_md_alg_t, oid_md_alg, mbedtls_md_type_t, md_alg)
/*
* For HMAC digestAlgorithm
*/
typedef struct {
mbedtls_oid_descriptor_t descriptor;
mbedtls_md_type_t md_hmac;
} oid_md_hmac_t;
static const oid_md_hmac_t oid_md_hmac[] =
{
#if defined(MBEDTLS_SHA1_C)
{
{ ADD_LEN( MBEDTLS_OID_HMAC_SHA1 ), "hmacSHA1", "HMAC-SHA-1" },
MBEDTLS_MD_SHA1,
},
#endif /* MBEDTLS_SHA1_C */
#if defined(MBEDTLS_SHA256_C)
{
{ ADD_LEN( MBEDTLS_OID_HMAC_SHA224 ), "hmacSHA224", "HMAC-SHA-224" },
MBEDTLS_MD_SHA224,
},
{
{ ADD_LEN( MBEDTLS_OID_HMAC_SHA256 ), "hmacSHA256", "HMAC-SHA-256" },
MBEDTLS_MD_SHA256,
},
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
{
{ ADD_LEN( MBEDTLS_OID_HMAC_SHA384 ), "hmacSHA384", "HMAC-SHA-384" },
MBEDTLS_MD_SHA384,
},
{
{ ADD_LEN( MBEDTLS_OID_HMAC_SHA512 ), "hmacSHA512", "HMAC-SHA-512" },
MBEDTLS_MD_SHA512,
},
#endif /* MBEDTLS_SHA512_C */
{
{ NULL, 0, NULL, NULL },
MBEDTLS_MD_NONE,
},
};
FN_OID_TYPED_FROM_ASN1(oid_md_hmac_t, md_hmac, oid_md_hmac)
FN_OID_GET_ATTR1(mbedtls_oid_get_md_hmac, oid_md_hmac_t, md_hmac, mbedtls_md_type_t, md_hmac)
#endif /* MBEDTLS_MD_C */
#if defined(MBEDTLS_PKCS12_C)
/*
* For PKCS#12 PBEs
*/
typedef struct {
mbedtls_oid_descriptor_t descriptor;
mbedtls_md_type_t md_alg;
mbedtls_cipher_type_t cipher_alg;
} oid_pkcs12_pbe_alg_t;
static const oid_pkcs12_pbe_alg_t oid_pkcs12_pbe_alg[] =
{
{
{ ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC ), "pbeWithSHAAnd3-KeyTripleDES-CBC", "PBE with SHA1 and 3-Key 3DES" },
MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE3_CBC,
},
{
{ ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC ), "pbeWithSHAAnd2-KeyTripleDES-CBC", "PBE with SHA1 and 2-Key 3DES" },
MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE_CBC,
},
{
{ NULL, 0, NULL, NULL },
MBEDTLS_MD_NONE, MBEDTLS_CIPHER_NONE,
},
};
FN_OID_TYPED_FROM_ASN1(oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, oid_pkcs12_pbe_alg)
FN_OID_GET_ATTR2(mbedtls_oid_get_pkcs12_pbe_alg, oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, mbedtls_md_type_t, md_alg, mbedtls_cipher_type_t, cipher_alg)
#endif /* MBEDTLS_PKCS12_C */
#define OID_SAFE_SNPRINTF \
do { \
if( ret < 0 || (size_t) ret >= n ) \
return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); \
\
n -= (size_t) ret; \
p += (size_t) ret; \
} while( 0 )
/* Return the x.y.z.... style numeric string for the given OID */
int mbedtls_oid_get_numeric_string( char *buf, size_t size,
const mbedtls_asn1_buf *oid )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t i, n;
unsigned int value;
char *p;
p = buf;
n = size;
/* First byte contains first two dots */
if( oid->len > 0 )
{
ret = mbedtls_snprintf( p, n, "%d.%d", oid->p[0] / 40, oid->p[0] % 40 );
OID_SAFE_SNPRINTF;
}
value = 0;
for( i = 1; i < oid->len; i++ )
{
/* Prevent overflow in value. */
if( ( ( value << 7 ) >> 7 ) != value )
return( MBEDTLS_ERR_OID_BUF_TOO_SMALL );
value <<= 7;
value += oid->p[i] & 0x7F;
if( !( oid->p[i] & 0x80 ) )
{
/* Last byte */
ret = mbedtls_snprintf( p, n, ".%d", value );
OID_SAFE_SNPRINTF;
value = 0;
}
}
return( (int) ( size - n ) );
}
#endif /* MBEDTLS_OID_C */

170
library/padlock.c Normal file
View File

@ -0,0 +1,170 @@
/*
* VIA PadLock support functions
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* This implementation is based on the VIA PadLock Programming Guide:
*
* http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/
* programming_guide.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PADLOCK_C)
#include "mbedtls/padlock.h"
#include <string.h>
#ifndef asm
#define asm __asm
#endif
#if defined(MBEDTLS_HAVE_X86)
/*
* PadLock detection routine
*/
int mbedtls_padlock_has_support( int feature )
{
static int flags = -1;
int ebx = 0, edx = 0;
if( flags == -1 )
{
asm( "movl %%ebx, %0 \n\t"
"movl $0xC0000000, %%eax \n\t"
"cpuid \n\t"
"cmpl $0xC0000001, %%eax \n\t"
"movl $0, %%edx \n\t"
"jb unsupported \n\t"
"movl $0xC0000001, %%eax \n\t"
"cpuid \n\t"
"unsupported: \n\t"
"movl %%edx, %1 \n\t"
"movl %2, %%ebx \n\t"
: "=m" (ebx), "=m" (edx)
: "m" (ebx)
: "eax", "ecx", "edx" );
flags = edx;
}
return( flags & feature );
}
/*
* PadLock AES-ECB block en(de)cryption
*/
int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] )
{
int ebx = 0;
uint32_t *rk;
uint32_t *blk;
uint32_t *ctrl;
unsigned char buf[256];
rk = ctx->rk;
blk = MBEDTLS_PADLOCK_ALIGN16( buf );
memcpy( blk, input, 16 );
ctrl = blk + 4;
*ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode^1 ) - 10 ) << 9 );
asm( "pushfl \n\t"
"popfl \n\t"
"movl %%ebx, %0 \n\t"
"movl $1, %%ecx \n\t"
"movl %2, %%edx \n\t"
"movl %3, %%ebx \n\t"
"movl %4, %%esi \n\t"
"movl %4, %%edi \n\t"
".byte 0xf3,0x0f,0xa7,0xc8 \n\t"
"movl %1, %%ebx \n\t"
: "=m" (ebx)
: "m" (ebx), "m" (ctrl), "m" (rk), "m" (blk)
: "memory", "ecx", "edx", "esi", "edi" );
memcpy( output, blk, 16 );
return( 0 );
}
/*
* PadLock AES-CBC buffer en(de)cryption
*/
int mbedtls_padlock_xcryptcbc( mbedtls_aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output )
{
int ebx = 0;
size_t count;
uint32_t *rk;
uint32_t *iw;
uint32_t *ctrl;
unsigned char buf[256];
if( ( (long) input & 15 ) != 0 ||
( (long) output & 15 ) != 0 )
return( MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED );
rk = ctx->rk;
iw = MBEDTLS_PADLOCK_ALIGN16( buf );
memcpy( iw, iv, 16 );
ctrl = iw + 4;
*ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode ^ 1 ) - 10 ) << 9 );
count = ( length + 15 ) >> 4;
asm( "pushfl \n\t"
"popfl \n\t"
"movl %%ebx, %0 \n\t"
"movl %2, %%ecx \n\t"
"movl %3, %%edx \n\t"
"movl %4, %%ebx \n\t"
"movl %5, %%esi \n\t"
"movl %6, %%edi \n\t"
"movl %7, %%eax \n\t"
".byte 0xf3,0x0f,0xa7,0xd0 \n\t"
"movl %1, %%ebx \n\t"
: "=m" (ebx)
: "m" (ebx), "m" (count), "m" (ctrl),
"m" (rk), "m" (input), "m" (output), "m" (iw)
: "memory", "eax", "ecx", "edx", "esi", "edi" );
memcpy( iv, iw, 16 );
return( 0 );
}
#endif /* MBEDTLS_HAVE_X86 */
#endif /* MBEDTLS_PADLOCK_C */

491
library/pem.c Normal file
View File

@ -0,0 +1,491 @@
/*
* Privacy Enhanced Mail (PEM) decoding
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C)
#include "mbedtls/pem.h"
#include "mbedtls/base64.h"
#include "mbedtls/des.h"
#include "mbedtls/aes.h"
#include "mbedtls/md5.h"
#include "mbedtls/cipher.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
#if defined(MBEDTLS_PEM_PARSE_C)
void mbedtls_pem_init( mbedtls_pem_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_pem_context ) );
}
#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
/*
* Read a 16-byte hex string and convert it to binary
*/
static int pem_get_iv( const unsigned char *s, unsigned char *iv,
size_t iv_len )
{
size_t i, j, k;
memset( iv, 0, iv_len );
for( i = 0; i < iv_len * 2; i++, s++ )
{
if( *s >= '0' && *s <= '9' ) j = *s - '0'; else
if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else
if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else
return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
k = ( ( i & 1 ) != 0 ) ? j : j << 4;
iv[i >> 1] = (unsigned char)( iv[i >> 1] | k );
}
return( 0 );
}
static int pem_pbkdf1( unsigned char *key, size_t keylen,
unsigned char *iv,
const unsigned char *pwd, size_t pwdlen )
{
mbedtls_md5_context md5_ctx;
unsigned char md5sum[16];
size_t use_len;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_md5_init( &md5_ctx );
/*
* key[ 0..15] = MD5(pwd || IV)
*/
if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 )
goto exit;
if( keylen <= 16 )
{
memcpy( key, md5sum, keylen );
goto exit;
}
memcpy( key, md5sum, 16 );
/*
* key[16..23] = MD5(key[ 0..15] || pwd || IV])
*/
if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md5_update_ret( &md5_ctx, md5sum, 16 ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 )
goto exit;
use_len = 16;
if( keylen < 32 )
use_len = keylen - 16;
memcpy( key + 16, md5sum, use_len );
exit:
mbedtls_md5_free( &md5_ctx );
mbedtls_platform_zeroize( md5sum, 16 );
return( ret );
}
#if defined(MBEDTLS_DES_C)
/*
* Decrypt with DES-CBC, using PBKDF1 for key derivation
*/
static int pem_des_decrypt( unsigned char des_iv[8],
unsigned char *buf, size_t buflen,
const unsigned char *pwd, size_t pwdlen )
{
mbedtls_des_context des_ctx;
unsigned char des_key[8];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_des_init( &des_ctx );
if( ( ret = pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_des_setkey_dec( &des_ctx, des_key ) ) != 0 )
goto exit;
ret = mbedtls_des_crypt_cbc( &des_ctx, MBEDTLS_DES_DECRYPT, buflen,
des_iv, buf, buf );
exit:
mbedtls_des_free( &des_ctx );
mbedtls_platform_zeroize( des_key, 8 );
return( ret );
}
/*
* Decrypt with 3DES-CBC, using PBKDF1 for key derivation
*/
static int pem_des3_decrypt( unsigned char des3_iv[8],
unsigned char *buf, size_t buflen,
const unsigned char *pwd, size_t pwdlen )
{
mbedtls_des3_context des3_ctx;
unsigned char des3_key[24];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_des3_init( &des3_ctx );
if( ( ret = pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_des3_set3key_dec( &des3_ctx, des3_key ) ) != 0 )
goto exit;
ret = mbedtls_des3_crypt_cbc( &des3_ctx, MBEDTLS_DES_DECRYPT, buflen,
des3_iv, buf, buf );
exit:
mbedtls_des3_free( &des3_ctx );
mbedtls_platform_zeroize( des3_key, 24 );
return( ret );
}
#endif /* MBEDTLS_DES_C */
#if defined(MBEDTLS_AES_C)
/*
* Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
*/
static int pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen,
unsigned char *buf, size_t buflen,
const unsigned char *pwd, size_t pwdlen )
{
mbedtls_aes_context aes_ctx;
unsigned char aes_key[32];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_aes_init( &aes_ctx );
if( ( ret = pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ) ) != 0 )
goto exit;
ret = mbedtls_aes_crypt_cbc( &aes_ctx, MBEDTLS_AES_DECRYPT, buflen,
aes_iv, buf, buf );
exit:
mbedtls_aes_free( &aes_ctx );
mbedtls_platform_zeroize( aes_key, keylen );
return( ret );
}
#endif /* MBEDTLS_AES_C */
#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer,
const unsigned char *data, const unsigned char *pwd,
size_t pwdlen, size_t *use_len )
{
int ret, enc;
size_t len;
unsigned char *buf;
const unsigned char *s1, *s2, *end;
#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
unsigned char pem_iv[16];
mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE;
#else
((void) pwd);
((void) pwdlen);
#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
if( ctx == NULL )
return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA );
s1 = (unsigned char *) strstr( (const char *) data, header );
if( s1 == NULL )
return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
s2 = (unsigned char *) strstr( (const char *) data, footer );
if( s2 == NULL || s2 <= s1 )
return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
s1 += strlen( header );
if( *s1 == ' ' ) s1++;
if( *s1 == '\r' ) s1++;
if( *s1 == '\n' ) s1++;
else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
end = s2;
end += strlen( footer );
if( *end == ' ' ) end++;
if( *end == '\r' ) end++;
if( *end == '\n' ) end++;
*use_len = end - data;
enc = 0;
if( s2 - s1 >= 22 && memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
{
#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
enc++;
s1 += 22;
if( *s1 == '\r' ) s1++;
if( *s1 == '\n' ) s1++;
else return( MBEDTLS_ERR_PEM_INVALID_DATA );
#if defined(MBEDTLS_DES_C)
if( s2 - s1 >= 23 && memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 )
{
enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC;
s1 += 23;
if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8 ) != 0 )
return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
s1 += 16;
}
else if( s2 - s1 >= 18 && memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 )
{
enc_alg = MBEDTLS_CIPHER_DES_CBC;
s1 += 18;
if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8) != 0 )
return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
s1 += 16;
}
#endif /* MBEDTLS_DES_C */
#if defined(MBEDTLS_AES_C)
if( s2 - s1 >= 14 && memcmp( s1, "DEK-Info: AES-", 14 ) == 0 )
{
if( s2 - s1 < 22 )
return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG );
else if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 )
enc_alg = MBEDTLS_CIPHER_AES_128_CBC;
else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 )
enc_alg = MBEDTLS_CIPHER_AES_192_CBC;
else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 )
enc_alg = MBEDTLS_CIPHER_AES_256_CBC;
else
return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG );
s1 += 22;
if( s2 - s1 < 32 || pem_get_iv( s1, pem_iv, 16 ) != 0 )
return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
s1 += 32;
}
#endif /* MBEDTLS_AES_C */
if( enc_alg == MBEDTLS_CIPHER_NONE )
return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG );
if( *s1 == '\r' ) s1++;
if( *s1 == '\n' ) s1++;
else return( MBEDTLS_ERR_PEM_INVALID_DATA );
#else
return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE );
#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
}
if( s1 >= s2 )
return( MBEDTLS_ERR_PEM_INVALID_DATA );
ret = mbedtls_base64_decode( NULL, 0, &len, s1, s2 - s1 );
if( ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER )
return( MBEDTLS_ERR_PEM_INVALID_DATA + ret );
if( ( buf = mbedtls_calloc( 1, len ) ) == NULL )
return( MBEDTLS_ERR_PEM_ALLOC_FAILED );
if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 )
{
mbedtls_platform_zeroize( buf, len );
mbedtls_free( buf );
return( MBEDTLS_ERR_PEM_INVALID_DATA + ret );
}
if( enc != 0 )
{
#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
if( pwd == NULL )
{
mbedtls_platform_zeroize( buf, len );
mbedtls_free( buf );
return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED );
}
ret = 0;
#if defined(MBEDTLS_DES_C)
if( enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC )
ret = pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen );
else if( enc_alg == MBEDTLS_CIPHER_DES_CBC )
ret = pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen );
#endif /* MBEDTLS_DES_C */
#if defined(MBEDTLS_AES_C)
if( enc_alg == MBEDTLS_CIPHER_AES_128_CBC )
ret = pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen );
else if( enc_alg == MBEDTLS_CIPHER_AES_192_CBC )
ret = pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen );
else if( enc_alg == MBEDTLS_CIPHER_AES_256_CBC )
ret = pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen );
#endif /* MBEDTLS_AES_C */
if( ret != 0 )
{
mbedtls_free( buf );
return( ret );
}
/*
* The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
* length bytes (allow 4 to be sure) in all known use cases.
*
* Use that as a heuristic to try to detect password mismatches.
*/
if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 )
{
mbedtls_platform_zeroize( buf, len );
mbedtls_free( buf );
return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH );
}
#else
mbedtls_platform_zeroize( buf, len );
mbedtls_free( buf );
return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE );
#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
}
ctx->buf = buf;
ctx->buflen = len;
return( 0 );
}
void mbedtls_pem_free( mbedtls_pem_context *ctx )
{
if ( ctx->buf != NULL )
{
mbedtls_platform_zeroize( ctx->buf, ctx->buflen );
mbedtls_free( ctx->buf );
}
mbedtls_free( ctx->info );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pem_context ) );
}
#endif /* MBEDTLS_PEM_PARSE_C */
#if defined(MBEDTLS_PEM_WRITE_C)
int mbedtls_pem_write_buffer( const char *header, const char *footer,
const unsigned char *der_data, size_t der_len,
unsigned char *buf, size_t buf_len, size_t *olen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char *encode_buf = NULL, *c, *p = buf;
size_t len = 0, use_len, add_len = 0;
mbedtls_base64_encode( NULL, 0, &use_len, der_data, der_len );
add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1;
if( use_len + add_len > buf_len )
{
*olen = use_len + add_len;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
if( use_len != 0 &&
( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL ) )
return( MBEDTLS_ERR_PEM_ALLOC_FAILED );
if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data,
der_len ) ) != 0 )
{
mbedtls_free( encode_buf );
return( ret );
}
memcpy( p, header, strlen( header ) );
p += strlen( header );
c = encode_buf;
while( use_len )
{
len = ( use_len > 64 ) ? 64 : use_len;
memcpy( p, c, len );
use_len -= len;
p += len;
c += len;
*p++ = '\n';
}
memcpy( p, footer, strlen( footer ) );
p += strlen( footer );
*p++ = '\0';
*olen = p - buf;
mbedtls_free( encode_buf );
return( 0 );
}
#endif /* MBEDTLS_PEM_WRITE_C */
#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */

641
library/pk.c Normal file
View File

@ -0,0 +1,641 @@
/*
* Public Key abstraction layer
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PK_C)
#include "mbedtls/pk.h"
#include "mbedtls/pk_internal.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#if defined(MBEDTLS_RSA_C)
#include "mbedtls/rsa.h"
#endif
#if defined(MBEDTLS_ECP_C)
#include "mbedtls/ecp.h"
#endif
#if defined(MBEDTLS_ECDSA_C)
#include "mbedtls/ecdsa.h"
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO)
#include "mbedtls/psa_util.h"
#endif
#include <limits.h>
#include <stdint.h>
/* Parameter validation macros based on platform_util.h */
#define PK_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA )
#define PK_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
/*
* Initialise a mbedtls_pk_context
*/
void mbedtls_pk_init( mbedtls_pk_context *ctx )
{
PK_VALIDATE( ctx != NULL );
ctx->pk_info = NULL;
ctx->pk_ctx = NULL;
}
/*
* Free (the components of) a mbedtls_pk_context
*/
void mbedtls_pk_free( mbedtls_pk_context *ctx )
{
if( ctx == NULL )
return;
if ( ctx->pk_info != NULL )
ctx->pk_info->ctx_free_func( ctx->pk_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pk_context ) );
}
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/*
* Initialize a restart context
*/
void mbedtls_pk_restart_init( mbedtls_pk_restart_ctx *ctx )
{
PK_VALIDATE( ctx != NULL );
ctx->pk_info = NULL;
ctx->rs_ctx = NULL;
}
/*
* Free the components of a restart context
*/
void mbedtls_pk_restart_free( mbedtls_pk_restart_ctx *ctx )
{
if( ctx == NULL || ctx->pk_info == NULL ||
ctx->pk_info->rs_free_func == NULL )
{
return;
}
ctx->pk_info->rs_free_func( ctx->rs_ctx );
ctx->pk_info = NULL;
ctx->rs_ctx = NULL;
}
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
/*
* Get pk_info structure from type
*/
const mbedtls_pk_info_t * mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type )
{
switch( pk_type ) {
#if defined(MBEDTLS_RSA_C)
case MBEDTLS_PK_RSA:
return( &mbedtls_rsa_info );
#endif
#if defined(MBEDTLS_ECP_C)
case MBEDTLS_PK_ECKEY:
return( &mbedtls_eckey_info );
case MBEDTLS_PK_ECKEY_DH:
return( &mbedtls_eckeydh_info );
#endif
#if defined(MBEDTLS_ECDSA_C)
case MBEDTLS_PK_ECDSA:
return( &mbedtls_ecdsa_info );
#endif
/* MBEDTLS_PK_RSA_ALT omitted on purpose */
default:
return( NULL );
}
}
/*
* Initialise context
*/
int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info )
{
PK_VALIDATE_RET( ctx != NULL );
if( info == NULL || ctx->pk_info != NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL )
return( MBEDTLS_ERR_PK_ALLOC_FAILED );
ctx->pk_info = info;
return( 0 );
}
#if defined(MBEDTLS_USE_PSA_CRYPTO)
/*
* Initialise a PSA-wrapping context
*/
int mbedtls_pk_setup_opaque( mbedtls_pk_context *ctx, const psa_key_handle_t key )
{
const mbedtls_pk_info_t * const info = &mbedtls_pk_opaque_info;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_handle_t *pk_ctx;
psa_key_type_t type;
if( ctx == NULL || ctx->pk_info != NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
if( PSA_SUCCESS != psa_get_key_attributes( key, &attributes ) )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
type = psa_get_key_type( &attributes );
psa_reset_key_attributes( &attributes );
/* Current implementation of can_do() relies on this. */
if( ! PSA_KEY_TYPE_IS_ECC_KEY_PAIR( type ) )
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE) ;
if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL )
return( MBEDTLS_ERR_PK_ALLOC_FAILED );
ctx->pk_info = info;
pk_ctx = (psa_key_handle_t *) ctx->pk_ctx;
*pk_ctx = key;
return( 0 );
}
#endif /* MBEDTLS_USE_PSA_CRYPTO */
#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
/*
* Initialize an RSA-alt context
*/
int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key,
mbedtls_pk_rsa_alt_decrypt_func decrypt_func,
mbedtls_pk_rsa_alt_sign_func sign_func,
mbedtls_pk_rsa_alt_key_len_func key_len_func )
{
mbedtls_rsa_alt_context *rsa_alt;
const mbedtls_pk_info_t *info = &mbedtls_rsa_alt_info;
PK_VALIDATE_RET( ctx != NULL );
if( ctx->pk_info != NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL )
return( MBEDTLS_ERR_PK_ALLOC_FAILED );
ctx->pk_info = info;
rsa_alt = (mbedtls_rsa_alt_context *) ctx->pk_ctx;
rsa_alt->key = key;
rsa_alt->decrypt_func = decrypt_func;
rsa_alt->sign_func = sign_func;
rsa_alt->key_len_func = key_len_func;
return( 0 );
}
#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */
/*
* Tell if a PK can do the operations of the given type
*/
int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type )
{
/* A context with null pk_info is not set up yet and can't do anything.
* For backward compatibility, also accept NULL instead of a context
* pointer. */
if( ctx == NULL || ctx->pk_info == NULL )
return( 0 );
return( ctx->pk_info->can_do( type ) );
}
/*
* Helper for mbedtls_pk_sign and mbedtls_pk_verify
*/
static inline int pk_hashlen_helper( mbedtls_md_type_t md_alg, size_t *hash_len )
{
const mbedtls_md_info_t *md_info;
if( *hash_len != 0 )
return( 0 );
if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL )
return( -1 );
*hash_len = mbedtls_md_get_size( md_info );
return( 0 );
}
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/*
* Helper to set up a restart context if needed
*/
static int pk_restart_setup( mbedtls_pk_restart_ctx *ctx,
const mbedtls_pk_info_t *info )
{
/* Don't do anything if already set up or invalid */
if( ctx == NULL || ctx->pk_info != NULL )
return( 0 );
/* Should never happen when we're called */
if( info->rs_alloc_func == NULL || info->rs_free_func == NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
if( ( ctx->rs_ctx = info->rs_alloc_func() ) == NULL )
return( MBEDTLS_ERR_PK_ALLOC_FAILED );
ctx->pk_info = info;
return( 0 );
}
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
/*
* Verify a signature (restartable)
*/
int mbedtls_pk_verify_restartable( mbedtls_pk_context *ctx,
mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
const unsigned char *sig, size_t sig_len,
mbedtls_pk_restart_ctx *rs_ctx )
{
PK_VALIDATE_RET( ctx != NULL );
PK_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && hash_len == 0 ) ||
hash != NULL );
PK_VALIDATE_RET( sig != NULL );
if( ctx->pk_info == NULL ||
pk_hashlen_helper( md_alg, &hash_len ) != 0 )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/* optimization: use non-restartable version if restart disabled */
if( rs_ctx != NULL &&
mbedtls_ecp_restart_is_enabled() &&
ctx->pk_info->verify_rs_func != NULL )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 )
return( ret );
ret = ctx->pk_info->verify_rs_func( ctx->pk_ctx,
md_alg, hash, hash_len, sig, sig_len, rs_ctx->rs_ctx );
if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
mbedtls_pk_restart_free( rs_ctx );
return( ret );
}
#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
(void) rs_ctx;
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
if( ctx->pk_info->verify_func == NULL )
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
return( ctx->pk_info->verify_func( ctx->pk_ctx, md_alg, hash, hash_len,
sig, sig_len ) );
}
/*
* Verify a signature
*/
int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
const unsigned char *sig, size_t sig_len )
{
return( mbedtls_pk_verify_restartable( ctx, md_alg, hash, hash_len,
sig, sig_len, NULL ) );
}
/*
* Verify a signature with options
*/
int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options,
mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
const unsigned char *sig, size_t sig_len )
{
PK_VALIDATE_RET( ctx != NULL );
PK_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && hash_len == 0 ) ||
hash != NULL );
PK_VALIDATE_RET( sig != NULL );
if( ctx->pk_info == NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
if( ! mbedtls_pk_can_do( ctx, type ) )
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
if( type == MBEDTLS_PK_RSASSA_PSS )
{
#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PKCS1_V21)
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
const mbedtls_pk_rsassa_pss_options *pss_opts;
#if SIZE_MAX > UINT_MAX
if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
#endif /* SIZE_MAX > UINT_MAX */
if( options == NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
pss_opts = (const mbedtls_pk_rsassa_pss_options *) options;
if( sig_len < mbedtls_pk_get_len( ctx ) )
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
ret = mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_pk_rsa( *ctx ),
NULL, NULL, MBEDTLS_RSA_PUBLIC,
md_alg, (unsigned int) hash_len, hash,
pss_opts->mgf1_hash_id,
pss_opts->expected_salt_len,
sig );
if( ret != 0 )
return( ret );
if( sig_len > mbedtls_pk_get_len( ctx ) )
return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH );
return( 0 );
#else
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
#endif /* MBEDTLS_RSA_C && MBEDTLS_PKCS1_V21 */
}
/* General case: no options */
if( options != NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
return( mbedtls_pk_verify( ctx, md_alg, hash, hash_len, sig, sig_len ) );
}
/*
* Make a signature (restartable)
*/
int mbedtls_pk_sign_restartable( mbedtls_pk_context *ctx,
mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
unsigned char *sig, size_t *sig_len,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_pk_restart_ctx *rs_ctx )
{
PK_VALIDATE_RET( ctx != NULL );
PK_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && hash_len == 0 ) ||
hash != NULL );
PK_VALIDATE_RET( sig != NULL );
if( ctx->pk_info == NULL ||
pk_hashlen_helper( md_alg, &hash_len ) != 0 )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
/* optimization: use non-restartable version if restart disabled */
if( rs_ctx != NULL &&
mbedtls_ecp_restart_is_enabled() &&
ctx->pk_info->sign_rs_func != NULL )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 )
return( ret );
ret = ctx->pk_info->sign_rs_func( ctx->pk_ctx, md_alg,
hash, hash_len, sig, sig_len, f_rng, p_rng, rs_ctx->rs_ctx );
if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
mbedtls_pk_restart_free( rs_ctx );
return( ret );
}
#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
(void) rs_ctx;
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
if( ctx->pk_info->sign_func == NULL )
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
return( ctx->pk_info->sign_func( ctx->pk_ctx, md_alg, hash, hash_len,
sig, sig_len, f_rng, p_rng ) );
}
/*
* Make a signature
*/
int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
unsigned char *sig, size_t *sig_len,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{
return( mbedtls_pk_sign_restartable( ctx, md_alg, hash, hash_len,
sig, sig_len, f_rng, p_rng, NULL ) );
}
/*
* Decrypt message
*/
int mbedtls_pk_decrypt( mbedtls_pk_context *ctx,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen, size_t osize,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{
PK_VALIDATE_RET( ctx != NULL );
PK_VALIDATE_RET( input != NULL || ilen == 0 );
PK_VALIDATE_RET( output != NULL || osize == 0 );
PK_VALIDATE_RET( olen != NULL );
if( ctx->pk_info == NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
if( ctx->pk_info->decrypt_func == NULL )
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
return( ctx->pk_info->decrypt_func( ctx->pk_ctx, input, ilen,
output, olen, osize, f_rng, p_rng ) );
}
/*
* Encrypt message
*/
int mbedtls_pk_encrypt( mbedtls_pk_context *ctx,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen, size_t osize,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{
PK_VALIDATE_RET( ctx != NULL );
PK_VALIDATE_RET( input != NULL || ilen == 0 );
PK_VALIDATE_RET( output != NULL || osize == 0 );
PK_VALIDATE_RET( olen != NULL );
if( ctx->pk_info == NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
if( ctx->pk_info->encrypt_func == NULL )
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
return( ctx->pk_info->encrypt_func( ctx->pk_ctx, input, ilen,
output, olen, osize, f_rng, p_rng ) );
}
/*
* Check public-private key pair
*/
int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv )
{
PK_VALIDATE_RET( pub != NULL );
PK_VALIDATE_RET( prv != NULL );
if( pub->pk_info == NULL ||
prv->pk_info == NULL )
{
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
}
if( prv->pk_info->check_pair_func == NULL )
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT )
{
if( pub->pk_info->type != MBEDTLS_PK_RSA )
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
}
else
{
if( pub->pk_info != prv->pk_info )
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
}
return( prv->pk_info->check_pair_func( pub->pk_ctx, prv->pk_ctx ) );
}
/*
* Get key size in bits
*/
size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx )
{
/* For backward compatibility, accept NULL or a context that
* isn't set up yet, and return a fake value that should be safe. */
if( ctx == NULL || ctx->pk_info == NULL )
return( 0 );
return( ctx->pk_info->get_bitlen( ctx->pk_ctx ) );
}
/*
* Export debug information
*/
int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items )
{
PK_VALIDATE_RET( ctx != NULL );
if( ctx->pk_info == NULL )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
if( ctx->pk_info->debug_func == NULL )
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
ctx->pk_info->debug_func( ctx->pk_ctx, items );
return( 0 );
}
/*
* Access the PK type name
*/
const char *mbedtls_pk_get_name( const mbedtls_pk_context *ctx )
{
if( ctx == NULL || ctx->pk_info == NULL )
return( "invalid PK" );
return( ctx->pk_info->name );
}
/*
* Access the PK type
*/
mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx )
{
if( ctx == NULL || ctx->pk_info == NULL )
return( MBEDTLS_PK_NONE );
return( ctx->pk_info->type );
}
#if defined(MBEDTLS_USE_PSA_CRYPTO)
/*
* Load the key to a PSA key slot,
* then turn the PK context into a wrapper for that key slot.
*
* Currently only works for EC private keys.
*/
int mbedtls_pk_wrap_as_opaque( mbedtls_pk_context *pk,
psa_key_handle_t *handle,
psa_algorithm_t hash_alg )
{
#if !defined(MBEDTLS_ECP_C)
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
#else
const mbedtls_ecp_keypair *ec;
unsigned char d[MBEDTLS_ECP_MAX_BYTES];
size_t d_len;
psa_ecc_curve_t curve_id;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_type_t key_type;
size_t bits;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* export the private key material in the format PSA wants */
if( mbedtls_pk_get_type( pk ) != MBEDTLS_PK_ECKEY )
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
ec = mbedtls_pk_ec( *pk );
d_len = ( ec->grp.nbits + 7 ) / 8;
if( ( ret = mbedtls_mpi_write_binary( &ec->d, d, d_len ) ) != 0 )
return( ret );
curve_id = mbedtls_ecc_group_to_psa( ec->grp.id, &bits );
key_type = PSA_KEY_TYPE_ECC_KEY_PAIR( curve_id );
/* prepare the key attributes */
psa_set_key_type( &attributes, key_type );
psa_set_key_bits( &attributes, bits );
psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH );
psa_set_key_algorithm( &attributes, PSA_ALG_ECDSA(hash_alg) );
/* import private key into PSA */
if( PSA_SUCCESS != psa_import_key( &attributes, d, d_len, handle ) )
return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
/* make PK context wrap the key slot */
mbedtls_pk_free( pk );
mbedtls_pk_init( pk );
return( mbedtls_pk_setup_opaque( pk, *handle ) );
#endif /* MBEDTLS_ECP_C */
}
#endif /* MBEDTLS_USE_PSA_CRYPTO */
#endif /* MBEDTLS_PK_C */

1063
library/pk_wrap.c Normal file

File diff suppressed because it is too large Load Diff

366
library/pkcs12.c Normal file
View File

@ -0,0 +1,366 @@
/*
* PKCS#12 Personal Information Exchange Syntax
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The PKCS #12 Personal Information Exchange Syntax Standard v1.1
*
* http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf
* ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PKCS12_C)
#include "mbedtls/pkcs12.h"
#include "mbedtls/asn1.h"
#include "mbedtls/cipher.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_ARC4_C)
#include "mbedtls/arc4.h"
#endif
#if defined(MBEDTLS_DES_C)
#include "mbedtls/des.h"
#endif
#if defined(MBEDTLS_ASN1_PARSE_C)
static int pkcs12_parse_pbe_params( mbedtls_asn1_buf *params,
mbedtls_asn1_buf *salt, int *iterations )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char **p = &params->p;
const unsigned char *end = params->p + params->len;
/*
* pkcs-12PbeParams ::= SEQUENCE {
* salt OCTET STRING,
* iterations INTEGER
* }
*
*/
if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) )
return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
if( ( ret = mbedtls_asn1_get_tag( p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret );
salt->p = *p;
*p += salt->len;
if( ( ret = mbedtls_asn1_get_int( p, end, iterations ) ) != 0 )
return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret );
if( *p != end )
return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
#define PKCS12_MAX_PWDLEN 128
static int pkcs12_pbe_derive_key_iv( mbedtls_asn1_buf *pbe_params, mbedtls_md_type_t md_type,
const unsigned char *pwd, size_t pwdlen,
unsigned char *key, size_t keylen,
unsigned char *iv, size_t ivlen )
{
int ret, iterations = 0;
mbedtls_asn1_buf salt;
size_t i;
unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2];
if( pwdlen > PKCS12_MAX_PWDLEN )
return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA );
memset( &salt, 0, sizeof(mbedtls_asn1_buf) );
memset( &unipwd, 0, sizeof(unipwd) );
if( ( ret = pkcs12_parse_pbe_params( pbe_params, &salt,
&iterations ) ) != 0 )
return( ret );
for( i = 0; i < pwdlen; i++ )
unipwd[i * 2 + 1] = pwd[i];
if( ( ret = mbedtls_pkcs12_derivation( key, keylen, unipwd, pwdlen * 2 + 2,
salt.p, salt.len, md_type,
MBEDTLS_PKCS12_DERIVE_KEY, iterations ) ) != 0 )
{
return( ret );
}
if( iv == NULL || ivlen == 0 )
return( 0 );
if( ( ret = mbedtls_pkcs12_derivation( iv, ivlen, unipwd, pwdlen * 2 + 2,
salt.p, salt.len, md_type,
MBEDTLS_PKCS12_DERIVE_IV, iterations ) ) != 0 )
{
return( ret );
}
return( 0 );
}
#undef PKCS12_MAX_PWDLEN
int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode,
const unsigned char *pwd, size_t pwdlen,
const unsigned char *data, size_t len,
unsigned char *output )
{
#if !defined(MBEDTLS_ARC4_C)
((void) pbe_params);
((void) mode);
((void) pwd);
((void) pwdlen);
((void) data);
((void) len);
((void) output);
return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE );
#else
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char key[16];
mbedtls_arc4_context ctx;
((void) mode);
mbedtls_arc4_init( &ctx );
if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, MBEDTLS_MD_SHA1,
pwd, pwdlen,
key, 16, NULL, 0 ) ) != 0 )
{
return( ret );
}
mbedtls_arc4_setup( &ctx, key, 16 );
if( ( ret = mbedtls_arc4_crypt( &ctx, len, data, output ) ) != 0 )
goto exit;
exit:
mbedtls_platform_zeroize( key, sizeof( key ) );
mbedtls_arc4_free( &ctx );
return( ret );
#endif /* MBEDTLS_ARC4_C */
}
int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode,
mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type,
const unsigned char *pwd, size_t pwdlen,
const unsigned char *data, size_t len,
unsigned char *output )
{
int ret, keylen = 0;
unsigned char key[32];
unsigned char iv[16];
const mbedtls_cipher_info_t *cipher_info;
mbedtls_cipher_context_t cipher_ctx;
size_t olen = 0;
cipher_info = mbedtls_cipher_info_from_type( cipher_type );
if( cipher_info == NULL )
return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE );
keylen = cipher_info->key_bitlen / 8;
if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, md_type, pwd, pwdlen,
key, keylen,
iv, cipher_info->iv_size ) ) != 0 )
{
return( ret );
}
mbedtls_cipher_init( &cipher_ctx );
if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 )
goto exit;
if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 )
goto exit;
if( ( ret = mbedtls_cipher_set_iv( &cipher_ctx, iv, cipher_info->iv_size ) ) != 0 )
goto exit;
if( ( ret = mbedtls_cipher_reset( &cipher_ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_cipher_update( &cipher_ctx, data, len,
output, &olen ) ) != 0 )
{
goto exit;
}
if( ( ret = mbedtls_cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 )
ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH;
exit:
mbedtls_platform_zeroize( key, sizeof( key ) );
mbedtls_platform_zeroize( iv, sizeof( iv ) );
mbedtls_cipher_free( &cipher_ctx );
return( ret );
}
#endif /* MBEDTLS_ASN1_PARSE_C */
static void pkcs12_fill_buffer( unsigned char *data, size_t data_len,
const unsigned char *filler, size_t fill_len )
{
unsigned char *p = data;
size_t use_len;
while( data_len > 0 )
{
use_len = ( data_len > fill_len ) ? fill_len : data_len;
memcpy( p, filler, use_len );
p += use_len;
data_len -= use_len;
}
}
int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen,
const unsigned char *pwd, size_t pwdlen,
const unsigned char *salt, size_t saltlen,
mbedtls_md_type_t md_type, int id, int iterations )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned int j;
unsigned char diversifier[128];
unsigned char salt_block[128], pwd_block[128], hash_block[128];
unsigned char hash_output[MBEDTLS_MD_MAX_SIZE];
unsigned char *p;
unsigned char c;
size_t hlen, use_len, v, i;
const mbedtls_md_info_t *md_info;
mbedtls_md_context_t md_ctx;
// This version only allows max of 64 bytes of password or salt
if( datalen > 128 || pwdlen > 64 || saltlen > 64 )
return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA );
md_info = mbedtls_md_info_from_type( md_type );
if( md_info == NULL )
return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE );
mbedtls_md_init( &md_ctx );
if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
return( ret );
hlen = mbedtls_md_get_size( md_info );
if( hlen <= 32 )
v = 64;
else
v = 128;
memset( diversifier, (unsigned char) id, v );
pkcs12_fill_buffer( salt_block, v, salt, saltlen );
pkcs12_fill_buffer( pwd_block, v, pwd, pwdlen );
p = data;
while( datalen > 0 )
{
// Calculate hash( diversifier || salt_block || pwd_block )
if( ( ret = mbedtls_md_starts( &md_ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_update( &md_ctx, diversifier, v ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_update( &md_ctx, salt_block, v ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_update( &md_ctx, pwd_block, v ) ) != 0 )
goto exit;
if( ( ret = mbedtls_md_finish( &md_ctx, hash_output ) ) != 0 )
goto exit;
// Perform remaining ( iterations - 1 ) recursive hash calculations
for( i = 1; i < (size_t) iterations; i++ )
{
if( ( ret = mbedtls_md( md_info, hash_output, hlen, hash_output ) ) != 0 )
goto exit;
}
use_len = ( datalen > hlen ) ? hlen : datalen;
memcpy( p, hash_output, use_len );
datalen -= use_len;
p += use_len;
if( datalen == 0 )
break;
// Concatenating copies of hash_output into hash_block (B)
pkcs12_fill_buffer( hash_block, v, hash_output, hlen );
// B += 1
for( i = v; i > 0; i-- )
if( ++hash_block[i - 1] != 0 )
break;
// salt_block += B
c = 0;
for( i = v; i > 0; i-- )
{
j = salt_block[i - 1] + hash_block[i - 1] + c;
c = (unsigned char) (j >> 8);
salt_block[i - 1] = j & 0xFF;
}
// pwd_block += B
c = 0;
for( i = v; i > 0; i-- )
{
j = pwd_block[i - 1] + hash_block[i - 1] + c;
c = (unsigned char) (j >> 8);
pwd_block[i - 1] = j & 0xFF;
}
}
ret = 0;
exit:
mbedtls_platform_zeroize( salt_block, sizeof( salt_block ) );
mbedtls_platform_zeroize( pwd_block, sizeof( pwd_block ) );
mbedtls_platform_zeroize( hash_block, sizeof( hash_block ) );
mbedtls_platform_zeroize( hash_output, sizeof( hash_output ) );
mbedtls_md_free( &md_ctx );
return( ret );
}
#endif /* MBEDTLS_PKCS12_C */

420
library/pkcs5.c Normal file
View File

@ -0,0 +1,420 @@
/**
* \file pkcs5.c
*
* \brief PKCS#5 functions
*
* \author Mathias Olsson <mathias@kompetensum.com>
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* PKCS#5 includes PBKDF2 and more
*
* http://tools.ietf.org/html/rfc2898 (Specification)
* http://tools.ietf.org/html/rfc6070 (Test vectors)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PKCS5_C)
#include "mbedtls/pkcs5.h"
#include "mbedtls/error.h"
#if defined(MBEDTLS_ASN1_PARSE_C)
#include "mbedtls/asn1.h"
#include "mbedtls/cipher.h"
#include "mbedtls/oid.h"
#endif /* MBEDTLS_ASN1_PARSE_C */
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif
#if defined(MBEDTLS_ASN1_PARSE_C)
static int pkcs5_parse_pbkdf2_params( const mbedtls_asn1_buf *params,
mbedtls_asn1_buf *salt, int *iterations,
int *keylen, mbedtls_md_type_t *md_type )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_asn1_buf prf_alg_oid;
unsigned char *p = params->p;
const unsigned char *end = params->p + params->len;
if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) )
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
/*
* PBKDF2-params ::= SEQUENCE {
* salt OCTET STRING,
* iterationCount INTEGER,
* keyLength INTEGER OPTIONAL
* prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1
* }
*
*/
if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len,
MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
salt->p = p;
p += salt->len;
if( ( ret = mbedtls_asn1_get_int( &p, end, iterations ) ) != 0 )
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
if( p == end )
return( 0 );
if( ( ret = mbedtls_asn1_get_int( &p, end, keylen ) ) != 0 )
{
if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
}
if( p == end )
return( 0 );
if( ( ret = mbedtls_asn1_get_alg_null( &p, end, &prf_alg_oid ) ) != 0 )
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
if( mbedtls_oid_get_md_hmac( &prf_alg_oid, md_type ) != 0 )
return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE );
if( p != end )
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode,
const unsigned char *pwd, size_t pwdlen,
const unsigned char *data, size_t datalen,
unsigned char *output )
{
int ret, iterations = 0, keylen = 0;
unsigned char *p, *end;
mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
mbedtls_asn1_buf salt;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1;
unsigned char key[32], iv[32];
size_t olen = 0;
const mbedtls_md_info_t *md_info;
const mbedtls_cipher_info_t *cipher_info;
mbedtls_md_context_t md_ctx;
mbedtls_cipher_type_t cipher_alg;
mbedtls_cipher_context_t cipher_ctx;
p = pbe_params->p;
end = p + pbe_params->len;
/*
* PBES2-params ::= SEQUENCE {
* keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
* }
*/
if( pbe_params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) )
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
if( ( ret = mbedtls_asn1_get_alg( &p, end, &kdf_alg_oid,
&kdf_alg_params ) ) != 0 )
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
// Only PBKDF2 supported at the moment
//
if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid ) != 0 )
return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE );
if( ( ret = pkcs5_parse_pbkdf2_params( &kdf_alg_params,
&salt, &iterations, &keylen,
&md_type ) ) != 0 )
{
return( ret );
}
md_info = mbedtls_md_info_from_type( md_type );
if( md_info == NULL )
return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE );
if( ( ret = mbedtls_asn1_get_alg( &p, end, &enc_scheme_oid,
&enc_scheme_params ) ) != 0 )
{
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
}
if( mbedtls_oid_get_cipher_alg( &enc_scheme_oid, &cipher_alg ) != 0 )
return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE );
cipher_info = mbedtls_cipher_info_from_type( cipher_alg );
if( cipher_info == NULL )
return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE );
/*
* The value of keylen from pkcs5_parse_pbkdf2_params() is ignored
* since it is optional and we don't know if it was set or not
*/
keylen = cipher_info->key_bitlen / 8;
if( enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING ||
enc_scheme_params.len != cipher_info->iv_size )
{
return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT );
}
mbedtls_md_init( &md_ctx );
mbedtls_cipher_init( &cipher_ctx );
memcpy( iv, enc_scheme_params.p, enc_scheme_params.len );
if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 )
goto exit;
if( ( ret = mbedtls_pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len,
iterations, keylen, key ) ) != 0 )
{
goto exit;
}
if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 )
goto exit;
if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen,
(mbedtls_operation_t) mode ) ) != 0 )
goto exit;
if( ( ret = mbedtls_cipher_crypt( &cipher_ctx, iv, enc_scheme_params.len,
data, datalen, output, &olen ) ) != 0 )
ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH;
exit:
mbedtls_md_free( &md_ctx );
mbedtls_cipher_free( &cipher_ctx );
return( ret );
}
#endif /* MBEDTLS_ASN1_PARSE_C */
int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx,
const unsigned char *password,
size_t plen, const unsigned char *salt, size_t slen,
unsigned int iteration_count,
uint32_t key_length, unsigned char *output )
{
int ret, j;
unsigned int i;
unsigned char md1[MBEDTLS_MD_MAX_SIZE];
unsigned char work[MBEDTLS_MD_MAX_SIZE];
unsigned char md_size = mbedtls_md_get_size( ctx->md_info );
size_t use_len;
unsigned char *out_p = output;
unsigned char counter[4];
memset( counter, 0, 4 );
counter[3] = 1;
#if UINT_MAX > 0xFFFFFFFF
if( iteration_count > 0xFFFFFFFF )
return( MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA );
#endif
if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 )
return( ret );
while( key_length )
{
// U1 ends up in work
//
if( ( ret = mbedtls_md_hmac_update( ctx, salt, slen ) ) != 0 )
return( ret );
if( ( ret = mbedtls_md_hmac_update( ctx, counter, 4 ) ) != 0 )
return( ret );
if( ( ret = mbedtls_md_hmac_finish( ctx, work ) ) != 0 )
return( ret );
if( ( ret = mbedtls_md_hmac_reset( ctx ) ) != 0 )
return( ret );
memcpy( md1, work, md_size );
for( i = 1; i < iteration_count; i++ )
{
// U2 ends up in md1
//
if( ( ret = mbedtls_md_hmac_update( ctx, md1, md_size ) ) != 0 )
return( ret );
if( ( ret = mbedtls_md_hmac_finish( ctx, md1 ) ) != 0 )
return( ret );
if( ( ret = mbedtls_md_hmac_reset( ctx ) ) != 0 )
return( ret );
// U1 xor U2
//
for( j = 0; j < md_size; j++ )
work[j] ^= md1[j];
}
use_len = ( key_length < md_size ) ? key_length : md_size;
memcpy( out_p, work, use_len );
key_length -= (uint32_t) use_len;
out_p += use_len;
for( i = 4; i > 0; i-- )
if( ++counter[i - 1] != 0 )
break;
}
return( 0 );
}
#if defined(MBEDTLS_SELF_TEST)
#if !defined(MBEDTLS_SHA1_C)
int mbedtls_pkcs5_self_test( int verbose )
{
if( verbose != 0 )
mbedtls_printf( " PBKDF2 (SHA1): skipped\n\n" );
return( 0 );
}
#else
#define MAX_TESTS 6
static const size_t plen_test_data[MAX_TESTS] =
{ 8, 8, 8, 24, 9 };
static const unsigned char password_test_data[MAX_TESTS][32] =
{
"password",
"password",
"password",
"passwordPASSWORDpassword",
"pass\0word",
};
static const size_t slen_test_data[MAX_TESTS] =
{ 4, 4, 4, 36, 5 };
static const unsigned char salt_test_data[MAX_TESTS][40] =
{
"salt",
"salt",
"salt",
"saltSALTsaltSALTsaltSALTsaltSALTsalt",
"sa\0lt",
};
static const uint32_t it_cnt_test_data[MAX_TESTS] =
{ 1, 2, 4096, 4096, 4096 };
static const uint32_t key_len_test_data[MAX_TESTS] =
{ 20, 20, 20, 25, 16 };
static const unsigned char result_key_test_data[MAX_TESTS][32] =
{
{ 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
0x2f, 0xe0, 0x37, 0xa6 },
{ 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
0xd8, 0xde, 0x89, 0x57 },
{ 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
0x65, 0xa4, 0x29, 0xc1 },
{ 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
0x38 },
{ 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 },
};
int mbedtls_pkcs5_self_test( int verbose )
{
mbedtls_md_context_t sha1_ctx;
const mbedtls_md_info_t *info_sha1;
int ret, i;
unsigned char key[64];
mbedtls_md_init( &sha1_ctx );
info_sha1 = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 );
if( info_sha1 == NULL )
{
ret = 1;
goto exit;
}
if( ( ret = mbedtls_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0 )
{
ret = 1;
goto exit;
}
for( i = 0; i < MAX_TESTS; i++ )
{
if( verbose != 0 )
mbedtls_printf( " PBKDF2 (SHA1) #%d: ", i );
ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, password_test_data[i],
plen_test_data[i], salt_test_data[i],
slen_test_data[i], it_cnt_test_data[i],
key_len_test_data[i], key );
if( ret != 0 ||
memcmp( result_key_test_data[i], key, key_len_test_data[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
exit:
mbedtls_md_free( &sha1_ctx );
return( ret );
}
#endif /* MBEDTLS_SHA1_C */
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_PKCS5_C */

1539
library/pkparse.c Normal file

File diff suppressed because it is too large Load Diff

629
library/pkwrite.c Normal file
View File

@ -0,0 +1,629 @@
/*
* Public Key layer for writing key files and structures
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PK_WRITE_C)
#include "mbedtls/pk.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/oid.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_RSA_C)
#include "mbedtls/rsa.h"
#endif
#if defined(MBEDTLS_ECP_C)
#include "mbedtls/bignum.h"
#include "mbedtls/ecp.h"
#include "mbedtls/platform_util.h"
#endif
#if defined(MBEDTLS_ECDSA_C)
#include "mbedtls/ecdsa.h"
#endif
#if defined(MBEDTLS_PEM_WRITE_C)
#include "mbedtls/pem.h"
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO)
#include "psa/crypto.h"
#include "mbedtls/psa_util.h"
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
/* Parameter validation macros based on platform_util.h */
#define PK_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA )
#define PK_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#if defined(MBEDTLS_RSA_C)
/*
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
* publicExponent INTEGER -- e
* }
*/
static int pk_write_rsa_pubkey( unsigned char **p, unsigned char *start,
mbedtls_rsa_context *rsa )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
mbedtls_mpi T;
mbedtls_mpi_init( &T );
/* Export E */
if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, NULL, NULL, &T ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( p, start, &T ) ) < 0 )
goto end_of_export;
len += ret;
/* Export N */
if ( ( ret = mbedtls_rsa_export( rsa, &T, NULL, NULL, NULL, NULL ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( p, start, &T ) ) < 0 )
goto end_of_export;
len += ret;
end_of_export:
mbedtls_mpi_free( &T );
if( ret < 0 )
return( ret );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE ) );
return( (int) len );
}
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_ECP_C)
/*
* EC public key is an EC point
*/
static int pk_write_ec_pubkey( unsigned char **p, unsigned char *start,
mbedtls_ecp_keypair *ec )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN];
if( ( ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q,
MBEDTLS_ECP_PF_UNCOMPRESSED,
&len, buf, sizeof( buf ) ) ) != 0 )
{
return( ret );
}
if( *p < start || (size_t)( *p - start ) < len )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*p -= len;
memcpy( *p, buf, len );
return( (int) len );
}
/*
* ECParameters ::= CHOICE {
* namedCurve OBJECT IDENTIFIER
* }
*/
static int pk_write_ec_param( unsigned char **p, unsigned char *start,
mbedtls_ecp_keypair *ec )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
const char *oid;
size_t oid_len;
if( ( ret = mbedtls_oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 )
return( ret );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
return( (int) len );
}
/*
* privateKey OCTET STRING -- always of length ceil(log2(n)/8)
*/
static int pk_write_ec_private( unsigned char **p, unsigned char *start,
mbedtls_ecp_keypair *ec )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t byte_length = ( ec->grp.pbits + 7 ) / 8;
unsigned char tmp[MBEDTLS_ECP_MAX_BYTES];
ret = mbedtls_mpi_write_binary( &ec->d, tmp, byte_length );
if( ret != 0 )
goto exit;
ret = mbedtls_asn1_write_octet_string( p, start, tmp, byte_length );
exit:
mbedtls_platform_zeroize( tmp, byte_length );
return( ret );
}
#endif /* MBEDTLS_ECP_C */
int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start,
const mbedtls_pk_context *key )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
PK_VALIDATE_RET( p != NULL );
PK_VALIDATE_RET( *p != NULL );
PK_VALIDATE_RET( start != NULL );
PK_VALIDATE_RET( key != NULL );
#if defined(MBEDTLS_RSA_C)
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA )
MBEDTLS_ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, mbedtls_pk_rsa( *key ) ) );
else
#endif
#if defined(MBEDTLS_ECP_C)
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY )
MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_pubkey( p, start, mbedtls_pk_ec( *key ) ) );
else
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO)
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_OPAQUE )
{
size_t buffer_size;
psa_key_handle_t* key_slot = (psa_key_handle_t*) key->pk_ctx;
if ( *p < start )
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
buffer_size = (size_t)( *p - start );
if ( psa_export_public_key( *key_slot, start, buffer_size, &len )
!= PSA_SUCCESS )
{
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
}
else
{
*p -= len;
memmove( *p, start, len );
}
}
else
#endif /* MBEDTLS_USE_PSA_CRYPTO */
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
return( (int) len );
}
int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, size_t size )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char *c;
size_t len = 0, par_len = 0, oid_len;
mbedtls_pk_type_t pk_type;
const char *oid;
PK_VALIDATE_RET( key != NULL );
if( size == 0 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
PK_VALIDATE_RET( buf != NULL );
c = buf + size;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, key ) );
if( c - buf < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
/*
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING }
*/
*--c = 0;
len += 1;
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) );
pk_type = mbedtls_pk_get_type( key );
#if defined(MBEDTLS_ECP_C)
if( pk_type == MBEDTLS_PK_ECKEY )
{
MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) );
}
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO)
if( pk_type == MBEDTLS_PK_OPAQUE )
{
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_type_t key_type;
psa_key_handle_t handle;
psa_ecc_curve_t curve;
size_t bits;
handle = *((psa_key_handle_t*) key->pk_ctx );
if( PSA_SUCCESS != psa_get_key_attributes( handle, &attributes ) )
return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
key_type = psa_get_key_type( &attributes );
bits = psa_get_key_bits( &attributes );
psa_reset_key_attributes( &attributes );
curve = PSA_KEY_TYPE_GET_CURVE( key_type );
if( curve == 0 )
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
ret = mbedtls_psa_get_ecc_oid_from_id( curve, bits, &oid, &oid_len );
if( ret != 0 )
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
/* Write EC algorithm parameters; that's akin
* to pk_write_ec_param() above. */
MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_oid( &c, buf,
oid, oid_len ) );
/* The rest of the function works as for legacy EC contexts. */
pk_type = MBEDTLS_PK_ECKEY;
}
#endif /* MBEDTLS_USE_PSA_CRYPTO */
if( ( ret = mbedtls_oid_get_oid_by_pk_alg( pk_type, &oid,
&oid_len ) ) != 0 )
{
return( ret );
}
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, buf, oid, oid_len,
par_len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE ) );
return( (int) len );
}
int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_t size )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char *c;
size_t len = 0;
PK_VALIDATE_RET( key != NULL );
if( size == 0 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
PK_VALIDATE_RET( buf != NULL );
c = buf + size;
#if defined(MBEDTLS_RSA_C)
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA )
{
mbedtls_mpi T; /* Temporary holding the exported parameters */
mbedtls_rsa_context *rsa = mbedtls_pk_rsa( *key );
/*
* Export the parameters one after another to avoid simultaneous copies.
*/
mbedtls_mpi_init( &T );
/* Export QP */
if( ( ret = mbedtls_rsa_export_crt( rsa, NULL, NULL, &T ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 )
goto end_of_export;
len += ret;
/* Export DQ */
if( ( ret = mbedtls_rsa_export_crt( rsa, NULL, &T, NULL ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 )
goto end_of_export;
len += ret;
/* Export DP */
if( ( ret = mbedtls_rsa_export_crt( rsa, &T, NULL, NULL ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 )
goto end_of_export;
len += ret;
/* Export Q */
if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL,
&T, NULL, NULL ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 )
goto end_of_export;
len += ret;
/* Export P */
if ( ( ret = mbedtls_rsa_export( rsa, NULL, &T,
NULL, NULL, NULL ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 )
goto end_of_export;
len += ret;
/* Export D */
if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL,
NULL, &T, NULL ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 )
goto end_of_export;
len += ret;
/* Export E */
if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL,
NULL, NULL, &T ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 )
goto end_of_export;
len += ret;
/* Export N */
if ( ( ret = mbedtls_rsa_export( rsa, &T, NULL,
NULL, NULL, NULL ) ) != 0 ||
( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 )
goto end_of_export;
len += ret;
end_of_export:
mbedtls_mpi_free( &T );
if( ret < 0 )
return( ret );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 0 ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c,
buf, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE ) );
}
else
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_ECP_C)
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY )
{
mbedtls_ecp_keypair *ec = mbedtls_pk_ec( *key );
size_t pub_len = 0, par_len = 0;
/*
* RFC 5915, or SEC1 Appendix C.4
*
* ECPrivateKey ::= SEQUENCE {
* version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
* privateKey OCTET STRING,
* parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
* publicKey [1] BIT STRING OPTIONAL
* }
*/
/* publicKey */
MBEDTLS_ASN1_CHK_ADD( pub_len, pk_write_ec_pubkey( &c, buf, ec ) );
if( c - buf < 1 )
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
*--c = 0;
pub_len += 1;
MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) );
MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) );
MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) );
MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) );
len += pub_len;
/* parameters */
MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, ec ) );
MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_len( &c, buf, par_len ) );
MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_tag( &c, buf,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) );
len += par_len;
/* privateKey */
MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_private( &c, buf, ec ) );
/* version */
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 1 ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE ) );
}
else
#endif /* MBEDTLS_ECP_C */
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
return( (int) len );
}
#if defined(MBEDTLS_PEM_WRITE_C)
#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n"
#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n"
#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n"
#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n"
#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n"
#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n"
/*
* Max sizes of key per types. Shown as tag + len (+ content).
*/
#if defined(MBEDTLS_RSA_C)
/*
* RSA public keys:
* SubjectPublicKeyInfo ::= SEQUENCE { 1 + 3
* algorithm AlgorithmIdentifier, 1 + 1 (sequence)
* + 1 + 1 + 9 (rsa oid)
* + 1 + 1 (params null)
* subjectPublicKey BIT STRING } 1 + 3 + (1 + below)
* RSAPublicKey ::= SEQUENCE { 1 + 3
* modulus INTEGER, -- n 1 + 3 + MPI_MAX + 1
* publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1
* }
*/
#define RSA_PUB_DER_MAX_BYTES 38 + 2 * MBEDTLS_MPI_MAX_SIZE
/*
* RSA private keys:
* RSAPrivateKey ::= SEQUENCE { 1 + 3
* version Version, 1 + 1 + 1
* modulus INTEGER, 1 + 3 + MPI_MAX + 1
* publicExponent INTEGER, 1 + 3 + MPI_MAX + 1
* privateExponent INTEGER, 1 + 3 + MPI_MAX + 1
* prime1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1
* prime2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1
* exponent1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1
* exponent2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1
* coefficient INTEGER, 1 + 3 + MPI_MAX / 2 + 1
* otherPrimeInfos OtherPrimeInfos OPTIONAL 0 (not supported)
* }
*/
#define MPI_MAX_SIZE_2 MBEDTLS_MPI_MAX_SIZE / 2 + \
MBEDTLS_MPI_MAX_SIZE % 2
#define RSA_PRV_DER_MAX_BYTES 47 + 3 * MBEDTLS_MPI_MAX_SIZE \
+ 5 * MPI_MAX_SIZE_2
#else /* MBEDTLS_RSA_C */
#define RSA_PUB_DER_MAX_BYTES 0
#define RSA_PRV_DER_MAX_BYTES 0
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_ECP_C)
/*
* EC public keys:
* SubjectPublicKeyInfo ::= SEQUENCE { 1 + 2
* algorithm AlgorithmIdentifier, 1 + 1 (sequence)
* + 1 + 1 + 7 (ec oid)
* + 1 + 1 + 9 (namedCurve oid)
* subjectPublicKey BIT STRING 1 + 2 + 1 [1]
* + 1 (point format) [1]
* + 2 * ECP_MAX (coords) [1]
* }
*/
#define ECP_PUB_DER_MAX_BYTES 30 + 2 * MBEDTLS_ECP_MAX_BYTES
/*
* EC private keys:
* ECPrivateKey ::= SEQUENCE { 1 + 2
* version INTEGER , 1 + 1 + 1
* privateKey OCTET STRING, 1 + 1 + ECP_MAX
* parameters [0] ECParameters OPTIONAL, 1 + 1 + (1 + 1 + 9)
* publicKey [1] BIT STRING OPTIONAL 1 + 2 + [1] above
* }
*/
#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES
#else /* MBEDTLS_ECP_C */
#define ECP_PUB_DER_MAX_BYTES 0
#define ECP_PRV_DER_MAX_BYTES 0
#endif /* MBEDTLS_ECP_C */
#define PUB_DER_MAX_BYTES RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES
#define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \
RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES
int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char output_buf[PUB_DER_MAX_BYTES];
size_t olen = 0;
PK_VALIDATE_RET( key != NULL );
PK_VALIDATE_RET( buf != NULL || size == 0 );
if( ( ret = mbedtls_pk_write_pubkey_der( key, output_buf,
sizeof(output_buf) ) ) < 0 )
{
return( ret );
}
if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
output_buf + sizeof(output_buf) - ret,
ret, buf, size, &olen ) ) != 0 )
{
return( ret );
}
return( 0 );
}
int mbedtls_pk_write_key_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char output_buf[PRV_DER_MAX_BYTES];
const char *begin, *end;
size_t olen = 0;
PK_VALIDATE_RET( key != NULL );
PK_VALIDATE_RET( buf != NULL || size == 0 );
if( ( ret = mbedtls_pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 )
return( ret );
#if defined(MBEDTLS_RSA_C)
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA )
{
begin = PEM_BEGIN_PRIVATE_KEY_RSA;
end = PEM_END_PRIVATE_KEY_RSA;
}
else
#endif
#if defined(MBEDTLS_ECP_C)
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY )
{
begin = PEM_BEGIN_PRIVATE_KEY_EC;
end = PEM_END_PRIVATE_KEY_EC;
}
else
#endif
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
if( ( ret = mbedtls_pem_write_buffer( begin, end,
output_buf + sizeof(output_buf) - ret,
ret, buf, size, &olen ) ) != 0 )
{
return( ret );
}
return( 0 );
}
#endif /* MBEDTLS_PEM_WRITE_C */
#endif /* MBEDTLS_PK_WRITE_C */

392
library/platform.c Normal file
View File

@ -0,0 +1,392 @@
/*
* Platform abstraction layer
*
* Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
/* The compile time configuration of memory allocation via the macros
* MBEDTLS_PLATFORM_{FREE/CALLOC}_MACRO takes precedence over the runtime
* configuration via mbedtls_platform_set_calloc_free(). So, omit everything
* related to the latter if MBEDTLS_PLATFORM_{FREE/CALLOC}_MACRO are defined. */
#if defined(MBEDTLS_PLATFORM_MEMORY) && \
!( defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && \
defined(MBEDTLS_PLATFORM_FREE_MACRO) )
#if !defined(MBEDTLS_PLATFORM_STD_CALLOC)
static void *platform_calloc_uninit( size_t n, size_t size )
{
((void) n);
((void) size);
return( NULL );
}
#define MBEDTLS_PLATFORM_STD_CALLOC platform_calloc_uninit
#endif /* !MBEDTLS_PLATFORM_STD_CALLOC */
#if !defined(MBEDTLS_PLATFORM_STD_FREE)
static void platform_free_uninit( void *ptr )
{
((void) ptr);
}
#define MBEDTLS_PLATFORM_STD_FREE platform_free_uninit
#endif /* !MBEDTLS_PLATFORM_STD_FREE */
static void * (*mbedtls_calloc_func)( size_t, size_t ) = MBEDTLS_PLATFORM_STD_CALLOC;
static void (*mbedtls_free_func)( void * ) = MBEDTLS_PLATFORM_STD_FREE;
void * mbedtls_calloc( size_t nmemb, size_t size )
{
return (*mbedtls_calloc_func)( nmemb, size );
}
void mbedtls_free( void * ptr )
{
(*mbedtls_free_func)( ptr );
}
int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ),
void (*free_func)( void * ) )
{
mbedtls_calloc_func = calloc_func;
mbedtls_free_func = free_func;
return( 0 );
}
#endif /* MBEDTLS_PLATFORM_MEMORY &&
!( defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&
defined(MBEDTLS_PLATFORM_FREE_MACRO) ) */
#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_SNPRINTF)
#include <stdarg.h>
int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
va_list argp;
va_start( argp, fmt );
ret = mbedtls_vsnprintf( s, n, fmt, argp );
va_end( argp );
return( ret );
}
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
/*
* Make dummy function to prevent NULL pointer dereferences
*/
static int platform_snprintf_uninit( char * s, size_t n,
const char * format, ... )
{
((void) s);
((void) n);
((void) format);
return( 0 );
}
#define MBEDTLS_PLATFORM_STD_SNPRINTF platform_snprintf_uninit
#endif /* !MBEDTLS_PLATFORM_STD_SNPRINTF */
int (*mbedtls_snprintf)( char * s, size_t n,
const char * format,
... ) = MBEDTLS_PLATFORM_STD_SNPRINTF;
int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n,
const char * format,
... ) )
{
mbedtls_snprintf = snprintf_func;
return( 0 );
}
#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_VSNPRINTF)
#include <stdarg.h>
int mbedtls_platform_win32_vsnprintf( char *s, size_t n, const char *fmt, va_list arg )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* Avoid calling the invalid parameter handler by checking ourselves */
if( s == NULL || n == 0 || fmt == NULL )
return( -1 );
#if defined(_TRUNCATE)
ret = vsnprintf_s( s, n, _TRUNCATE, fmt, arg );
#else
ret = vsnprintf( s, n, fmt, arg );
if( ret < 0 || (size_t) ret == n )
{
s[n-1] = '\0';
ret = -1;
}
#endif
return( ret );
}
#endif
#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT)
#if !defined(MBEDTLS_PLATFORM_STD_VSNPRINTF)
/*
* Make dummy function to prevent NULL pointer dereferences
*/
static int platform_vsnprintf_uninit( char * s, size_t n,
const char * format, va_list arg )
{
((void) s);
((void) n);
((void) format);
((void) arg);
return( -1 );
}
#define MBEDTLS_PLATFORM_STD_VSNPRINTF platform_vsnprintf_uninit
#endif /* !MBEDTLS_PLATFORM_STD_VSNPRINTF */
int (*mbedtls_vsnprintf)( char * s, size_t n,
const char * format,
va_list arg ) = MBEDTLS_PLATFORM_STD_VSNPRINTF;
int mbedtls_platform_set_vsnprintf( int (*vsnprintf_func)( char * s, size_t n,
const char * format,
va_list arg ) )
{
mbedtls_vsnprintf = vsnprintf_func;
return( 0 );
}
#endif /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_PRINTF_ALT)
#if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
/*
* Make dummy function to prevent NULL pointer dereferences
*/
static int platform_printf_uninit( const char *format, ... )
{
((void) format);
return( 0 );
}
#define MBEDTLS_PLATFORM_STD_PRINTF platform_printf_uninit
#endif /* !MBEDTLS_PLATFORM_STD_PRINTF */
int (*mbedtls_printf)( const char *, ... ) = MBEDTLS_PLATFORM_STD_PRINTF;
int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) )
{
mbedtls_printf = printf_func;
return( 0 );
}
#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF)
/*
* Make dummy function to prevent NULL pointer dereferences
*/
static int platform_fprintf_uninit( FILE *stream, const char *format, ... )
{
((void) stream);
((void) format);
return( 0 );
}
#define MBEDTLS_PLATFORM_STD_FPRINTF platform_fprintf_uninit
#endif /* !MBEDTLS_PLATFORM_STD_FPRINTF */
int (*mbedtls_fprintf)( FILE *, const char *, ... ) =
MBEDTLS_PLATFORM_STD_FPRINTF;
int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *, const char *, ... ) )
{
mbedtls_fprintf = fprintf_func;
return( 0 );
}
#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_EXIT_ALT)
#if !defined(MBEDTLS_PLATFORM_STD_EXIT)
/*
* Make dummy function to prevent NULL pointer dereferences
*/
static void platform_exit_uninit( int status )
{
((void) status);
}
#define MBEDTLS_PLATFORM_STD_EXIT platform_exit_uninit
#endif /* !MBEDTLS_PLATFORM_STD_EXIT */
void (*mbedtls_exit)( int status ) = MBEDTLS_PLATFORM_STD_EXIT;
int mbedtls_platform_set_exit( void (*exit_func)( int status ) )
{
mbedtls_exit = exit_func;
return( 0 );
}
#endif /* MBEDTLS_PLATFORM_EXIT_ALT */
#if defined(MBEDTLS_HAVE_TIME)
#if defined(MBEDTLS_PLATFORM_TIME_ALT)
#if !defined(MBEDTLS_PLATFORM_STD_TIME)
/*
* Make dummy function to prevent NULL pointer dereferences
*/
static mbedtls_time_t platform_time_uninit( mbedtls_time_t* timer )
{
((void) timer);
return( 0 );
}
#define MBEDTLS_PLATFORM_STD_TIME platform_time_uninit
#endif /* !MBEDTLS_PLATFORM_STD_TIME */
mbedtls_time_t (*mbedtls_time)( mbedtls_time_t* timer ) = MBEDTLS_PLATFORM_STD_TIME;
int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* timer ) )
{
mbedtls_time = time_func;
return( 0 );
}
#endif /* MBEDTLS_PLATFORM_TIME_ALT */
#endif /* MBEDTLS_HAVE_TIME */
#if defined(MBEDTLS_ENTROPY_NV_SEED)
#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO)
/* Default implementations for the platform independent seed functions use
* standard libc file functions to read from and write to a pre-defined filename
*/
int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len )
{
FILE *file;
size_t n;
if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL )
return( -1 );
if( ( n = fread( buf, 1, buf_len, file ) ) != buf_len )
{
fclose( file );
mbedtls_platform_zeroize( buf, buf_len );
return( -1 );
}
fclose( file );
return( (int)n );
}
int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len )
{
FILE *file;
size_t n;
if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL )
return -1;
if( ( n = fwrite( buf, 1, buf_len, file ) ) != buf_len )
{
fclose( file );
return -1;
}
fclose( file );
return( (int)n );
}
#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ)
/*
* Make dummy function to prevent NULL pointer dereferences
*/
static int platform_nv_seed_read_uninit( unsigned char *buf, size_t buf_len )
{
((void) buf);
((void) buf_len);
return( -1 );
}
#define MBEDTLS_PLATFORM_STD_NV_SEED_READ platform_nv_seed_read_uninit
#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_READ */
#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE)
/*
* Make dummy function to prevent NULL pointer dereferences
*/
static int platform_nv_seed_write_uninit( unsigned char *buf, size_t buf_len )
{
((void) buf);
((void) buf_len);
return( -1 );
}
#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE platform_nv_seed_write_uninit
#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_WRITE */
int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ) =
MBEDTLS_PLATFORM_STD_NV_SEED_READ;
int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ) =
MBEDTLS_PLATFORM_STD_NV_SEED_WRITE;
int mbedtls_platform_set_nv_seed(
int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ),
int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len ) )
{
mbedtls_nv_seed_read = nv_seed_read_func;
mbedtls_nv_seed_write = nv_seed_write_func;
return( 0 );
}
#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
#endif /* MBEDTLS_ENTROPY_NV_SEED */
#if !defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT)
/*
* Placeholder platform setup that does nothing by default
*/
int mbedtls_platform_setup( mbedtls_platform_context *ctx )
{
(void)ctx;
return( 0 );
}
/*
* Placeholder platform teardown that does nothing by default
*/
void mbedtls_platform_teardown( mbedtls_platform_context *ctx )
{
(void)ctx;
}
#endif /* MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */
#endif /* MBEDTLS_PLATFORM_C */

139
library/platform_util.c Normal file
View File

@ -0,0 +1,139 @@
/*
* Common and shared functions used by multiple modules in the Mbed TLS
* library.
*
* Copyright (C) 2018, Arm Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
/*
* Ensure gmtime_r is available even with -std=c99; must be defined before
* config.h, which pulls in glibc's features.h. Harmless on other platforms.
*/
#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200112L
#endif
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "mbedtls/platform_util.h"
#include "mbedtls/platform.h"
#include "mbedtls/threading.h"
#include <stddef.h>
#include <string.h>
#if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT)
/*
* This implementation should never be optimized out by the compiler
*
* This implementation for mbedtls_platform_zeroize() was inspired from Colin
* Percival's blog article at:
*
* http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html
*
* It uses a volatile function pointer to the standard memset(). Because the
* pointer is volatile the compiler expects it to change at
* any time and will not optimize out the call that could potentially perform
* other operations on the input buffer instead of just setting it to 0.
* Nevertheless, as pointed out by davidtgoldblatt on Hacker News
* (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for
* details), optimizations of the following form are still possible:
*
* if( memset_func != memset )
* memset_func( buf, 0, len );
*
* Note that it is extremely difficult to guarantee that
* mbedtls_platform_zeroize() will not be optimized out by aggressive compilers
* in a portable way. For this reason, Mbed TLS also provides the configuration
* option MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure
* mbedtls_platform_zeroize() to use a suitable implementation for their
* platform and needs.
*/
static void * (* const volatile memset_func)( void *, int, size_t ) = memset;
void mbedtls_platform_zeroize( void *buf, size_t len )
{
MBEDTLS_INTERNAL_VALIDATE( len == 0 || buf != NULL );
if( len > 0 )
memset_func( buf, 0, len );
}
#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */
#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
#include <time.h>
#if !defined(_WIN32) && (defined(unix) || \
defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
defined(__MACH__)))
#include <unistd.h>
#endif /* !_WIN32 && (unix || __unix || __unix__ ||
* (__APPLE__ && __MACH__)) */
#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
/*
* This is a convenience shorthand macro to avoid checking the long
* preprocessor conditions above. Ideally, we could expose this macro in
* platform_util.h and simply use it in platform_util.c, threading.c and
* threading.h. However, this macro is not part of the Mbed TLS public API, so
* we keep it private by only defining it in this file
*/
#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
#define PLATFORM_UTIL_USE_GMTIME
#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
struct tm *tm_buf )
{
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
return( ( gmtime_s( tm_buf, tt ) == 0 ) ? tm_buf : NULL );
#elif !defined(PLATFORM_UTIL_USE_GMTIME)
return( gmtime_r( tt, tm_buf ) );
#else
struct tm *lt;
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 )
return( NULL );
#endif /* MBEDTLS_THREADING_C */
lt = gmtime( tt );
if( lt != NULL )
{
memcpy( tm_buf, lt, sizeof( struct tm ) );
}
#if defined(MBEDTLS_THREADING_C)
if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 )
return( NULL );
#endif /* MBEDTLS_THREADING_C */
return( ( lt == NULL ) ? NULL : tm_buf );
#endif /* _WIN32 && !EFIX64 && !EFI32 */
}
#endif /* MBEDTLS_HAVE_TIME_DATE && MBEDTLS_PLATFORM_GMTIME_R_ALT */

560
library/poly1305.c Normal file
View File

@ -0,0 +1,560 @@
/**
* \file poly1305.c
*
* \brief Poly1305 authentication algorithm.
*
* Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_POLY1305_C)
#include "mbedtls/poly1305.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_POLY1305_ALT)
#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
!defined(inline) && !defined(__cplusplus)
#define inline __inline
#endif
/* Parameter validation macros */
#define POLY1305_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA )
#define POLY1305_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#define POLY1305_BLOCK_SIZE_BYTES ( 16U )
#define BYTES_TO_U32_LE( data, offset ) \
( (uint32_t) (data)[offset] \
| (uint32_t) ( (uint32_t) (data)[( offset ) + 1] << 8 ) \
| (uint32_t) ( (uint32_t) (data)[( offset ) + 2] << 16 ) \
| (uint32_t) ( (uint32_t) (data)[( offset ) + 3] << 24 ) \
)
/*
* Our implementation is tuned for 32-bit platforms with a 64-bit multiplier.
* However we provided an alternative for platforms without such a multiplier.
*/
#if defined(MBEDTLS_NO_64BIT_MULTIPLICATION)
static uint64_t mul64( uint32_t a, uint32_t b )
{
/* a = al + 2**16 ah, b = bl + 2**16 bh */
const uint16_t al = (uint16_t) a;
const uint16_t bl = (uint16_t) b;
const uint16_t ah = a >> 16;
const uint16_t bh = b >> 16;
/* ab = al*bl + 2**16 (ah*bl + bl*bh) + 2**32 ah*bh */
const uint32_t lo = (uint32_t) al * bl;
const uint64_t me = (uint64_t)( (uint32_t) ah * bl ) + (uint32_t) al * bh;
const uint32_t hi = (uint32_t) ah * bh;
return( lo + ( me << 16 ) + ( (uint64_t) hi << 32 ) );
}
#else
static inline uint64_t mul64( uint32_t a, uint32_t b )
{
return( (uint64_t) a * b );
}
#endif
/**
* \brief Process blocks with Poly1305.
*
* \param ctx The Poly1305 context.
* \param nblocks Number of blocks to process. Note that this
* function only processes full blocks.
* \param input Buffer containing the input block(s).
* \param needs_padding Set to 0 if the padding bit has already been
* applied to the input data before calling this
* function. Otherwise, set this parameter to 1.
*/
static void poly1305_process( mbedtls_poly1305_context *ctx,
size_t nblocks,
const unsigned char *input,
uint32_t needs_padding )
{
uint64_t d0, d1, d2, d3;
uint32_t acc0, acc1, acc2, acc3, acc4;
uint32_t r0, r1, r2, r3;
uint32_t rs1, rs2, rs3;
size_t offset = 0U;
size_t i;
r0 = ctx->r[0];
r1 = ctx->r[1];
r2 = ctx->r[2];
r3 = ctx->r[3];
rs1 = r1 + ( r1 >> 2U );
rs2 = r2 + ( r2 >> 2U );
rs3 = r3 + ( r3 >> 2U );
acc0 = ctx->acc[0];
acc1 = ctx->acc[1];
acc2 = ctx->acc[2];
acc3 = ctx->acc[3];
acc4 = ctx->acc[4];
/* Process full blocks */
for( i = 0U; i < nblocks; i++ )
{
/* The input block is treated as a 128-bit little-endian integer */
d0 = BYTES_TO_U32_LE( input, offset + 0 );
d1 = BYTES_TO_U32_LE( input, offset + 4 );
d2 = BYTES_TO_U32_LE( input, offset + 8 );
d3 = BYTES_TO_U32_LE( input, offset + 12 );
/* Compute: acc += (padded) block as a 130-bit integer */
d0 += (uint64_t) acc0;
d1 += (uint64_t) acc1 + ( d0 >> 32U );
d2 += (uint64_t) acc2 + ( d1 >> 32U );
d3 += (uint64_t) acc3 + ( d2 >> 32U );
acc0 = (uint32_t) d0;
acc1 = (uint32_t) d1;
acc2 = (uint32_t) d2;
acc3 = (uint32_t) d3;
acc4 += (uint32_t) ( d3 >> 32U ) + needs_padding;
/* Compute: acc *= r */
d0 = mul64( acc0, r0 ) +
mul64( acc1, rs3 ) +
mul64( acc2, rs2 ) +
mul64( acc3, rs1 );
d1 = mul64( acc0, r1 ) +
mul64( acc1, r0 ) +
mul64( acc2, rs3 ) +
mul64( acc3, rs2 ) +
mul64( acc4, rs1 );
d2 = mul64( acc0, r2 ) +
mul64( acc1, r1 ) +
mul64( acc2, r0 ) +
mul64( acc3, rs3 ) +
mul64( acc4, rs2 );
d3 = mul64( acc0, r3 ) +
mul64( acc1, r2 ) +
mul64( acc2, r1 ) +
mul64( acc3, r0 ) +
mul64( acc4, rs3 );
acc4 *= r0;
/* Compute: acc %= (2^130 - 5) (partial remainder) */
d1 += ( d0 >> 32 );
d2 += ( d1 >> 32 );
d3 += ( d2 >> 32 );
acc0 = (uint32_t) d0;
acc1 = (uint32_t) d1;
acc2 = (uint32_t) d2;
acc3 = (uint32_t) d3;
acc4 = (uint32_t) ( d3 >> 32 ) + acc4;
d0 = (uint64_t) acc0 + ( acc4 >> 2 ) + ( acc4 & 0xFFFFFFFCU );
acc4 &= 3U;
acc0 = (uint32_t) d0;
d0 = (uint64_t) acc1 + ( d0 >> 32U );
acc1 = (uint32_t) d0;
d0 = (uint64_t) acc2 + ( d0 >> 32U );
acc2 = (uint32_t) d0;
d0 = (uint64_t) acc3 + ( d0 >> 32U );
acc3 = (uint32_t) d0;
d0 = (uint64_t) acc4 + ( d0 >> 32U );
acc4 = (uint32_t) d0;
offset += POLY1305_BLOCK_SIZE_BYTES;
}
ctx->acc[0] = acc0;
ctx->acc[1] = acc1;
ctx->acc[2] = acc2;
ctx->acc[3] = acc3;
ctx->acc[4] = acc4;
}
/**
* \brief Compute the Poly1305 MAC
*
* \param ctx The Poly1305 context.
* \param mac The buffer to where the MAC is written. Must be
* big enough to contain the 16-byte MAC.
*/
static void poly1305_compute_mac( const mbedtls_poly1305_context *ctx,
unsigned char mac[16] )
{
uint64_t d;
uint32_t g0, g1, g2, g3, g4;
uint32_t acc0, acc1, acc2, acc3, acc4;
uint32_t mask;
uint32_t mask_inv;
acc0 = ctx->acc[0];
acc1 = ctx->acc[1];
acc2 = ctx->acc[2];
acc3 = ctx->acc[3];
acc4 = ctx->acc[4];
/* Before adding 's' we ensure that the accumulator is mod 2^130 - 5.
* We do this by calculating acc - (2^130 - 5), then checking if
* the 131st bit is set. If it is, then reduce: acc -= (2^130 - 5)
*/
/* Calculate acc + -(2^130 - 5) */
d = ( (uint64_t) acc0 + 5U );
g0 = (uint32_t) d;
d = ( (uint64_t) acc1 + ( d >> 32 ) );
g1 = (uint32_t) d;
d = ( (uint64_t) acc2 + ( d >> 32 ) );
g2 = (uint32_t) d;
d = ( (uint64_t) acc3 + ( d >> 32 ) );
g3 = (uint32_t) d;
g4 = acc4 + (uint32_t) ( d >> 32U );
/* mask == 0xFFFFFFFF if 131st bit is set, otherwise mask == 0 */
mask = (uint32_t) 0U - ( g4 >> 2U );
mask_inv = ~mask;
/* If 131st bit is set then acc=g, otherwise, acc is unmodified */
acc0 = ( acc0 & mask_inv ) | ( g0 & mask );
acc1 = ( acc1 & mask_inv ) | ( g1 & mask );
acc2 = ( acc2 & mask_inv ) | ( g2 & mask );
acc3 = ( acc3 & mask_inv ) | ( g3 & mask );
/* Add 's' */
d = (uint64_t) acc0 + ctx->s[0];
acc0 = (uint32_t) d;
d = (uint64_t) acc1 + ctx->s[1] + ( d >> 32U );
acc1 = (uint32_t) d;
d = (uint64_t) acc2 + ctx->s[2] + ( d >> 32U );
acc2 = (uint32_t) d;
acc3 += ctx->s[3] + (uint32_t) ( d >> 32U );
/* Compute MAC (128 least significant bits of the accumulator) */
mac[ 0] = (unsigned char)( acc0 );
mac[ 1] = (unsigned char)( acc0 >> 8 );
mac[ 2] = (unsigned char)( acc0 >> 16 );
mac[ 3] = (unsigned char)( acc0 >> 24 );
mac[ 4] = (unsigned char)( acc1 );
mac[ 5] = (unsigned char)( acc1 >> 8 );
mac[ 6] = (unsigned char)( acc1 >> 16 );
mac[ 7] = (unsigned char)( acc1 >> 24 );
mac[ 8] = (unsigned char)( acc2 );
mac[ 9] = (unsigned char)( acc2 >> 8 );
mac[10] = (unsigned char)( acc2 >> 16 );
mac[11] = (unsigned char)( acc2 >> 24 );
mac[12] = (unsigned char)( acc3 );
mac[13] = (unsigned char)( acc3 >> 8 );
mac[14] = (unsigned char)( acc3 >> 16 );
mac[15] = (unsigned char)( acc3 >> 24 );
}
void mbedtls_poly1305_init( mbedtls_poly1305_context *ctx )
{
POLY1305_VALIDATE( ctx != NULL );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_poly1305_context ) );
}
void mbedtls_poly1305_free( mbedtls_poly1305_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_poly1305_context ) );
}
int mbedtls_poly1305_starts( mbedtls_poly1305_context *ctx,
const unsigned char key[32] )
{
POLY1305_VALIDATE_RET( ctx != NULL );
POLY1305_VALIDATE_RET( key != NULL );
/* r &= 0x0ffffffc0ffffffc0ffffffc0fffffff */
ctx->r[0] = BYTES_TO_U32_LE( key, 0 ) & 0x0FFFFFFFU;
ctx->r[1] = BYTES_TO_U32_LE( key, 4 ) & 0x0FFFFFFCU;
ctx->r[2] = BYTES_TO_U32_LE( key, 8 ) & 0x0FFFFFFCU;
ctx->r[3] = BYTES_TO_U32_LE( key, 12 ) & 0x0FFFFFFCU;
ctx->s[0] = BYTES_TO_U32_LE( key, 16 );
ctx->s[1] = BYTES_TO_U32_LE( key, 20 );
ctx->s[2] = BYTES_TO_U32_LE( key, 24 );
ctx->s[3] = BYTES_TO_U32_LE( key, 28 );
/* Initial accumulator state */
ctx->acc[0] = 0U;
ctx->acc[1] = 0U;
ctx->acc[2] = 0U;
ctx->acc[3] = 0U;
ctx->acc[4] = 0U;
/* Queue initially empty */
mbedtls_platform_zeroize( ctx->queue, sizeof( ctx->queue ) );
ctx->queue_len = 0U;
return( 0 );
}
int mbedtls_poly1305_update( mbedtls_poly1305_context *ctx,
const unsigned char *input,
size_t ilen )
{
size_t offset = 0U;
size_t remaining = ilen;
size_t queue_free_len;
size_t nblocks;
POLY1305_VALIDATE_RET( ctx != NULL );
POLY1305_VALIDATE_RET( ilen == 0 || input != NULL );
if( ( remaining > 0U ) && ( ctx->queue_len > 0U ) )
{
queue_free_len = ( POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len );
if( ilen < queue_free_len )
{
/* Not enough data to complete the block.
* Store this data with the other leftovers.
*/
memcpy( &ctx->queue[ctx->queue_len],
input,
ilen );
ctx->queue_len += ilen;
remaining = 0U;
}
else
{
/* Enough data to produce a complete block */
memcpy( &ctx->queue[ctx->queue_len],
input,
queue_free_len );
ctx->queue_len = 0U;
poly1305_process( ctx, 1U, ctx->queue, 1U ); /* add padding bit */
offset += queue_free_len;
remaining -= queue_free_len;
}
}
if( remaining >= POLY1305_BLOCK_SIZE_BYTES )
{
nblocks = remaining / POLY1305_BLOCK_SIZE_BYTES;
poly1305_process( ctx, nblocks, &input[offset], 1U );
offset += nblocks * POLY1305_BLOCK_SIZE_BYTES;
remaining %= POLY1305_BLOCK_SIZE_BYTES;
}
if( remaining > 0U )
{
/* Store partial block */
ctx->queue_len = remaining;
memcpy( ctx->queue, &input[offset], remaining );
}
return( 0 );
}
int mbedtls_poly1305_finish( mbedtls_poly1305_context *ctx,
unsigned char mac[16] )
{
POLY1305_VALIDATE_RET( ctx != NULL );
POLY1305_VALIDATE_RET( mac != NULL );
/* Process any leftover data */
if( ctx->queue_len > 0U )
{
/* Add padding bit */
ctx->queue[ctx->queue_len] = 1U;
ctx->queue_len++;
/* Pad with zeroes */
memset( &ctx->queue[ctx->queue_len],
0,
POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len );
poly1305_process( ctx, 1U, /* Process 1 block */
ctx->queue, 0U ); /* Already padded above */
}
poly1305_compute_mac( ctx, mac );
return( 0 );
}
int mbedtls_poly1305_mac( const unsigned char key[32],
const unsigned char *input,
size_t ilen,
unsigned char mac[16] )
{
mbedtls_poly1305_context ctx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
POLY1305_VALIDATE_RET( key != NULL );
POLY1305_VALIDATE_RET( mac != NULL );
POLY1305_VALIDATE_RET( ilen == 0 || input != NULL );
mbedtls_poly1305_init( &ctx );
ret = mbedtls_poly1305_starts( &ctx, key );
if( ret != 0 )
goto cleanup;
ret = mbedtls_poly1305_update( &ctx, input, ilen );
if( ret != 0 )
goto cleanup;
ret = mbedtls_poly1305_finish( &ctx, mac );
cleanup:
mbedtls_poly1305_free( &ctx );
return( ret );
}
#endif /* MBEDTLS_POLY1305_ALT */
#if defined(MBEDTLS_SELF_TEST)
static const unsigned char test_keys[2][32] =
{
{
0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33,
0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8,
0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd,
0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b
},
{
0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0
}
};
static const unsigned char test_data[2][127] =
{
{
0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x67, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x46, 0x6f,
0x72, 0x75, 0x6d, 0x20, 0x52, 0x65, 0x73, 0x65,
0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6f,
0x75, 0x70
},
{
0x27, 0x54, 0x77, 0x61, 0x73, 0x20, 0x62, 0x72,
0x69, 0x6c, 0x6c, 0x69, 0x67, 0x2c, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
0x6c, 0x69, 0x74, 0x68, 0x79, 0x20, 0x74, 0x6f,
0x76, 0x65, 0x73, 0x0a, 0x44, 0x69, 0x64, 0x20,
0x67, 0x79, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64,
0x20, 0x67, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x20,
0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77,
0x61, 0x62, 0x65, 0x3a, 0x0a, 0x41, 0x6c, 0x6c,
0x20, 0x6d, 0x69, 0x6d, 0x73, 0x79, 0x20, 0x77,
0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20,
0x62, 0x6f, 0x72, 0x6f, 0x67, 0x6f, 0x76, 0x65,
0x73, 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x74,
0x68, 0x65, 0x20, 0x6d, 0x6f, 0x6d, 0x65, 0x20,
0x72, 0x61, 0x74, 0x68, 0x73, 0x20, 0x6f, 0x75,
0x74, 0x67, 0x72, 0x61, 0x62, 0x65, 0x2e
}
};
static const size_t test_data_len[2] =
{
34U,
127U
};
static const unsigned char test_mac[2][16] =
{
{
0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6,
0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9
},
{
0x45, 0x41, 0x66, 0x9a, 0x7e, 0xaa, 0xee, 0x61,
0xe7, 0x08, 0xdc, 0x7c, 0xbc, 0xc5, 0xeb, 0x62
}
};
#define ASSERT( cond, args ) \
do \
{ \
if( ! ( cond ) ) \
{ \
if( verbose != 0 ) \
mbedtls_printf args; \
\
return( -1 ); \
} \
} \
while( 0 )
int mbedtls_poly1305_self_test( int verbose )
{
unsigned char mac[16];
unsigned i;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
for( i = 0U; i < 2U; i++ )
{
if( verbose != 0 )
mbedtls_printf( " Poly1305 test %u ", i );
ret = mbedtls_poly1305_mac( test_keys[i],
test_data[i],
test_data_len[i],
mac );
ASSERT( 0 == ret, ( "error code: %i\n", ret ) );
ASSERT( 0 == memcmp( mac, test_mac[i], 16U ), ( "failed (mac)\n" ) );
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_POLY1305_C */

5854
library/psa_crypto.c Normal file

File diff suppressed because it is too large Load Diff

175
library/psa_crypto_core.h Normal file
View File

@ -0,0 +1,175 @@
/*
* PSA crypto core internal interfaces
*/
/* Copyright (C) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef PSA_CRYPTO_CORE_H
#define PSA_CRYPTO_CORE_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "psa/crypto.h"
#include "psa/crypto_se_driver.h"
#include "mbedtls/ecp.h"
#include "mbedtls/rsa.h"
/** The data structure representing a key slot, containing key material
* and metadata for one key.
*/
typedef struct
{
psa_core_key_attributes_t attr;
union
{
/* Raw-data key (key_type_is_raw_bytes() in psa_crypto.c) */
struct raw_data
{
uint8_t *data;
size_t bytes;
} raw;
#if defined(MBEDTLS_RSA_C)
/* RSA public key or key pair */
mbedtls_rsa_context *rsa;
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_ECP_C)
/* EC public key or key pair */
mbedtls_ecp_keypair *ecp;
#endif /* MBEDTLS_ECP_C */
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* Any key type in a secure element */
struct se
{
psa_key_slot_number_t slot_number;
} se;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
} data;
} psa_key_slot_t;
/* A mask of key attribute flags used only internally.
* Currently there aren't any. */
#define PSA_KA_MASK_INTERNAL_ONLY ( \
0 )
/** Test whether a key slot is occupied.
*
* A key slot is occupied iff the key type is nonzero. This works because
* no valid key can have 0 as its key type.
*
* \param[in] slot The key slot to test.
*
* \return 1 if the slot is occupied, 0 otherwise.
*/
static inline int psa_is_key_slot_occupied( const psa_key_slot_t *slot )
{
return( slot->attr.type != 0 );
}
/** Retrieve flags from psa_key_slot_t::attr::core::flags.
*
* \param[in] slot The key slot to query.
* \param mask The mask of bits to extract.
*
* \return The key attribute flags in the given slot,
* bitwise-anded with \p mask.
*/
static inline uint16_t psa_key_slot_get_flags( const psa_key_slot_t *slot,
uint16_t mask )
{
return( slot->attr.flags & mask );
}
/** Set flags in psa_key_slot_t::attr::core::flags.
*
* \param[in,out] slot The key slot to modify.
* \param mask The mask of bits to modify.
* \param value The new value of the selected bits.
*/
static inline void psa_key_slot_set_flags( psa_key_slot_t *slot,
uint16_t mask,
uint16_t value )
{
slot->attr.flags = ( ( ~mask & slot->attr.flags ) |
( mask & value ) );
}
/** Turn on flags in psa_key_slot_t::attr::core::flags.
*
* \param[in,out] slot The key slot to modify.
* \param mask The mask of bits to set.
*/
static inline void psa_key_slot_set_bits_in_flags( psa_key_slot_t *slot,
uint16_t mask )
{
slot->attr.flags |= mask;
}
/** Turn off flags in psa_key_slot_t::attr::core::flags.
*
* \param[in,out] slot The key slot to modify.
* \param mask The mask of bits to clear.
*/
static inline void psa_key_slot_clear_bits( psa_key_slot_t *slot,
uint16_t mask )
{
slot->attr.flags &= ~mask;
}
/** Completely wipe a slot in memory, including its policy.
*
* Persistent storage is not affected.
*
* \param[in,out] slot The key slot to wipe.
*
* \retval PSA_SUCCESS
* Success. This includes the case of a key slot that was
* already fully wiped.
* \retval PSA_ERROR_CORRUPTION_DETECTED
*/
psa_status_t psa_wipe_key_slot( psa_key_slot_t *slot );
/** Import key data into a slot.
*
* `slot->type` must have been set previously.
* This function assumes that the slot does not contain any key material yet.
* On failure, the slot content is unchanged.
*
* Persistent storage is not affected.
*
* \param[in,out] slot The key slot to import data into.
* Its `type` field must have previously been set to
* the desired key type.
* It must not contain any key material yet.
* \param[in] data Buffer containing the key material to parse and import.
* \param data_length Size of \p data in bytes.
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_INVALID_ARGUMENT
* \retval PSA_ERROR_NOT_SUPPORTED
* \retval PSA_ERROR_INSUFFICIENT_MEMORY
*/
psa_status_t psa_import_key_into_slot( psa_key_slot_t *slot,
const uint8_t *data,
size_t data_length );
#endif /* PSA_CRYPTO_CORE_H */

View File

@ -0,0 +1,79 @@
/**
* \file psa_crypto_invasive.h
*
* \brief PSA cryptography module: invasive interfaces for test only.
*
* The interfaces in this file are intended for testing purposes only.
* They MUST NOT be made available to clients over IPC in integrations
* with isolation, and they SHOULD NOT be made available in library
* integrations except when building the library for testing.
*/
/*
* Copyright (C) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef PSA_CRYPTO_INVASIVE_H
#define PSA_CRYPTO_INVASIVE_H
#if defined(MBEDTLS_CONFIG_FILE)
#include MBEDTLS_CONFIG_FILE
#else
#include "mbedtls/config.h"
#endif
#include "psa/crypto.h"
#include "mbedtls/entropy.h"
/** \brief Configure entropy sources.
*
* This function may only be called before a call to psa_crypto_init(),
* or after a call to mbedtls_psa_crypto_free() and before any
* subsequent call to psa_crypto_init().
*
* This function is only intended for test purposes. The functionality
* it provides is also useful for system integrators, but
* system integrators should configure entropy drivers instead of
* breaking through to the Mbed TLS API.
*
* \param entropy_init Function to initialize the entropy context
* and set up the desired entropy sources.
* It is called by psa_crypto_init().
* By default this is mbedtls_entropy_init().
* This function cannot report failures directly.
* To indicate a failure, set the entropy context
* to a state where mbedtls_entropy_func() will
* return an error.
* \param entropy_free Function to free the entropy context
* and associated resources.
* It is called by mbedtls_psa_crypto_free().
* By default this is mbedtls_entropy_free().
*
* \retval PSA_SUCCESS
* Success.
* \retval PSA_ERROR_NOT_PERMITTED
* The caller does not have the permission to configure
* entropy sources.
* \retval PSA_ERROR_BAD_STATE
* The library has already been initialized.
*/
psa_status_t mbedtls_psa_crypto_configure_entropy_sources(
void (* entropy_init )( mbedtls_entropy_context *ctx ),
void (* entropy_free )( mbedtls_entropy_context *ctx ) );
#endif /* PSA_CRYPTO_INVASIVE_H */

144
library/psa_crypto_its.h Normal file
View File

@ -0,0 +1,144 @@
/** \file psa_crypto_its.h
* \brief Interface of trusted storage that crypto is built on.
*/
/* Copyright (C) 2019, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PSA_CRYPTO_ITS_H
#define PSA_CRYPTO_ITS_H
#include <stddef.h>
#include <stdint.h>
#include <psa/crypto_types.h>
#include <psa/crypto_values.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \brief Flags used when creating a data entry
*/
typedef uint32_t psa_storage_create_flags_t;
/** \brief A type for UIDs used for identifying data
*/
typedef uint64_t psa_storage_uid_t;
#define PSA_STORAGE_FLAG_NONE 0 /**< No flags to pass */
#define PSA_STORAGE_FLAG_WRITE_ONCE (1 << 0) /**< The data associated with the uid will not be able to be modified or deleted. Intended to be used to set bits in `psa_storage_create_flags_t`*/
/**
* \brief A container for metadata associated with a specific uid
*/
struct psa_storage_info_t
{
uint32_t size; /**< The size of the data associated with a uid **/
psa_storage_create_flags_t flags; /**< The flags set when the uid was created **/
};
/** Flag indicating that \ref psa_storage_create and \ref psa_storage_set_extended are supported */
#define PSA_STORAGE_SUPPORT_SET_EXTENDED (1 << 0)
/** \brief PSA storage specific error codes
*/
#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149)
#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152)
#define PSA_ITS_API_VERSION_MAJOR 1 /**< The major version number of the PSA ITS API. It will be incremented on significant updates that may include breaking changes */
#define PSA_ITS_API_VERSION_MINOR 1 /**< The minor version number of the PSA ITS API. It will be incremented in small updates that are unlikely to include breaking changes */
/**
* \brief create a new or modify an existing uid/value pair
*
* \param[in] uid the identifier for the data
* \param[in] data_length The size in bytes of the data in `p_data`
* \param[in] p_data A buffer containing the data
* \param[in] create_flags The flags that the data will be stored with
*
* \return A status indicating the success/failure of the operation
*
* \retval PSA_SUCCESS The operation completed successfully
* \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided `uid` value was already created with PSA_STORAGE_WRITE_ONCE_FLAG
* \retval PSA_ERROR_NOT_SUPPORTED The operation failed because one or more of the flags provided in `create_flags` is not supported or is not valid
* \retval PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there was insufficient space on the storage medium
* \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error)
* \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`)
* is invalid, for example is `NULL` or references memory the caller cannot access
*/
psa_status_t psa_its_set(psa_storage_uid_t uid,
uint32_t data_length,
const void *p_data,
psa_storage_create_flags_t create_flags);
/**
* \brief Retrieve the value associated with a provided uid
*
* \param[in] uid The uid value
* \param[in] data_offset The starting offset of the data requested
* \param[in] data_length the amount of data requested (and the minimum allocated size of the `p_data` buffer)
* \param[out] p_data The buffer where the data will be placed upon successful completion
* \param[out] p_data_length The amount of data returned in the p_data buffer
*
*
* \return A status indicating the success/failure of the operation
*
* \retval PSA_SUCCESS The operation completed successfully
* \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided `uid` value was not found in the storage
* \retval PSA_ERROR_INVALID_SIZE The operation failed because the data associated with provided uid is larger than `data_size`
* \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error)
* \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`, `p_data_length`)
* is invalid. For example is `NULL` or references memory the caller cannot access.
* In addition, this can also happen if an invalid offset was provided.
*/
psa_status_t psa_its_get(psa_storage_uid_t uid,
uint32_t data_offset,
uint32_t data_length,
void *p_data,
size_t *p_data_length );
/**
* \brief Retrieve the metadata about the provided uid
*
* \param[in] uid The uid value
* \param[out] p_info A pointer to the `psa_storage_info_t` struct that will be populated with the metadata
*
* \return A status indicating the success/failure of the operation
*
* \retval PSA_SUCCESS The operation completed successfully
* \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage
* \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error)
* \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_info`)
* is invalid, for example is `NULL` or references memory the caller cannot access
*/
psa_status_t psa_its_get_info(psa_storage_uid_t uid,
struct psa_storage_info_t *p_info);
/**
* \brief Remove the provided key and its associated data from the storage
*
* \param[in] uid The uid value
*
* \return A status indicating the success/failure of the operation
*
* \retval PSA_SUCCESS The operation completed successfully
* \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided key value was not found in the storage
* \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided key value was created with PSA_STORAGE_WRITE_ONCE_FLAG
* \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error)
*/
psa_status_t psa_its_remove(psa_storage_uid_t uid);
#endif /* PSA_CRYPTO_ITS_H */

388
library/psa_crypto_se.c Normal file
View File

@ -0,0 +1,388 @@
/*
* PSA crypto support for secure element drivers
*/
/* Copyright (C) 2019, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "psa/crypto_se_driver.h"
#include "psa_crypto_se.h"
#if defined(MBEDTLS_PSA_ITS_FILE_C)
#include "psa_crypto_its.h"
#else /* Native ITS implementation */
#include "psa/error.h"
#include "psa/internal_trusted_storage.h"
#endif
#include "mbedtls/platform.h"
#if !defined(MBEDTLS_PLATFORM_C)
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
/****************************************************************/
/* Driver lookup */
/****************************************************************/
/* This structure is identical to psa_drv_se_context_t declared in
* `crypto_se_driver.h`, except that some parts are writable here
* (non-const, or pointer to non-const). */
typedef struct
{
void *persistent_data;
size_t persistent_data_size;
uintptr_t transient_data;
} psa_drv_se_internal_context_t;
typedef struct psa_se_drv_table_entry_s
{
psa_key_lifetime_t lifetime;
const psa_drv_se_t *methods;
union
{
psa_drv_se_internal_context_t internal;
psa_drv_se_context_t context;
};
} psa_se_drv_table_entry_t;
static psa_se_drv_table_entry_t driver_table[PSA_MAX_SE_DRIVERS];
psa_se_drv_table_entry_t *psa_get_se_driver_entry(
psa_key_lifetime_t lifetime )
{
size_t i;
/* In the driver table, lifetime=0 means an entry that isn't used.
* No driver has a lifetime of 0 because it's a reserved value
* (which designates volatile keys). Make sure we never return
* a driver entry for lifetime 0. */
if( lifetime == 0 )
return( NULL );
for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
{
if( driver_table[i].lifetime == lifetime )
return( &driver_table[i] );
}
return( NULL );
}
const psa_drv_se_t *psa_get_se_driver_methods(
const psa_se_drv_table_entry_t *driver )
{
return( driver->methods );
}
psa_drv_se_context_t *psa_get_se_driver_context(
psa_se_drv_table_entry_t *driver )
{
return( &driver->context );
}
int psa_get_se_driver( psa_key_lifetime_t lifetime,
const psa_drv_se_t **p_methods,
psa_drv_se_context_t **p_drv_context)
{
psa_se_drv_table_entry_t *driver = psa_get_se_driver_entry( lifetime );
if( p_methods != NULL )
*p_methods = ( driver ? driver->methods : NULL );
if( p_drv_context != NULL )
*p_drv_context = ( driver ? &driver->context : NULL );
return( driver != NULL );
}
/****************************************************************/
/* Persistent data management */
/****************************************************************/
static psa_status_t psa_get_se_driver_its_file_uid(
const psa_se_drv_table_entry_t *driver,
psa_storage_uid_t *uid )
{
if( driver->lifetime > PSA_MAX_SE_LIFETIME )
return( PSA_ERROR_NOT_SUPPORTED );
#if SIZE_MAX > UINT32_MAX
/* ITS file sizes are limited to 32 bits. */
if( driver->internal.persistent_data_size > UINT32_MAX )
return( PSA_ERROR_NOT_SUPPORTED );
#endif
/* See the documentation of PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE. */
*uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + driver->lifetime;
return( PSA_SUCCESS );
}
psa_status_t psa_load_se_persistent_data(
const psa_se_drv_table_entry_t *driver )
{
psa_status_t status;
psa_storage_uid_t uid;
size_t length;
status = psa_get_se_driver_its_file_uid( driver, &uid );
if( status != PSA_SUCCESS )
return( status );
/* Read the amount of persistent data that the driver requests.
* If the data in storage is larger, it is truncated. If the data
* in storage is smaller, silently keep what is already at the end
* of the output buffer. */
/* psa_get_se_driver_its_file_uid ensures that the size_t
* persistent_data_size is in range, but compilers don't know that,
* so cast to reassure them. */
return( psa_its_get( uid, 0,
(uint32_t) driver->internal.persistent_data_size,
driver->internal.persistent_data,
&length ) );
}
psa_status_t psa_save_se_persistent_data(
const psa_se_drv_table_entry_t *driver )
{
psa_status_t status;
psa_storage_uid_t uid;
status = psa_get_se_driver_its_file_uid( driver, &uid );
if( status != PSA_SUCCESS )
return( status );
/* psa_get_se_driver_its_file_uid ensures that the size_t
* persistent_data_size is in range, but compilers don't know that,
* so cast to reassure them. */
return( psa_its_set( uid,
(uint32_t) driver->internal.persistent_data_size,
driver->internal.persistent_data,
0 ) );
}
psa_status_t psa_destroy_se_persistent_data( psa_key_lifetime_t lifetime )
{
psa_storage_uid_t uid;
if( lifetime > PSA_MAX_SE_LIFETIME )
return( PSA_ERROR_NOT_SUPPORTED );
uid = PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime;
return( psa_its_remove( uid ) );
}
psa_status_t psa_find_se_slot_for_key(
const psa_key_attributes_t *attributes,
psa_key_creation_method_t method,
psa_se_drv_table_entry_t *driver,
psa_key_slot_number_t *slot_number )
{
psa_status_t status;
/* If the lifetime is wrong, it's a bug in the library. */
if( driver->lifetime != psa_get_key_lifetime( attributes ) )
return( PSA_ERROR_CORRUPTION_DETECTED );
/* If the driver doesn't support key creation in any way, give up now. */
if( driver->methods->key_management == NULL )
return( PSA_ERROR_NOT_SUPPORTED );
if( psa_get_key_slot_number( attributes, slot_number ) == PSA_SUCCESS )
{
/* The application wants to use a specific slot. Allow it if
* the driver supports it. On a system with isolation,
* the crypto service must check that the application is
* permitted to request this slot. */
psa_drv_se_validate_slot_number_t p_validate_slot_number =
driver->methods->key_management->p_validate_slot_number;
if( p_validate_slot_number == NULL )
return( PSA_ERROR_NOT_SUPPORTED );
status = p_validate_slot_number( &driver->context,
driver->internal.persistent_data,
attributes, method,
*slot_number );
}
else if( method == PSA_KEY_CREATION_REGISTER )
{
/* The application didn't specify a slot number. This doesn't
* make sense when registering a slot. */
return( PSA_ERROR_INVALID_ARGUMENT );
}
else
{
/* The application didn't tell us which slot to use. Let the driver
* choose. This is the normal case. */
psa_drv_se_allocate_key_t p_allocate =
driver->methods->key_management->p_allocate;
if( p_allocate == NULL )
return( PSA_ERROR_NOT_SUPPORTED );
status = p_allocate( &driver->context,
driver->internal.persistent_data,
attributes, method,
slot_number );
}
return( status );
}
psa_status_t psa_destroy_se_key( psa_se_drv_table_entry_t *driver,
psa_key_slot_number_t slot_number )
{
psa_status_t status;
psa_status_t storage_status;
/* Normally a missing method would mean that the action is not
* supported. But psa_destroy_key() is not supposed to return
* PSA_ERROR_NOT_SUPPORTED: if you can create a key, you should
* be able to destroy it. The only use case for a driver that
* does not have a way to destroy keys at all is if the keys are
* locked in a read-only state: we can use the keys but not
* destroy them. Hence, if the driver doesn't support destroying
* keys, it's really a lack of permission. */
if( driver->methods->key_management == NULL ||
driver->methods->key_management->p_destroy == NULL )
return( PSA_ERROR_NOT_PERMITTED );
status = driver->methods->key_management->p_destroy(
&driver->context,
driver->internal.persistent_data,
slot_number );
storage_status = psa_save_se_persistent_data( driver );
return( status == PSA_SUCCESS ? storage_status : status );
}
psa_status_t psa_init_all_se_drivers( void )
{
size_t i;
for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
{
psa_se_drv_table_entry_t *driver = &driver_table[i];
if( driver->lifetime == 0 )
continue; /* skipping unused entry */
const psa_drv_se_t *methods = psa_get_se_driver_methods( driver );
if( methods->p_init != NULL )
{
psa_status_t status = methods->p_init(
&driver->context,
driver->internal.persistent_data,
driver->lifetime );
if( status != PSA_SUCCESS )
return( status );
status = psa_save_se_persistent_data( driver );
if( status != PSA_SUCCESS )
return( status );
}
}
return( PSA_SUCCESS );
}
/****************************************************************/
/* Driver registration */
/****************************************************************/
psa_status_t psa_register_se_driver(
psa_key_lifetime_t lifetime,
const psa_drv_se_t *methods)
{
size_t i;
psa_status_t status;
if( methods->hal_version != PSA_DRV_SE_HAL_VERSION )
return( PSA_ERROR_NOT_SUPPORTED );
/* Driver table entries are 0-initialized. 0 is not a valid driver
* lifetime because it means a volatile key. */
#if defined(static_assert)
static_assert( PSA_KEY_LIFETIME_VOLATILE == 0,
"Secure element support requires 0 to mean a volatile key" );
#endif
if( lifetime == PSA_KEY_LIFETIME_VOLATILE ||
lifetime == PSA_KEY_LIFETIME_PERSISTENT )
{
return( PSA_ERROR_INVALID_ARGUMENT );
}
if( lifetime > PSA_MAX_SE_LIFETIME )
return( PSA_ERROR_NOT_SUPPORTED );
for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
{
if( driver_table[i].lifetime == 0 )
break;
/* Check that lifetime isn't already in use up to the first free
* entry. Since entries are created in order and never deleted,
* there can't be a used entry after the first free entry. */
if( driver_table[i].lifetime == lifetime )
return( PSA_ERROR_ALREADY_EXISTS );
}
if( i == PSA_MAX_SE_DRIVERS )
return( PSA_ERROR_INSUFFICIENT_MEMORY );
driver_table[i].lifetime = lifetime;
driver_table[i].methods = methods;
driver_table[i].internal.persistent_data_size =
methods->persistent_data_size;
if( methods->persistent_data_size != 0 )
{
driver_table[i].internal.persistent_data =
mbedtls_calloc( 1, methods->persistent_data_size );
if( driver_table[i].internal.persistent_data == NULL )
{
status = PSA_ERROR_INSUFFICIENT_MEMORY;
goto error;
}
/* Load the driver's persistent data. On first use, the persistent
* data does not exist in storage, and is initialized to
* all-bits-zero by the calloc call just above. */
status = psa_load_se_persistent_data( &driver_table[i] );
if( status != PSA_SUCCESS && status != PSA_ERROR_DOES_NOT_EXIST )
goto error;
}
return( PSA_SUCCESS );
error:
memset( &driver_table[i], 0, sizeof( driver_table[i] ) );
return( status );
}
void psa_unregister_all_se_drivers( void )
{
size_t i;
for( i = 0; i < PSA_MAX_SE_DRIVERS; i++ )
{
if( driver_table[i].internal.persistent_data != NULL )
mbedtls_free( driver_table[i].internal.persistent_data );
}
memset( driver_table, 0, sizeof( driver_table ) );
}
/****************************************************************/
/* The end */
/****************************************************************/
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */

190
library/psa_crypto_se.h Normal file
View File

@ -0,0 +1,190 @@
/*
* PSA crypto support for secure element drivers
*/
/* Copyright (C) 2019, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef PSA_CRYPTO_SE_H
#define PSA_CRYPTO_SE_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "psa/crypto.h"
#include "psa/crypto_se_driver.h"
/** The maximum lifetime value that this implementation supports
* for a secure element.
*
* This is not a characteristic that each PSA implementation has, but a
* limitation of the current implementation due to the constraints imposed
* by storage. See #PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE.
*
* The minimum lifetime value for a secure element is 2, like on any
* PSA implementation (0=volatile and 1=internal-storage are taken).
*/
#define PSA_MAX_SE_LIFETIME 255
/** The base of the range of ITS file identifiers for secure element
* driver persistent data.
*
* We use a slice of the implemenation reserved range 0xffff0000..0xffffffff,
* specifically the range 0xfffffe00..0xfffffeff. The length of this range
* drives the value of #PSA_MAX_SE_LIFETIME.
* The identifiers 0xfffffe00 and 0xfffffe01 are actually not used since
* they correspond to #PSA_KEY_LIFETIME_VOLATILE and
* #PSA_KEY_LIFETIME_PERSISTENT which don't have a driver.
*/
#define PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE ( (psa_key_id_t) 0xfffffe00 )
/** The maximum number of registered secure element driver lifetimes. */
#define PSA_MAX_SE_DRIVERS 4
/** Unregister all secure element drivers.
*
* \warning Do not call this function while the library is in the initialized
* state. This function is only intended to be called at the end
* of mbedtls_psa_crypto_free().
*/
void psa_unregister_all_se_drivers( void );
/** Initialize all secure element drivers.
*
* Called from psa_crypto_init().
*/
psa_status_t psa_init_all_se_drivers( void );
/** A structure that describes a registered secure element driver.
*
* A secure element driver table entry contains a pointer to the
* driver's method table as well as the driver context structure.
*/
typedef struct psa_se_drv_table_entry_s psa_se_drv_table_entry_t;
/** Return the secure element driver information for a lifetime value.
*
* \param lifetime The lifetime value to query.
* \param[out] p_methods On output, if there is a driver,
* \c *methods points to its method table.
* Otherwise \c *methods is \c NULL.
* \param[out] p_drv_context On output, if there is a driver,
* \c *drv_context points to its context
* structure.
* Otherwise \c *drv_context is \c NULL.
*
* \retval 1
* \p lifetime corresponds to a registered driver.
* \retval 0
* \p lifetime does not correspond to a registered driver.
*/
int psa_get_se_driver( psa_key_lifetime_t lifetime,
const psa_drv_se_t **p_methods,
psa_drv_se_context_t **p_drv_context);
/** Return the secure element driver table entry for a lifetime value.
*
* \param lifetime The lifetime value to query.
*
* \return The driver table entry for \p lifetime, or
* \p NULL if \p lifetime does not correspond to a registered driver.
*/
psa_se_drv_table_entry_t *psa_get_se_driver_entry(
psa_key_lifetime_t lifetime );
/** Return the method table for a secure element driver.
*
* \param[in] driver The driver table entry to access, or \c NULL.
*
* \return The driver's method table.
* \c NULL if \p driver is \c NULL.
*/
const psa_drv_se_t *psa_get_se_driver_methods(
const psa_se_drv_table_entry_t *driver );
/** Return the context of a secure element driver.
*
* \param[in] driver The driver table entry to access, or \c NULL.
*
* \return A pointer to the driver context.
* \c NULL if \p driver is \c NULL.
*/
psa_drv_se_context_t *psa_get_se_driver_context(
psa_se_drv_table_entry_t *driver );
/** Find a free slot for a key that is to be created.
*
* This function calls the relevant method in the driver to find a suitable
* slot for a key with the given attributes.
*
* \param[in] attributes Metadata about the key that is about to be created.
* \param[in] driver The driver table entry to query.
* \param[out] slot_number On success, a slot number that is free in this
* secure element.
*/
psa_status_t psa_find_se_slot_for_key(
const psa_key_attributes_t *attributes,
psa_key_creation_method_t method,
psa_se_drv_table_entry_t *driver,
psa_key_slot_number_t *slot_number );
/** Destoy a key in a secure element.
*
* This function calls the relevant driver method to destroy a key
* and updates the driver's persistent data.
*/
psa_status_t psa_destroy_se_key( psa_se_drv_table_entry_t *driver,
psa_key_slot_number_t slot_number );
/** Load the persistent data of a secure element driver.
*
* \param driver The driver table entry containing the persistent
* data to load from storage.
*/
psa_status_t psa_load_se_persistent_data(
const psa_se_drv_table_entry_t *driver );
/** Save the persistent data of a secure element driver.
*
* \param[in] driver The driver table entry containing the persistent
* data to save to storage.
*/
psa_status_t psa_save_se_persistent_data(
const psa_se_drv_table_entry_t *driver );
/** Destroy the persistent data of a secure element driver.
*
* This is currently only used for testing.
*
* \param[in] lifetime The driver lifetime whose persistent data should
* be erased.
*/
psa_status_t psa_destroy_se_persistent_data( psa_key_lifetime_t lifetime );
/** The storage representation of a key whose data is in a secure element.
*/
typedef struct
{
uint8_t slot_number[sizeof( psa_key_slot_number_t )];
uint8_t bits[sizeof( psa_key_bits_t )];
} psa_se_key_data_storage_t;
#endif /* PSA_CRYPTO_SE_H */

View File

@ -0,0 +1,40 @@
/* Copyright (C) 2019, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef PSA_CRYPTO_SERVICE_INTEGRATION_H
#define PSA_CRYPTO_SERVICE_INTEGRATION_H
/*
* When MBEDTLS_PSA_CRYPTO_SPM is defined, the code is being built for SPM
* (Secure Partition Manager) integration which separates the code into two
* parts: NSPE (Non-Secure Processing Environment) and SPE (Secure Processing
* Environment). When building for the SPE, an additional header file should be
* included.
*/
#if defined(MBEDTLS_PSA_CRYPTO_SPM)
/*
* PSA_CRYPTO_SECURE means that the file which included this file is being
* compiled for SPE. The files crypto_structs.h and crypto_types.h have
* different implementations for NSPE and SPE and are compiled according to this
* flag.
*/
#define PSA_CRYPTO_SECURE 1
#include "crypto_spe.h"
#endif // MBEDTLS_PSA_CRYPTO_SPM
#endif // PSA_CRYPTO_SERVICE_INTEGRATION_H

View File

@ -0,0 +1,299 @@
/*
* PSA crypto layer on top of Mbed TLS crypto
*/
/* Copyright (C) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PSA_CRYPTO_C)
#include "psa_crypto_service_integration.h"
#include "psa/crypto.h"
#include "psa_crypto_core.h"
#include "psa_crypto_slot_management.h"
#include "psa_crypto_storage.h"
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
#include "psa_crypto_se.h"
#endif
#include <stdlib.h>
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
#define ARRAY_LENGTH( array ) ( sizeof( array ) / sizeof( *( array ) ) )
typedef struct
{
psa_key_slot_t key_slots[PSA_KEY_SLOT_COUNT];
unsigned key_slots_initialized : 1;
} psa_global_data_t;
static psa_global_data_t global_data;
/* Access a key slot at the given handle. The handle of a key slot is
* the index of the slot in the global slot array, plus one so that handles
* start at 1 and not 0. */
psa_status_t psa_get_key_slot( psa_key_handle_t handle,
psa_key_slot_t **p_slot )
{
psa_key_slot_t *slot = NULL;
if( ! global_data.key_slots_initialized )
return( PSA_ERROR_BAD_STATE );
/* 0 is not a valid handle under any circumstance. This
* implementation provides slots number 1 to N where N is the
* number of available slots. */
if( handle == 0 || handle > ARRAY_LENGTH( global_data.key_slots ) )
return( PSA_ERROR_INVALID_HANDLE );
slot = &global_data.key_slots[handle - 1];
/* If the slot isn't occupied, the handle is invalid. */
if( ! psa_is_key_slot_occupied( slot ) )
return( PSA_ERROR_INVALID_HANDLE );
*p_slot = slot;
return( PSA_SUCCESS );
}
psa_status_t psa_initialize_key_slots( void )
{
/* Nothing to do: program startup and psa_wipe_all_key_slots() both
* guarantee that the key slots are initialized to all-zero, which
* means that all the key slots are in a valid, empty state. */
global_data.key_slots_initialized = 1;
return( PSA_SUCCESS );
}
void psa_wipe_all_key_slots( void )
{
psa_key_handle_t key;
for( key = 1; key <= PSA_KEY_SLOT_COUNT; key++ )
{
psa_key_slot_t *slot = &global_data.key_slots[key - 1];
(void) psa_wipe_key_slot( slot );
}
global_data.key_slots_initialized = 0;
}
psa_status_t psa_get_empty_key_slot( psa_key_handle_t *handle,
psa_key_slot_t **p_slot )
{
if( ! global_data.key_slots_initialized )
return( PSA_ERROR_BAD_STATE );
for( *handle = PSA_KEY_SLOT_COUNT; *handle != 0; --( *handle ) )
{
*p_slot = &global_data.key_slots[*handle - 1];
if( ! psa_is_key_slot_occupied( *p_slot ) )
return( PSA_SUCCESS );
}
*p_slot = NULL;
return( PSA_ERROR_INSUFFICIENT_MEMORY );
}
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
static psa_status_t psa_load_persistent_key_into_slot( psa_key_slot_t *slot )
{
psa_status_t status = PSA_SUCCESS;
uint8_t *key_data = NULL;
size_t key_data_length = 0;
status = psa_load_persistent_key( &slot->attr,
&key_data, &key_data_length );
if( status != PSA_SUCCESS )
goto exit;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( psa_key_lifetime_is_external( slot->attr.lifetime ) )
{
psa_se_key_data_storage_t *data;
if( key_data_length != sizeof( *data ) )
{
status = PSA_ERROR_STORAGE_FAILURE;
goto exit;
}
data = (psa_se_key_data_storage_t *) key_data;
memcpy( &slot->data.se.slot_number, &data->slot_number,
sizeof( slot->data.se.slot_number ) );
memcpy( &slot->attr.bits, &data->bits,
sizeof( slot->attr.bits ) );
}
else
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
{
status = psa_import_key_into_slot( slot, key_data, key_data_length );
}
exit:
psa_free_persistent_key_data( key_data, key_data_length );
return( status );
}
/** Check whether a key identifier is acceptable.
*
* For backward compatibility, key identifiers that were valid in a
* past released version must remain valid, unless a migration path
* is provided.
*
* \param file_id The key identifier to check.
* \param vendor_ok Nonzero to allow key ids in the vendor range.
* 0 to allow only key ids in the application range.
*
* \return 1 if \p file_id is acceptable, otherwise 0.
*/
static int psa_is_key_id_valid( psa_key_file_id_t file_id,
int vendor_ok )
{
psa_app_key_id_t key_id = PSA_KEY_FILE_GET_KEY_ID( file_id );
if( PSA_KEY_ID_USER_MIN <= key_id && key_id <= PSA_KEY_ID_USER_MAX )
return( 1 );
else if( vendor_ok &&
PSA_KEY_ID_VENDOR_MIN <= key_id &&
key_id <= PSA_KEY_ID_VENDOR_MAX )
return( 1 );
else
return( 0 );
}
#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
psa_status_t psa_validate_persistent_key_parameters(
psa_key_lifetime_t lifetime,
psa_key_file_id_t id,
psa_se_drv_table_entry_t **p_drv,
int creating )
{
if( p_drv != NULL )
*p_drv = NULL;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( psa_key_lifetime_is_external( lifetime ) )
{
*p_drv = psa_get_se_driver_entry( lifetime );
if( *p_drv == NULL )
return( PSA_ERROR_INVALID_ARGUMENT );
}
else
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
if( lifetime != PSA_KEY_LIFETIME_PERSISTENT )
return( PSA_ERROR_INVALID_ARGUMENT );
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
if( ! psa_is_key_id_valid( id, ! creating ) )
return( PSA_ERROR_INVALID_ARGUMENT );
return( PSA_SUCCESS );
#else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
(void) id;
(void) creating;
return( PSA_ERROR_NOT_SUPPORTED );
#endif /* !MBEDTLS_PSA_CRYPTO_STORAGE_C */
}
psa_status_t psa_open_key( psa_key_file_id_t id, psa_key_handle_t *handle )
{
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
psa_status_t status;
psa_key_slot_t *slot;
*handle = 0;
status = psa_validate_persistent_key_parameters(
PSA_KEY_LIFETIME_PERSISTENT, id, NULL, 0 );
if( status != PSA_SUCCESS )
return( status );
status = psa_get_empty_key_slot( handle, &slot );
if( status != PSA_SUCCESS )
return( status );
slot->attr.lifetime = PSA_KEY_LIFETIME_PERSISTENT;
slot->attr.id = id;
status = psa_load_persistent_key_into_slot( slot );
if( status != PSA_SUCCESS )
{
psa_wipe_key_slot( slot );
*handle = 0;
}
return( status );
#else /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
(void) id;
*handle = 0;
return( PSA_ERROR_NOT_SUPPORTED );
#endif /* !defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
}
psa_status_t psa_close_key( psa_key_handle_t handle )
{
psa_status_t status;
psa_key_slot_t *slot;
if( handle == 0 )
return( PSA_SUCCESS );
status = psa_get_key_slot( handle, &slot );
if( status != PSA_SUCCESS )
return( status );
return( psa_wipe_key_slot( slot ) );
}
void mbedtls_psa_get_stats( mbedtls_psa_stats_t *stats )
{
psa_key_handle_t key;
memset( stats, 0, sizeof( *stats ) );
for( key = 1; key <= PSA_KEY_SLOT_COUNT; key++ )
{
const psa_key_slot_t *slot = &global_data.key_slots[key - 1];
if( ! psa_is_key_slot_occupied( slot ) )
{
++stats->empty_slots;
continue;
}
if( slot->attr.lifetime == PSA_KEY_LIFETIME_VOLATILE )
++stats->volatile_slots;
else if( slot->attr.lifetime == PSA_KEY_LIFETIME_PERSISTENT )
{
psa_app_key_id_t id = PSA_KEY_FILE_GET_KEY_ID(slot->attr.id);
++stats->persistent_slots;
if( id > stats->max_open_internal_key_id )
stats->max_open_internal_key_id = id;
}
else
{
psa_app_key_id_t id = PSA_KEY_FILE_GET_KEY_ID(slot->attr.id);
++stats->external_slots;
if( id > stats->max_open_external_key_id )
stats->max_open_external_key_id = id;
}
}
}
#endif /* MBEDTLS_PSA_CRYPTO_C */

View File

@ -0,0 +1,129 @@
/*
* PSA crypto layer on top of Mbed TLS crypto
*/
/* Copyright (C) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef PSA_CRYPTO_SLOT_MANAGEMENT_H
#define PSA_CRYPTO_SLOT_MANAGEMENT_H
#include "psa/crypto.h"
#include "psa_crypto_se.h"
/* Number of key slots (plus one because 0 is not used).
* The value is a compile-time constant for now, for simplicity. */
#define PSA_KEY_SLOT_COUNT 32
/** Access a key slot at the given handle.
*
* \param handle Key handle to query.
* \param[out] p_slot On success, `*p_slot` contains a pointer to the
* key slot in memory designated by \p handle.
*
* \retval PSA_SUCCESS
* Success: \p handle is a handle to `*p_slot`. Note that `*p_slot`
* may be empty or occupied.
* \retval PSA_ERROR_INVALID_HANDLE
* \p handle is out of range or is not in use.
* \retval PSA_ERROR_BAD_STATE
* The library has not been initialized.
*/
psa_status_t psa_get_key_slot( psa_key_handle_t handle,
psa_key_slot_t **p_slot );
/** Initialize the key slot structures.
*
* \retval PSA_SUCCESS
* Currently this function always succeeds.
*/
psa_status_t psa_initialize_key_slots( void );
/** Delete all data from key slots in memory.
*
* This does not affect persistent storage. */
void psa_wipe_all_key_slots( void );
/** Find a free key slot.
*
* This function returns a key slot that is available for use and is in its
* ground state (all-bits-zero).
*
* \param[out] handle On success, a slot number that can be used as a
* handle to the slot.
* \param[out] p_slot On success, a pointer to the slot.
*
* \retval #PSA_SUCCESS
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* \retval #PSA_ERROR_BAD_STATE
*/
psa_status_t psa_get_empty_key_slot( psa_key_handle_t *handle,
psa_key_slot_t **p_slot );
/** Test whether a lifetime designates a key in an external cryptoprocessor.
*
* \param lifetime The lifetime to test.
*
* \retval 1
* The lifetime designates an external key. There should be a
* registered driver for this lifetime, otherwise the key cannot
* be created or manipulated.
* \retval 0
* The lifetime designates a key that is volatile or in internal
* storage.
*/
static inline int psa_key_lifetime_is_external( psa_key_lifetime_t lifetime )
{
return( lifetime != PSA_KEY_LIFETIME_VOLATILE &&
lifetime != PSA_KEY_LIFETIME_PERSISTENT );
}
/** Test whether the given parameters are acceptable for a persistent key.
*
* This function does not access the storage in any way. It only tests
* whether the parameters are meaningful and permitted by general policy.
* It does not test whether the a file by the given id exists or could be
* created.
*
* If the key is in external storage, this function returns the corresponding
* driver.
*
* \param lifetime The lifetime to test.
* \param id The key id to test.
* \param[out] p_drv On output, if \p lifetime designates a key
* in an external processor, \c *p_drv is a pointer
* to the driver table entry fot this lifetime.
* If \p lifetime designates a transparent key,
* \c *p_drv is \c NULL.
* \param creating 0 if attempting to open an existing key.
* Nonzero if attempting to create a key.
*
* \retval PSA_SUCCESS
* The given parameters are valid.
* \retval PSA_ERROR_INVALID_ARGUMENT
* \p lifetime is volatile or is invalid.
* \retval PSA_ERROR_INVALID_ARGUMENT
* \p id is invalid.
*/
psa_status_t psa_validate_persistent_key_parameters(
psa_key_lifetime_t lifetime,
psa_key_file_id_t id,
psa_se_drv_table_entry_t **p_drv,
int creating );
#endif /* PSA_CRYPTO_SLOT_MANAGEMENT_H */

View File

@ -0,0 +1,504 @@
/*
* PSA persistent key storage
*/
/* Copyright (C) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if defined(MBEDTLS_CONFIG_FILE)
#include MBEDTLS_CONFIG_FILE
#else
#include "mbedtls/config.h"
#endif
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
#include <stdlib.h>
#include <string.h>
#include "psa_crypto_service_integration.h"
#include "psa/crypto.h"
#include "psa_crypto_storage.h"
#include "mbedtls/platform_util.h"
#if defined(MBEDTLS_PSA_ITS_FILE_C)
#include "psa_crypto_its.h"
#else /* Native ITS implementation */
#include "psa/error.h"
#include "psa/internal_trusted_storage.h"
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
/****************************************************************/
/* Key storage */
/****************************************************************/
/* Determine a file name (ITS file identifier) for the given key file
* identifier. The file name must be distinct from any file that is used
* for a purpose other than storing a key. Currently, the only such file
* is the random seed file whose name is PSA_CRYPTO_ITS_RANDOM_SEED_UID
* and whose value is 0xFFFFFF52. */
static psa_storage_uid_t psa_its_identifier_of_slot( psa_key_file_id_t file_id )
{
#if defined(MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER) && \
defined(PSA_CRYPTO_SECURE)
/* Encode the owner in the upper 32 bits. This means that if
* owner values are nonzero (as they are on a PSA platform),
* no key file will ever have a value less than 0x100000000, so
* the whole range 0..0xffffffff is available for non-key files. */
uint32_t unsigned_owner = (uint32_t) file_id.owner;
return( (uint64_t) unsigned_owner << 32 | file_id.key_id );
#else
/* Use the key id directly as a file name.
* psa_is_key_file_id_valid() in psa_crypto_slot_management.c
* is responsible for ensuring that key identifiers do not have a
* value that is reserved for non-key files. */
return( file_id );
#endif
}
/**
* \brief Load persistent data for the given key slot number.
*
* This function reads data from a storage backend and returns the data in a
* buffer.
*
* \param key Persistent identifier of the key to be loaded. This
* should be an occupied storage location.
* \param[out] data Buffer where the data is to be written.
* \param data_size Size of the \c data buffer in bytes.
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_STORAGE_FAILURE
* \retval PSA_ERROR_DOES_NOT_EXIST
*/
static psa_status_t psa_crypto_storage_load( const psa_key_file_id_t key,
uint8_t *data,
size_t data_size )
{
psa_status_t status;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot( key );
struct psa_storage_info_t data_identifier_info;
size_t data_length = 0;
status = psa_its_get_info( data_identifier, &data_identifier_info );
if( status != PSA_SUCCESS )
return( status );
status = psa_its_get( data_identifier, 0, (uint32_t) data_size, data, &data_length );
if( data_size != data_length )
return( PSA_ERROR_STORAGE_FAILURE );
return( status );
}
int psa_is_key_present_in_storage( const psa_key_file_id_t key )
{
psa_status_t ret;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot( key );
struct psa_storage_info_t data_identifier_info;
ret = psa_its_get_info( data_identifier, &data_identifier_info );
if( ret == PSA_ERROR_DOES_NOT_EXIST )
return( 0 );
return( 1 );
}
/**
* \brief Store persistent data for the given key slot number.
*
* This function stores the given data buffer to a persistent storage.
*
* \param key Persistent identifier of the key to be stored. This
* should be an unoccupied storage location.
* \param[in] data Buffer containing the data to be stored.
* \param data_length The number of bytes
* that make up the data.
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_INSUFFICIENT_STORAGE
* \retval PSA_ERROR_STORAGE_FAILURE
* \retval PSA_ERROR_ALREADY_EXISTS
*/
static psa_status_t psa_crypto_storage_store( const psa_key_file_id_t key,
const uint8_t *data,
size_t data_length )
{
psa_status_t status;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot( key );
struct psa_storage_info_t data_identifier_info;
if( psa_is_key_present_in_storage( key ) == 1 )
return( PSA_ERROR_ALREADY_EXISTS );
status = psa_its_set( data_identifier, (uint32_t) data_length, data, 0 );
if( status != PSA_SUCCESS )
{
return( PSA_ERROR_STORAGE_FAILURE );
}
status = psa_its_get_info( data_identifier, &data_identifier_info );
if( status != PSA_SUCCESS )
{
goto exit;
}
if( data_identifier_info.size != data_length )
{
status = PSA_ERROR_STORAGE_FAILURE;
goto exit;
}
exit:
if( status != PSA_SUCCESS )
psa_its_remove( data_identifier );
return( status );
}
psa_status_t psa_destroy_persistent_key( const psa_key_file_id_t key )
{
psa_status_t ret;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot( key );
struct psa_storage_info_t data_identifier_info;
ret = psa_its_get_info( data_identifier, &data_identifier_info );
if( ret == PSA_ERROR_DOES_NOT_EXIST )
return( PSA_SUCCESS );
if( psa_its_remove( data_identifier ) != PSA_SUCCESS )
return( PSA_ERROR_STORAGE_FAILURE );
ret = psa_its_get_info( data_identifier, &data_identifier_info );
if( ret != PSA_ERROR_DOES_NOT_EXIST )
return( PSA_ERROR_STORAGE_FAILURE );
return( PSA_SUCCESS );
}
/**
* \brief Get data length for given key slot number.
*
* \param key Persistent identifier whose stored data length
* is to be obtained.
* \param[out] data_length The number of bytes that make up the data.
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_STORAGE_FAILURE
*/
static psa_status_t psa_crypto_storage_get_data_length(
const psa_key_file_id_t key,
size_t *data_length )
{
psa_status_t status;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot( key );
struct psa_storage_info_t data_identifier_info;
status = psa_its_get_info( data_identifier, &data_identifier_info );
if( status != PSA_SUCCESS )
return( status );
*data_length = (size_t) data_identifier_info.size;
return( PSA_SUCCESS );
}
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_UINT32_LE
#define GET_UINT32_LE( n, b, i ) \
{ \
(n) = ( (uint32_t) (b)[(i) ] ) \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
| ( (uint32_t) (b)[(i) + 3] << 24 ); \
}
#endif
#ifndef PUT_UINT32_LE
#define PUT_UINT32_LE( n, b, i ) \
{ \
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
(b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
(b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
}
#endif
/**
* Persistent key storage magic header.
*/
#define PSA_KEY_STORAGE_MAGIC_HEADER "PSA\0KEY"
#define PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH ( sizeof( PSA_KEY_STORAGE_MAGIC_HEADER ) )
typedef struct {
uint8_t magic[PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH];
uint8_t version[4];
uint8_t lifetime[sizeof( psa_key_lifetime_t )];
uint8_t type[4]; /* Size=4 for a 2-byte type to keep the structure more
* regular and aligned and to make potential future
* extensibility easier. */
uint8_t policy[sizeof( psa_key_policy_t )];
uint8_t data_len[4];
uint8_t key_data[];
} psa_persistent_key_storage_format;
void psa_format_key_data_for_storage( const uint8_t *data,
const size_t data_length,
const psa_core_key_attributes_t *attr,
uint8_t *storage_data )
{
psa_persistent_key_storage_format *storage_format =
(psa_persistent_key_storage_format *) storage_data;
memcpy( storage_format->magic, PSA_KEY_STORAGE_MAGIC_HEADER, PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH );
PUT_UINT32_LE( 0, storage_format->version, 0 );
PUT_UINT32_LE( attr->lifetime, storage_format->lifetime, 0 );
PUT_UINT32_LE( (uint32_t) attr->type, storage_format->type, 0 );
PUT_UINT32_LE( attr->policy.usage, storage_format->policy, 0 );
PUT_UINT32_LE( attr->policy.alg, storage_format->policy, sizeof( uint32_t ) );
PUT_UINT32_LE( attr->policy.alg2, storage_format->policy, 2 * sizeof( uint32_t ) );
PUT_UINT32_LE( data_length, storage_format->data_len, 0 );
memcpy( storage_format->key_data, data, data_length );
}
static psa_status_t check_magic_header( const uint8_t *data )
{
if( memcmp( data, PSA_KEY_STORAGE_MAGIC_HEADER,
PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH ) != 0 )
return( PSA_ERROR_STORAGE_FAILURE );
return( PSA_SUCCESS );
}
psa_status_t psa_parse_key_data_from_storage( const uint8_t *storage_data,
size_t storage_data_length,
uint8_t **key_data,
size_t *key_data_length,
psa_core_key_attributes_t *attr )
{
psa_status_t status;
const psa_persistent_key_storage_format *storage_format =
(const psa_persistent_key_storage_format *)storage_data;
uint32_t version;
uint32_t type;
if( storage_data_length < sizeof(*storage_format) )
return( PSA_ERROR_STORAGE_FAILURE );
status = check_magic_header( storage_data );
if( status != PSA_SUCCESS )
return( status );
GET_UINT32_LE( version, storage_format->version, 0 );
if( version != 0 )
return( PSA_ERROR_STORAGE_FAILURE );
GET_UINT32_LE( *key_data_length, storage_format->data_len, 0 );
if( *key_data_length > ( storage_data_length - sizeof(*storage_format) ) ||
*key_data_length > PSA_CRYPTO_MAX_STORAGE_SIZE )
return( PSA_ERROR_STORAGE_FAILURE );
if( *key_data_length == 0 )
{
*key_data = NULL;
}
else
{
*key_data = mbedtls_calloc( 1, *key_data_length );
if( *key_data == NULL )
return( PSA_ERROR_INSUFFICIENT_MEMORY );
memcpy( *key_data, storage_format->key_data, *key_data_length );
}
GET_UINT32_LE( attr->lifetime, storage_format->lifetime, 0 );
GET_UINT32_LE( type, storage_format->type, 0 );
if( type <= (psa_key_type_t) -1 )
attr->type = (psa_key_type_t) type;
else
return( PSA_ERROR_STORAGE_FAILURE );
GET_UINT32_LE( attr->policy.usage, storage_format->policy, 0 );
GET_UINT32_LE( attr->policy.alg, storage_format->policy, sizeof( uint32_t ) );
GET_UINT32_LE( attr->policy.alg2, storage_format->policy, 2 * sizeof( uint32_t ) );
return( PSA_SUCCESS );
}
psa_status_t psa_save_persistent_key( const psa_core_key_attributes_t *attr,
const uint8_t *data,
const size_t data_length )
{
size_t storage_data_length;
uint8_t *storage_data;
psa_status_t status;
if( data_length > PSA_CRYPTO_MAX_STORAGE_SIZE )
return PSA_ERROR_INSUFFICIENT_STORAGE;
storage_data_length = data_length + sizeof( psa_persistent_key_storage_format );
storage_data = mbedtls_calloc( 1, storage_data_length );
if( storage_data == NULL )
return( PSA_ERROR_INSUFFICIENT_MEMORY );
psa_format_key_data_for_storage( data, data_length, attr, storage_data );
status = psa_crypto_storage_store( attr->id,
storage_data, storage_data_length );
mbedtls_free( storage_data );
return( status );
}
void psa_free_persistent_key_data( uint8_t *key_data, size_t key_data_length )
{
if( key_data != NULL )
{
mbedtls_platform_zeroize( key_data, key_data_length );
}
mbedtls_free( key_data );
}
psa_status_t psa_load_persistent_key( psa_core_key_attributes_t *attr,
uint8_t **data,
size_t *data_length )
{
psa_status_t status = PSA_SUCCESS;
uint8_t *loaded_data;
size_t storage_data_length = 0;
psa_key_id_t key = attr->id;
status = psa_crypto_storage_get_data_length( key, &storage_data_length );
if( status != PSA_SUCCESS )
return( status );
loaded_data = mbedtls_calloc( 1, storage_data_length );
if( loaded_data == NULL )
return( PSA_ERROR_INSUFFICIENT_MEMORY );
status = psa_crypto_storage_load( key, loaded_data, storage_data_length );
if( status != PSA_SUCCESS )
goto exit;
status = psa_parse_key_data_from_storage( loaded_data, storage_data_length,
data, data_length, attr );
exit:
mbedtls_free( loaded_data );
return( status );
}
/****************************************************************/
/* Transactions */
/****************************************************************/
#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
psa_crypto_transaction_t psa_crypto_transaction;
psa_status_t psa_crypto_save_transaction( void )
{
struct psa_storage_info_t p_info;
psa_status_t status;
status = psa_its_get_info( PSA_CRYPTO_ITS_TRANSACTION_UID, &p_info );
if( status == PSA_SUCCESS )
{
/* This shouldn't happen: we're trying to start a transaction while
* there is still a transaction that hasn't been replayed. */
return( PSA_ERROR_CORRUPTION_DETECTED );
}
else if( status != PSA_ERROR_DOES_NOT_EXIST )
return( status );
return( psa_its_set( PSA_CRYPTO_ITS_TRANSACTION_UID,
sizeof( psa_crypto_transaction ),
&psa_crypto_transaction,
0 ) );
}
psa_status_t psa_crypto_load_transaction( void )
{
psa_status_t status;
size_t length;
status = psa_its_get( PSA_CRYPTO_ITS_TRANSACTION_UID, 0,
sizeof( psa_crypto_transaction ),
&psa_crypto_transaction, &length );
if( status != PSA_SUCCESS )
return( status );
if( length != sizeof( psa_crypto_transaction ) )
return( PSA_ERROR_STORAGE_FAILURE );
return( PSA_SUCCESS );
}
psa_status_t psa_crypto_stop_transaction( void )
{
psa_status_t status = psa_its_remove( PSA_CRYPTO_ITS_TRANSACTION_UID );
/* Whether or not updating the storage succeeded, the transaction is
* finished now. It's too late to go back, so zero out the in-memory
* data. */
memset( &psa_crypto_transaction, 0, sizeof( psa_crypto_transaction ) );
return( status );
}
#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
/****************************************************************/
/* Random generator state */
/****************************************************************/
#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
psa_status_t mbedtls_psa_storage_inject_entropy( const unsigned char *seed,
size_t seed_size )
{
psa_status_t status;
struct psa_storage_info_t p_info;
status = psa_its_get_info( PSA_CRYPTO_ITS_RANDOM_SEED_UID, &p_info );
if( PSA_ERROR_DOES_NOT_EXIST == status ) /* No seed exists */
{
status = psa_its_set( PSA_CRYPTO_ITS_RANDOM_SEED_UID, seed_size, seed, 0 );
}
else if( PSA_SUCCESS == status )
{
/* You should not be here. Seed needs to be injected only once */
status = PSA_ERROR_NOT_PERMITTED;
}
return( status );
}
#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
/****************************************************************/
/* The end */
/****************************************************************/
#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */

View File

@ -0,0 +1,390 @@
/**
* \file psa_crypto_storage.h
*
* \brief PSA cryptography module: Mbed TLS key storage
*/
/*
* Copyright (C) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef PSA_CRYPTO_STORAGE_H
#define PSA_CRYPTO_STORAGE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include "psa/crypto_se_driver.h"
#include <stdint.h>
#include <string.h>
/* Limit the maximum key size in storage. This should have no effect
* since the key size is limited in memory. */
#define PSA_CRYPTO_MAX_STORAGE_SIZE ( PSA_BITS_TO_BYTES( PSA_MAX_KEY_BITS ) )
/* Sanity check: a file size must fit in 32 bits. Allow a generous
* 64kB of metadata. */
#if PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000
#error PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000
#endif
/** The maximum permitted persistent slot number.
*
* In Mbed Crypto 0.1.0b:
* - Using the file backend, all key ids are ok except 0.
* - Using the ITS backend, all key ids are ok except 0xFFFFFF52
* (#PSA_CRYPTO_ITS_RANDOM_SEED_UID) for which the file contains the
* device's random seed (if this feature is enabled).
* - Only key ids from 1 to #PSA_KEY_SLOT_COUNT are actually used.
*
* Since we need to preserve the random seed, avoid using that key slot.
* Reserve a whole range of key slots just in case something else comes up.
*
* This limitation will probably become moot when we implement client
* separation for key storage.
*/
#define PSA_MAX_PERSISTENT_KEY_IDENTIFIER PSA_KEY_ID_VENDOR_MAX
/**
* \brief Checks if persistent data is stored for the given key slot number
*
* This function checks if any key data or metadata exists for the key slot in
* the persistent storage.
*
* \param key Persistent identifier to check.
*
* \retval 0
* No persistent data present for slot number
* \retval 1
* Persistent data present for slot number
*/
int psa_is_key_present_in_storage( const psa_key_file_id_t key );
/**
* \brief Format key data and metadata and save to a location for given key
* slot.
*
* This function formats the key data and metadata and saves it to a
* persistent storage backend. The storage location corresponding to the
* key slot must be empty, otherwise this function will fail. This function
* should be called after psa_import_key_into_slot() to ensure the
* persistent key is not saved into a storage location corresponding to an
* already occupied non-persistent key, as well as validating the key data.
*
*
* \param[in] attr The attributes of the key to save.
* The key identifier field in the attributes
* determines the key's location.
* \param[in] data Buffer containing the key data.
* \param data_length The number of bytes that make up the key data.
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_INSUFFICIENT_MEMORY
* \retval PSA_ERROR_INSUFFICIENT_STORAGE
* \retval PSA_ERROR_STORAGE_FAILURE
* \retval PSA_ERROR_ALREADY_EXISTS
*/
psa_status_t psa_save_persistent_key( const psa_core_key_attributes_t *attr,
const uint8_t *data,
const size_t data_length );
/**
* \brief Parses key data and metadata and load persistent key for given
* key slot number.
*
* This function reads from a storage backend, parses the key data and
* metadata and writes them to the appropriate output parameters.
*
* Note: This function allocates a buffer and returns a pointer to it through
* the data parameter. psa_free_persistent_key_data() must be called after
* this function to zeroize and free this buffer, regardless of whether this
* function succeeds or fails.
*
* \param[in,out] attr On input, the key identifier field identifies
* the key to load. Other fields are ignored.
* On success, the attribute structure contains
* the key metadata that was loaded from storage.
* \param[out] data Pointer to an allocated key data buffer on return.
* \param[out] data_length The number of bytes that make up the key data.
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_INSUFFICIENT_MEMORY
* \retval PSA_ERROR_STORAGE_FAILURE
* \retval PSA_ERROR_DOES_NOT_EXIST
*/
psa_status_t psa_load_persistent_key( psa_core_key_attributes_t *attr,
uint8_t **data,
size_t *data_length );
/**
* \brief Remove persistent data for the given key slot number.
*
* \param key Persistent identifier of the key to remove
* from persistent storage.
*
* \retval PSA_SUCCESS
* The key was successfully removed,
* or the key did not exist.
* \retval PSA_ERROR_STORAGE_FAILURE
*/
psa_status_t psa_destroy_persistent_key( const psa_key_file_id_t key );
/**
* \brief Free the temporary buffer allocated by psa_load_persistent_key().
*
* This function must be called at some point after psa_load_persistent_key()
* to zeroize and free the memory allocated to the buffer in that function.
*
* \param key_data Buffer for the key data.
* \param key_data_length Size of the key data buffer.
*
*/
void psa_free_persistent_key_data( uint8_t *key_data, size_t key_data_length );
/**
* \brief Formats key data and metadata for persistent storage
*
* \param[in] data Buffer containing the key data.
* \param data_length Length of the key data buffer.
* \param[in] attr The core attributes of the key.
* \param[out] storage_data Output buffer for the formatted data.
*
*/
void psa_format_key_data_for_storage( const uint8_t *data,
const size_t data_length,
const psa_core_key_attributes_t *attr,
uint8_t *storage_data );
/**
* \brief Parses persistent storage data into key data and metadata
*
* \param[in] storage_data Buffer for the storage data.
* \param storage_data_length Length of the storage data buffer
* \param[out] key_data On output, pointer to a newly allocated buffer
* containing the key data. This must be freed
* using psa_free_persistent_key_data()
* \param[out] key_data_length Length of the key data buffer
* \param[out] attr On success, the attribute structure is filled
* with the loaded key metadata.
*
* \retval PSA_SUCCESS
* \retval PSA_ERROR_INSUFFICIENT_STORAGE
* \retval PSA_ERROR_INSUFFICIENT_MEMORY
* \retval PSA_ERROR_STORAGE_FAILURE
*/
psa_status_t psa_parse_key_data_from_storage( const uint8_t *storage_data,
size_t storage_data_length,
uint8_t **key_data,
size_t *key_data_length,
psa_core_key_attributes_t *attr );
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/** This symbol is defined if transaction support is required. */
#define PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS
#endif
#if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
/** The type of transaction that is in progress.
*/
/* This is an integer type rather than an enum for two reasons: to support
* unknown values when loading a transaction file, and to ensure that the
* type has a known size.
*/
typedef uint16_t psa_crypto_transaction_type_t;
/** No transaction is in progress.
*
* This has the value 0, so zero-initialization sets a transaction's type to
* this value.
*/
#define PSA_CRYPTO_TRANSACTION_NONE ( (psa_crypto_transaction_type_t) 0x0000 )
/** A key creation transaction.
*
* This is only used for keys in an external cryptoprocessor (secure element).
* Keys in RAM or in internal storage are created atomically in storage
* (simple file creation), so they do not need a transaction mechanism.
*/
#define PSA_CRYPTO_TRANSACTION_CREATE_KEY ( (psa_crypto_transaction_type_t) 0x0001 )
/** A key destruction transaction.
*
* This is only used for keys in an external cryptoprocessor (secure element).
* Keys in RAM or in internal storage are destroyed atomically in storage
* (simple file deletion), so they do not need a transaction mechanism.
*/
#define PSA_CRYPTO_TRANSACTION_DESTROY_KEY ( (psa_crypto_transaction_type_t) 0x0002 )
/** Transaction data.
*
* This type is designed to be serialized by writing the memory representation
* and reading it back on the same device.
*
* \note The transaction mechanism is designed for a single active transaction
* at a time. The transaction object is #psa_crypto_transaction.
*
* \note If an API call starts a transaction, it must complete this transaction
* before returning to the application.
*
* The lifetime of a transaction is the following (note that only one
* transaction may be active at a time):
*
* -# Call psa_crypto_prepare_transaction() to initialize the transaction
* object in memory and declare the type of transaction that is starting.
* -# Fill in the type-specific fields of #psa_crypto_transaction.
* -# Call psa_crypto_save_transaction() to start the transaction. This
* saves the transaction data to internal storage.
* -# Perform the work of the transaction by modifying files, contacting
* external entities, or whatever needs doing. Note that the transaction
* may be interrupted by a power failure, so you need to have a way
* recover from interruptions either by undoing what has been done
* so far or by resuming where you left off.
* -# If there are intermediate stages in the transaction, update
* the fields of #psa_crypto_transaction and call
* psa_crypto_save_transaction() again when each stage is reached.
* -# When the transaction is over, call psa_crypto_stop_transaction() to
* remove the transaction data in storage and in memory.
*
* If the system crashes while a transaction is in progress, psa_crypto_init()
* calls psa_crypto_load_transaction() and takes care of completing or
* rewinding the transaction. This is done in psa_crypto_recover_transaction()
* in psa_crypto.c. If you add a new type of transaction, be
* sure to add code for it in psa_crypto_recover_transaction().
*/
typedef union
{
/* Each element of this union must have the following properties
* to facilitate serialization and deserialization:
*
* - The element is a struct.
* - The first field of the struct is `psa_crypto_transaction_type_t type`.
* - Elements of the struct are arranged such a way that there is
* no padding.
*/
struct psa_crypto_transaction_unknown_s
{
psa_crypto_transaction_type_t type;
uint16_t unused1;
uint32_t unused2;
uint64_t unused3;
uint64_t unused4;
} unknown;
/* ::type is #PSA_CRYPTO_TRANSACTION_CREATE_KEY or
* #PSA_CRYPTO_TRANSACTION_DESTROY_KEY. */
struct psa_crypto_transaction_key_s
{
psa_crypto_transaction_type_t type;
uint16_t unused1;
psa_key_lifetime_t lifetime;
psa_key_slot_number_t slot;
psa_key_id_t id;
} key;
} psa_crypto_transaction_t;
/** The single active transaction.
*/
extern psa_crypto_transaction_t psa_crypto_transaction;
/** Prepare for a transaction.
*
* There must not be an ongoing transaction.
*
* \param type The type of transaction to start.
*/
static inline void psa_crypto_prepare_transaction(
psa_crypto_transaction_type_t type )
{
psa_crypto_transaction.unknown.type = type;
}
/** Save the transaction data to storage.
*
* You may call this function multiple times during a transaction to
* atomically update the transaction state.
*
* \retval #PSA_SUCCESS
* \retval #PSA_ERROR_INSUFFICIENT_STORAGE
* \retval #PSA_ERROR_STORAGE_FAILURE
*/
psa_status_t psa_crypto_save_transaction( void );
/** Load the transaction data from storage, if any.
*
* This function is meant to be called from psa_crypto_init() to recover
* in case a transaction was interrupted by a system crash.
*
* \retval #PSA_SUCCESS
* The data about the ongoing transaction has been loaded to
* #psa_crypto_transaction.
* \retval #PSA_ERROR_DOES_NOT_EXIST
* There is no ongoing transaction.
* \retval #PSA_ERROR_STORAGE_FAILURE
*/
psa_status_t psa_crypto_load_transaction( void );
/** Indicate that the current transaction is finished.
*
* Call this function at the very end of transaction processing.
* This function does not "commit" or "abort" the transaction: the storage
* subsystem has no concept of "commit" and "abort", just saving and
* removing the transaction information in storage.
*
* This function erases the transaction data in storage (if any) and
* resets the transaction data in memory.
*
* \retval #PSA_SUCCESS
* There was transaction data in storage.
* \retval #PSA_ERROR_DOES_NOT_EXIST
* There was no transaction data in storage.
* \retval #PSA_ERROR_STORAGE_FAILURE
* It was impossible to determine whether there was transaction data
* in storage, or the transaction data could not be erased.
*/
psa_status_t psa_crypto_stop_transaction( void );
/** The ITS file identifier for the transaction data.
*
* 0xffffffNN = special file; 0x74 = 't' for transaction.
*/
#define PSA_CRYPTO_ITS_TRANSACTION_UID ( (psa_key_id_t) 0xffffff74 )
#endif /* PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS */
#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
/** Backend side of mbedtls_psa_inject_entropy().
*
* This function stores the supplied data into the entropy seed file.
*
* \retval #PSA_SUCCESS
* Success
* \retval #PSA_ERROR_STORAGE_FAILURE
* \retval #PSA_ERROR_INSUFFICIENT_STORAGE
* \retval #PSA_ERROR_NOT_PERMITTED
* The entropy seed file already exists.
*/
psa_status_t mbedtls_psa_storage_inject_entropy( const unsigned char *seed,
size_t seed_size );
#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_STORAGE_H */

255
library/psa_its_file.c Normal file
View File

@ -0,0 +1,255 @@
/*
* PSA ITS simulator over stdio files.
*/
/* Copyright (C) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if defined(MBEDTLS_CONFIG_FILE)
#include MBEDTLS_CONFIG_FILE
#else
#include "mbedtls/config.h"
#endif
#if defined(MBEDTLS_PSA_ITS_FILE_C)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#define mbedtls_snprintf snprintf
#endif
#if defined(_WIN32)
#include <windows.h>
#endif
#include "psa_crypto_its.h"
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#if !defined(PSA_ITS_STORAGE_PREFIX)
#define PSA_ITS_STORAGE_PREFIX ""
#endif
#define PSA_ITS_STORAGE_FILENAME_PATTERN "%08lx%08lx"
#define PSA_ITS_STORAGE_SUFFIX ".psa_its"
#define PSA_ITS_STORAGE_FILENAME_LENGTH \
( sizeof( PSA_ITS_STORAGE_PREFIX ) - 1 + /*prefix without terminating 0*/ \
16 + /*UID (64-bit number in hex)*/ \
sizeof( PSA_ITS_STORAGE_SUFFIX ) - 1 + /*suffix without terminating 0*/ \
1 /*terminating null byte*/ )
#define PSA_ITS_STORAGE_TEMP \
PSA_ITS_STORAGE_PREFIX "tempfile" PSA_ITS_STORAGE_SUFFIX
/* The maximum value of psa_storage_info_t.size */
#define PSA_ITS_MAX_SIZE 0xffffffff
#define PSA_ITS_MAGIC_STRING "PSA\0ITS\0"
#define PSA_ITS_MAGIC_LENGTH 8
/* As rename fails on Windows if the new filepath already exists,
* use MoveFileExA with the MOVEFILE_REPLACE_EXISTING flag instead.
* Returns 0 on success, nonzero on failure. */
#if defined(_WIN32)
#define rename_replace_existing( oldpath, newpath ) \
( ! MoveFileExA( oldpath, newpath, MOVEFILE_REPLACE_EXISTING ) )
#else
#define rename_replace_existing( oldpath, newpath ) rename( oldpath, newpath )
#endif
typedef struct
{
uint8_t magic[PSA_ITS_MAGIC_LENGTH];
uint8_t size[sizeof( uint32_t )];
uint8_t flags[sizeof( psa_storage_create_flags_t )];
} psa_its_file_header_t;
static void psa_its_fill_filename( psa_storage_uid_t uid, char *filename )
{
/* Break up the UID into two 32-bit pieces so as not to rely on
* long long support in snprintf. */
mbedtls_snprintf( filename, PSA_ITS_STORAGE_FILENAME_LENGTH,
"%s" PSA_ITS_STORAGE_FILENAME_PATTERN "%s",
PSA_ITS_STORAGE_PREFIX,
(unsigned long) ( uid >> 32 ),
(unsigned long) ( uid & 0xffffffff ),
PSA_ITS_STORAGE_SUFFIX );
}
static psa_status_t psa_its_read_file( psa_storage_uid_t uid,
struct psa_storage_info_t *p_info,
FILE **p_stream )
{
char filename[PSA_ITS_STORAGE_FILENAME_LENGTH];
psa_its_file_header_t header;
size_t n;
*p_stream = NULL;
psa_its_fill_filename( uid, filename );
*p_stream = fopen( filename, "rb" );
if( *p_stream == NULL )
return( PSA_ERROR_DOES_NOT_EXIST );
n = fread( &header, 1, sizeof( header ), *p_stream );
if( n != sizeof( header ) )
return( PSA_ERROR_DATA_CORRUPT );
if( memcmp( header.magic, PSA_ITS_MAGIC_STRING,
PSA_ITS_MAGIC_LENGTH ) != 0 )
return( PSA_ERROR_DATA_CORRUPT );
p_info->size = ( header.size[0] |
header.size[1] << 8 |
header.size[2] << 16 |
header.size[3] << 24 );
p_info->flags = ( header.flags[0] |
header.flags[1] << 8 |
header.flags[2] << 16 |
header.flags[3] << 24 );
return( PSA_SUCCESS );
}
psa_status_t psa_its_get_info( psa_storage_uid_t uid,
struct psa_storage_info_t *p_info )
{
psa_status_t status;
FILE *stream = NULL;
status = psa_its_read_file( uid, p_info, &stream );
if( stream != NULL )
fclose( stream );
return( status );
}
psa_status_t psa_its_get( psa_storage_uid_t uid,
uint32_t data_offset,
uint32_t data_length,
void *p_data,
size_t *p_data_length )
{
psa_status_t status;
FILE *stream = NULL;
size_t n;
struct psa_storage_info_t info;
status = psa_its_read_file( uid, &info, &stream );
if( status != PSA_SUCCESS )
goto exit;
status = PSA_ERROR_INVALID_ARGUMENT;
if( data_offset + data_length < data_offset )
goto exit;
#if SIZE_MAX < 0xffffffff
if( data_offset + data_length > SIZE_MAX )
goto exit;
#endif
if( data_offset + data_length > info.size )
goto exit;
status = PSA_ERROR_STORAGE_FAILURE;
#if LONG_MAX < 0xffffffff
while( data_offset > LONG_MAX )
{
if( fseek( stream, LONG_MAX, SEEK_CUR ) != 0 )
goto exit;
data_offset -= LONG_MAX;
}
#endif
if( fseek( stream, data_offset, SEEK_CUR ) != 0 )
goto exit;
n = fread( p_data, 1, data_length, stream );
if( n != data_length )
goto exit;
status = PSA_SUCCESS;
if( p_data_length != NULL )
*p_data_length = n;
exit:
if( stream != NULL )
fclose( stream );
return( status );
}
psa_status_t psa_its_set( psa_storage_uid_t uid,
uint32_t data_length,
const void *p_data,
psa_storage_create_flags_t create_flags )
{
psa_status_t status = PSA_ERROR_STORAGE_FAILURE;
char filename[PSA_ITS_STORAGE_FILENAME_LENGTH];
FILE *stream = NULL;
psa_its_file_header_t header;
size_t n;
memcpy( header.magic, PSA_ITS_MAGIC_STRING, PSA_ITS_MAGIC_LENGTH );
header.size[0] = data_length & 0xff;
header.size[1] = ( data_length >> 8 ) & 0xff;
header.size[2] = ( data_length >> 16 ) & 0xff;
header.size[3] = ( data_length >> 24 ) & 0xff;
header.flags[0] = create_flags & 0xff;
header.flags[1] = ( create_flags >> 8 ) & 0xff;
header.flags[2] = ( create_flags >> 16 ) & 0xff;
header.flags[3] = ( create_flags >> 24 ) & 0xff;
psa_its_fill_filename( uid, filename );
stream = fopen( PSA_ITS_STORAGE_TEMP, "wb" );
if( stream == NULL )
goto exit;
status = PSA_ERROR_INSUFFICIENT_STORAGE;
n = fwrite( &header, 1, sizeof( header ), stream );
if( n != sizeof( header ) )
goto exit;
if( data_length != 0 )
{
n = fwrite( p_data, 1, data_length, stream );
if( n != data_length )
goto exit;
}
status = PSA_SUCCESS;
exit:
if( stream != NULL )
{
int ret = fclose( stream );
if( status == PSA_SUCCESS && ret != 0 )
status = PSA_ERROR_INSUFFICIENT_STORAGE;
}
if( status == PSA_SUCCESS )
{
if( rename_replace_existing( PSA_ITS_STORAGE_TEMP, filename ) != 0 )
status = PSA_ERROR_STORAGE_FAILURE;
}
remove( PSA_ITS_STORAGE_TEMP );
return( status );
}
psa_status_t psa_its_remove( psa_storage_uid_t uid )
{
char filename[PSA_ITS_STORAGE_FILENAME_LENGTH];
FILE *stream;
psa_its_fill_filename( uid, filename );
stream = fopen( filename, "rb" );
if( stream == NULL )
return( PSA_ERROR_DOES_NOT_EXIST );
fclose( stream );
if( remove( filename ) != 0 )
return( PSA_ERROR_STORAGE_FAILURE );
return( PSA_SUCCESS );
}
#endif /* MBEDTLS_PSA_ITS_FILE_C */

560
library/ripemd160.c Normal file
View File

@ -0,0 +1,560 @@
/*
* RIPE MD-160 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The RIPEMD-160 algorithm was designed by RIPE in 1996
* http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html
* http://ehash.iaik.tugraz.at/wiki/RIPEMD-160
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_RIPEMD160_C)
#include "mbedtls/ripemd160.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_RIPEMD160_ALT)
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_UINT32_LE
#define GET_UINT32_LE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] ) \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
| ( (uint32_t) (b)[(i) + 3] << 24 ); \
}
#endif
#ifndef PUT_UINT32_LE
#define PUT_UINT32_LE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
(b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
(b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
}
#endif
void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_ripemd160_context ) );
}
void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ripemd160_context ) );
}
void mbedtls_ripemd160_clone( mbedtls_ripemd160_context *dst,
const mbedtls_ripemd160_context *src )
{
*dst = *src;
}
/*
* RIPEMD-160 context setup
*/
int mbedtls_ripemd160_starts_ret( mbedtls_ripemd160_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_ripemd160_starts( mbedtls_ripemd160_context *ctx )
{
mbedtls_ripemd160_starts_ret( ctx );
}
#endif
#if !defined(MBEDTLS_RIPEMD160_PROCESS_ALT)
/*
* Process one block
*/
int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx,
const unsigned char data[64] )
{
uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16];
GET_UINT32_LE( X[ 0], data, 0 );
GET_UINT32_LE( X[ 1], data, 4 );
GET_UINT32_LE( X[ 2], data, 8 );
GET_UINT32_LE( X[ 3], data, 12 );
GET_UINT32_LE( X[ 4], data, 16 );
GET_UINT32_LE( X[ 5], data, 20 );
GET_UINT32_LE( X[ 6], data, 24 );
GET_UINT32_LE( X[ 7], data, 28 );
GET_UINT32_LE( X[ 8], data, 32 );
GET_UINT32_LE( X[ 9], data, 36 );
GET_UINT32_LE( X[10], data, 40 );
GET_UINT32_LE( X[11], data, 44 );
GET_UINT32_LE( X[12], data, 48 );
GET_UINT32_LE( X[13], data, 52 );
GET_UINT32_LE( X[14], data, 56 );
GET_UINT32_LE( X[15], data, 60 );
A = Ap = ctx->state[0];
B = Bp = ctx->state[1];
C = Cp = ctx->state[2];
D = Dp = ctx->state[3];
E = Ep = ctx->state[4];
#define F1( x, y, z ) ( (x) ^ (y) ^ (z) )
#define F2( x, y, z ) ( ( (x) & (y) ) | ( ~(x) & (z) ) )
#define F3( x, y, z ) ( ( (x) | ~(y) ) ^ (z) )
#define F4( x, y, z ) ( ( (x) & (z) ) | ( (y) & ~(z) ) )
#define F5( x, y, z ) ( (x) ^ ( (y) | ~(z) ) )
#define S( x, n ) ( ( (x) << (n) ) | ( (x) >> (32 - (n)) ) )
#define P( a, b, c, d, e, r, s, f, k ) \
do \
{ \
(a) += f( (b), (c), (d) ) + X[r] + (k); \
(a) = S( (a), (s) ) + (e); \
(c) = S( (c), 10 ); \
} while( 0 )
#define P2( a, b, c, d, e, r, s, rp, sp ) \
do \
{ \
P( (a), (b), (c), (d), (e), (r), (s), F, K ); \
P( a ## p, b ## p, c ## p, d ## p, e ## p, \
(rp), (sp), Fp, Kp ); \
} while( 0 )
#define F F1
#define K 0x00000000
#define Fp F5
#define Kp 0x50A28BE6
P2( A, B, C, D, E, 0, 11, 5, 8 );
P2( E, A, B, C, D, 1, 14, 14, 9 );
P2( D, E, A, B, C, 2, 15, 7, 9 );
P2( C, D, E, A, B, 3, 12, 0, 11 );
P2( B, C, D, E, A, 4, 5, 9, 13 );
P2( A, B, C, D, E, 5, 8, 2, 15 );
P2( E, A, B, C, D, 6, 7, 11, 15 );
P2( D, E, A, B, C, 7, 9, 4, 5 );
P2( C, D, E, A, B, 8, 11, 13, 7 );
P2( B, C, D, E, A, 9, 13, 6, 7 );
P2( A, B, C, D, E, 10, 14, 15, 8 );
P2( E, A, B, C, D, 11, 15, 8, 11 );
P2( D, E, A, B, C, 12, 6, 1, 14 );
P2( C, D, E, A, B, 13, 7, 10, 14 );
P2( B, C, D, E, A, 14, 9, 3, 12 );
P2( A, B, C, D, E, 15, 8, 12, 6 );
#undef F
#undef K
#undef Fp
#undef Kp
#define F F2
#define K 0x5A827999
#define Fp F4
#define Kp 0x5C4DD124
P2( E, A, B, C, D, 7, 7, 6, 9 );
P2( D, E, A, B, C, 4, 6, 11, 13 );
P2( C, D, E, A, B, 13, 8, 3, 15 );
P2( B, C, D, E, A, 1, 13, 7, 7 );
P2( A, B, C, D, E, 10, 11, 0, 12 );
P2( E, A, B, C, D, 6, 9, 13, 8 );
P2( D, E, A, B, C, 15, 7, 5, 9 );
P2( C, D, E, A, B, 3, 15, 10, 11 );
P2( B, C, D, E, A, 12, 7, 14, 7 );
P2( A, B, C, D, E, 0, 12, 15, 7 );
P2( E, A, B, C, D, 9, 15, 8, 12 );
P2( D, E, A, B, C, 5, 9, 12, 7 );
P2( C, D, E, A, B, 2, 11, 4, 6 );
P2( B, C, D, E, A, 14, 7, 9, 15 );
P2( A, B, C, D, E, 11, 13, 1, 13 );
P2( E, A, B, C, D, 8, 12, 2, 11 );
#undef F
#undef K
#undef Fp
#undef Kp
#define F F3
#define K 0x6ED9EBA1
#define Fp F3
#define Kp 0x6D703EF3
P2( D, E, A, B, C, 3, 11, 15, 9 );
P2( C, D, E, A, B, 10, 13, 5, 7 );
P2( B, C, D, E, A, 14, 6, 1, 15 );
P2( A, B, C, D, E, 4, 7, 3, 11 );
P2( E, A, B, C, D, 9, 14, 7, 8 );
P2( D, E, A, B, C, 15, 9, 14, 6 );
P2( C, D, E, A, B, 8, 13, 6, 6 );
P2( B, C, D, E, A, 1, 15, 9, 14 );
P2( A, B, C, D, E, 2, 14, 11, 12 );
P2( E, A, B, C, D, 7, 8, 8, 13 );
P2( D, E, A, B, C, 0, 13, 12, 5 );
P2( C, D, E, A, B, 6, 6, 2, 14 );
P2( B, C, D, E, A, 13, 5, 10, 13 );
P2( A, B, C, D, E, 11, 12, 0, 13 );
P2( E, A, B, C, D, 5, 7, 4, 7 );
P2( D, E, A, B, C, 12, 5, 13, 5 );
#undef F
#undef K
#undef Fp
#undef Kp
#define F F4
#define K 0x8F1BBCDC
#define Fp F2
#define Kp 0x7A6D76E9
P2( C, D, E, A, B, 1, 11, 8, 15 );
P2( B, C, D, E, A, 9, 12, 6, 5 );
P2( A, B, C, D, E, 11, 14, 4, 8 );
P2( E, A, B, C, D, 10, 15, 1, 11 );
P2( D, E, A, B, C, 0, 14, 3, 14 );
P2( C, D, E, A, B, 8, 15, 11, 14 );
P2( B, C, D, E, A, 12, 9, 15, 6 );
P2( A, B, C, D, E, 4, 8, 0, 14 );
P2( E, A, B, C, D, 13, 9, 5, 6 );
P2( D, E, A, B, C, 3, 14, 12, 9 );
P2( C, D, E, A, B, 7, 5, 2, 12 );
P2( B, C, D, E, A, 15, 6, 13, 9 );
P2( A, B, C, D, E, 14, 8, 9, 12 );
P2( E, A, B, C, D, 5, 6, 7, 5 );
P2( D, E, A, B, C, 6, 5, 10, 15 );
P2( C, D, E, A, B, 2, 12, 14, 8 );
#undef F
#undef K
#undef Fp
#undef Kp
#define F F5
#define K 0xA953FD4E
#define Fp F1
#define Kp 0x00000000
P2( B, C, D, E, A, 4, 9, 12, 8 );
P2( A, B, C, D, E, 0, 15, 15, 5 );
P2( E, A, B, C, D, 5, 5, 10, 12 );
P2( D, E, A, B, C, 9, 11, 4, 9 );
P2( C, D, E, A, B, 7, 6, 1, 12 );
P2( B, C, D, E, A, 12, 8, 5, 5 );
P2( A, B, C, D, E, 2, 13, 8, 14 );
P2( E, A, B, C, D, 10, 12, 7, 6 );
P2( D, E, A, B, C, 14, 5, 6, 8 );
P2( C, D, E, A, B, 1, 12, 2, 13 );
P2( B, C, D, E, A, 3, 13, 13, 6 );
P2( A, B, C, D, E, 8, 14, 14, 5 );
P2( E, A, B, C, D, 11, 11, 0, 15 );
P2( D, E, A, B, C, 6, 8, 3, 13 );
P2( C, D, E, A, B, 15, 5, 9, 11 );
P2( B, C, D, E, A, 13, 6, 11, 11 );
#undef F
#undef K
#undef Fp
#undef Kp
C = ctx->state[1] + C + Dp;
ctx->state[1] = ctx->state[2] + D + Ep;
ctx->state[2] = ctx->state[3] + E + Ap;
ctx->state[3] = ctx->state[4] + A + Bp;
ctx->state[4] = ctx->state[0] + B + Cp;
ctx->state[0] = C;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_ripemd160_process( mbedtls_ripemd160_context *ctx,
const unsigned char data[64] )
{
mbedtls_internal_ripemd160_process( ctx, data );
}
#endif
#endif /* !MBEDTLS_RIPEMD160_PROCESS_ALT */
/*
* RIPEMD-160 process buffer
*/
int mbedtls_ripemd160_update_ret( mbedtls_ripemd160_context *ctx,
const unsigned char *input,
size_t ilen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t fill;
uint32_t left;
if( ilen == 0 )
return( 0 );
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (uint32_t) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
memcpy( (void *) (ctx->buffer + left), input, fill );
if( ( ret = mbedtls_internal_ripemd160_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
if( ( ret = mbedtls_internal_ripemd160_process( ctx, input ) ) != 0 )
return( ret );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
{
memcpy( (void *) (ctx->buffer + left), input, ilen );
}
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_ripemd160_update( mbedtls_ripemd160_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_ripemd160_update_ret( ctx, input, ilen );
}
#endif
static const unsigned char ripemd160_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* RIPEMD-160 final digest
*/
int mbedtls_ripemd160_finish_ret( mbedtls_ripemd160_context *ctx,
unsigned char output[20] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_LE( low, msglen, 0 );
PUT_UINT32_LE( high, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
ret = mbedtls_ripemd160_update_ret( ctx, ripemd160_padding, padn );
if( ret != 0 )
return( ret );
ret = mbedtls_ripemd160_update_ret( ctx, msglen, 8 );
if( ret != 0 )
return( ret );
PUT_UINT32_LE( ctx->state[0], output, 0 );
PUT_UINT32_LE( ctx->state[1], output, 4 );
PUT_UINT32_LE( ctx->state[2], output, 8 );
PUT_UINT32_LE( ctx->state[3], output, 12 );
PUT_UINT32_LE( ctx->state[4], output, 16 );
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_ripemd160_finish( mbedtls_ripemd160_context *ctx,
unsigned char output[20] )
{
mbedtls_ripemd160_finish_ret( ctx, output );
}
#endif
#endif /* ! MBEDTLS_RIPEMD160_ALT */
/*
* output = RIPEMD-160( input buffer )
*/
int mbedtls_ripemd160_ret( const unsigned char *input,
size_t ilen,
unsigned char output[20] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ripemd160_context ctx;
mbedtls_ripemd160_init( &ctx );
if( ( ret = mbedtls_ripemd160_starts_ret( &ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_ripemd160_update_ret( &ctx, input, ilen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_ripemd160_finish_ret( &ctx, output ) ) != 0 )
goto exit;
exit:
mbedtls_ripemd160_free( &ctx );
return( ret );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_ripemd160( const unsigned char *input,
size_t ilen,
unsigned char output[20] )
{
mbedtls_ripemd160_ret( input, ilen, output );
}
#endif
#if defined(MBEDTLS_SELF_TEST)
/*
* Test vectors from the RIPEMD-160 paper and
* http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html#HMAC
*/
#define TESTS 8
static const unsigned char ripemd160_test_str[TESTS][81] =
{
{ "" },
{ "a" },
{ "abc" },
{ "message digest" },
{ "abcdefghijklmnopqrstuvwxyz" },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
{ "12345678901234567890123456789012345678901234567890123456789012"
"345678901234567890" },
};
static const size_t ripemd160_test_strlen[TESTS] =
{
0, 1, 3, 14, 26, 56, 62, 80
};
static const unsigned char ripemd160_test_md[TESTS][20] =
{
{ 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28,
0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 },
{ 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae,
0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe },
{ 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04,
0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc },
{ 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8,
0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 },
{ 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb,
0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc },
{ 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05,
0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b },
{ 0xb0, 0xe2, 0x0b, 0x6e, 0x31, 0x16, 0x64, 0x02, 0x86, 0xed,
0x3a, 0x87, 0xa5, 0x71, 0x30, 0x79, 0xb2, 0x1f, 0x51, 0x89 },
{ 0x9b, 0x75, 0x2e, 0x45, 0x57, 0x3d, 0x4b, 0x39, 0xf4, 0xdb,
0xd3, 0x32, 0x3c, 0xab, 0x82, 0xbf, 0x63, 0x32, 0x6b, 0xfb },
};
/*
* Checkup routine
*/
int mbedtls_ripemd160_self_test( int verbose )
{
int i, ret = 0;
unsigned char output[20];
memset( output, 0, sizeof output );
for( i = 0; i < TESTS; i++ )
{
if( verbose != 0 )
mbedtls_printf( " RIPEMD-160 test #%d: ", i + 1 );
ret = mbedtls_ripemd160_ret( ripemd160_test_str[i],
ripemd160_test_strlen[i], output );
if( ret != 0 )
goto fail;
if( memcmp( output, ripemd160_test_md[i], 20 ) != 0 )
{
ret = 1;
goto fail;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
fail:
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_RIPEMD160_C */

2739
library/rsa.c Normal file

File diff suppressed because it is too large Load Diff

492
library/rsa_internal.c Normal file
View File

@ -0,0 +1,492 @@
/*
* Helper functions for the RSA module
*
* Copyright (C) 2006-2017, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_RSA_C)
#include "mbedtls/rsa.h"
#include "mbedtls/bignum.h"
#include "mbedtls/rsa_internal.h"
/*
* Compute RSA prime factors from public and private exponents
*
* Summary of algorithm:
* Setting F := lcm(P-1,Q-1), the idea is as follows:
*
* (a) For any 1 <= X < N with gcd(X,N)=1, we have X^F = 1 modulo N, so X^(F/2)
* is a square root of 1 in Z/NZ. Since Z/NZ ~= Z/PZ x Z/QZ by CRT and the
* square roots of 1 in Z/PZ and Z/QZ are +1 and -1, this leaves the four
* possibilities X^(F/2) = (+-1, +-1). If it happens that X^(F/2) = (-1,+1)
* or (+1,-1), then gcd(X^(F/2) + 1, N) will be equal to one of the prime
* factors of N.
*
* (b) If we don't know F/2 but (F/2) * K for some odd (!) K, then the same
* construction still applies since (-)^K is the identity on the set of
* roots of 1 in Z/NZ.
*
* The public and private key primitives (-)^E and (-)^D are mutually inverse
* bijections on Z/NZ if and only if (-)^(DE) is the identity on Z/NZ, i.e.
* if and only if DE - 1 is a multiple of F, say DE - 1 = F * L.
* Splitting L = 2^t * K with K odd, we have
*
* DE - 1 = FL = (F/2) * (2^(t+1)) * K,
*
* so (F / 2) * K is among the numbers
*
* (DE - 1) >> 1, (DE - 1) >> 2, ..., (DE - 1) >> ord
*
* where ord is the order of 2 in (DE - 1).
* We can therefore iterate through these numbers apply the construction
* of (a) and (b) above to attempt to factor N.
*
*/
int mbedtls_rsa_deduce_primes( mbedtls_mpi const *N,
mbedtls_mpi const *E, mbedtls_mpi const *D,
mbedtls_mpi *P, mbedtls_mpi *Q )
{
int ret = 0;
uint16_t attempt; /* Number of current attempt */
uint16_t iter; /* Number of squares computed in the current attempt */
uint16_t order; /* Order of 2 in DE - 1 */
mbedtls_mpi T; /* Holds largest odd divisor of DE - 1 */
mbedtls_mpi K; /* Temporary holding the current candidate */
const unsigned char primes[] = { 2,
3, 5, 7, 11, 13, 17, 19, 23,
29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97,
101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179,
181, 191, 193, 197, 199, 211, 223, 227,
229, 233, 239, 241, 251
};
const size_t num_primes = sizeof( primes ) / sizeof( *primes );
if( P == NULL || Q == NULL || P->p != NULL || Q->p != NULL )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 ||
mbedtls_mpi_cmp_int( D, 1 ) <= 0 ||
mbedtls_mpi_cmp_mpi( D, N ) >= 0 ||
mbedtls_mpi_cmp_int( E, 1 ) <= 0 ||
mbedtls_mpi_cmp_mpi( E, N ) >= 0 )
{
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
}
/*
* Initializations and temporary changes
*/
mbedtls_mpi_init( &K );
mbedtls_mpi_init( &T );
/* T := DE - 1 */
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, D, E ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &T, &T, 1 ) );
if( ( order = (uint16_t) mbedtls_mpi_lsb( &T ) ) == 0 )
{
ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
goto cleanup;
}
/* After this operation, T holds the largest odd divisor of DE - 1. */
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &T, order ) );
/*
* Actual work
*/
/* Skip trying 2 if N == 1 mod 8 */
attempt = 0;
if( N->p[0] % 8 == 1 )
attempt = 1;
for( ; attempt < num_primes; ++attempt )
{
mbedtls_mpi_lset( &K, primes[attempt] );
/* Check if gcd(K,N) = 1 */
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( P, &K, N ) );
if( mbedtls_mpi_cmp_int( P, 1 ) != 0 )
continue;
/* Go through K^T + 1, K^(2T) + 1, K^(4T) + 1, ...
* and check whether they have nontrivial GCD with N. */
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &K, &K, &T, N,
Q /* temporarily use Q for storing Montgomery
* multiplication helper values */ ) );
for( iter = 1; iter <= order; ++iter )
{
/* If we reach 1 prematurely, there's no point
* in continuing to square K */
if( mbedtls_mpi_cmp_int( &K, 1 ) == 0 )
break;
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &K, &K, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( P, &K, N ) );
if( mbedtls_mpi_cmp_int( P, 1 ) == 1 &&
mbedtls_mpi_cmp_mpi( P, N ) == -1 )
{
/*
* Have found a nontrivial divisor P of N.
* Set Q := N / P.
*/
MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( Q, NULL, N, P ) );
goto cleanup;
}
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, &K, &K ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, N ) );
}
/*
* If we get here, then either we prematurely aborted the loop because
* we reached 1, or K holds primes[attempt]^(DE - 1) mod N, which must
* be 1 if D,E,N were consistent.
* Check if that's the case and abort if not, to avoid very long,
* yet eventually failing, computations if N,D,E were not sane.
*/
if( mbedtls_mpi_cmp_int( &K, 1 ) != 0 )
{
break;
}
}
ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
cleanup:
mbedtls_mpi_free( &K );
mbedtls_mpi_free( &T );
return( ret );
}
/*
* Given P, Q and the public exponent E, deduce D.
* This is essentially a modular inversion.
*/
int mbedtls_rsa_deduce_private_exponent( mbedtls_mpi const *P,
mbedtls_mpi const *Q,
mbedtls_mpi const *E,
mbedtls_mpi *D )
{
int ret = 0;
mbedtls_mpi K, L;
if( D == NULL || mbedtls_mpi_cmp_int( D, 0 ) != 0 )
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
if( mbedtls_mpi_cmp_int( P, 1 ) <= 0 ||
mbedtls_mpi_cmp_int( Q, 1 ) <= 0 ||
mbedtls_mpi_cmp_int( E, 0 ) == 0 )
{
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
}
mbedtls_mpi_init( &K );
mbedtls_mpi_init( &L );
/* Temporarily put K := P-1 and L := Q-1 */
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, Q, 1 ) );
/* Temporarily put D := gcd(P-1, Q-1) */
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( D, &K, &L ) );
/* K := LCM(P-1, Q-1) */
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, &K, &L ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &K, NULL, &K, D ) );
/* Compute modular inverse of E in LCM(P-1, Q-1) */
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( D, E, &K ) );
cleanup:
mbedtls_mpi_free( &K );
mbedtls_mpi_free( &L );
return( ret );
}
/*
* Check that RSA CRT parameters are in accordance with core parameters.
*/
int mbedtls_rsa_validate_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q,
const mbedtls_mpi *D, const mbedtls_mpi *DP,
const mbedtls_mpi *DQ, const mbedtls_mpi *QP )
{
int ret = 0;
mbedtls_mpi K, L;
mbedtls_mpi_init( &K );
mbedtls_mpi_init( &L );
/* Check that DP - D == 0 mod P - 1 */
if( DP != NULL )
{
if( P == NULL )
{
ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
goto cleanup;
}
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &L, DP, D ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &L, &L, &K ) );
if( mbedtls_mpi_cmp_int( &L, 0 ) != 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
/* Check that DQ - D == 0 mod Q - 1 */
if( DQ != NULL )
{
if( Q == NULL )
{
ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
goto cleanup;
}
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, Q, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &L, DQ, D ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &L, &L, &K ) );
if( mbedtls_mpi_cmp_int( &L, 0 ) != 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
/* Check that QP * Q - 1 == 0 mod P */
if( QP != NULL )
{
if( P == NULL || Q == NULL )
{
ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
goto cleanup;
}
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, QP, Q ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, P ) );
if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
cleanup:
/* Wrap MPI error codes by RSA check failure error code */
if( ret != 0 &&
ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED &&
ret != MBEDTLS_ERR_RSA_BAD_INPUT_DATA )
{
ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
}
mbedtls_mpi_free( &K );
mbedtls_mpi_free( &L );
return( ret );
}
/*
* Check that core RSA parameters are sane.
*/
int mbedtls_rsa_validate_params( const mbedtls_mpi *N, const mbedtls_mpi *P,
const mbedtls_mpi *Q, const mbedtls_mpi *D,
const mbedtls_mpi *E,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng )
{
int ret = 0;
mbedtls_mpi K, L;
mbedtls_mpi_init( &K );
mbedtls_mpi_init( &L );
/*
* Step 1: If PRNG provided, check that P and Q are prime
*/
#if defined(MBEDTLS_GENPRIME)
/*
* When generating keys, the strongest security we support aims for an error
* rate of at most 2^-100 and we are aiming for the same certainty here as
* well.
*/
if( f_rng != NULL && P != NULL &&
( ret = mbedtls_mpi_is_prime_ext( P, 50, f_rng, p_rng ) ) != 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
if( f_rng != NULL && Q != NULL &&
( ret = mbedtls_mpi_is_prime_ext( Q, 50, f_rng, p_rng ) ) != 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
#else
((void) f_rng);
((void) p_rng);
#endif /* MBEDTLS_GENPRIME */
/*
* Step 2: Check that 1 < N = P * Q
*/
if( P != NULL && Q != NULL && N != NULL )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, P, Q ) );
if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 ||
mbedtls_mpi_cmp_mpi( &K, N ) != 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
/*
* Step 3: Check and 1 < D, E < N if present.
*/
if( N != NULL && D != NULL && E != NULL )
{
if ( mbedtls_mpi_cmp_int( D, 1 ) <= 0 ||
mbedtls_mpi_cmp_int( E, 1 ) <= 0 ||
mbedtls_mpi_cmp_mpi( D, N ) >= 0 ||
mbedtls_mpi_cmp_mpi( E, N ) >= 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
/*
* Step 4: Check that D, E are inverse modulo P-1 and Q-1
*/
if( P != NULL && Q != NULL && D != NULL && E != NULL )
{
if( mbedtls_mpi_cmp_int( P, 1 ) <= 0 ||
mbedtls_mpi_cmp_int( Q, 1 ) <= 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
/* Compute DE-1 mod P-1 */
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, D, E ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, P, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, &L ) );
if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
/* Compute DE-1 mod Q-1 */
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, D, E ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, Q, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, &L ) );
if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 )
{
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
cleanup:
mbedtls_mpi_free( &K );
mbedtls_mpi_free( &L );
/* Wrap MPI error codes by RSA check failure error code */
if( ret != 0 && ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED )
{
ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
}
return( ret );
}
int mbedtls_rsa_deduce_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q,
const mbedtls_mpi *D, mbedtls_mpi *DP,
mbedtls_mpi *DQ, mbedtls_mpi *QP )
{
int ret = 0;
mbedtls_mpi K;
mbedtls_mpi_init( &K );
/* DP = D mod P-1 */
if( DP != NULL )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( DP, D, &K ) );
}
/* DQ = D mod Q-1 */
if( DQ != NULL )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, Q, 1 ) );
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( DQ, D, &K ) );
}
/* QP = Q^{-1} mod P */
if( QP != NULL )
{
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( QP, Q, P ) );
}
cleanup:
mbedtls_mpi_free( &K );
return( ret );
}
#endif /* MBEDTLS_RSA_C */

574
library/sha1.c Normal file
View File

@ -0,0 +1,574 @@
/*
* FIPS-180-1 compliant SHA-1 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The SHA-1 standard was published by NIST in 1993.
*
* http://www.itl.nist.gov/fipspubs/fip180-1.htm
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SHA1_C)
#include "mbedtls/sha1.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#define SHA1_VALIDATE_RET(cond) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA1_BAD_INPUT_DATA )
#define SHA1_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond )
#if !defined(MBEDTLS_SHA1_ALT)
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
}
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
void mbedtls_sha1_init( mbedtls_sha1_context *ctx )
{
SHA1_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_sha1_context ) );
}
void mbedtls_sha1_free( mbedtls_sha1_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha1_context ) );
}
void mbedtls_sha1_clone( mbedtls_sha1_context *dst,
const mbedtls_sha1_context *src )
{
SHA1_VALIDATE( dst != NULL );
SHA1_VALIDATE( src != NULL );
*dst = *src;
}
/*
* SHA-1 context setup
*/
int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx )
{
SHA1_VALIDATE_RET( ctx != NULL );
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha1_starts( mbedtls_sha1_context *ctx )
{
mbedtls_sha1_starts_ret( ctx );
}
#endif
#if !defined(MBEDTLS_SHA1_PROCESS_ALT)
int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx,
const unsigned char data[64] )
{
uint32_t temp, W[16], A, B, C, D, E;
SHA1_VALIDATE_RET( ctx != NULL );
SHA1_VALIDATE_RET( (const unsigned char *)data != NULL );
GET_UINT32_BE( W[ 0], data, 0 );
GET_UINT32_BE( W[ 1], data, 4 );
GET_UINT32_BE( W[ 2], data, 8 );
GET_UINT32_BE( W[ 3], data, 12 );
GET_UINT32_BE( W[ 4], data, 16 );
GET_UINT32_BE( W[ 5], data, 20 );
GET_UINT32_BE( W[ 6], data, 24 );
GET_UINT32_BE( W[ 7], data, 28 );
GET_UINT32_BE( W[ 8], data, 32 );
GET_UINT32_BE( W[ 9], data, 36 );
GET_UINT32_BE( W[10], data, 40 );
GET_UINT32_BE( W[11], data, 44 );
GET_UINT32_BE( W[12], data, 48 );
GET_UINT32_BE( W[13], data, 52 );
GET_UINT32_BE( W[14], data, 56 );
GET_UINT32_BE( W[15], data, 60 );
#define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n))))
#define R(t) \
( \
temp = W[( (t) - 3 ) & 0x0F] ^ W[( (t) - 8 ) & 0x0F] ^ \
W[( (t) - 14 ) & 0x0F] ^ W[ (t) & 0x0F], \
( W[(t) & 0x0F] = S(temp,1) ) \
)
#define P(a,b,c,d,e,x) \
do \
{ \
(e) += S((a),5) + F((b),(c),(d)) + K + (x); \
(b) = S((b),30); \
} while( 0 )
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
#define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define K 0x5A827999
P( A, B, C, D, E, W[0] );
P( E, A, B, C, D, W[1] );
P( D, E, A, B, C, W[2] );
P( C, D, E, A, B, W[3] );
P( B, C, D, E, A, W[4] );
P( A, B, C, D, E, W[5] );
P( E, A, B, C, D, W[6] );
P( D, E, A, B, C, W[7] );
P( C, D, E, A, B, W[8] );
P( B, C, D, E, A, W[9] );
P( A, B, C, D, E, W[10] );
P( E, A, B, C, D, W[11] );
P( D, E, A, B, C, W[12] );
P( C, D, E, A, B, W[13] );
P( B, C, D, E, A, W[14] );
P( A, B, C, D, E, W[15] );
P( E, A, B, C, D, R(16) );
P( D, E, A, B, C, R(17) );
P( C, D, E, A, B, R(18) );
P( B, C, D, E, A, R(19) );
#undef K
#undef F
#define F(x,y,z) ((x) ^ (y) ^ (z))
#define K 0x6ED9EBA1
P( A, B, C, D, E, R(20) );
P( E, A, B, C, D, R(21) );
P( D, E, A, B, C, R(22) );
P( C, D, E, A, B, R(23) );
P( B, C, D, E, A, R(24) );
P( A, B, C, D, E, R(25) );
P( E, A, B, C, D, R(26) );
P( D, E, A, B, C, R(27) );
P( C, D, E, A, B, R(28) );
P( B, C, D, E, A, R(29) );
P( A, B, C, D, E, R(30) );
P( E, A, B, C, D, R(31) );
P( D, E, A, B, C, R(32) );
P( C, D, E, A, B, R(33) );
P( B, C, D, E, A, R(34) );
P( A, B, C, D, E, R(35) );
P( E, A, B, C, D, R(36) );
P( D, E, A, B, C, R(37) );
P( C, D, E, A, B, R(38) );
P( B, C, D, E, A, R(39) );
#undef K
#undef F
#define F(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
#define K 0x8F1BBCDC
P( A, B, C, D, E, R(40) );
P( E, A, B, C, D, R(41) );
P( D, E, A, B, C, R(42) );
P( C, D, E, A, B, R(43) );
P( B, C, D, E, A, R(44) );
P( A, B, C, D, E, R(45) );
P( E, A, B, C, D, R(46) );
P( D, E, A, B, C, R(47) );
P( C, D, E, A, B, R(48) );
P( B, C, D, E, A, R(49) );
P( A, B, C, D, E, R(50) );
P( E, A, B, C, D, R(51) );
P( D, E, A, B, C, R(52) );
P( C, D, E, A, B, R(53) );
P( B, C, D, E, A, R(54) );
P( A, B, C, D, E, R(55) );
P( E, A, B, C, D, R(56) );
P( D, E, A, B, C, R(57) );
P( C, D, E, A, B, R(58) );
P( B, C, D, E, A, R(59) );
#undef K
#undef F
#define F(x,y,z) ((x) ^ (y) ^ (z))
#define K 0xCA62C1D6
P( A, B, C, D, E, R(60) );
P( E, A, B, C, D, R(61) );
P( D, E, A, B, C, R(62) );
P( C, D, E, A, B, R(63) );
P( B, C, D, E, A, R(64) );
P( A, B, C, D, E, R(65) );
P( E, A, B, C, D, R(66) );
P( D, E, A, B, C, R(67) );
P( C, D, E, A, B, R(68) );
P( B, C, D, E, A, R(69) );
P( A, B, C, D, E, R(70) );
P( E, A, B, C, D, R(71) );
P( D, E, A, B, C, R(72) );
P( C, D, E, A, B, R(73) );
P( B, C, D, E, A, R(74) );
P( A, B, C, D, E, R(75) );
P( E, A, B, C, D, R(76) );
P( D, E, A, B, C, R(77) );
P( C, D, E, A, B, R(78) );
P( B, C, D, E, A, R(79) );
#undef K
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha1_process( mbedtls_sha1_context *ctx,
const unsigned char data[64] )
{
mbedtls_internal_sha1_process( ctx, data );
}
#endif
#endif /* !MBEDTLS_SHA1_PROCESS_ALT */
/*
* SHA-1 process buffer
*/
int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx,
const unsigned char *input,
size_t ilen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t fill;
uint32_t left;
SHA1_VALIDATE_RET( ctx != NULL );
SHA1_VALIDATE_RET( ilen == 0 || input != NULL );
if( ilen == 0 )
return( 0 );
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (uint32_t) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
memcpy( (void *) (ctx->buffer + left), input, fill );
if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
if( ( ret = mbedtls_internal_sha1_process( ctx, input ) ) != 0 )
return( ret );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
memcpy( (void *) (ctx->buffer + left), input, ilen );
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha1_update( mbedtls_sha1_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_sha1_update_ret( ctx, input, ilen );
}
#endif
/*
* SHA-1 final digest
*/
int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx,
unsigned char output[20] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
uint32_t used;
uint32_t high, low;
SHA1_VALIDATE_RET( ctx != NULL );
SHA1_VALIDATE_RET( (unsigned char *)output != NULL );
/*
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
*/
used = ctx->total[0] & 0x3F;
ctx->buffer[used++] = 0x80;
if( used <= 56 )
{
/* Enough room for padding + length in current block */
memset( ctx->buffer + used, 0, 56 - used );
}
else
{
/* We'll need an extra block */
memset( ctx->buffer + used, 0, 64 - used );
if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
memset( ctx->buffer, 0, 56 );
}
/*
* Add message length
*/
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_BE( high, ctx->buffer, 56 );
PUT_UINT32_BE( low, ctx->buffer, 60 );
if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
/*
* Output final state
*/
PUT_UINT32_BE( ctx->state[0], output, 0 );
PUT_UINT32_BE( ctx->state[1], output, 4 );
PUT_UINT32_BE( ctx->state[2], output, 8 );
PUT_UINT32_BE( ctx->state[3], output, 12 );
PUT_UINT32_BE( ctx->state[4], output, 16 );
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha1_finish( mbedtls_sha1_context *ctx,
unsigned char output[20] )
{
mbedtls_sha1_finish_ret( ctx, output );
}
#endif
#endif /* !MBEDTLS_SHA1_ALT */
/*
* output = SHA-1( input buffer )
*/
int mbedtls_sha1_ret( const unsigned char *input,
size_t ilen,
unsigned char output[20] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_sha1_context ctx;
SHA1_VALIDATE_RET( ilen == 0 || input != NULL );
SHA1_VALIDATE_RET( (unsigned char *)output != NULL );
mbedtls_sha1_init( &ctx );
if( ( ret = mbedtls_sha1_starts_ret( &ctx ) ) != 0 )
goto exit;
if( ( ret = mbedtls_sha1_update_ret( &ctx, input, ilen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_sha1_finish_ret( &ctx, output ) ) != 0 )
goto exit;
exit:
mbedtls_sha1_free( &ctx );
return( ret );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha1( const unsigned char *input,
size_t ilen,
unsigned char output[20] )
{
mbedtls_sha1_ret( input, ilen, output );
}
#endif
#if defined(MBEDTLS_SELF_TEST)
/*
* FIPS-180-1 test vectors
*/
static const unsigned char sha1_test_buf[3][57] =
{
{ "abc" },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
{ "" }
};
static const size_t sha1_test_buflen[3] =
{
3, 56, 1000
};
static const unsigned char sha1_test_sum[3][20] =
{
{ 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
{ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
{ 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
};
/*
* Checkup routine
*/
int mbedtls_sha1_self_test( int verbose )
{
int i, j, buflen, ret = 0;
unsigned char buf[1024];
unsigned char sha1sum[20];
mbedtls_sha1_context ctx;
mbedtls_sha1_init( &ctx );
/*
* SHA-1
*/
for( i = 0; i < 3; i++ )
{
if( verbose != 0 )
mbedtls_printf( " SHA-1 test #%d: ", i + 1 );
if( ( ret = mbedtls_sha1_starts_ret( &ctx ) ) != 0 )
goto fail;
if( i == 2 )
{
memset( buf, 'a', buflen = 1000 );
for( j = 0; j < 1000; j++ )
{
ret = mbedtls_sha1_update_ret( &ctx, buf, buflen );
if( ret != 0 )
goto fail;
}
}
else
{
ret = mbedtls_sha1_update_ret( &ctx, sha1_test_buf[i],
sha1_test_buflen[i] );
if( ret != 0 )
goto fail;
}
if( ( ret = mbedtls_sha1_finish_ret( &ctx, sha1sum ) ) != 0 )
goto fail;
if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
{
ret = 1;
goto fail;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
goto exit;
fail:
if( verbose != 0 )
mbedtls_printf( "failed\n" );
exit:
mbedtls_sha1_free( &ctx );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_SHA1_C */

587
library/sha256.c Normal file
View File

@ -0,0 +1,587 @@
/*
* FIPS-180-2 compliant SHA-256 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The SHA-256 Secure Hash Standard was published by NIST in 2002.
*
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SHA256_C)
#include "mbedtls/sha256.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#include <stdlib.h>
#define mbedtls_printf printf
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#define SHA256_VALIDATE_RET(cond) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA256_BAD_INPUT_DATA )
#define SHA256_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond )
#if !defined(MBEDTLS_SHA256_ALT)
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
do { \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
} while( 0 )
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
do { \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
} while( 0 )
#endif
void mbedtls_sha256_init( mbedtls_sha256_context *ctx )
{
SHA256_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_sha256_context ) );
}
void mbedtls_sha256_free( mbedtls_sha256_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha256_context ) );
}
void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
const mbedtls_sha256_context *src )
{
SHA256_VALIDATE( dst != NULL );
SHA256_VALIDATE( src != NULL );
*dst = *src;
}
/*
* SHA-256 context setup
*/
int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 )
{
SHA256_VALIDATE_RET( ctx != NULL );
SHA256_VALIDATE_RET( is224 == 0 || is224 == 1 );
ctx->total[0] = 0;
ctx->total[1] = 0;
if( is224 == 0 )
{
/* SHA-256 */
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
else
{
/* SHA-224 */
ctx->state[0] = 0xC1059ED8;
ctx->state[1] = 0x367CD507;
ctx->state[2] = 0x3070DD17;
ctx->state[3] = 0xF70E5939;
ctx->state[4] = 0xFFC00B31;
ctx->state[5] = 0x68581511;
ctx->state[6] = 0x64F98FA7;
ctx->state[7] = 0xBEFA4FA4;
}
ctx->is224 = is224;
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_starts( mbedtls_sha256_context *ctx,
int is224 )
{
mbedtls_sha256_starts_ret( ctx, is224 );
}
#endif
#if !defined(MBEDTLS_SHA256_PROCESS_ALT)
static const uint32_t K[] =
{
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
};
#define SHR(x,n) (((x) & 0xFFFFFFFF) >> (n))
#define ROTR(x,n) (SHR(x,n) | ((x) << (32 - (n))))
#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
#define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
#define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define R(t) \
( \
W[t] = S1(W[(t) - 2]) + W[(t) - 7] + \
S0(W[(t) - 15]) + W[(t) - 16] \
)
#define P(a,b,c,d,e,f,g,h,x,K) \
do \
{ \
temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \
temp2 = S2(a) + F0((a),(b),(c)); \
(d) += temp1; (h) = temp1 + temp2; \
} while( 0 )
int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx,
const unsigned char data[64] )
{
uint32_t temp1, temp2, W[64];
uint32_t A[8];
unsigned int i;
SHA256_VALIDATE_RET( ctx != NULL );
SHA256_VALIDATE_RET( (const unsigned char *)data != NULL );
for( i = 0; i < 8; i++ )
A[i] = ctx->state[i];
#if defined(MBEDTLS_SHA256_SMALLER)
for( i = 0; i < 64; i++ )
{
if( i < 16 )
GET_UINT32_BE( W[i], data, 4 * i );
else
R( i );
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
}
#else /* MBEDTLS_SHA256_SMALLER */
for( i = 0; i < 16; i++ )
GET_UINT32_BE( W[i], data, 4 * i );
for( i = 0; i < 16; i += 8 )
{
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] );
P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] );
P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] );
P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] );
P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] );
P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] );
P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] );
P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] );
}
for( i = 16; i < 64; i += 8 )
{
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] );
P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] );
P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] );
P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] );
P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] );
P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] );
P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] );
P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] );
}
#endif /* MBEDTLS_SHA256_SMALLER */
for( i = 0; i < 8; i++ )
ctx->state[i] += A[i];
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_process( mbedtls_sha256_context *ctx,
const unsigned char data[64] )
{
mbedtls_internal_sha256_process( ctx, data );
}
#endif
#endif /* !MBEDTLS_SHA256_PROCESS_ALT */
/*
* SHA-256 process buffer
*/
int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx,
const unsigned char *input,
size_t ilen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t fill;
uint32_t left;
SHA256_VALIDATE_RET( ctx != NULL );
SHA256_VALIDATE_RET( ilen == 0 || input != NULL );
if( ilen == 0 )
return( 0 );
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (uint32_t) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
memcpy( (void *) (ctx->buffer + left), input, fill );
if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
if( ( ret = mbedtls_internal_sha256_process( ctx, input ) ) != 0 )
return( ret );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
memcpy( (void *) (ctx->buffer + left), input, ilen );
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_update( mbedtls_sha256_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_sha256_update_ret( ctx, input, ilen );
}
#endif
/*
* SHA-256 final digest
*/
int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx,
unsigned char output[32] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
uint32_t used;
uint32_t high, low;
SHA256_VALIDATE_RET( ctx != NULL );
SHA256_VALIDATE_RET( (unsigned char *)output != NULL );
/*
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
*/
used = ctx->total[0] & 0x3F;
ctx->buffer[used++] = 0x80;
if( used <= 56 )
{
/* Enough room for padding + length in current block */
memset( ctx->buffer + used, 0, 56 - used );
}
else
{
/* We'll need an extra block */
memset( ctx->buffer + used, 0, 64 - used );
if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
memset( ctx->buffer, 0, 56 );
}
/*
* Add message length
*/
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_BE( high, ctx->buffer, 56 );
PUT_UINT32_BE( low, ctx->buffer, 60 );
if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
/*
* Output final state
*/
PUT_UINT32_BE( ctx->state[0], output, 0 );
PUT_UINT32_BE( ctx->state[1], output, 4 );
PUT_UINT32_BE( ctx->state[2], output, 8 );
PUT_UINT32_BE( ctx->state[3], output, 12 );
PUT_UINT32_BE( ctx->state[4], output, 16 );
PUT_UINT32_BE( ctx->state[5], output, 20 );
PUT_UINT32_BE( ctx->state[6], output, 24 );
if( ctx->is224 == 0 )
PUT_UINT32_BE( ctx->state[7], output, 28 );
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_finish( mbedtls_sha256_context *ctx,
unsigned char output[32] )
{
mbedtls_sha256_finish_ret( ctx, output );
}
#endif
#endif /* !MBEDTLS_SHA256_ALT */
/*
* output = SHA-256( input buffer )
*/
int mbedtls_sha256_ret( const unsigned char *input,
size_t ilen,
unsigned char output[32],
int is224 )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_sha256_context ctx;
SHA256_VALIDATE_RET( is224 == 0 || is224 == 1 );
SHA256_VALIDATE_RET( ilen == 0 || input != NULL );
SHA256_VALIDATE_RET( (unsigned char *)output != NULL );
mbedtls_sha256_init( &ctx );
if( ( ret = mbedtls_sha256_starts_ret( &ctx, is224 ) ) != 0 )
goto exit;
if( ( ret = mbedtls_sha256_update_ret( &ctx, input, ilen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_sha256_finish_ret( &ctx, output ) ) != 0 )
goto exit;
exit:
mbedtls_sha256_free( &ctx );
return( ret );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256( const unsigned char *input,
size_t ilen,
unsigned char output[32],
int is224 )
{
mbedtls_sha256_ret( input, ilen, output, is224 );
}
#endif
#if defined(MBEDTLS_SELF_TEST)
/*
* FIPS-180-2 test vectors
*/
static const unsigned char sha256_test_buf[3][57] =
{
{ "abc" },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
{ "" }
};
static const size_t sha256_test_buflen[3] =
{
3, 56, 1000
};
static const unsigned char sha256_test_sum[6][32] =
{
/*
* SHA-224 test vectors
*/
{ 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
0xE3, 0x6C, 0x9D, 0xA7 },
{ 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
0x52, 0x52, 0x25, 0x25 },
{ 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
0x4E, 0xE7, 0xAD, 0x67 },
/*
* SHA-256 test vectors
*/
{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
{ 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }
};
/*
* Checkup routine
*/
int mbedtls_sha256_self_test( int verbose )
{
int i, j, k, buflen, ret = 0;
unsigned char *buf;
unsigned char sha256sum[32];
mbedtls_sha256_context ctx;
buf = mbedtls_calloc( 1024, sizeof(unsigned char) );
if( NULL == buf )
{
if( verbose != 0 )
mbedtls_printf( "Buffer allocation failed\n" );
return( 1 );
}
mbedtls_sha256_init( &ctx );
for( i = 0; i < 6; i++ )
{
j = i % 3;
k = i < 3;
if( verbose != 0 )
mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 );
if( ( ret = mbedtls_sha256_starts_ret( &ctx, k ) ) != 0 )
goto fail;
if( j == 2 )
{
memset( buf, 'a', buflen = 1000 );
for( j = 0; j < 1000; j++ )
{
ret = mbedtls_sha256_update_ret( &ctx, buf, buflen );
if( ret != 0 )
goto fail;
}
}
else
{
ret = mbedtls_sha256_update_ret( &ctx, sha256_test_buf[j],
sha256_test_buflen[j] );
if( ret != 0 )
goto fail;
}
if( ( ret = mbedtls_sha256_finish_ret( &ctx, sha256sum ) ) != 0 )
goto fail;
if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 )
{
ret = 1;
goto fail;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
goto exit;
fail:
if( verbose != 0 )
mbedtls_printf( "failed\n" );
exit:
mbedtls_sha256_free( &ctx );
mbedtls_free( buf );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_SHA256_C */

680
library/sha512.c Normal file
View File

@ -0,0 +1,680 @@
/*
* FIPS-180-2 compliant SHA-384/512 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The SHA-512 Secure Hash Standard was published by NIST in 2002.
*
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SHA512_C)
#include "mbedtls/sha512.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#if defined(_MSC_VER) || defined(__WATCOMC__)
#define UL64(x) x##ui64
#else
#define UL64(x) x##ULL
#endif
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#include <stdlib.h>
#define mbedtls_printf printf
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#define SHA512_VALIDATE_RET(cond) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA512_BAD_INPUT_DATA )
#define SHA512_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond )
#if !defined(MBEDTLS_SHA512_ALT)
/*
* 64-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT64_BE
#define GET_UINT64_BE(n,b,i) \
{ \
(n) = ( (uint64_t) (b)[(i) ] << 56 ) \
| ( (uint64_t) (b)[(i) + 1] << 48 ) \
| ( (uint64_t) (b)[(i) + 2] << 40 ) \
| ( (uint64_t) (b)[(i) + 3] << 32 ) \
| ( (uint64_t) (b)[(i) + 4] << 24 ) \
| ( (uint64_t) (b)[(i) + 5] << 16 ) \
| ( (uint64_t) (b)[(i) + 6] << 8 ) \
| ( (uint64_t) (b)[(i) + 7] ); \
}
#endif /* GET_UINT64_BE */
#ifndef PUT_UINT64_BE
#define PUT_UINT64_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 56 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \
(b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \
(b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 7] = (unsigned char) ( (n) ); \
}
#endif /* PUT_UINT64_BE */
#if defined(MBEDTLS_SHA512_SMALLER)
static void sha512_put_uint64_be( uint64_t n, unsigned char *b, uint8_t i )
{
PUT_UINT64_BE(n, b, i);
}
#else
#define sha512_put_uint64_be PUT_UINT64_BE
#endif /* MBEDTLS_SHA512_SMALLER */
void mbedtls_sha512_init( mbedtls_sha512_context *ctx )
{
SHA512_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_sha512_context ) );
}
void mbedtls_sha512_free( mbedtls_sha512_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha512_context ) );
}
void mbedtls_sha512_clone( mbedtls_sha512_context *dst,
const mbedtls_sha512_context *src )
{
SHA512_VALIDATE( dst != NULL );
SHA512_VALIDATE( src != NULL );
*dst = *src;
}
/*
* SHA-512 context setup
*/
int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 )
{
SHA512_VALIDATE_RET( ctx != NULL );
#if !defined(MBEDTLS_SHA512_NO_SHA384)
SHA512_VALIDATE_RET( is384 == 0 || is384 == 1 );
#else
SHA512_VALIDATE_RET( is384 == 0 );
#endif
ctx->total[0] = 0;
ctx->total[1] = 0;
if( is384 == 0 )
{
/* SHA-512 */
ctx->state[0] = UL64(0x6A09E667F3BCC908);
ctx->state[1] = UL64(0xBB67AE8584CAA73B);
ctx->state[2] = UL64(0x3C6EF372FE94F82B);
ctx->state[3] = UL64(0xA54FF53A5F1D36F1);
ctx->state[4] = UL64(0x510E527FADE682D1);
ctx->state[5] = UL64(0x9B05688C2B3E6C1F);
ctx->state[6] = UL64(0x1F83D9ABFB41BD6B);
ctx->state[7] = UL64(0x5BE0CD19137E2179);
}
else
{
#if defined(MBEDTLS_SHA512_NO_SHA384)
return( MBEDTLS_ERR_SHA512_BAD_INPUT_DATA );
#else
/* SHA-384 */
ctx->state[0] = UL64(0xCBBB9D5DC1059ED8);
ctx->state[1] = UL64(0x629A292A367CD507);
ctx->state[2] = UL64(0x9159015A3070DD17);
ctx->state[3] = UL64(0x152FECD8F70E5939);
ctx->state[4] = UL64(0x67332667FFC00B31);
ctx->state[5] = UL64(0x8EB44A8768581511);
ctx->state[6] = UL64(0xDB0C2E0D64F98FA7);
ctx->state[7] = UL64(0x47B5481DBEFA4FA4);
#endif /* MBEDTLS_SHA512_NO_SHA384 */
}
#if !defined(MBEDTLS_SHA512_NO_SHA384)
ctx->is384 = is384;
#endif
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha512_starts( mbedtls_sha512_context *ctx,
int is384 )
{
mbedtls_sha512_starts_ret( ctx, is384 );
}
#endif
#if !defined(MBEDTLS_SHA512_PROCESS_ALT)
/*
* Round constants
*/
static const uint64_t K[80] =
{
UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD),
UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC),
UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019),
UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118),
UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE),
UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2),
UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1),
UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694),
UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3),
UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65),
UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483),
UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5),
UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210),
UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4),
UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725),
UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70),
UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926),
UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF),
UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8),
UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B),
UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001),
UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30),
UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910),
UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8),
UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53),
UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8),
UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB),
UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3),
UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60),
UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC),
UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9),
UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B),
UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207),
UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178),
UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6),
UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B),
UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493),
UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C),
UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A),
UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817)
};
int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx,
const unsigned char data[128] )
{
int i;
uint64_t temp1, temp2, W[80];
uint64_t A[8];
SHA512_VALIDATE_RET( ctx != NULL );
SHA512_VALIDATE_RET( (const unsigned char *)data != NULL );
#define SHR(x,n) ((x) >> (n))
#define ROTR(x,n) (SHR((x),(n)) | ((x) << (64 - (n))))
#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7))
#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6))
#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39))
#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41))
#define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
#define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define P(a,b,c,d,e,f,g,h,x,K) \
do \
{ \
temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \
temp2 = S2(a) + F0((a),(b),(c)); \
(d) += temp1; (h) = temp1 + temp2; \
} while( 0 )
for( i = 0; i < 8; i++ )
A[i] = ctx->state[i];
#if defined(MBEDTLS_SHA512_SMALLER)
for( i = 0; i < 80; i++ )
{
if( i < 16 )
{
GET_UINT64_BE( W[i], data, i << 3 );
}
else
{
W[i] = S1(W[i - 2]) + W[i - 7] +
S0(W[i - 15]) + W[i - 16];
}
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
}
#else /* MBEDTLS_SHA512_SMALLER */
for( i = 0; i < 16; i++ )
{
GET_UINT64_BE( W[i], data, i << 3 );
}
for( ; i < 80; i++ )
{
W[i] = S1(W[i - 2]) + W[i - 7] +
S0(W[i - 15]) + W[i - 16];
}
i = 0;
do
{
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] ); i++;
P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i], K[i] ); i++;
P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i], K[i] ); i++;
P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i], K[i] ); i++;
P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i], K[i] ); i++;
P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i], K[i] ); i++;
P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i], K[i] ); i++;
P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i], K[i] ); i++;
}
while( i < 80 );
#endif /* MBEDTLS_SHA512_SMALLER */
for( i = 0; i < 8; i++ )
ctx->state[i] += A[i];
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha512_process( mbedtls_sha512_context *ctx,
const unsigned char data[128] )
{
mbedtls_internal_sha512_process( ctx, data );
}
#endif
#endif /* !MBEDTLS_SHA512_PROCESS_ALT */
/*
* SHA-512 process buffer
*/
int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx,
const unsigned char *input,
size_t ilen )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t fill;
unsigned int left;
SHA512_VALIDATE_RET( ctx != NULL );
SHA512_VALIDATE_RET( ilen == 0 || input != NULL );
if( ilen == 0 )
return( 0 );
left = (unsigned int) (ctx->total[0] & 0x7F);
fill = 128 - left;
ctx->total[0] += (uint64_t) ilen;
if( ctx->total[0] < (uint64_t) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
memcpy( (void *) (ctx->buffer + left), input, fill );
if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 128 )
{
if( ( ret = mbedtls_internal_sha512_process( ctx, input ) ) != 0 )
return( ret );
input += 128;
ilen -= 128;
}
if( ilen > 0 )
memcpy( (void *) (ctx->buffer + left), input, ilen );
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha512_update( mbedtls_sha512_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_sha512_update_ret( ctx, input, ilen );
}
#endif
/*
* SHA-512 final digest
*/
int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx,
unsigned char output[64] )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned used;
uint64_t high, low;
SHA512_VALIDATE_RET( ctx != NULL );
SHA512_VALIDATE_RET( (unsigned char *)output != NULL );
/*
* Add padding: 0x80 then 0x00 until 16 bytes remain for the length
*/
used = ctx->total[0] & 0x7F;
ctx->buffer[used++] = 0x80;
if( used <= 112 )
{
/* Enough room for padding + length in current block */
memset( ctx->buffer + used, 0, 112 - used );
}
else
{
/* We'll need an extra block */
memset( ctx->buffer + used, 0, 128 - used );
if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
memset( ctx->buffer, 0, 112 );
}
/*
* Add message length
*/
high = ( ctx->total[0] >> 61 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
sha512_put_uint64_be( high, ctx->buffer, 112 );
sha512_put_uint64_be( low, ctx->buffer, 120 );
if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 )
return( ret );
/*
* Output final state
*/
sha512_put_uint64_be( ctx->state[0], output, 0 );
sha512_put_uint64_be( ctx->state[1], output, 8 );
sha512_put_uint64_be( ctx->state[2], output, 16 );
sha512_put_uint64_be( ctx->state[3], output, 24 );
sha512_put_uint64_be( ctx->state[4], output, 32 );
sha512_put_uint64_be( ctx->state[5], output, 40 );
#if !defined(MBEDTLS_SHA512_NO_SHA384)
if( ctx->is384 == 0 )
#endif
{
sha512_put_uint64_be( ctx->state[6], output, 48 );
sha512_put_uint64_be( ctx->state[7], output, 56 );
}
return( 0 );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha512_finish( mbedtls_sha512_context *ctx,
unsigned char output[64] )
{
mbedtls_sha512_finish_ret( ctx, output );
}
#endif
#endif /* !MBEDTLS_SHA512_ALT */
/*
* output = SHA-512( input buffer )
*/
int mbedtls_sha512_ret( const unsigned char *input,
size_t ilen,
unsigned char output[64],
int is384 )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_sha512_context ctx;
#if !defined(MBEDTLS_SHA512_NO_SHA384)
SHA512_VALIDATE_RET( is384 == 0 || is384 == 1 );
#else
SHA512_VALIDATE_RET( is384 == 0 );
#endif
SHA512_VALIDATE_RET( ilen == 0 || input != NULL );
SHA512_VALIDATE_RET( (unsigned char *)output != NULL );
mbedtls_sha512_init( &ctx );
if( ( ret = mbedtls_sha512_starts_ret( &ctx, is384 ) ) != 0 )
goto exit;
if( ( ret = mbedtls_sha512_update_ret( &ctx, input, ilen ) ) != 0 )
goto exit;
if( ( ret = mbedtls_sha512_finish_ret( &ctx, output ) ) != 0 )
goto exit;
exit:
mbedtls_sha512_free( &ctx );
return( ret );
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha512( const unsigned char *input,
size_t ilen,
unsigned char output[64],
int is384 )
{
mbedtls_sha512_ret( input, ilen, output, is384 );
}
#endif
#if defined(MBEDTLS_SELF_TEST)
/*
* FIPS-180-2 test vectors
*/
static const unsigned char sha512_test_buf[3][113] =
{
{ "abc" },
{ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" },
{ "" }
};
static const size_t sha512_test_buflen[3] =
{
3, 112, 1000
};
static const unsigned char sha512_test_sum[][64] =
{
#if !defined(MBEDTLS_SHA512_NO_SHA384)
/*
* SHA-384 test vectors
*/
{ 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B,
0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07,
0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63,
0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED,
0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23,
0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 },
{ 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8,
0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47,
0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2,
0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12,
0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9,
0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 },
{ 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB,
0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C,
0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52,
0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B,
0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB,
0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 },
#endif /* !MBEDTLS_SHA512_NO_SHA384 */
/*
* SHA-512 test vectors
*/
{ 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA,
0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31,
0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2,
0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A,
0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8,
0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD,
0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E,
0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F },
{ 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 },
{ 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64,
0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63,
0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28,
0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB,
0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A,
0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B,
0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E,
0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B }
};
#define ARRAY_LENGTH( a ) ( sizeof( a ) / sizeof( ( a )[0] ) )
/*
* Checkup routine
*/
int mbedtls_sha512_self_test( int verbose )
{
int i, j, k, buflen, ret = 0;
unsigned char *buf;
unsigned char sha512sum[64];
mbedtls_sha512_context ctx;
buf = mbedtls_calloc( 1024, sizeof(unsigned char) );
if( NULL == buf )
{
if( verbose != 0 )
mbedtls_printf( "Buffer allocation failed\n" );
return( 1 );
}
mbedtls_sha512_init( &ctx );
for( i = 0; i < (int) ARRAY_LENGTH(sha512_test_sum); i++ )
{
j = i % 3;
#if !defined(MBEDTLS_SHA512_NO_SHA384)
k = i < 3;
#else
k = 0;
#endif
if( verbose != 0 )
mbedtls_printf( " SHA-%d test #%d: ", 512 - k * 128, j + 1 );
if( ( ret = mbedtls_sha512_starts_ret( &ctx, k ) ) != 0 )
goto fail;
if( j == 2 )
{
memset( buf, 'a', buflen = 1000 );
for( j = 0; j < 1000; j++ )
{
ret = mbedtls_sha512_update_ret( &ctx, buf, buflen );
if( ret != 0 )
goto fail;
}
}
else
{
ret = mbedtls_sha512_update_ret( &ctx, sha512_test_buf[j],
sha512_test_buflen[j] );
if( ret != 0 )
goto fail;
}
if( ( ret = mbedtls_sha512_finish_ret( &ctx, sha512sum ) ) != 0 )
goto fail;
if( memcmp( sha512sum, sha512_test_sum[i], 64 - k * 16 ) != 0 )
{
ret = 1;
goto fail;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
goto exit;
fail:
if( verbose != 0 )
mbedtls_printf( "failed\n" );
exit:
mbedtls_sha512_free( &ctx );
mbedtls_free( buf );
return( ret );
}
#undef ARRAY_LENGTH
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_SHA512_C */

187
library/threading.c Normal file
View File

@ -0,0 +1,187 @@
/*
* Threading abstraction layer
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Ensure gmtime_r is available even with -std=c99; must be defined before
* config.h, which pulls in glibc's features.h. Harmless on other platforms.
*/
#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200112L
#endif
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_THREADING_C)
#include "mbedtls/threading.h"
#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
#if !defined(_WIN32) && (defined(unix) || \
defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
defined(__MACH__)))
#include <unistd.h>
#endif /* !_WIN32 && (unix || __unix || __unix__ ||
* (__APPLE__ && __MACH__)) */
#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
/*
* This is a convenience shorthand macro to avoid checking the long
* preprocessor conditions above. Ideally, we could expose this macro in
* platform_util.h and simply use it in platform_util.c, threading.c and
* threading.h. However, this macro is not part of the Mbed TLS public API, so
* we keep it private by only defining it in this file
*/
#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
#define THREADING_USE_GMTIME
#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */
#if defined(MBEDTLS_THREADING_PTHREAD)
static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex )
{
if( mutex == NULL )
return;
mutex->is_valid = pthread_mutex_init( &mutex->mutex, NULL ) == 0;
}
static void threading_mutex_free_pthread( mbedtls_threading_mutex_t *mutex )
{
if( mutex == NULL || !mutex->is_valid )
return;
(void) pthread_mutex_destroy( &mutex->mutex );
mutex->is_valid = 0;
}
static int threading_mutex_lock_pthread( mbedtls_threading_mutex_t *mutex )
{
if( mutex == NULL || ! mutex->is_valid )
return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA );
if( pthread_mutex_lock( &mutex->mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
return( 0 );
}
static int threading_mutex_unlock_pthread( mbedtls_threading_mutex_t *mutex )
{
if( mutex == NULL || ! mutex->is_valid )
return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA );
if( pthread_mutex_unlock( &mutex->mutex ) != 0 )
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
return( 0 );
}
void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_init_pthread;
void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_free_pthread;
int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_lock_pthread;
int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_unlock_pthread;
/*
* With phtreads we can statically initialize mutexes
*/
#define MUTEX_INIT = { PTHREAD_MUTEX_INITIALIZER, 1 }
#endif /* MBEDTLS_THREADING_PTHREAD */
#if defined(MBEDTLS_THREADING_ALT)
static int threading_mutex_fail( mbedtls_threading_mutex_t *mutex )
{
((void) mutex );
return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA );
}
static void threading_mutex_dummy( mbedtls_threading_mutex_t *mutex )
{
((void) mutex );
return;
}
void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy;
void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy;
int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail;
int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail;
/*
* Set functions pointers and initialize global mutexes
*/
void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ),
void (*mutex_free)( mbedtls_threading_mutex_t * ),
int (*mutex_lock)( mbedtls_threading_mutex_t * ),
int (*mutex_unlock)( mbedtls_threading_mutex_t * ) )
{
mbedtls_mutex_init = mutex_init;
mbedtls_mutex_free = mutex_free;
mbedtls_mutex_lock = mutex_lock;
mbedtls_mutex_unlock = mutex_unlock;
#if defined(MBEDTLS_FS_IO)
mbedtls_mutex_init( &mbedtls_threading_readdir_mutex );
#endif
#if defined(THREADING_USE_GMTIME)
mbedtls_mutex_init( &mbedtls_threading_gmtime_mutex );
#endif
}
/*
* Free global mutexes
*/
void mbedtls_threading_free_alt( void )
{
#if defined(MBEDTLS_FS_IO)
mbedtls_mutex_free( &mbedtls_threading_readdir_mutex );
#endif
#if defined(THREADING_USE_GMTIME)
mbedtls_mutex_free( &mbedtls_threading_gmtime_mutex );
#endif
}
#endif /* MBEDTLS_THREADING_ALT */
/*
* Define global mutexes
*/
#ifndef MUTEX_INIT
#define MUTEX_INIT
#endif
#if defined(MBEDTLS_FS_IO)
mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT;
#endif
#if defined(THREADING_USE_GMTIME)
mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex MUTEX_INIT;
#endif
#endif /* MBEDTLS_THREADING_C */

536
library/timing.c Normal file
View File

@ -0,0 +1,536 @@
/*
* Portable interface to the CPU cycle counter
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif
#if defined(MBEDTLS_TIMING_C)
#include "mbedtls/timing.h"
#if !defined(MBEDTLS_TIMING_ALT)
#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
!defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
!defined(__HAIKU__)
#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h"
#endif
#ifndef asm
#define asm __asm
#endif
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
#include <windows.h>
#include <process.h>
struct _hr_time
{
LARGE_INTEGER start;
};
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <time.h>
struct _hr_time
{
struct timeval start;
};
#endif /* _WIN32 && !EFIX64 && !EFI32 */
#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__)
#define HAVE_HARDCLOCK
unsigned long mbedtls_timing_hardclock( void )
{
unsigned long tsc;
__asm rdtsc
__asm mov [tsc], eax
return( tsc );
}
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
( _MSC_VER && _M_IX86 ) || __WATCOMC__ */
/* some versions of mingw-64 have 32-bit longs even on x84_64 */
#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
defined(__GNUC__) && ( defined(__i386__) || ( \
( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) )
#define HAVE_HARDCLOCK
unsigned long mbedtls_timing_hardclock( void )
{
unsigned long lo, hi;
asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) );
return( lo );
}
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
__GNUC__ && __i386__ */
#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) )
#define HAVE_HARDCLOCK
unsigned long mbedtls_timing_hardclock( void )
{
unsigned long lo, hi;
asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) );
return( lo | ( hi << 32 ) );
}
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
__GNUC__ && ( __amd64__ || __x86_64__ ) */
#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) )
#define HAVE_HARDCLOCK
unsigned long mbedtls_timing_hardclock( void )
{
unsigned long tbl, tbu0, tbu1;
do
{
asm volatile( "mftbu %0" : "=r" (tbu0) );
asm volatile( "mftb %0" : "=r" (tbl ) );
asm volatile( "mftbu %0" : "=r" (tbu1) );
}
while( tbu0 != tbu1 );
return( tbl );
}
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
__GNUC__ && ( __powerpc__ || __ppc__ ) */
#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
defined(__GNUC__) && defined(__sparc64__)
#if defined(__OpenBSD__)
#warning OpenBSD does not allow access to tick register using software version instead
#else
#define HAVE_HARDCLOCK
unsigned long mbedtls_timing_hardclock( void )
{
unsigned long tick;
asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) );
return( tick );
}
#endif /* __OpenBSD__ */
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
__GNUC__ && __sparc64__ */
#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__)
#define HAVE_HARDCLOCK
unsigned long mbedtls_timing_hardclock( void )
{
unsigned long tick;
asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" );
asm volatile( "mov %%g1, %0" : "=r" (tick) );
return( tick );
}
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
__GNUC__ && __sparc__ && !__sparc64__ */
#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
defined(__GNUC__) && defined(__alpha__)
#define HAVE_HARDCLOCK
unsigned long mbedtls_timing_hardclock( void )
{
unsigned long cc;
asm volatile( "rpcc %0" : "=r" (cc) );
return( cc & 0xFFFFFFFF );
}
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
__GNUC__ && __alpha__ */
#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
defined(__GNUC__) && defined(__ia64__)
#define HAVE_HARDCLOCK
unsigned long mbedtls_timing_hardclock( void )
{
unsigned long itc;
asm volatile( "mov %0 = ar.itc" : "=r" (itc) );
return( itc );
}
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
__GNUC__ && __ia64__ */
#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \
!defined(EFIX64) && !defined(EFI32)
#define HAVE_HARDCLOCK
unsigned long mbedtls_timing_hardclock( void )
{
LARGE_INTEGER offset;
QueryPerformanceCounter( &offset );
return( (unsigned long)( offset.QuadPart ) );
}
#endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */
#if !defined(HAVE_HARDCLOCK)
#define HAVE_HARDCLOCK
static int hardclock_init = 0;
static struct timeval tv_init;
unsigned long mbedtls_timing_hardclock( void )
{
struct timeval tv_cur;
if( hardclock_init == 0 )
{
gettimeofday( &tv_init, NULL );
hardclock_init = 1;
}
gettimeofday( &tv_cur, NULL );
return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000
+ ( tv_cur.tv_usec - tv_init.tv_usec ) );
}
#endif /* !HAVE_HARDCLOCK */
volatile int mbedtls_timing_alarmed = 0;
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset )
{
struct _hr_time *t = (struct _hr_time *) val;
if( reset )
{
QueryPerformanceCounter( &t->start );
return( 0 );
}
else
{
unsigned long delta;
LARGE_INTEGER now, hfreq;
QueryPerformanceCounter( &now );
QueryPerformanceFrequency( &hfreq );
delta = (unsigned long)( ( now.QuadPart - t->start.QuadPart ) * 1000ul
/ hfreq.QuadPart );
return( delta );
}
}
/* It's OK to use a global because alarm() is supposed to be global anyway */
static DWORD alarmMs;
static void TimerProc( void *TimerContext )
{
(void) TimerContext;
Sleep( alarmMs );
mbedtls_timing_alarmed = 1;
/* _endthread will be called implicitly on return
* That ensures execution of thread funcition's epilogue */
}
void mbedtls_set_alarm( int seconds )
{
if( seconds == 0 )
{
/* No need to create a thread for this simple case.
* Also, this shorcut is more reliable at least on MinGW32 */
mbedtls_timing_alarmed = 1;
return;
}
mbedtls_timing_alarmed = 0;
alarmMs = seconds * 1000;
(void) _beginthread( TimerProc, 0, NULL );
}
#else /* _WIN32 && !EFIX64 && !EFI32 */
unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset )
{
struct _hr_time *t = (struct _hr_time *) val;
if( reset )
{
gettimeofday( &t->start, NULL );
return( 0 );
}
else
{
unsigned long delta;
struct timeval now;
gettimeofday( &now, NULL );
delta = ( now.tv_sec - t->start.tv_sec ) * 1000ul
+ ( now.tv_usec - t->start.tv_usec ) / 1000;
return( delta );
}
}
static void sighandler( int signum )
{
mbedtls_timing_alarmed = 1;
signal( signum, sighandler );
}
void mbedtls_set_alarm( int seconds )
{
mbedtls_timing_alarmed = 0;
signal( SIGALRM, sighandler );
alarm( seconds );
if( seconds == 0 )
{
/* alarm(0) cancelled any previous pending alarm, but the
handler won't fire, so raise the flag straight away. */
mbedtls_timing_alarmed = 1;
}
}
#endif /* _WIN32 && !EFIX64 && !EFI32 */
/*
* Set delays to watch
*/
void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms )
{
mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
ctx->int_ms = int_ms;
ctx->fin_ms = fin_ms;
if( fin_ms != 0 )
(void) mbedtls_timing_get_timer( &ctx->timer, 1 );
}
/*
* Get number of delays expired
*/
int mbedtls_timing_get_delay( void *data )
{
mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
unsigned long elapsed_ms;
if( ctx->fin_ms == 0 )
return( -1 );
elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 );
if( elapsed_ms >= ctx->fin_ms )
return( 2 );
if( elapsed_ms >= ctx->int_ms )
return( 1 );
return( 0 );
}
#endif /* !MBEDTLS_TIMING_ALT */
#if defined(MBEDTLS_SELF_TEST)
/*
* Busy-waits for the given number of milliseconds.
* Used for testing mbedtls_timing_hardclock.
*/
static void busy_msleep( unsigned long msec )
{
struct mbedtls_timing_hr_time hires;
unsigned long i = 0; /* for busy-waiting */
volatile unsigned long j; /* to prevent optimisation */
(void) mbedtls_timing_get_timer( &hires, 1 );
while( mbedtls_timing_get_timer( &hires, 0 ) < msec )
i++;
j = i;
(void) j;
}
#define FAIL do \
{ \
if( verbose != 0 ) \
{ \
mbedtls_printf( "failed at line %d\n", __LINE__ ); \
mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \
cycles, ratio, millisecs, secs, hardfail, \
(unsigned long) a, (unsigned long) b ); \
mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \
mbedtls_timing_get_timer( &hires, 0 ), \
mbedtls_timing_get_timer( &ctx.timer, 0 ), \
mbedtls_timing_get_delay( &ctx ) ); \
} \
return( 1 ); \
} while( 0 )
/*
* Checkup routine
*
* Warning: this is work in progress, some tests may not be reliable enough
* yet! False positives may happen.
*/
int mbedtls_timing_self_test( int verbose )
{
unsigned long cycles = 0, ratio = 0;
unsigned long millisecs = 0, secs = 0;
int hardfail = 0;
struct mbedtls_timing_hr_time hires;
uint32_t a = 0, b = 0;
mbedtls_timing_delay_context ctx;
if( verbose != 0 )
mbedtls_printf( " TIMING tests note: will take some time!\n" );
if( verbose != 0 )
mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " );
{
secs = 1;
(void) mbedtls_timing_get_timer( &hires, 1 );
mbedtls_set_alarm( (int) secs );
while( !mbedtls_timing_alarmed )
;
millisecs = mbedtls_timing_get_timer( &hires, 0 );
/* For some reason on Windows it looks like alarm has an extra delay
* (maybe related to creating a new thread). Allow some room here. */
if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 )
FAIL;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
if( verbose != 0 )
mbedtls_printf( " TIMING test #2 (set/get_delay ): " );
{
a = 800;
b = 400;
mbedtls_timing_set_delay( &ctx, a, a + b ); /* T = 0 */
busy_msleep( a - a / 4 ); /* T = a - a/4 */
if( mbedtls_timing_get_delay( &ctx ) != 0 )
FAIL;
busy_msleep( a / 4 + b / 4 ); /* T = a + b/4 */
if( mbedtls_timing_get_delay( &ctx ) != 1 )
FAIL;
busy_msleep( b ); /* T = a + b + b/4 */
if( mbedtls_timing_get_delay( &ctx ) != 2 )
FAIL;
}
mbedtls_timing_set_delay( &ctx, 0, 0 );
busy_msleep( 200 );
if( mbedtls_timing_get_delay( &ctx ) != -1 )
FAIL;
if( verbose != 0 )
mbedtls_printf( "passed\n" );
if( verbose != 0 )
mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " );
/*
* Allow one failure for possible counter wrapping.
* On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
* since the whole test is about 10ms, it shouldn't happen twice in a row.
*/
hard_test:
if( hardfail > 1 )
{
if( verbose != 0 )
mbedtls_printf( "failed (ignored)\n" );
goto hard_test_done;
}
/* Get a reference ratio cycles/ms */
millisecs = 1;
cycles = mbedtls_timing_hardclock();
busy_msleep( millisecs );
cycles = mbedtls_timing_hardclock() - cycles;
ratio = cycles / millisecs;
/* Check that the ratio is mostly constant */
for( millisecs = 2; millisecs <= 4; millisecs++ )
{
cycles = mbedtls_timing_hardclock();
busy_msleep( millisecs );
cycles = mbedtls_timing_hardclock() - cycles;
/* Allow variation up to 20% */
if( cycles / millisecs < ratio - ratio / 5 ||
cycles / millisecs > ratio + ratio / 5 )
{
hardfail++;
goto hard_test;
}
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
hard_test_done:
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_TIMING_C */

View File

@ -300,6 +300,9 @@ static const char * const features[] = {
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
"MBEDTLS_CIPHER_PADDING_ZEROS",
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
"MBEDTLS_CTR_DRBG_USE_128_BIT_KEY",
#endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
#if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES)
"MBEDTLS_ENABLE_WEAK_CIPHERSUITES",
#endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */
@ -417,6 +420,9 @@ static const char * const features[] = {
#if defined(MBEDTLS_ENTROPY_NV_SEED)
"MBEDTLS_ENTROPY_NV_SEED",
#endif /* MBEDTLS_ENTROPY_NV_SEED */
#if defined(MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER)
"MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER",
#endif /* MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER */
#if defined(MBEDTLS_MEMORY_DEBUG)
"MBEDTLS_MEMORY_DEBUG",
#endif /* MBEDTLS_MEMORY_DEBUG */
@ -447,21 +453,18 @@ static const char * const features[] = {
#if defined(MBEDTLS_SHA256_SMALLER)
"MBEDTLS_SHA256_SMALLER",
#endif /* MBEDTLS_SHA256_SMALLER */
#if defined(MBEDTLS_SHA512_SMALLER)
"MBEDTLS_SHA512_SMALLER",
#endif /* MBEDTLS_SHA512_SMALLER */
#if defined(MBEDTLS_SHA512_NO_SHA384)
"MBEDTLS_SHA512_NO_SHA384",
#endif /* MBEDTLS_SHA512_NO_SHA384 */
#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
"MBEDTLS_SSL_ALL_ALERT_MESSAGES",
#endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */
#if defined(MBEDTLS_SSL_RECORD_CHECKING)
"MBEDTLS_SSL_RECORD_CHECKING",
#endif /* MBEDTLS_SSL_RECORD_CHECKING */
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
"MBEDTLS_SSL_DTLS_CONNECTION_ID",
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
"MBEDTLS_SSL_ASYNC_PRIVATE",
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
"MBEDTLS_SSL_CONTEXT_SERIALIZATION",
#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
#if defined(MBEDTLS_SSL_DEBUG_ALL)
"MBEDTLS_SSL_DEBUG_ALL",
#endif /* MBEDTLS_SSL_DEBUG_ALL */
@ -723,6 +726,9 @@ static const char * const features[] = {
#if defined(MBEDTLS_PSA_CRYPTO_C)
"MBEDTLS_PSA_CRYPTO_C",
#endif /* MBEDTLS_PSA_CRYPTO_C */
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
"MBEDTLS_PSA_CRYPTO_SE_C",
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
"MBEDTLS_PSA_CRYPTO_STORAGE_C",
#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */

277
library/xtea.c Normal file
View File

@ -0,0 +1,277 @@
/*
* An 32-bit implementation of the XTEA algorithm
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_XTEA_C)
#include "mbedtls/xtea.h"
#include "mbedtls/platform_util.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_XTEA_ALT)
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
{ \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
}
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
void mbedtls_xtea_init( mbedtls_xtea_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_xtea_context ) );
}
void mbedtls_xtea_free( mbedtls_xtea_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_xtea_context ) );
}
/*
* XTEA key schedule
*/
void mbedtls_xtea_setup( mbedtls_xtea_context *ctx, const unsigned char key[16] )
{
int i;
memset( ctx, 0, sizeof(mbedtls_xtea_context) );
for( i = 0; i < 4; i++ )
{
GET_UINT32_BE( ctx->k[i], key, i << 2 );
}
}
/*
* XTEA encrypt function
*/
int mbedtls_xtea_crypt_ecb( mbedtls_xtea_context *ctx, int mode,
const unsigned char input[8], unsigned char output[8])
{
uint32_t *k, v0, v1, i;
k = ctx->k;
GET_UINT32_BE( v0, input, 0 );
GET_UINT32_BE( v1, input, 4 );
if( mode == MBEDTLS_XTEA_ENCRYPT )
{
uint32_t sum = 0, delta = 0x9E3779B9;
for( i = 0; i < 32; i++ )
{
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
}
}
else /* MBEDTLS_XTEA_DECRYPT */
{
uint32_t delta = 0x9E3779B9, sum = delta * 32;
for( i = 0; i < 32; i++ )
{
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
}
}
PUT_UINT32_BE( v0, output, 0 );
PUT_UINT32_BE( v1, output, 4 );
return( 0 );
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/*
* XTEA-CBC buffer encryption/decryption
*/
int mbedtls_xtea_crypt_cbc( mbedtls_xtea_context *ctx, int mode, size_t length,
unsigned char iv[8], const unsigned char *input,
unsigned char *output)
{
int i;
unsigned char temp[8];
if( length % 8 )
return( MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH );
if( mode == MBEDTLS_XTEA_DECRYPT )
{
while( length > 0 )
{
memcpy( temp, input, 8 );
mbedtls_xtea_crypt_ecb( ctx, mode, input, output );
for( i = 0; i < 8; i++ )
output[i] = (unsigned char)( output[i] ^ iv[i] );
memcpy( iv, temp, 8 );
input += 8;
output += 8;
length -= 8;
}
}
else
{
while( length > 0 )
{
for( i = 0; i < 8; i++ )
output[i] = (unsigned char)( input[i] ^ iv[i] );
mbedtls_xtea_crypt_ecb( ctx, mode, output, output );
memcpy( iv, output, 8 );
input += 8;
output += 8;
length -= 8;
}
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#endif /* !MBEDTLS_XTEA_ALT */
#if defined(MBEDTLS_SELF_TEST)
/*
* XTEA tests vectors (non-official)
*/
static const unsigned char xtea_test_key[6][16] =
{
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 }
};
static const unsigned char xtea_test_pt[6][8] =
{
{ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 },
{ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 },
{ 0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f },
{ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 },
{ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 },
{ 0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55 }
};
static const unsigned char xtea_test_ct[6][8] =
{
{ 0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5 },
{ 0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8 },
{ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 },
{ 0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5 },
{ 0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d },
{ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }
};
/*
* Checkup routine
*/
int mbedtls_xtea_self_test( int verbose )
{
int i, ret = 0;
unsigned char buf[8];
mbedtls_xtea_context ctx;
mbedtls_xtea_init( &ctx );
for( i = 0; i < 6; i++ )
{
if( verbose != 0 )
mbedtls_printf( " XTEA test #%d: ", i + 1 );
memcpy( buf, xtea_test_pt[i], 8 );
mbedtls_xtea_setup( &ctx, xtea_test_key[i] );
mbedtls_xtea_crypt_ecb( &ctx, MBEDTLS_XTEA_ENCRYPT, buf, buf );
if( memcmp( buf, xtea_test_ct[i], 8 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
exit:
mbedtls_xtea_free( &ctx );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_XTEA_C */