Commit f58d1de6 authored by YannGarcia's avatar YannGarcia
Browse files

Add C ITS security library

parent 6988b9f3
......@@ -53,6 +53,7 @@ ifneq ($(filter dmalloc, $(packages)),)
endif
ifneq ($(filter thread, $(packages)),)
cflags += -pthread
defines += USE_THREADS
libs += -lpthread
endif
......@@ -79,6 +80,11 @@ ifneq ($(filter openssl, $(packages)),)
endif
endif
ifneq ($(filter googletest, $(packages)),)
includes += /usr/local/include
libs += -L/usr/local/lib -lgtest -lgtest_main
endif
ifneq ($(filter cxml, $(packages)),)
predirs += $(PROJECTROOT)/cxml
endif
......
######################################################################
##
## Created by: Denis Filatov
##
## Copyleft (c) 2015
## This code is provided under the CeCill-C license agreement.
######################################################################
export LANG=en_US
ALL_CONFIGURATIONS := POSIX WIN32
.PHONY: all clean tests docs cleandocs distr DUMMY
ifeq ($(ARCH),)
ARCH = $(shell gcc -dumpmachine)
GCC := gcc
GPP := g++
else
GCC := $(addprefix $(addsuffix -,$(ARCH)), gcc)
GPP := $(addprefix $(addsuffix -,$(ARCH)), g++)
endif
LINK := $(GCC)
JAVA := java
JAVAC := javac
JAR := jar
ifneq ($(findstring w32,$(ARCH)),)
packages := $(filter-out readline threads, $(packages))
CFG += WIN32
else
CFG += POSIX
endif
cflags := -Wall -fPIC $(cflags)
jflags := -g
ifeq ($(DEBUG),)
DEBUG=no
endif
ifeq ($(DEBUG),yes)
cflags += -ggdb -O0
defines += DEBUG
dsuffix = -d
else
defines += NDEBUG
cflags += -O2
endif
ifneq ($(filter readline, $(packages)),)
defines += USE_READLINE
libs += -lreadline
endif
ifneq ($(filter dmalloc, $(packages)),)
defines += DMALLOC DMALLOC_FUNC_CHECK
libs += -ldmalloc
dsuffix = -dmalloc
endif
ifneq ($(filter thread, $(packages)),)
cflags += -pthread
defines += USE_THREADS
libs += -lpthread
endif
ifneq ($(filter profile, $(packages)),)
cflags += -pg
endif
ifneq ($(filter openssl, $(packages)),)
ifneq ($(findstring 64, $(ARCH)),)
OPENSSL_ARCH:=Win64
else
OPENSSL_ARCH:=Win32
endif
ifneq ($(findstring mingw32,$(ARCH)),)
includes += C:/OpenSSL/$(OPENSSL_ARCH)/include
libs += C:/OpenSSL/$(OPENSSL_ARCH)/lib/MinGW/libeay32.a C:/OpenSSL/$(OPENSSL_ARCH)/lib/MinGW/ssleay32.a
else
ifneq ($(findstring cygwin,$(ARCH)),)
includes += C:/OpenSSL/$(OPENSSL_ARCH)/include
cflags += -LC:/OpenSSL/$(OPENSSL_ARCH)/lib
endif
libs += -lm -lssl -lcrypto
endif
endif
ifneq ($(filter googletest, $(packages)),)
includes += /usr/local/include
libs += -L/usr/local/lib -lgtest -lgtest_main
endif
ifneq ($(filter cxml, $(packages)),)
predirs += $(PROJECTROOT)/cxml
endif
ifneq ($(filter cshared, $(packages)),)
predirs += $(PROJECTROOT)/cshared
endif
ifeq ($(testdir), )
testdir := tests
endif
ifeq ($(PROJECTROOT),)
PROJECTROOT := .
endif
ifeq ($(BUILDROOT),)
BUILDROOT := $(PROJECTROOT)
endif
includes += $(PROJECTROOT)
includes += $(foreach cfg,$(CFG),$(includes-$(cfg)))
defines += $(foreach cfg,$(CFG),$(defines-$(cfg)))
libs += $(foreach cfg,$(CFG),$(libs-$(cfg)))
sources += $(foreach cfg,$(CFG),$(sources-$(cfg)))
headers += $(foreach cfg,$(CFG),$(headers-$(cfg)))
tests += $(foreach cfg,$(CFG),$(tests-$(cfg)))
distfiles += $(foreach cfg,$(CFG),$(distfiles-$(cfg)))
predirs += $(foreach cfg,$(CFG),$(predirs-$(cfg)))
postdirs += $(foreach cfg,$(CFG),$(postdirs-$(cfg)))
tests := $(addprefix $(addsuffix /,$(testdir)),$(tests))
sources := $(addprefix $(addsuffix /,$(srcdir)),$(sources))
csources := $(filter %.c, $(sources))
ccsources := $(filter %.cc, $(sources))
cppsources := $(filter %.cpp, $(sources))
jvsources := $(filter %.java, $(jsources))
headers := $(addprefix $(addsuffix /,$(incdir)),$(headers))
cflags += $(addprefix -I, $(includes)) $(addprefix -D, $(defines))
outdir := $(BUILDROOT)/$(ARCH)$(dsuffix)
objdir := $(outdir)/o-$(PROJECT)
cobjects := $(patsubst %.c, $(objdir)/%.o, $(csources))
ccobjects := $(patsubst %.cc, $(objdir)/%.o, $(ccsources))
ccpobjects:= $(patsubst %.cc, $(objdir)/%.o, $(ccpsources))
objects := $(cobjects) $(ccobjects) $(cppobjects)
jvobjects := $(patsubst %.java, $(objdir)/%.class, $(jvsources))
jobjects := $(jvobjects)
testbins := $(patsubst %.c, $(outdir)/%, $(tests))
jtestbins := $(patsubst %.java, $(outdir)/%, $(tests))
dirs := $(objdir) $(outdir)/tests
alibnames := $(patsubst %, $(outdir)/lib%.a, $(alibs))
solibnames := $(patsubst %, $(outdir)/lib%.so, $(solibs))
binnames := $(patsubst %, $(outdir)/%, $(bins))
jbinnames := $(patsubst %, $(outdir)/%, $(jbins))
ldflags += $(patsubst %, -L%, $(outdir) $(libdirs))
cpflags :=
ifneq ($(filter cxml, $(packages)),)
libs += $(outdir)/libcxml.a
endif
ifneq ($(filter cshared, $(packages)),)
libs += $(outdir)/libcshared.a
endif
ifneq (,$(sort $(ccobjects) $(cppobjects)))
LINK := $(GPP)
endif
all: $(dirs) $(predirs) $(alibnames) $(solibnames) $(binnames) $(jbinnames) $(postdirs)
tests: all $(testbins) $(jtestbins)
$(predirs) $(postdirs): DUMMY
$(MAKE) -C $@ DEBUG=$(DEBUG)
$(alibnames): $(outdir)/lib%.a : $(objects)
ar rcs $@ $^
$(solibnames): $(outdir)/lib%.so : $(objects)
$(LINK) $(cflags) -shared $(ldflags) -o $@ $^ $(csharedlib) $(libs)
$(binnames): $(outdir)/% : $(objects)
$(LINK) $(cflags) $(ldflags) -o $@ $^ $(csharedlib) $(libs)
$(jbinnames): $(outdir)/% : $(jobjects)
$(JAR) cf -C$(objdir) $@ $^
$(testbins): $(alibnames)
$(testbins): $(outdir)/tests/% : tests/%.c
$(LINK) $(cflags) -o $@ $< $(alibnames) $(libs)
$(jtestbins): $(jbinnames)
$(jtestbins): $(outdir)/tests/% : tests/%.java
$(JAR) cf $@ $^
$(dirs):
mkdir -p $@
$(cobjects): $(objdir)/%.o: %.c
@mkdir -p $(dir $@)
$(GCC) $(cflags) -o $@ -MMD -MF $(objdir)/$*.d -c $<
$(ccobjects): $(objdir)/%.o: %.cc
@mkdir -p $(dir $@)
$(GPP) $(cflags) -o $@ -MMD -MF $(objdir)/$*.d -c $<
$(cppobjects): $(objdir)/%.o: %.cpp
@mkdir -p $(dir $@)
$(GPP) $(cflags) -o $@ -MMD -MF $(objdir)/$*.d -c $<
$(jvobjects): $(objdir)/%.class: %.java
@mkdir -p $(dir $@)
$(JAVAC) -d $(dir $@) $(jflags) $<
clean:
rm -rf $(outdir) $(wildcard $(addsuffix /*~, . $(predirs) $(postdirs)))
distfiles += $(wildcard Makefile $(DOXYFILE))
dist:
-rm -rf $(PROJECT) $(PROJECT)-$(shell date -u '+%Y%m%d').tar.gz
mkdir $(PROJECT)
cp --parents $(sources) $(headers) $(distfiles) $(addprefix tests/, $(tests)) $(PROJECT)
tar -zcvf $(PROJECT)-$(shell date -u '+%Y%m%d').tar.gz $(PROJECT)
rm -rf $(PROJECT)
# tar -zcvf $(PROJECT)-$(shell date -u '+%Y%m%d').tar.gz $(sources) $(headers) $(distfiles) $(addprefix tests/, $(tests))
ifneq (,$(DOXYFILE))
docs: $(DOXYFILE)
doxygen $(DOXYFILE)
cleandocs:
rm -rf doc/html
endif
include $(wildcard $(addsuffix /*.d, $(objdir)))
PROJECTROOT = ..
BUILDROOT = ../build
PROJECT = ItsSecurity
DEBUG = yes
testdir = tests
alibs = $(PROJECT)
solibs = $(PROJECT)
sources := lib_its_security.c
sources-WIN32 :=
headers := lib_its_security.h
cflags += -Werror
include ../common.mk
/*!
* \File lib_its_security.c
* \brief Source file for Security external functions.
* \author FSCOM
* \copyright FSCOM Copyright Notification
* No part may be reproduced except as authorized by written permission.
* The copyright and the foregoing restriction extend to reproduction in all media.
* All rights reserved.
* \version 0.1
* \remark gcc -Wall -Werror -O0 -ggdb -fstack-check -fstack-protector -fsanitize=leak -fsanitize=address -I. -D__MAIN__ ./lib_its_security.c -L/usr/lib -lssl -lcrypto -lm
*/
#include "lib_its_security.h"
#include <math.h>
#include <assert.h>
#include <arpa/inet.h>
#include <openssl/bio.h>
/**
* Internal functions
*/
void show_ec_key(const int8_t* p_prefix, lib_its_security_context_t* p_lib_its_security_context) {
fprintf(stderr, "%s: ", p_prefix);
BIGNUM *x = BN_new();
BIGNUM *y = BN_new();
const EC_POINT *keys = EC_KEY_get0_public_key(p_lib_its_security_context->ec_key);
if (EC_POINT_get_affine_coordinates_GFp(p_lib_its_security_context->ec_group, keys, x, y, NULL)) {
BN_print_fp(stderr, x);
fprintf(stderr, "\n");
BN_print_fp(stderr, y);
fprintf(stderr, "\n");
}
BN_free(x);
BN_free(y);
}
void show_ec_point(const int8_t* p_prefix, lib_its_security_context_t* p_lib_its_security_context, EC_POINT* p_ec_point) {
fprintf(stderr, "%s: ", p_prefix);
char* result = EC_POINT_point2hex(p_lib_its_security_context->ec_group, p_ec_point, POINT_CONVERSION_UNCOMPRESSED, p_lib_its_security_context->bn_ctx);
if (result != NULL) {
fprintf(stderr, "%s\n", result);
free(result);
} else {
fprintf(stderr, "(null)\n");
}
}
void show_hex(const int8_t* p_prefix, const void* p_buffer, size_t p_buffer_length) {
fprintf(stderr, "%s: ", p_prefix);
for (uint8_t* p = (unsigned char*)p_buffer; p_buffer_length; p_buffer_length--, p++) {
fprintf(stderr, "%02x", *p);
}
putc ('\n', stderr);
}
int8_t* bin_to_hex(const uint8_t* p_buffer, const size_t p_buffer_length) {
int8_t* buf = NULL;
size_t i = 0, j = 0;
// Sanity check
if (p_buffer_length == 0) {
return NULL;
}
buf = (int8_t*)malloc(p_buffer_length << 1);
do {
*(buf + j) = "0123456789ABCDEF"[(*(p_buffer + i) >> 4) & 0x0F];
*(buf + j + 1) = "0123456789ABCDEF"[*(p_buffer + i) & 0x0F];
i += 1; j += 2;
} while (i < p_buffer_length);
return buf;
}
uint8_t* hex_to_bin(const int8_t* p_buffer, size_t* p_buffer_length) {
int8_t a;
size_t i, len;
uint8_t* retval = NULL;
// Sanity check
if (p_buffer == NULL) {
return NULL;
}
if ((len = strlen((const char*)p_buffer)) & 1) {
return NULL;
}
retval = (uint8_t*)malloc(len >> 1);
for ( i = 0; i < len; i ++) {
a = toupper(*(p_buffer + i));
if (!isxdigit(a)) {
break;
}
if (isdigit(a)) {
a -= '0';
} else {
a = a - 'A' + 0x0A;
}
if (i & 1) {
retval[i >> 1] |= a;
} else {
retval[i >> 1] = a<<4;
}
} // End of 'for' statement
if (i < len) {
free(retval);
retval = NULL;
}
*p_buffer_length = len >> 1;
return retval;
}
int32_t sign(
lib_its_security_context_t* p_lib_its_security_context,
const uint8_t* p_data,
const size_t p_data_length,
uint8_t** p_sig_r,
uint8_t** p_sig_s,
size_t* p_sig_length
) {
// Sanity checks
if ((p_lib_its_security_context == NULL) || (p_data == NULL)) {
return -1;
}
ECDSA_SIG *signature = ECDSA_do_sign(p_data, p_data_length, p_lib_its_security_context->ec_key);
if (signature == NULL) {
return -1;
}
if (ECDSA_do_verify(p_data, p_data_length, signature, p_lib_its_security_context->ec_key) != 1) {
return -1;
}
const BIGNUM* r;
const BIGNUM* s;
ECDSA_SIG_get0(signature, &r, &s);
*p_sig_length = BN_num_bytes(s);
*p_sig_r = (uint8_t*)malloc(*p_sig_length);
BN_bn2bin(r, (uint8_t*)(*p_sig_r));
*p_sig_s = (uint8_t*)malloc(*p_sig_length);
BN_bn2bin(s, (uint8_t*)(*p_sig_s));
ECDSA_SIG_free(signature);
return 0;
}
int32_t sign_verify(
lib_its_security_context_t* p_lib_its_security_context,
const uint8_t* p_data,
const size_t p_data_length,
const uint8_t* p_sig_r,
const uint8_t* p_sig_s,
const size_t p_sig_length
) {
// Sanity checks
if ((p_lib_its_security_context == NULL) || (p_data == NULL) || (p_sig_r == NULL) || (p_sig_s == NULL)) {
return -1;
}
// Build the signature
BIGNUM* r = BN_bin2bn(p_sig_r, p_sig_length, NULL);
BIGNUM* s = BN_bin2bn(p_sig_s, p_sig_length, NULL);
ECDSA_SIG *signature = ECDSA_SIG_new();
ECDSA_SIG_set0(signature, r, s);
// Check the signature
int32_t result = ECDSA_do_verify(p_data, p_data_length, signature, p_lib_its_security_context->ec_key);
ECDSA_SIG_free(signature);
return (result == 1) ? 0 : -1;
}
int bin_to_ec_point(
lib_its_security_context_t* p_lib_its_security_context,
const uint8_t* p_public_key_x,
const uint8_t* p_public_key_y, EC_POINT** p_ec_point
) {
BIGNUM* pubk_bn = NULL;
size_t l = 2 * p_lib_its_security_context->key_length + 1;
uint8_t* v = (uint8_t*)malloc(l);
*v = 0x04;
memcpy((void*)(v + 1), (const void*)p_public_key_x, p_lib_its_security_context->key_length);
memcpy((void*)(v + 1 + p_lib_its_security_context->key_length), (const void*)p_public_key_y, p_lib_its_security_context->key_length);
pubk_bn = BN_bin2bn(v, l, NULL);
*p_ec_point = EC_POINT_new(p_lib_its_security_context->ec_group);
EC_POINT_bn2point(p_lib_its_security_context->ec_group, pubk_bn, *p_ec_point, p_lib_its_security_context->bn_ctx);
BN_clear_free(pubk_bn);
free(v);
return 0;
}
int public_key_to_bin(
lib_its_security_context_t* p_lib_its_security_context,
uint8_t** p_bin_key
) {
const EC_GROUP *ec_group = EC_KEY_get0_group(p_lib_its_security_context->ec_key);
const EC_POINT *pub = EC_KEY_get0_public_key(p_lib_its_security_context->ec_key);
BIGNUM *pub_bn = BN_new();
EC_POINT_point2bn(ec_group, pub, POINT_CONVERSION_UNCOMPRESSED, pub_bn, p_lib_its_security_context->bn_ctx);
*p_bin_key = (uint8_t*)malloc(BN_num_bytes(pub_bn));
BN_bn2bin(pub_bn, *p_bin_key);
BN_clear_free(pub_bn);
return 0;
}
int kdf2_sha256(
lib_its_security_context_t* p_lib_its_security_context,
const uint8_t* p_salt,
const int32_t p_salt_length,
const int32_t p_key_length,
uint8_t** p_digest, size_t* p_digest_length
) {
// Sanity checks
int sha256_blk_len = 32;
int num_blk_out = (int)ceil(p_key_length/(float)sha256_blk_len);
uint8_t* digest = (uint8_t*)malloc((num_blk_out + 1) * sha256_blk_len);
int32_t digest_idx = 0;
const size_t hash_input_length = p_lib_its_security_context->secret_key_length + sizeof(int32_t) + p_salt_length;
uint8_t* hash_input = (uint8_t*)malloc(hash_input_length);
int i_ntonl;
for (int32_t i = 1; i < num_blk_out + 1; i++) {
uint8_t* p = hash_input;
memcpy((void*)p, (const void*)p_lib_its_security_context->secret_key, p_lib_its_security_context->secret_key_length);
p += p_lib_its_security_context->secret_key_length;
i_ntonl = htonl(i);
memcpy((void*)p, (const void*)&i_ntonl, sizeof(int32_t));
p += sizeof(int32_t);
memcpy((void*)p, (const void*)p_salt, p_salt_length);
//show_hex((const int8_t*)"hash_input", (const void*)hash_input, hash_input_length);
uint8_t* h;
hash_with_sha256(hash_input, hash_input_length, &h);
//show_hex((const int8_t*)"h", (const void*)h, 32);
memcpy((void*)digest + digest_idx, (const void*)h, sha256_blk_len);
//show_hex((const int8_t*)"digest", (const void*)digest, digest_idx + sha256_blk_len);
digest_idx += sha256_blk_len;
free(h);
} // End of 'for' statement
free(hash_input);
if (digest_idx > p_key_length * 2) {
digest_idx = p_key_length * 2;
}
*p_digest = (uint8_t*)malloc(digest_idx);
memcpy((void*)(*p_digest), (const void*)digest, digest_idx);
*p_digest_length = digest_idx;
free(digest);
return 0;
}
int32_t kdf2(
lib_its_security_context_t* p_lib_its_security_context,
const uint8_t* p_salt,
const int32_t p_salt_length,
const int32_t p_key_length,
const unsigned char p_hash_algorithm,
uint8_t** p_digest,
size_t* p_digest_length
) {
// Sanity checks
int result = -1;
switch (p_hash_algorithm) {
case 0x00: // SHA 256
result = kdf2_sha256(p_lib_its_security_context, p_salt, p_salt_length, p_key_length, p_digest, p_digest_length);
break;
} // End of 'switch' statement
return result;
}
int32_t generate_and_derive_ephemeral_key_for_encryption(
lib_its_security_context_t* p_ecdh_private_key,
const encryption_algorithm_t p_enc_algorithm,
lib_its_security_context_t* p_public_keys,
const uint8_t* p_salt,
const size_t p_salt_length
) {
// Sanity checks
if (p_public_keys->private_key != NULL) {
return -1;
}
if ((p_public_keys->public_key_x == NULL) || (p_public_keys->public_key_y == NULL)) {
return -1;
}
// Set buffers size
p_ecdh_private_key->encryption_algorithm = p_enc_algorithm;
switch (p_ecdh_private_key->encryption_algorithm) {
case aes_128_ccm:
// No break;
case aes_128_gcm:
p_ecdh_private_key->nonce_length = 12;
p_ecdh_private_key->sym_key_length = 16;
p_ecdh_private_key->tag_length = 16;
break;
default:
return -1;
} // End of 'switch' statement
uint8_t k_enc;
uint8_t k_mac;
switch (p_ecdh_private_key->elliptic_curve) {
case nist_p_256: // Use the ANSI X9.62 Prime 256v1 curve
// No break;
case brainpool_p_256_r1:
k_enc = 16;
k_mac = 32;
break;
case brainpool_p_384_r1:
k_enc = 24; // TODO To be checked
k_mac = 48;
break;
default:
return -1;
} // End of 'switch' statement
/* Convert the ephemeral public encryption keys to an EC point */
EC_POINT *ec_point = NULL;