diff --git a/include/crypto.h b/include/crypto.h index 7d9d6857..417d5725 100644 --- a/include/crypto.h +++ b/include/crypto.h @@ -82,8 +82,9 @@ Note: MySQL server MUST be configured for encrypted connections: * https://dev.mysql.com/doc/refman/5.7/en/using-encrypted-connections.html ==========================================================*/ extern int32_t Crypto_Config_MariaDB(char* mysql_username, char* mysql_password, char* mysql_hostname, char* mysql_database, uint16_t mysql_port, uint8_t encrypted_connection, char* ssl_cert, char* ssl_key, char* ssl_ca, char* ssl_capath); -extern int32_t Crypto_Config_Kmc_Crypto_Service(char *kmc_crypto_hostname, uint16_t kmc_crypto_port, char *mtls_cert_path, - char *mtls_key_path, uint8_t ignore_ssl_hostname_validation); +extern int32_t Crypto_Config_Kmc_Crypto_Service(char *protocol, char *kmc_crypto_hostname, uint16_t kmc_crypto_port, char *kmc_crypto_app_uri, char *mtls_client_cert_path, char *mtls_client_cert_type, + char *mtls_client_key_path,char *mtls_client_key_pass, char *mtls_ca_bundle, char *mtls_ca_path, + char *mtls_issuer_cert, uint8_t ignore_ssl_hostname_validation); extern int32_t Crypto_Config_Add_Gvcid_Managed_Parameter(uint8_t tfvn, uint16_t scid, uint8_t vcid, uint8_t has_fecf, uint8_t has_segmentation_hdr); diff --git a/include/crypto_config_structs.h b/include/crypto_config_structs.h index 3d26404d..034f49fe 100644 --- a/include/crypto_config_structs.h +++ b/include/crypto_config_structs.h @@ -151,14 +151,21 @@ typedef struct #define SADB_MARIADB_CONFIG_SIZE (sizeof(SadbMariaDBConfig_t)) /* -** SaDB MariaDB Configuration Block +** KMC Cryptography Service Configuration Block */ typedef struct { - char *kmc_crypto_hostname; + char* kmc_crypto_hostname; + char* protocol; uint16_t kmc_crypto_port; - char *mtls_cert_path; - char *mtls_key_path; + char* kmc_crypto_app_uri; + char* mtls_client_cert_path; + char* mtls_client_cert_type; // default "PEM", supports "P12" and "DER" + char* mtls_client_key_path; + char* mtls_client_key_pass; + char* mtls_ca_bundle; + char* mtls_ca_path; + char* mtls_issuer_cert; uint8_t ignore_ssl_hostname_validation; } CryptographyKmcCryptoServiceConfig_t; diff --git a/include/crypto_error.h b/include/crypto_error.h index 9d4fb99a..1a8d6cac 100644 --- a/include/crypto_error.h +++ b/include/crypto_error.h @@ -31,9 +31,18 @@ #define SADB_INSERT_FAILED 303 #define CRYPTOGRAPHY_INVALID_CRYPTO_INTERFACE_TYPE 400 -#define CRYPTOGRAPHY_KMC_CRYPTO_SERVICE_CONFIGURATION_NOT_COMPLETE 401 -#define CRYPTOGRAPHY_UNSUPPORTED_OPERATION_FOR_KEY_RING 402 -#define CRYPTOGRAPHY_LIBRARY_INITIALIZIATION_ERROR 403 +#define CRYPTOGRAPHY_UNSUPPORTED_OPERATION_FOR_KEY_RING 401 +#define CRYPTOGRAPHY_LIBRARY_INITIALIZIATION_ERROR 402 + +#define CRYPTOGRAPHY_KMC_CRYPTO_SERVICE_CONFIGURATION_NOT_COMPLETE 501 +#define CRYPTOGRAPHY_KMC_CURL_INITIALIZATION_FAILURE 502 +#define CRYPTOGRAHPY_KMC_CRYPTO_SERVICE_CONNECTION_ERROR 503 +#define CRYPTOGRAHPY_KMC_CRYPTO_SERVICE_AEAD_ENCRYPT_ERROR 504 +#define CRYPTOGRAHPY_KMC_CRYPTO_SERVICE_AEAD_DECRYPT_ERROR 505 +#define CRYPTOGRAHPY_KMC_CRYPTO_JSON_PARSE_ERROR 506 +#define CRYPTOGRAHPY_KMC_CIPHER_TEXT_NOT_FOUND_IN_JSON_RESPONSE 507 +#define CRYPTOGRAHPY_KMC_CRYPTO_SERVICE_GENERIC_FAILURE 508 + #define CRYPTO_LIB_SUCCESS (0) #define CRYPTO_LIB_ERROR (-1) diff --git a/include/crypto_structs.h b/include/crypto_structs.h index 59127023..d7ca5764 100644 --- a/include/crypto_structs.h +++ b/include/crypto_structs.h @@ -54,8 +54,9 @@ typedef struct // Status uint16_t spi; // Security Parameter Index uint16_t ekid; // Encryption Key ID (Used with numerically indexed keystores, EG inmemory keyring) - char* ek_ref; // Encryption Key Reference (Used with string-referenced keystores,EG-PKCS12 keystores, KMC crypto) uint16_t akid; // Authentication Key ID + char* ek_ref; // Encryption Key Reference (Used with string-referenced keystores,EG-PKCS12 keystores, KMC crypto) + char* ak_ref; // Authentication Key Reference (Used with string-referenced keystores,EG-PKCS12 keystores, KMC crypto) uint8_t sa_state : 2; crypto_gvcid_t gvcid_tc_blk; crypto_gvcid_t gvcid_tm_blk[NUM_GVCID]; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c30a943..0c2b6f8b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,6 +54,14 @@ else() #standalone build add_library(Crypto SHARED ${LIB_SRC_FILES}) endif() +if(LIBGCRYPT) + target_link_libraries(Crypto gcrypt) +endif() + +if(KMCCRYPTO) + target_link_libraries(Crypto curl) +endif() + if(MYSQL) execute_process(COMMAND mysql_config --cflags OUTPUT_VARIABLE MYSQL_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -64,8 +72,6 @@ if(MYSQL) target_link_libraries(Crypto ${MYSQL_LIBS}) endif() -# Add libgcrypt -target_link_libraries(Crypto gcrypt) #Include cmake install module - todo #include(GNUInstallDirs) diff --git a/src/crypto_sadb/sadb_mariadb_admin_scripts/create_sadb.sql b/src/crypto_sadb/sadb_mariadb_admin_scripts/create_sadb.sql index f9eec3fb..5b0cf5af 100644 --- a/src/crypto_sadb/sadb_mariadb_admin_scripts/create_sadb.sql +++ b/src/crypto_sadb/sadb_mariadb_admin_scripts/create_sadb.sql @@ -7,8 +7,8 @@ USE sadb; CREATE TABLE security_associations ( spi INT NOT NULL - ,ekid MEDIUMINT NOT NULL DEFAULT spi - ,akid MEDIUMINT NOT NULL DEFAULT spi + ,ekid VARCHAR(20) CHARACTER SET utf8 NOT NULL DEFAULT '0' -- 'EG, for KMC Crypto KeyRef, 'kmc/test/KEY0', for libgcrypt '130' + ,akid VARCHAR(20) CHARACTER SET utf8 NOT NULL DEFAULT '0' -- Same as ekid ,sa_state SMALLINT NOT NULL DEFAULT 0 ,tfvn TINYINT NOT NULL ,scid SMALLINT NOT NULL @@ -21,8 +21,8 @@ CREATE TABLE security_associations ,shsnf_len SMALLINT NOT NULL DEFAULT 0 ,shplf_len SMALLINT NOT NULL DEFAULT 0 ,stmacf_len SMALLINT NOT NULL DEFAULT 0 - ,ecs_len SMALLINT - ,ecs VARBINARY(4) NOT NULL DEFAULT X'00000000' -- ECS_SIZE=4 + ,ecs_len SMALLINT NOT NULL DEFAULT 1 + ,ecs VARBINARY(4) NOT NULL DEFAULT X'01' -- ECS_SIZE=4 ,iv_len SMALLINT NOT NULL DEFAULT 12 ,iv VARBINARY(20) NOT NULL DEFAULT X'000000000000000000000000' -- IV_SIZE=12 ,acs_len SMALLINT NOT NULL DEFAULT 0 diff --git a/src/crypto_sadb/sadb_mariadb_admin_scripts/create_sadb_jpl_unit_test_security_associations.sql b/src/crypto_sadb/sadb_mariadb_admin_scripts/create_sadb_jpl_unit_test_security_associations.sql index 7a5e4635..dc8fa454 100644 --- a/src/crypto_sadb/sadb_mariadb_admin_scripts/create_sadb_jpl_unit_test_security_associations.sql +++ b/src/crypto_sadb/sadb_mariadb_admin_scripts/create_sadb_jpl_unit_test_security_associations.sql @@ -1,21 +1,17 @@ USE sadb; --- SA 1 - CLEAR MODE -INSERT INTO security_associations (spi,sa_state,est,ast,arc_len,arc,arcw_len,arcw,tfvn,scid,vcid,mapid) -VALUES (1,0,0,0,1,X'0000000000000000000000000000000000000000',1,5,0,44,1,0); +-- SA 1 - OPERATIONAL; ENC + AUTH - ARCW:5; AES-GCM; IV:00...01; IV-len:12; MAC-len:16; Key-ID: 130, SCID 44, VC-0 +INSERT INTO security_associations (spi,ekid,sa_state,ecs,est,ast,shivf_len,stmacf_len,iv,abm_len,abm,arcw_len,arcw,arc_len,tfvn,scid,vcid,mapid) +VALUES (1,'kmc/test/key130',3,X'01',1,1,12,16,X'000000000000000000000001',19,X'00000000000000000000000000000000000000',1,5,0,0,44,0,0); --- SA 2 - OPERATIONAL; ARCW:5; AES-GCM; IV:00...01; IV-len:12; MAC-len:16; Key-ID: 130, SCID 44, VC-0 -INSERT INTO security_associations (spi,ekid,sa_state,est,ast,shivf_len,iv,abm_len,abm,arcw_len,arcw,arc_len,tfvn,scid,vcid,mapid) -VALUES (2,130,3,1,0,12,X'000000000000000000000001',19,X'00000000000000000000000000000000000000',1,5,0,0,44,0,0); +-- SA 2 - OPERATIONAL; ENC + AUTH - ARCW:5; AES-GCM; IV:00...01; IV-len:12; MAC-len:16; Key-ID: 130, SCID 44, VC-1 +INSERT INTO security_associations (spi,ekid,sa_state,ecs,est,ast,shivf_len,stmacf_len,iv,abm_len,abm,arcw_len,arcw,arc_len,tfvn,scid,vcid,mapid) +VALUES (2,'kmc/test/key130',3,X'01',1,1,12,16,X'000000000000000000000001',19,X'00000000000000000000000000000000000000',1,5,0,0,44,1,0); --- SA 3 - OPERATIONAL; ARCW:5; AES-GCM; IV:00...01; IV-len:12; MAC-len:16; Key-ID: 130, SCID 44, VC-1 -INSERT INTO security_associations (spi,ekid,sa_state,est,ast,shivf_len,iv,abm_len,abm,arcw_len,arcw,arc_len,tfvn,scid,vcid,mapid) -VALUES (3,130,3,1,0,12,X'000000000000000000000001',19,X'00000000000000000000000000000000000000',1,5,0,0,44,1,0); +-- SA 3 - OPERATIONAL; ENC Only - ARCW:5; AES-GCM; IV:00...01; IV-len:12; MAC-len:16; Key-ID: 130, SCID 44, VC-2 +INSERT INTO security_associations (spi,ekid,sa_state,ecs,est,ast,shivf_len,stmacf_len,iv,abm_len,abm,arcw_len,arcw,arc_len,tfvn,scid,vcid,mapid) +VALUES (3,'kmc/test/key130',3,X'01',1,0,12,0,X'000000000000000000000001',19,X'00000000000000000000000000000000000000',1,5,0,0,44,2,0); --- SA 4 - OPERATIONAL; ARCW:5; AES-GCM; IV:00...01; IV-len:12; MAC-len:16; Key-ID: 130, SCID 44, VC-2 -INSERT INTO security_associations (spi,ekid,sa_state,est,ast,shivf_len,iv,abm_len,abm,arcw_len,arcw,arc_len,tfvn,scid,vcid,mapid) -VALUES (4,130,3,1,0,12,X'000000000000000000000001',19,X'00000000000000000000000000000000000000',1,5,0,0,44,2,0); - --- SA 5 - OPERATIONAL; ARCW:5; AES-GCM; IV:00...01; IV-len:12; MAC-len:16; Key-ID: 130, SCID 44, VC-3 -INSERT INTO security_associations (spi,ekid,sa_state,est,ast,shivf_len,iv,abm_len,abm,arcw_len,arcw,arc_len,tfvn,scid,vcid,mapid) -VALUES (4,130,3,1,0,12,X'000000000000000000000001',19,X'00000000000000000000000000000000000000',1,5,0,0,44,3,0); \ No newline at end of file +-- SA 4 - OPERATIONAL; AUTH Only - ARCW:5; AES-GCM; IV:00...01; IV-len:12; MAC-len:16; Key-ID: 130, SCID 44, VC-3 +INSERT INTO security_associations (spi,ekid,sa_state,ecs,est,ast,shivf_len,stmacf_len,iv,abm_len,abm,arcw_len,arcw,arc_len,tfvn,scid,vcid,mapid) +VALUES (4,'kmc/test/key130',3,X'01',0,1,12,16,X'000000000000000000000001',1024,X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',1,5,0,0,44,3,0); \ No newline at end of file diff --git a/src/src_cryptography/src_kmc_crypto_service/base64.c b/src/src_cryptography/src_kmc_crypto_service/base64.c new file mode 100644 index 00000000..b396e229 --- /dev/null +++ b/src/src_cryptography/src_kmc_crypto_service/base64.c @@ -0,0 +1,312 @@ +/** + * @file base64.c + * @brief Base64 encoding scheme + * + * @section License + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (C) 2010-2021 Oryx Embedded SARL. All rights reserved. + * + * This file is part of CycloneCRYPTO Open. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * @section Description + * + * Base64 is a encoding scheme that represents binary data in an ASCII string + * format by translating it into a radix-64 representation. Refer to RFC 4648 + * for more details + * + * @author Oryx Embedded SARL (www.oryx-embedded.com) + * @version 2.1.2 + **/ + +#include "base64.h" + +//Base64 encoding table +static const char_t base64EncTable[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', '+', '/' + }; + +//Base64 decoding table +static const uint8_t base64DecTable[128] = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + +/** + * @brief Base64 encoding algorithm + * @param[in] input Input data to encode + * @param[in] inputLen Length of the data to encode + * @param[out] output NULL-terminated string encoded with Base64 algorithm + * @param[out] outputLen Length of the encoded string (optional parameter) + **/ + +void base64Encode(const void *input, size_t inputLen, char_t *output, + size_t *outputLen) +{ + size_t n; + uint8_t a; + uint8_t b; + uint8_t c; + uint8_t d; + const uint8_t *p; + + //Point to the first byte of the input data + p = (const uint8_t *) input; + + //Divide the input stream into blocks of 3 bytes + n = inputLen / 3; + + //A full encoding quantum is always completed at the end of a quantity + if(inputLen == (n * 3 + 1)) + { + //The final quantum of encoding input is exactly 8 bits + if(input != NULL && output != NULL) + { + //Read input data + a = (p[n * 3] & 0xFC) >> 2; + b = (p[n * 3] & 0x03) << 4; + + //The final unit of encoded output will be two characters followed + //by two "=" padding characters + output[n * 4] = base64EncTable[a]; + output[n * 4 + 1] = base64EncTable[b]; + output[n * 4 + 2] = '='; + output[n * 4 + 3] = '='; + output[n * 4 + 4] = '\0'; + } + + //Length of the encoded string (excluding the terminating NULL) + if(outputLen != NULL) + { + *outputLen = n * 4 + 4; + } + } + else if(inputLen == (n * 3 + 2)) + { + //The final quantum of encoding input is exactly 16 bits + if(input != NULL && output != NULL) + { + //Read input data + a = (p[n * 3] & 0xFC) >> 2; + b = ((p[n * 3] & 0x03) << 4) | ((p[n * 3 + 1] & 0xF0) >> 4); + c = (p[n * 3 + 1] & 0x0F) << 2; + + //The final unit of encoded output will be three characters followed + //by one "=" padding character + output[n * 4] = base64EncTable[a]; + output[n * 4 + 1] = base64EncTable[b]; + output[n * 4 + 2] = base64EncTable[c]; + output[n * 4 + 3] = '='; + output[n * 4 + 4] = '\0'; + } + + //Length of the encoded string (excluding the terminating NULL) + if(outputLen != NULL) + { + *outputLen = n * 4 + 4; + } + } + else + { + //The final quantum of encoding input is an integral multiple of 24 bits + if(output != NULL) + { + //The final unit of encoded output will be an integral multiple of 4 + //characters with no "=" padding + output[n * 4] = '\0'; + } + + //Length of the encoded string (excluding the terminating NULL) + if(outputLen != NULL) + { + *outputLen = n * 4; + } + } + + //If the output parameter is NULL, then the function calculates the + //length of the resulting Base64 string without copying any data + if(input != NULL && output != NULL) + { + //The input data is processed block by block + while(n-- > 0) + { + //Read input data + a = (p[n * 3] & 0xFC) >> 2; + b = ((p[n * 3] & 0x03) << 4) | ((p[n * 3 + 1] & 0xF0) >> 4); + c = ((p[n * 3 + 1] & 0x0F) << 2) | ((p[n * 3 + 2] & 0xC0) >> 6); + d = p[n * 3 + 2] & 0x3F; + + //Map each 3-byte block to 4 printable characters using the Base64 + //character set + output[n * 4] = base64EncTable[a]; + output[n * 4 + 1] = base64EncTable[b]; + output[n * 4 + 2] = base64EncTable[c]; + output[n * 4 + 3] = base64EncTable[d]; + } + } +} + + +/** + * @brief Base64 decoding algorithm + * @param[in] input Base64-encoded string + * @param[in] inputLen Length of the encoded string + * @param[out] output Resulting decoded data + * @param[out] outputLen Length of the decoded data + * @return Error code + **/ + +int32_t base64Decode(const char_t *input, size_t inputLen, void *output, + size_t *outputLen) +{ + int32_t error; + uint32_t value; + uint_t c; + size_t i; + size_t j; + size_t n; + size_t padLen; + uint8_t *p; + + //Check parameters + if(input == NULL && inputLen != 0) + return ERROR_INVALID_PARAMETER; + if(outputLen == NULL) + return ERROR_INVALID_PARAMETER; + + //Initialize status code + error = NO_ERROR; + + //Point to the buffer where to write the decoded data + p = (uint8_t *) output; + + //Initialize variables + j = 0; + n = 0; + value = 0; + padLen = 0; + + //Process the Base64-encoded string + for(i = 0; i < inputLen && !error; i++) + { + //Get current character + c = (uint_t) input[i]; + + //Check the value of the current character + if(c == '\r' || c == '\n') + { + //CR and LF characters should be ignored + } + else if(c == '=') + { + //Increment the number of pad characters + padLen++; + } + else if(c < 128 && base64DecTable[c] < 64 && padLen == 0) + { + //Decode the current character + value = (value << 6) | base64DecTable[c]; + + //Divide the input stream into blocks of 4 characters + if(++j == 4) + { + //Map each 4-character block to 3 bytes + if(p != NULL) + { + p[n] = (value >> 16) & 0xFF; + p[n + 1] = (value >> 8) & 0xFF; + p[n + 2] = value & 0xFF; + } + + //Adjust the length of the decoded data + n += 3; + + //Decode next block + j = 0; + value = 0; + } + } + else + { + //Implementations must reject the encoded data if it contains + //characters outside the base alphabet (refer to RFC 4648, + //section 3.3) + error = ERROR_INVALID_CHARACTER; + } + } + + //Check status code + if(!error) + { + //Check the number of pad characters + if(padLen == 0 && j == 0) + { + //No pad characters in this case + } + else if(padLen == 1 && j == 3) + { + //The "=" sequence indicates that the last block contains only 2 bytes + if(p != NULL) + { + //Decode the last two bytes + p[n] = (value >> 10) & 0xFF; + p[n + 1] = (value >> 2) & 0xFF; + } + + //Adjust the length of the decoded data + n += 2; + } + else if(padLen == 2 && j == 2) + { + //The "==" sequence indicates that the last block contains only 1 byte + if(p != NULL) + { + //Decode the last byte + p[n] = (value >> 4) & 0xFF; + } + + //Adjust the length of the decoded data + n++; + //Skip trailing pad characters + i++; + } + else + { + //The length of the input string must be a multiple of 4 + error = ERROR_INVALID_LENGTH; + } + } + + //Total number of bytes that have been written + *outputLen = n; + + //Return status code + return error; +} diff --git a/src/src_cryptography/src_kmc_crypto_service/base64.h b/src/src_cryptography/src_kmc_crypto_service/base64.h new file mode 100644 index 00000000..46f678f0 --- /dev/null +++ b/src/src_cryptography/src_kmc_crypto_service/base64.h @@ -0,0 +1,63 @@ +/** + * @file base64.h + * @brief Base64 encoding scheme + * + * @section License + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (C) 2010-2021 Oryx Embedded SARL. All rights reserved. + * + * This file is part of CycloneCRYPTO Open. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * @author Oryx Embedded SARL (www.oryx-embedded.com) + * @version 2.1.2 + **/ + +#ifndef _BASE64_H +#define _BASE64_H + +#include +#include +#include + +//C++ guard +#ifdef __cplusplus +extern "C" { +#endif + +typedef char char_t; +typedef unsigned int uint_t; + +//Base64 encoding related functions +void base64Encode(const void *input, size_t inputLen, char_t *output, + size_t *outputLen); + +int32_t base64Decode(const char_t *input, size_t inputLen, void *output, + size_t *outputLen); + +#define ERROR_INVALID_PARAMETER 21 +#define ERROR_INVALID_LENGTH 22 +#define ERROR_INVALID_CHARACTER 23 +#define NO_ERROR 0 + +//C++ guard +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/src_cryptography/src_kmc_crypto_service/base64url.c b/src/src_cryptography/src_kmc_crypto_service/base64url.c new file mode 100644 index 00000000..c03ace5e --- /dev/null +++ b/src/src_cryptography/src_kmc_crypto_service/base64url.c @@ -0,0 +1,286 @@ +/** + * @file base64url.c + * @brief Base64url encoding scheme + * + * @section License + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (C) 2010-2021 Oryx Embedded SARL. All rights reserved. + * + * This file is part of CycloneCRYPTO Open. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * @author Oryx Embedded SARL (www.oryx-embedded.com) + * @version 2.1.2 + **/ + +// https://www.oryx-embedded.com/doc/base64url_8c_source.html + +//Dependencies +#include "base64url.h" + +//Base64url encoding table +static const char_t base64urlEncTable[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', '-', '_' + }; + +//Base64url decoding table +static const uint8_t base64urlDecTable[128] = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, + 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + +/** + * @brief Base64url encoding algorithm + * @param[in] input Input data to encode + * @param[in] inputLen Length of the data to encode + * @param[out] output NULL-terminated string encoded with Base64url algorithm + * @param[out] outputLen Length of the encoded string (optional parameter) + **/ + +void base64urlEncode(const void *input, size_t inputLen, char_t *output, + size_t *outputLen) +{ + size_t n; + uint8_t a; + uint8_t b; + uint8_t c; + uint8_t d; + const uint8_t *p; + + //Point to the first byte of the input data + p = (const uint8_t *) input; + + //Divide the input stream into blocks of 3 bytes + n = inputLen / 3; + + //A full encoding quantum is always completed at the end of a quantity + if(inputLen == (n * 3 + 1)) + { + //The final quantum of encoding input is exactly 8 bits + if(input != NULL && output != NULL) + { + //Read input data + a = (p[n * 3] & 0xFC) >> 2; + b = (p[n * 3] & 0x03) << 4; + + //The final unit of encoded output will be two characters + output[n * 4] = base64urlEncTable[a]; + output[n * 4 + 1] = base64urlEncTable[b]; + output[n * 4 + 2] = '\0'; + } + + //Length of the encoded string (excluding the terminating NULL) + if(outputLen != NULL) + { + *outputLen = n * 4 + 2; + } + } + else if(inputLen == (n * 3 + 2)) + { + //The final quantum of encoding input is exactly 16 bits + if(input != NULL && output != NULL) + { + //Read input data + a = (p[n * 3] & 0xFC) >> 2; + b = ((p[n * 3] & 0x03) << 4) | ((p[n * 3 + 1] & 0xF0) >> 4); + c = (p[n * 3 + 1] & 0x0F) << 2; + + //The final unit of encoded output will be three characters followed + //by one "=" padding character + output[n * 4] = base64urlEncTable[a]; + output[n * 4 + 1] = base64urlEncTable[b]; + output[n * 4 + 2] = base64urlEncTable[c]; + output[n * 4 + 3] = '\0'; + } + + //Length of the encoded string (excluding the terminating NULL) + if(outputLen != NULL) + { + *outputLen = n * 4 + 3; + } + } + else + { + //The final quantum of encoding input is an integral multiple of 24 bits + if(output != NULL) + { + //The final unit of encoded output will be an integral multiple of 4 + //characters + output[n * 4] = '\0'; + } + + //Length of the encoded string (excluding the terminating NULL) + if(outputLen != NULL) + { + *outputLen = n * 4; + } + } + + //If the output parameter is NULL, then the function calculates the + //length of the resulting Base64url string without copying any data + if(input != NULL && output != NULL) + { + //The input data is processed block by block + while(n-- > 0) + { + //Read input data + a = (p[n * 3] & 0xFC) >> 2; + b = ((p[n * 3] & 0x03) << 4) | ((p[n * 3 + 1] & 0xF0) >> 4); + c = ((p[n * 3 + 1] & 0x0F) << 2) | ((p[n * 3 + 2] & 0xC0) >> 6); + d = p[n * 3 + 2] & 0x3F; + + //Map each 3-byte block to 4 printable characters using the Base64url + //character set + output[n * 4] = base64urlEncTable[a]; + output[n * 4 + 1] = base64urlEncTable[b]; + output[n * 4 + 2] = base64urlEncTable[c]; + output[n * 4 + 3] = base64urlEncTable[d]; + } + } +} + + +/** + * @brief Base64url decoding algorithm + * @param[in] input Base64url-encoded string + * @param[in] inputLen Length of the encoded string + * @param[out] output Resulting decoded data + * @param[out] outputLen Length of the decoded data + * @return Error code + **/ + +int32_t base64urlDecode(const char_t *input, size_t inputLen, void *output, + size_t *outputLen) +{ + int32_t error; + uint32_t value; + uint_t c; + size_t i; + size_t n; + uint8_t *p; + + //Check parameters + if(input == NULL && inputLen != 0) + return ERROR_INVALID_PARAMETER; + if(outputLen == NULL) + return ERROR_INVALID_PARAMETER; + + //Check the length of the input string + if((inputLen % 4) == 1) + return ERROR_INVALID_LENGTH; + + //Initialize status code + error = NO_ERROR; + + //Point to the buffer where to write the decoded data + p = (uint8_t *) output; + + //Initialize variables + n = 0; + value = 0; + + //Process the Base64url-encoded string + for(i = 0; i < inputLen && !error; i++) + { + //Get current character + c = (uint_t) input[i]; + + //Check the value of the current character + if(c < 128 && base64urlDecTable[c] < 64) + { + //Decode the current character + value = (value << 6) | base64urlDecTable[c]; + + //Divide the input stream into blocks of 4 characters + if((i % 4) == 3) + { + //Map each 4-character block to 3 bytes + if(p != NULL) + { + p[n] = (value >> 16) & 0xFF; + p[n + 1] = (value >> 8) & 0xFF; + p[n + 2] = value & 0xFF; + } + + //Adjust the length of the decoded data + n += 3; + //Decode next block + value = 0; + } + } + else + { + //Implementations must reject the encoded data if it contains + //characters outside the base alphabet + error = ERROR_INVALID_CHARACTER; + } + } + + //Check status code + if(!error) + { + //All trailing pad characters are omitted in Base64url + if((inputLen % 4) == 2) + { + //The last block contains only 1 byte + if(p != NULL) + { + //Decode the last byte + p[n] = (value >> 4) & 0xFF; + } + + //Adjust the length of the decoded data + n++; + } + else if((inputLen % 4) == 3) + { + //The last block contains only 2 bytes + if(p != NULL) + { + //Decode the last two bytes + p[n] = (value >> 10) & 0xFF; + p[n + 1] = (value >> 2) & 0xFF; + } + + //Adjust the length of the decoded data + n += 2; + } + else + { + //No pad characters in this case + } + } + + //Total number of bytes that have been written + *outputLen = n; + + //Return status code + return error; +} diff --git a/src/src_cryptography/src_kmc_crypto_service/base64url.h b/src/src_cryptography/src_kmc_crypto_service/base64url.h new file mode 100644 index 00000000..8d198379 --- /dev/null +++ b/src/src_cryptography/src_kmc_crypto_service/base64url.h @@ -0,0 +1,66 @@ +/** + * @file base64.h + * @brief Base64 encoding scheme + * + * @section License + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (C) 2010-2021 Oryx Embedded SARL. All rights reserved. + * + * This file is part of CycloneCRYPTO Open. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * @author Oryx Embedded SARL (www.oryx-embedded.com) + * @version 2.1.2 + **/ + +// https://www.oryx-embedded.com/doc/base64_8h_source.html + +#ifndef _BASE64URL_H +#define _BASE64URL_H + +#include +#include +#include + +//C++ guard +#ifdef __cplusplus +extern "C" { +#endif + +typedef char char_t; +typedef unsigned int uint_t; + +//Base64 encoding related functions +void base64urlEncode(const void *input, size_t inputLen, char_t *output, + size_t *outputLen); + +int32_t base64urlDecode(const char_t *input, size_t inputLen, void *output, + size_t *outputLen); + +#define ERROR_INVALID_PARAMETER 21 +#define ERROR_INVALID_LENGTH 22 +#define ERROR_INVALID_CHARACTER 23 +#define NO_ERROR 0 + + +//C++ guard +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/src_cryptography/src_kmc_crypto_service/cryptography_interface_kmc_crypto_service.template.c b/src/src_cryptography/src_kmc_crypto_service/cryptography_interface_kmc_crypto_service.template.c index b0611422..b2850ade 100644 --- a/src/src_cryptography/src_kmc_crypto_service/cryptography_interface_kmc_crypto_service.template.c +++ b/src/src_cryptography/src_kmc_crypto_service/cryptography_interface_kmc_crypto_service.template.c @@ -14,8 +14,18 @@ #include "crypto_error.h" #include "cryptography_interface.h" +#include "crypto.h" #include +#include + +#include + +// base64 & base64url encoding/decoding libraries +#include "base64url.h" +#include "base64.h" +// JSON marshalling libraries +#include "jsmn.h" // Cryptography Interface Initialization & Management Functions static int32_t cryptography_config(void); @@ -25,8 +35,22 @@ static int32_t cryptography_shutdown(void); // Cryptography Interface Functions static int32_t cryptography_encrypt(void); static int32_t cryptography_decrypt(void); -static int32_t cryptography_authenticate(void); -static int32_t cryptography_validate_authentication(void); +static int32_t cryptography_authenticate(uint8_t* data_out, size_t len_data_out, + uint8_t* data_in, size_t len_data_in, + uint8_t* key, uint32_t len_key, + SecurityAssociation_t* sa_ptr, + uint8_t* iv, uint32_t iv_len, + uint8_t* mac, uint32_t mac_size, + uint8_t* aad, uint32_t aad_len, + uint8_t ecs, uint8_t acs); +static int32_t cryptography_validate_authentication(uint8_t* data_out, size_t len_data_out, + uint8_t* data_in, size_t len_data_in, + uint8_t* key, uint32_t len_key, + SecurityAssociation_t* sa_ptr, + uint8_t* iv, uint32_t iv_len, + uint8_t* mac, uint32_t mac_size, + uint8_t* aad, uint32_t aad_len, + uint8_t ecs, uint8_t acs); static int32_t cryptography_aead_encrypt(uint8_t* data_out, size_t len_data_out, uint8_t* data_in, size_t len_data_in, uint8_t* key, uint32_t len_key, @@ -45,11 +69,50 @@ static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, uint8_t* aad, uint32_t aad_len, uint8_t decrypt_bool, uint8_t authenticate_bool, uint8_t aad_bool); + +// libcurl call back and support function declarations +static void configure_curl_connect_opts(CURL* curl); +static size_t write_callback(void *data, size_t size, size_t nmemb, void *userp); +static size_t read_callback(char *dest, size_t size, size_t nmemb, void *userp); +static char* int_to_str(uint32_t int_src, uint32_t* converted_str_length); +static int jsoneq(const char *json, jsmntok_t *tok, const char *s); + + /* ** Module Variables */ // Cryptography Interface static CryptographyInterfaceStruct cryptography_if_struct; +static CURL* curl; +struct curl_slist *http_headers_list; +// KMC Crypto Service Endpoints +static char* kmc_root_uri; +static const char* status_endpoint = "key-info?keyRef=kmc/test/KEY0"; +static const char* encrypt_endpoint = "encrypt?keyRef=%s&transformation=%s&iv=%s"; +static const char* encrypt_offset_endpoint = "encrypt?keyRef=%s&transformation=%s&iv=%s&encryptOffset=%s"; +static const char* decrypt_endpoint = "decrypt?metadata=keyLength:%s,keyRef:%s,cipherTransformation:%s,initialVector:%s,cryptoAlgorithm:%s,metadataType:EncryptionMetadata"; +static const char* decrypt_offset_endpoint = "decrypt?metadata=keyLength:%s,keyRef:%s,cipherTransformation:%s,initialVector:%s,cryptoAlgorithm:%s,metadataType:EncryptionMetadata,encryptOffset:%s"; + +// Supported KMC Cipher Transformation Strings +static const char* AES_GCM_TRANSFORMATION="AES/GCM/NoPadding"; +static const char* AES_CRYPTO_ALGORITHM="AES"; +//static const char* AES_CBC_TRANSFORMATION="AES/CBC/PKCS5Padding"; +//static const char* AES_CMAC_TRANSFORMATION="AESCMAC"; +//static const char* AES_DES_CMAC_TRANSFORMATION="DESedeCMAC"; + + +// libcurl call-back response handling Structures +typedef struct { + char *response; + size_t size; +} memory_write; +#define MEMORY_WRITE_SIZE (sizeof(memory_write)) +typedef struct { + char *response; + size_t size; +} memory_read; +#define MEMORY_READ_SIZE (sizeof(memory_read)) + CryptographyInterface get_cryptography_interface_kmc_crypto_service(void) { @@ -66,23 +129,123 @@ CryptographyInterface get_cryptography_interface_kmc_crypto_service(void) return &cryptography_if_struct; } -static int32_t cryptography_config(void){ return CRYPTO_LIB_SUCCESS; } -static int32_t cryptography_init(void){ return CRYPTO_LIB_SUCCESS; } -static crypto_key_t* get_ek_ring(void){ return NULL; } -static int32_t cryptography_shutdown(void){ return CRYPTO_LIB_SUCCESS; } +static int32_t cryptography_config(void) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + + // Error out if Crypto_Config_Kmc_Crypto_Service(...) function was not called before intializing library. + if(cryptography_kmc_crypto_config == NULL) + { + fprintf(stderr, "You must configure the KMC Crypto Service before starting the interface!\n"); + status = CRYPTOGRAPHY_KMC_CRYPTO_SERVICE_CONFIGURATION_NOT_COMPLETE; + return status; + } + + if(curl) + { + //Determine length of port and convert to string for use in URL + uint32_t port_str_len = 0; + char* port_str = int_to_str(cryptography_kmc_crypto_config->kmc_crypto_port, &port_str_len); + + // Form Root URI + //len(protocol)+len(://)+len(hostname)+ len(:) + len(port_str) + len(/) + len(app_uri) + strlen('\0') + uint32_t len_root_uri = strlen(cryptography_kmc_crypto_config->protocol) + 3 + // "://" + strlen(cryptography_kmc_crypto_config->kmc_crypto_hostname) + 1 + // ":" + port_str_len + 1 + // "/" + strlen(cryptography_kmc_crypto_config->kmc_crypto_app_uri) + 2; // "/\0" + + kmc_root_uri = malloc(len_root_uri); + snprintf(kmc_root_uri,len_root_uri,"%s://%s:%s/%s/",cryptography_kmc_crypto_config->protocol, + cryptography_kmc_crypto_config->kmc_crypto_hostname, port_str, + cryptography_kmc_crypto_config->kmc_crypto_app_uri); + + + char* status_uri = (char*) malloc(strlen(kmc_root_uri)+strlen(status_endpoint)); + status_uri[0] = '\0'; + strcat(status_uri, kmc_root_uri); + strcat(status_uri, status_endpoint); +#ifdef DEBUG + printf("Setting up cURL connection to KMC Crypto Service with Params:\n"); + printf("\tKMC Root URI: %s\n",kmc_root_uri); + printf("\tKMC Status URL: %s\n",status_uri); + //printf("\tPort: %d\n",cryptography_kmc_crypto_config->kmc_crypto_port); + printf("\tSSL Client Cert: %s\n",cryptography_kmc_crypto_config->mtls_client_cert_path); + printf("\tSSL Client Key: %s\n",cryptography_kmc_crypto_config->mtls_client_key_path); + printf("\tSSL CA Bundle: %s\n",cryptography_kmc_crypto_config->mtls_ca_bundle); +#endif + configure_curl_connect_opts(curl); + curl_easy_setopt(curl, CURLOPT_URL, status_uri); + + memory_write* chunk = calloc(1,MEMORY_WRITE_SIZE); + /* send all data to this function */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)chunk); + + CURLcode res; + res = curl_easy_perform(curl); + + if(res != CURLE_OK) // This is not return code, this is successful response! + { + status = CRYPTOGRAHPY_KMC_CRYPTO_SERVICE_CONNECTION_ERROR; + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + return status; + } + +#ifdef DEBUG + printf("cURL response:\n\t %s\n",chunk->response); +#endif + } + return status; +} +static int32_t cryptography_init(void) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + curl = curl_easy_init(); + curl_global_init(CURL_GLOBAL_ALL); + http_headers_list = NULL; + // Prepare HTTP headers list + http_headers_list = curl_slist_append(http_headers_list, "Content-Type: application/octet-stream"); + // http_headers_list = curl_slist_append(http_headers_list, "Accept: application/json"); + // curl_slist_append(http_headers_list, "Content-Type: application/json"); + // http_headers_list = curl_slist_append(http_headers_list, "charset: utf-8"); + + if(curl == NULL) { + status = CRYPTOGRAPHY_KMC_CURL_INITIALIZATION_FAILURE; + } + kmc_root_uri = NULL; + return status; +} +static crypto_key_t* get_ek_ring(void) +{ + fprintf(stderr, "Attempting to access key ring with KMC Crypto Service. This shouldn't happen!\n "); + return NULL; +} +static int32_t cryptography_shutdown(void) +{ +// if(curl){ +// curl_easy_cleanup(curl); +// curl_global_cleanup(); +// } +// if(http_headers_list != NULL){ +// curl_slist_free_all(http_headers_list); +// } + if(kmc_root_uri != NULL){ + free(kmc_root_uri); + } + return CRYPTO_LIB_SUCCESS; +} static int32_t cryptography_encrypt(void){ return CRYPTO_LIB_SUCCESS; } static int32_t cryptography_decrypt(void){ return CRYPTO_LIB_SUCCESS; } -static int32_t cryptography_authenticate(void){ return CRYPTO_LIB_SUCCESS; } -static int32_t cryptography_validate_authentication(void){ return CRYPTO_LIB_SUCCESS; } -static int32_t cryptography_aead_encrypt(uint8_t* data_out, size_t len_data_out, +static int32_t cryptography_authenticate(uint8_t* data_out, size_t len_data_out, uint8_t* data_in, size_t len_data_in, uint8_t* key, uint32_t len_key, SecurityAssociation_t* sa_ptr, uint8_t* iv, uint32_t iv_len, uint8_t* mac, uint32_t mac_size, uint8_t* aad, uint32_t aad_len, - uint8_t encrypt_bool, uint8_t authenticate_bool, - uint8_t aad_bool) + uint8_t ecs, uint8_t acs) { data_out = data_out; len_data_out = len_data_out; @@ -97,20 +260,18 @@ static int32_t cryptography_aead_encrypt(uint8_t* data_out, size_t len_data_out, mac_size = mac_size; aad = aad; aad_len = aad_len; - encrypt_bool = encrypt_bool; - authenticate_bool = authenticate_bool; - aad_bool = aad_bool; + ecs = ecs; + acs = acs; return CRYPTO_LIB_SUCCESS; } -static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, - uint8_t* data_in, size_t len_data_in, - uint8_t* key, uint32_t len_key, - SecurityAssociation_t* sa_ptr, - uint8_t* iv, uint32_t iv_len, - uint8_t* mac, uint32_t mac_size, - uint8_t* aad, uint32_t aad_len, - uint8_t decrypt_bool, uint8_t authenticate_bool, - uint8_t aad_bool) +static int32_t cryptography_validate_authentication(uint8_t* data_out, size_t len_data_out, + uint8_t* data_in, size_t len_data_in, + uint8_t* key, uint32_t len_key, + SecurityAssociation_t* sa_ptr, + uint8_t* iv, uint32_t iv_len, + uint8_t* mac, uint32_t mac_size, + uint8_t* aad, uint32_t aad_len, + uint8_t ecs, uint8_t acs) { data_out = data_out; len_data_out = len_data_out; @@ -125,8 +286,552 @@ static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, mac_size = mac_size; aad = aad; aad_len = aad_len; - decrypt_bool = decrypt_bool; - authenticate_bool = authenticate_bool; - aad_bool = aad_bool; + ecs = ecs; + acs = acs; return CRYPTO_LIB_SUCCESS; } +static int32_t cryptography_aead_encrypt(uint8_t* data_out, size_t len_data_out, + uint8_t* data_in, size_t len_data_in, + uint8_t* key, uint32_t len_key, + SecurityAssociation_t* sa_ptr, + uint8_t* iv, uint32_t iv_len, + uint8_t* mac, uint32_t mac_size, + uint8_t* aad, uint32_t aad_len, + uint8_t encrypt_bool, uint8_t authenticate_bool, + uint8_t aad_bool) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + key = key; // Direct key input is not supported in KMC interface + len_key = len_key; // Direct key input is not supported in KMC interface + + curl_easy_reset(curl); + configure_curl_connect_opts(curl); + + // Base64 URL encode IV for KMC REST Encrypt + char* iv_base64 = (char*)calloc(1,iv_len*4); + base64urlEncode(iv,iv_len,iv_base64,NULL); + + uint8_t* encrypt_payload = data_in; + size_t encrypt_payload_len = len_data_in; + +#ifdef DEBUG + printf("IV Base64 URL Encoded: %s\n",iv_base64); +#endif + char* encrypt_uri; + if(aad_bool == CRYPTO_TRUE) + { + //Determine length of aad offset string and convert to string for use in URL + uint32_t aad_offset_str_len = 0; + char* aad_offset_str = int_to_str(aad_len, &aad_offset_str_len); +#ifdef DEBUG + printf("AAD Offset Str: %s\n",aad_offset_str); +#endif + + + int len_encrypt_endpoint = strlen(encrypt_offset_endpoint)+strlen(sa_ptr->ek_ref)+strlen(iv_base64)+strlen(AES_GCM_TRANSFORMATION)+aad_offset_str_len; + char* encrypt_endpoint_final = (char*) malloc(len_encrypt_endpoint); + + snprintf(encrypt_endpoint_final,len_encrypt_endpoint,encrypt_offset_endpoint,sa_ptr->ek_ref,AES_GCM_TRANSFORMATION, iv_base64,aad_offset_str); + + encrypt_uri = (char*) malloc(strlen(kmc_root_uri)+len_encrypt_endpoint); + encrypt_uri[0] = '\0'; + strcat(encrypt_uri, kmc_root_uri); + strcat(encrypt_uri, encrypt_endpoint_final); + + // Prepare encrypt_payload with AAD at the front for KMC Crypto Service. + if(encrypt_bool == CRYPTO_FALSE) //Not encrypting data, only passing in AAD for TAG. + { + encrypt_payload_len = aad_len; + } + else // Encrypt & AAD + { + encrypt_payload_len = len_data_in + aad_len; + } + +#ifdef DEBUG + printf("Encrypt Payload Length: %ld\n",encrypt_payload_len); +#endif + encrypt_payload = (uint8_t*) malloc(encrypt_payload_len); + memcpy(&encrypt_payload[0],aad,aad_len); + if(encrypt_bool == CRYPTO_TRUE) + { + memcpy(&encrypt_payload[aad_len],data_in,len_data_in); + } + } + else //No AAD -- just prepare the endpoint URI + { + int len_encrypt_endpoint = strlen(encrypt_endpoint)+strlen(sa_ptr->ek_ref)+strlen(iv_base64)+strlen(AES_GCM_TRANSFORMATION); + char* encrypt_endpoint_final = (char*) malloc(len_encrypt_endpoint); + + snprintf(encrypt_endpoint_final,len_encrypt_endpoint,encrypt_endpoint,sa_ptr->ek_ref,AES_GCM_TRANSFORMATION, iv_base64); + + encrypt_uri = (char*) malloc(strlen(kmc_root_uri)+len_encrypt_endpoint); + encrypt_uri[0] = '\0'; + strcat(encrypt_uri, kmc_root_uri); + strcat(encrypt_uri, encrypt_endpoint_final); + } + +#ifdef DEBUG + printf("Encrypt URI: %s\n",encrypt_uri); +#endif + curl_easy_setopt(curl, CURLOPT_URL, encrypt_uri); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_headers_list); + + memory_write* chunk_write = (memory_write*) calloc(1,MEMORY_WRITE_SIZE); + memory_read* chunk_read = (memory_read*) calloc(1,MEMORY_READ_SIZE);; + /* Configure CURL for POST */ + curl_easy_setopt(curl, CURLOPT_POST, 1L); + /* send all data to this function */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl, CURLOPT_READDATA, chunk_read); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, chunk_write); + + /* size of the POST data */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) encrypt_payload_len); + /* binary data */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, encrypt_payload); + +#ifdef DEBUG + printf("Data to Encrypt: \n"); + for (uint32_t i=0; i < encrypt_payload_len; i++) + { + printf("%02x ", encrypt_payload[i]); + } + printf("\n"); +#endif + + CURLcode res; + res = curl_easy_perform(curl); + + if(res != CURLE_OK) // This is not return code, this is successful response! + { + status = CRYPTOGRAHPY_KMC_CRYPTO_SERVICE_AEAD_ENCRYPT_ERROR; + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + return status; + } + +#ifdef DEBUG + printf("\ncURL Encrypt Response:\n\t %s\n",chunk_write->response); +#endif + + /* JSON Response Handling */ + + // Parse the JSON string response + jsmn_parser p; + jsmntok_t t[64]; /* We expect no more than 64 JSON tokens */ + jsmn_init(&p); + int parse_result = jsmn_parse(&p, chunk_write->response, strlen(chunk_write->response), t, 64); // "chunk->response" is the char array holding the json content + + // Find the 'base64ciphertext' token + if (parse_result < 0) { + status = CRYPTOGRAHPY_KMC_CRYPTO_JSON_PARSE_ERROR; + printf("Failed to parse JSON: %d\n", parse_result); + return status; + } + + int json_idx = 0; + uint8_t ciphertext_found = CRYPTO_FALSE; + char* ciphertext_base64 = NULL; + for (json_idx = 1; json_idx < parse_result; json_idx++) + { + if (jsoneq(chunk_write->response, &t[json_idx], "base64ciphertext") == 0) + { + /* We may use strndup() to fetch string value */ +#ifdef DEBUG + printf("Json base64ciphertext: %.*s\n", t[json_idx + 1].end - t[json_idx + 1].start, + chunk_write->response + t[json_idx + 1].start); +#endif + uint32_t len_ciphertext = t[json_idx + 1].end - t[json_idx + 1].start; + ciphertext_base64 = malloc(len_ciphertext+1); + memcpy(ciphertext_base64,chunk_write->response + t[json_idx + 1].start, len_ciphertext); + ciphertext_base64[len_ciphertext] = '\0'; +#ifdef DEBUG + printf("Parsed base64ciphertext: %s\n",ciphertext_base64); +#endif + json_idx++; + ciphertext_found = CRYPTO_TRUE; + break; + } + } + if(ciphertext_found == CRYPTO_FALSE){ + status = CRYPTOGRAHPY_KMC_CIPHER_TEXT_NOT_FOUND_IN_JSON_RESPONSE; + return status; + } + + /* JSON Response Handling End */ + + uint8_t* ciphertext_decoded = malloc((len_data_out + mac_size + aad_len)*2 + 1); + size_t ciphertext_decoded_len = 0; + base64Decode(ciphertext_base64,strlen(ciphertext_base64),ciphertext_decoded, &ciphertext_decoded_len); +#ifdef DEBUG + printf("Mac size: %d\n",mac_size); + printf("Decoded Cipher Text Length: %ld\n",ciphertext_decoded_len); + printf("Decoded Cipher Text: \n"); + for (uint32_t i=0; i < ciphertext_decoded_len; i++) + { + printf("%02x ", ciphertext_decoded[i]); + } + printf("\n"); +#endif + + + // Copy the encrypted data to the output stream + if(encrypt_bool == CRYPTO_TRUE) + { + // Crypto Service returns aad - cipher_text - tag + memcpy(data_out,ciphertext_decoded + aad_len,len_data_out); + } + + // If authenticate, Copy the MAC to the output stream + if(authenticate_bool == CRYPTO_TRUE) + { + memcpy(mac,ciphertext_decoded + aad_len + len_data_out, mac_size); + } + return status; +} +static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, + uint8_t* data_in, size_t len_data_in, + uint8_t* key, uint32_t len_key, + SecurityAssociation_t* sa_ptr, + uint8_t* iv, uint32_t iv_len, + uint8_t* mac, uint32_t mac_size, + uint8_t* aad, uint32_t aad_len, + uint8_t decrypt_bool, uint8_t authenticate_bool, + uint8_t aad_bool) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + key = key; // Direct key input is not supported in KMC interface + + // Get the key length in bits, in string format. + // TODO -- Parse the key length from the keyInfo endpoint of the Crypto Service! + uint32_t key_len_in_bits = len_key * 8; // 8 bits per byte. + uint32_t key_len_in_bits_str_len = 0; + char* key_len_in_bits_str = int_to_str(key_len_in_bits, &key_len_in_bits); + + + + curl_easy_reset(curl); + configure_curl_connect_opts(curl); + + // Base64 URL encode IV for KMC REST Encrypt + char* iv_base64 = (char*)calloc(1,iv_len*4); + base64urlEncode(iv,iv_len,iv_base64,NULL); + + uint8_t* decrypt_payload = data_in; + size_t decrypt_payload_len = len_data_in; + +#ifdef DEBUG + printf("IV Base64 URL Encoded: %s\n",iv_base64); +#endif + + char* decrypt_uri; + if(aad_bool == CRYPTO_TRUE) + { + //Determine length of aad offset string and convert to string for use in URL + uint32_t aad_offset_str_len = 0; + char* aad_offset_str = int_to_str(aad_len, &aad_offset_str_len); +#ifdef DEBUG + printf("AAD Offset Str: %s\n",aad_offset_str); +#endif + + int len_decrypt_endpoint = strlen(decrypt_offset_endpoint)+ key_len_in_bits_str_len + strlen(sa_ptr->ek_ref)+strlen(iv_base64)+strlen(AES_GCM_TRANSFORMATION) + strlen(AES_CRYPTO_ALGORITHM) + aad_offset_str_len; + char* decrypt_endpoint_final = (char*) malloc(len_decrypt_endpoint); + + snprintf(decrypt_endpoint_final,len_decrypt_endpoint,decrypt_offset_endpoint,key_len_in_bits_str,sa_ptr->ek_ref,AES_GCM_TRANSFORMATION, iv_base64, AES_CRYPTO_ALGORITHM, aad_offset_str); + + decrypt_uri = (char*) malloc(strlen(kmc_root_uri)+len_decrypt_endpoint); + decrypt_uri[0] = '\0'; + strcat(decrypt_uri, kmc_root_uri); + strcat(decrypt_uri, decrypt_endpoint_final); + + // Prepare decrypt_payload with AAD at the front for KMC Crypto Service. + if(decrypt_bool == CRYPTO_FALSE) //Not decrypting data, only passing in AAD for TAG validation. + { + decrypt_payload_len = aad_len + mac_size; + } + else // Decrypt & AAD/TAG validation + { + decrypt_payload_len = len_data_in + aad_len + mac_size; + } +#ifdef DEBUG + printf("Decrypt Payload Length: %ld\n",decrypt_payload_len); +#endif + decrypt_payload = (uint8_t*) malloc(decrypt_payload_len); + memcpy(&decrypt_payload[0],aad,aad_len); + if(decrypt_bool == CRYPTO_TRUE) + { + memcpy(&decrypt_payload[aad_len],data_in,len_data_in); + } + if(authenticate_bool == CRYPTO_TRUE) + { + memcpy(&decrypt_payload[aad_len + len_data_in],mac,mac_size); + } + } + else //No AAD - just prepare the endpoint URI string + { + int len_decrypt_endpoint = strlen(decrypt_endpoint)+ key_len_in_bits_str_len + strlen(sa_ptr->ek_ref)+strlen(iv_base64)+strlen(AES_GCM_TRANSFORMATION) + strlen(AES_CRYPTO_ALGORITHM); + char* decrypt_endpoint_final = (char*) malloc(len_decrypt_endpoint); + + snprintf(decrypt_endpoint_final,len_decrypt_endpoint,decrypt_endpoint,key_len_in_bits_str,sa_ptr->ek_ref,AES_GCM_TRANSFORMATION, iv_base64, AES_CRYPTO_ALGORITHM); + + decrypt_uri = (char*) malloc(strlen(kmc_root_uri)+len_decrypt_endpoint); + decrypt_uri[0] = '\0'; + strcat(decrypt_uri, kmc_root_uri); + strcat(decrypt_uri, decrypt_endpoint_final); + } +#ifdef DEBUG + printf("Decrypt URI: %s\n",decrypt_uri); +#endif + curl_easy_setopt(curl, CURLOPT_URL, decrypt_uri); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_headers_list); + + memory_write* chunk_write = (memory_write*) calloc(1,MEMORY_WRITE_SIZE); + memory_read* chunk_read = (memory_read*) calloc(1,MEMORY_READ_SIZE);; + + /* Configure CURL for POST */ + curl_easy_setopt(curl, CURLOPT_POST, 1L); + /* send all data to this function */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl, CURLOPT_READDATA, chunk_read); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, chunk_write); + + /* size of the POST data */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) decrypt_payload_len); + /* binary data */ + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, decrypt_payload); + +#ifdef DEBUG + printf("Len of decrypt payload: %ld\n",decrypt_payload_len); + printf("Data to Decrypt: \n"); + for (uint32_t i=0; i < decrypt_payload_len; i++) + { + printf("%02x ", decrypt_payload[i]); + } + printf("\n"); +#endif + + CURLcode res; + res = curl_easy_perform(curl); + + if(res != CURLE_OK) // This is not return code, this is successful response! + { + status = CRYPTOGRAHPY_KMC_CRYPTO_SERVICE_AEAD_DECRYPT_ERROR; + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + return status; + } + +#ifdef DEBUG + printf("\ncURL Decrypt Response:\n\t %s\n",chunk_write->response); +#endif + + /* JSON Response Handling */ + + // Parse the JSON string response + jsmn_parser p; + jsmntok_t t[64]; /* We expect no more than 64 JSON tokens */ + jsmn_init(&p); + int parse_result = jsmn_parse(&p, chunk_write->response, strlen(chunk_write->response), t, 64); // "chunk->response" is the char array holding the json content + + // Find the 'base64ciphertext' token + if (parse_result < 0) { + status = CRYPTOGRAHPY_KMC_CRYPTO_JSON_PARSE_ERROR; + printf("Failed to parse JSON: %d\n", parse_result); + return status; + } + + int json_idx = 0; + uint8_t ciphertext_found = CRYPTO_FALSE; + char* cleartext_base64 = NULL; + for (json_idx = 1; json_idx < parse_result; json_idx++) + { + // check "httpCode" field for non-200 status codes!!! + if (jsoneq(chunk_write->response, &t[json_idx], "base64cleartext") == 0) + { + /* We may use strndup() to fetch string value */ +#ifdef DEBUG + printf("Json base64cleartext: %.*s\n", t[json_idx + 1].end - t[json_idx + 1].start, + chunk_write->response + t[json_idx + 1].start); +#endif + uint32_t len_cleartext = t[json_idx + 1].end - t[json_idx + 1].start; + cleartext_base64 = malloc(len_cleartext+1); + memcpy(cleartext_base64,chunk_write->response + t[json_idx + 1].start, len_cleartext); + cleartext_base64[len_cleartext] = '\0'; +#ifdef DEBUG + printf("Parsed base64cleartext: %s\n",cleartext_base64); +#endif + json_idx++; + ciphertext_found = CRYPTO_TRUE; + continue; + } + if (jsoneq(chunk_write->response, &t[json_idx], "httpCode") == 0) + { + /* We may use strndup() to fetch string value */ +#ifdef DEBUG + printf("httpCode: %.*s\n", t[json_idx + 1].end - t[json_idx + 1].start, + chunk_write->response + t[json_idx + 1].start); +#endif + uint32_t len_httpcode = t[json_idx + 1].end - t[json_idx + 1].start; + char* http_code_str = malloc(len_httpcode+1); + memcpy(http_code_str,chunk_write->response + t[json_idx + 1].start, len_httpcode); + http_code_str[len_httpcode] = '\0'; + int http_code = atoi(http_code_str); +#ifdef DEBUG + printf("Parsed http code: %d\n",http_code); +#endif + if(http_code != 200) + { + status = CRYPTOGRAHPY_KMC_CRYPTO_SERVICE_GENERIC_FAILURE; + fprintf(stderr,"KMC Crypto Failure Response:\n%s\n",chunk_write->response); + return status; + } + json_idx++; + continue; + } + } + if(ciphertext_found == CRYPTO_FALSE){ + status = CRYPTOGRAHPY_KMC_CIPHER_TEXT_NOT_FOUND_IN_JSON_RESPONSE; + return status; + } + + /* JSON Response Handling End */ + + uint8_t* cleartext_decoded = malloc((len_data_out + mac_size + aad_len)*2 + 1); + size_t cleartext_decoded_len = 0; + base64Decode(cleartext_base64,strlen(cleartext_base64),cleartext_decoded, &cleartext_decoded_len); +#ifdef DEBUG + printf("Decoded Cipher Text Length: %ld\n",cleartext_decoded_len); + printf("Decoded Cipher Text: \n"); + for (uint32_t i=0; i < cleartext_decoded_len; i++) + { + printf("%02x ", cleartext_decoded[i]); + } + printf("\n"); +#endif + + // Copy the decrypted data to the output stream + // Crypto Service returns aad - clear_text + if(decrypt_bool == CRYPTO_TRUE) + { + memcpy(data_out,cleartext_decoded + aad_len, len_data_out); + } + return status; +} + +// libcurl local functions +static size_t write_callback(void *data, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + memory_write *mem = (memory_write *)userp; + + char *ptr; + if(mem->response != NULL) + { + ptr = realloc(mem->response, mem->size + realsize + 1); + } + else + { + ptr = malloc(realsize+1); + } + + if(ptr == NULL) + return 0; /* out of memory! */ + + mem->response = ptr; + memcpy(&(mem->response[mem->size]), data, realsize); + mem->size += realsize; + mem->response[mem->size] = 0; + + return realsize; +} + +static size_t read_callback(char *dest, size_t size, size_t nmemb, void *userp) +{ + memory_read *wt = (memory_read *)userp; + size_t buffer_size = size*nmemb; + if(wt->size) { + /* copy as much as possible from the source to the destination */ + size_t copy_this_much = wt->size; + if(copy_this_much > buffer_size) + copy_this_much = buffer_size; + memcpy(dest, wt->response, copy_this_much); + + wt->response += copy_this_much; + wt->size -= copy_this_much; + return copy_this_much; /* we copied this many bytes */ + } + + return 0; /* no more data left to deliver */ +} + +static void configure_curl_connect_opts(CURL* curl_handle) +{ + //curl_easy_setopt(curl_handle, CURLOPT_PROTOCOLS,CURLPROTO_HTTPS); // use default CURLPROTO_ALL +#ifdef DEBUG + printf("KMC Crypto Port: %d\n",cryptography_kmc_crypto_config->kmc_crypto_port); + printf("KMC mTLS Client Cert Path: %s\n",cryptography_kmc_crypto_config->mtls_client_cert_path); + printf("KMC mTLS Client Key Path: %s\n",cryptography_kmc_crypto_config->mtls_client_key_path); + + if(cryptography_kmc_crypto_config->mtls_client_cert_type != NULL && (strcmp(cryptography_kmc_crypto_config->mtls_client_cert_type,"")!=0)){ + printf("KMC mTLS Client Cert Type: %s\n",cryptography_kmc_crypto_config->mtls_client_cert_type); + } + if(cryptography_kmc_crypto_config->mtls_ca_bundle != NULL && (strcmp(cryptography_kmc_crypto_config->mtls_ca_bundle,"")!=0)){ + printf("KMC mTLS CA Bundle: %s\n",cryptography_kmc_crypto_config->mtls_ca_bundle); + } + if(cryptography_kmc_crypto_config->mtls_ca_path != NULL && (strcmp(cryptography_kmc_crypto_config->mtls_ca_path,"")!=0)){ + printf("KMC mTLS CA Path: %s\n",cryptography_kmc_crypto_config->mtls_ca_path); + } + if(cryptography_kmc_crypto_config->mtls_issuer_cert != NULL && (strcmp(cryptography_kmc_crypto_config->mtls_issuer_cert,"")!=0)){ + printf("KMC mTLS Client Issuer Cert: %s\n",cryptography_kmc_crypto_config->mtls_issuer_cert); + } +#endif + curl_easy_setopt(curl_handle, CURLOPT_PORT, cryptography_kmc_crypto_config->kmc_crypto_port); + curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, cryptography_kmc_crypto_config->mtls_client_cert_path); + curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, cryptography_kmc_crypto_config->mtls_client_key_path); + if(cryptography_kmc_crypto_config->mtls_client_cert_type != NULL && (strcmp(cryptography_kmc_crypto_config->mtls_client_cert_type,"")!=0)){ + curl_easy_setopt(curl_handle, CURLOPT_SSLCERTTYPE, cryptography_kmc_crypto_config->mtls_client_cert_type); + } + if(cryptography_kmc_crypto_config->mtls_client_key_pass != NULL && (strcmp(cryptography_kmc_crypto_config->mtls_client_key_pass,"")!=0)){ + curl_easy_setopt(curl_handle, CURLOPT_KEYPASSWD, cryptography_kmc_crypto_config->mtls_client_key_pass); + } + if(cryptography_kmc_crypto_config->mtls_ca_bundle != NULL && (strcmp(cryptography_kmc_crypto_config->mtls_ca_bundle,"")!=0)){ + curl_easy_setopt(curl_handle, CURLOPT_CAINFO, cryptography_kmc_crypto_config->mtls_ca_bundle); + } + if(cryptography_kmc_crypto_config->mtls_ca_path != NULL && (strcmp(cryptography_kmc_crypto_config->mtls_ca_path,"")!=0)){ + curl_easy_setopt(curl_handle, CURLOPT_CAPATH, cryptography_kmc_crypto_config->mtls_ca_path); + } + if(cryptography_kmc_crypto_config->mtls_issuer_cert != NULL && (strcmp(cryptography_kmc_crypto_config->mtls_issuer_cert,"")!=0)){ + curl_easy_setopt(curl_handle, CURLOPT_ISSUERCERT, cryptography_kmc_crypto_config->mtls_issuer_cert); + } + if(cryptography_kmc_crypto_config->ignore_ssl_hostname_validation == CRYPTO_TRUE){ + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + } +} +static char* int_to_str(uint32_t int_src, uint32_t* converted_str_length) +{ + int int_str_len = snprintf( NULL, 0, "%d", int_src); + char* int_str = malloc( int_str_len + 1); + snprintf(int_str, int_str_len + 1, "%d", int_src); + *converted_str_length = int_str_len; + return int_str; +} + +// JSON local functions + +static int jsoneq(const char *json, jsmntok_t *tok, const char *s) +{ + if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start && + strncmp(json + tok->start, s, tok->end - tok->start) == 0) { + return 0; + } + return -1; +} \ No newline at end of file diff --git a/src/src_cryptography/src_kmc_crypto_service/jsmn.h b/src/src_cryptography/src_kmc_crypto_service/jsmn.h new file mode 100644 index 00000000..8ac14c1b --- /dev/null +++ b/src/src_cryptography/src_kmc_crypto_service/jsmn.h @@ -0,0 +1,471 @@ +/* + * MIT License + * + * Copyright (c) 2010 Serge Zaitsev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef JSMN_H +#define JSMN_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef JSMN_STATIC +#define JSMN_API static +#else +#define JSMN_API extern +#endif + +/** + * JSON type identifier. Basic types are: + * o Object + * o Array + * o String + * o Other primitive: number, boolean (true/false) or null + */ +typedef enum { + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1 << 0, + JSMN_ARRAY = 1 << 1, + JSMN_STRING = 1 << 2, + JSMN_PRIMITIVE = 1 << 3 +} jsmntype_t; + +enum jsmnerr { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 +}; + +/** + * JSON token description. + * type type (object, array, string etc.) + * start start position in JSON data string + * end end position in JSON data string + */ +typedef struct jsmntok { + jsmntype_t type; + int start; + int end; + int size; +#ifdef JSMN_PARENT_LINKS + int parent; +#endif +} jsmntok_t; + +/** + * JSON parser. Contains an array of token blocks available. Also stores + * the string being parsed now and current position in that string. + */ +typedef struct jsmn_parser { + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g. parent object or array */ +} jsmn_parser; + +/** + * Create JSON parser over an array of tokens + */ +JSMN_API void jsmn_init(jsmn_parser *parser); + +/** + * Run JSON parser. It parses a JSON data string into and array of tokens, each + * describing + * a single JSON object. + */ +JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, + jsmntok_t *tokens, const unsigned int num_tokens); + +#ifndef JSMN_HEADER +/** + * Allocates a fresh unused token from the token pool. + */ +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, + const size_t num_tokens) { + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + return tok; +} + +/** + * Fills token type and boundaries. + */ +static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, + const int start, const int end) { + token->type = type; + token->start = start; + token->end = end; + token->size = 0; +} + +/** + * Fills next available token with JSON primitive. + */ +static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, + const size_t len, jsmntok_t *tokens, + const size_t num_tokens) { + jsmntok_t *token; + int start; + + start = parser->pos; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + case '\t': + case '\r': + case '\n': + case ' ': + case ',': + case ']': + case '}': + goto found; + default: + /* to quiet a warning from gcc*/ + break; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** + * Fills next token with JSON string. + */ +static int jsmn_parse_string(jsmn_parser *parser, const char *js, + const size_t len, jsmntok_t *tokens, + const size_t num_tokens) { + jsmntok_t *token; + + int start = parser->pos; + + /* Skip starting quote */ + parser->pos++; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': + case '/': + case '\\': + case 'b': + case 'f': + case 'r': + case 'n': + case 't': + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; + i++) { + /* If it isn't a hex character we have an error */ + if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; +} + +/** + * Parse JSON string and fill tokens. + */ +JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, + jsmntok_t *tokens, const unsigned int num_tokens) { + int r; + int i; + jsmntok_t *token; + int count = parser->toknext; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; + + c = js[parser->pos]; + switch (c) { + case '{': + case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + return JSMN_ERROR_NOMEM; + } + if (parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; +#ifdef JSMN_STRICT + /* In strict mode an object or array can't become a key */ + if (t->type == JSMN_OBJECT) { + return JSMN_ERROR_INVAL; + } +#endif + t->size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': + case ']': + if (tokens == NULL) { + break; + } + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + if (token->type != type || parser->toksuper == -1) { + return JSMN_ERROR_INVAL; + } + break; + } + token = &tokens[token->parent]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) { + return JSMN_ERROR_INVAL; + } + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) { + return r; + } + count++; + if (parser->toksuper != -1 && tokens != NULL) { + tokens[parser->toksuper].size++; + } + break; + case '\t': + case '\r': + case '\n': + case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 't': + case 'f': + case 'n': + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + const jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) { + return r; + } + count++; + if (parser->toksuper != -1 && tokens != NULL) { + tokens[parser->toksuper].size++; + } + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + if (tokens != NULL) { + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } + } + + return count; +} + +/** + * Creates a new parser based over a given buffer with an array of tokens + * available. + */ +JSMN_API void jsmn_init(jsmn_parser *parser) { + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; +} + +#endif /* JSMN_HEADER */ + +#ifdef __cplusplus +} +#endif + +#endif /* JSMN_H */ diff --git a/src/src_main/crypto_config.c b/src/src_main/crypto_config.c index 9108e5ab..ab545f93 100644 --- a/src/src_main/crypto_config.c +++ b/src/src_main/crypto_config.c @@ -140,9 +140,19 @@ int32_t Crypto_Init(void) // Initialize the cryptography library. status = cryptography_if->cryptography_init(); + if(status != CRYPTO_LIB_SUCCESS){ + fprintf(stderr, "Fatal Error: Unable to initialize Cryptography Interface.\n"); + return status; + } + // Configure the cryptography library. status = cryptography_if->cryptography_config(); + if(status != CRYPTO_LIB_SUCCESS){ + fprintf(stderr, "Fatal Error: Unable to configure Cryptography Interface.\n"); + return status; + } + // Init Security Associations status = sadb_routine->sadb_init(); @@ -272,15 +282,28 @@ int32_t Crypto_Config_MariaDB(char* mysql_username, char* mysql_password, char* return status; } -extern int32_t Crypto_Config_Kmc_Crypto_Service(char *kmc_crypto_hostname, uint16_t kmc_crypto_port, char *mtls_cert_path, - char *mtls_key_path, uint8_t ignore_ssl_hostname_validation) +extern int32_t Crypto_Config_Kmc_Crypto_Service(char* protocol, char *kmc_crypto_hostname, uint16_t kmc_crypto_port, char *kmc_crypto_app_uri, char *mtls_client_cert_path, char *mtls_client_cert_type, + char *mtls_client_key_path,char *mtls_client_key_pass,char *mtls_ca_bundle, char *mtls_ca_path, char *mtls_issuer_cert, + uint8_t ignore_ssl_hostname_validation) { int32_t status = CRYPTO_LIB_SUCCESS; cryptography_kmc_crypto_config = (CryptographyKmcCryptoServiceConfig_t *)calloc(1, CRYPTOGRAPHY_KMC_CRYPTO_SERVICE_CONFIG_SIZE); + cryptography_kmc_crypto_config->protocol = protocol; cryptography_kmc_crypto_config->kmc_crypto_hostname = kmc_crypto_hostname; cryptography_kmc_crypto_config->kmc_crypto_port = kmc_crypto_port; - cryptography_kmc_crypto_config->mtls_cert_path = mtls_cert_path; - cryptography_kmc_crypto_config->mtls_key_path = mtls_key_path; + if(kmc_crypto_app_uri != NULL){ + cryptography_kmc_crypto_config->kmc_crypto_app_uri = kmc_crypto_app_uri; + } else{ + cryptography_kmc_crypto_config->kmc_crypto_app_uri = "crypto-service"; + } + + cryptography_kmc_crypto_config->mtls_client_cert_path = mtls_client_cert_path; + cryptography_kmc_crypto_config->mtls_client_cert_type = mtls_client_cert_type; + cryptography_kmc_crypto_config->mtls_client_key_path = mtls_client_key_path; + cryptography_kmc_crypto_config->mtls_client_key_pass = mtls_client_key_pass; + cryptography_kmc_crypto_config->mtls_ca_bundle = mtls_ca_bundle; + cryptography_kmc_crypto_config->mtls_ca_path = mtls_ca_path; + cryptography_kmc_crypto_config->mtls_issuer_cert = mtls_issuer_cert; cryptography_kmc_crypto_config->ignore_ssl_hostname_validation = ignore_ssl_hostname_validation; return status; } diff --git a/src/src_main/crypto_tc.c b/src/src_main/crypto_tc.c index 16164c4f..1a41e325 100644 --- a/src/src_main/crypto_tc.c +++ b/src/src_main/crypto_tc.c @@ -181,6 +181,9 @@ int32_t Crypto_TC_ApplySecurity(const uint8_t *p_in_frame, const uint16_t in_fra if (sa_ptr->ecs != NULL) { encryption_cipher = *sa_ptr->ecs; +#ifdef TC_DEBUG + printf(KYEL "SA Encryption Cipher: %d\n", encryption_cipher); +#endif } // If no pointer, must not be using ECS at all else @@ -420,7 +423,7 @@ int32_t Crypto_TC_ApplySecurity(const uint8_t *p_in_frame, const uint16_t in_fra sa_ptr->shplf_len + tf_payload_len; #ifdef MAC_DEBUG printf(KYEL "MAC location is: %d\n" RESET, mac_loc); - printf(KYEL "MAC size is: %d\n" RESET, MAC_SIZE); + printf(KYEL "MAC size is: %d\n" RESET, sa_ptr->stmacf_len); #endif mac_ptr = &p_new_enc_frame[mac_loc]; @@ -456,7 +459,7 @@ int32_t Crypto_TC_ApplySecurity(const uint8_t *p_in_frame, const uint16_t in_fra sa_ptr->iv, // IV sa_ptr->shivf_len, // IV Length mac_ptr, // tag output - MAC_SIZE, // tag size // TODO - why is this hard-coded?! + sa_ptr->stmacf_len, // tag size aad, // AAD Input aad_len, // Length of AAD (sa_ptr->est==1), @@ -484,7 +487,7 @@ int32_t Crypto_TC_ApplySecurity(const uint8_t *p_in_frame, const uint16_t in_fra sa_ptr->iv, // IV sa_ptr->shivf_len, // IV Length mac_ptr, // tag output - MAC_SIZE, // tag size // TODO - why is this hard-coded?! + sa_ptr->stmacf_len, // tag size aad, // AAD Input aad_len, // Length of AAD *sa_ptr->ecs, // encryption cipher @@ -809,6 +812,7 @@ int32_t Crypto_TC_ProcessSecurity(uint8_t *ingest, int *len_ingest, TC_t *tc_sdl uint16_t tc_enc_payload_start_index = TC_FRAME_HEADER_SIZE + segment_hdr_len + SPI_LEN + sa_ptr->shivf_len + sa_ptr->shsnf_len + sa_ptr->shplf_len; + // Todo -- if encrypt only, ignore stmacf_len entirely to avoid erroring on SA misconfiguration... Or just throw a warning/error indicating SA misconfiguration? tc_sdls_processed_frame->tc_pdu_len = tc_sdls_processed_frame->tc_header.fl + 1 - tc_enc_payload_start_index - sa_ptr->stmacf_len - fecf_len; diff --git a/src/src_mysql/sadb_routine_mariadb.template.c b/src/src_mysql/sadb_routine_mariadb.template.c index 26578e30..dacda773 100644 --- a/src/src_mysql/sadb_routine_mariadb.template.c +++ b/src/src_mysql/sadb_routine_mariadb.template.c @@ -124,8 +124,8 @@ static int32_t sadb_init(void) { status = CRYPTO_LIB_ERROR; } else { status = CRYPTO_LIB_SUCCESS; - if (status) { - printf("sadb_initUsing an encrypted connection \n"); + if (status==CRYPTO_LIB_SUCCESS) { + printf("sadb_init Using an encrypted connection \n"); } } }//end if TLS connection @@ -142,6 +142,10 @@ static int32_t sadb_init(void) { status = CRYPTO_LIB_ERROR; } else { status = CRYPTO_LIB_SUCCESS; + if (status==CRYPTO_LIB_SUCCESS) { + printf("sadb_init Using plain socket connection \n"); + } + } }//end regular password } @@ -290,6 +294,7 @@ static int32_t parse_sa_from_mysql_query(char *query, SecurityAssociation_t **se char *iv_byte_str; char *arc_byte_str; char *abm_byte_str; + char *ecs_byte_str; while ((row = mysql_fetch_row(result))) { for (int i = 0; i < num_fields; i++) @@ -316,12 +321,24 @@ static int32_t parse_sa_from_mysql_query(char *query, SecurityAssociation_t **se } if (strcmp(field_names[i], "ekid") == 0) { - sa->ekid = atoi(row[i]); + if(crypto_config->cryptography_type==CRYPTOGRAPHY_TYPE_LIBGCRYPT) + { + sa->ekid = atoi(row[i]); + } else // Cryptography Type KMC Crypto Service with PKCS12 String Key References + { + sa->ek_ref = row[i]; + } continue; } if (strcmp(field_names[i], "akid") == 0) { - sa->akid = atoi(row[i]); + if(crypto_config->cryptography_type==CRYPTOGRAPHY_TYPE_LIBGCRYPT) + { + sa->akid = atoi(row[i]); + } else // Cryptography Type KMC Crypto Service with PKCS12 String Key References + { + sa->ak_ref = row[i]; + } continue; } if (strcmp(field_names[i], "sa_state") == 0) @@ -391,7 +408,7 @@ static int32_t parse_sa_from_mysql_query(char *query, SecurityAssociation_t **se } if (strcmp(field_names[i], "HEX(ecs)") == 0) { - convert_hexstring_to_byte_array(row[i], sa->ecs); + ecs_byte_str = row[i]; continue; } // if(strcmp(field_names[i],"HEX(iv)")==0){memcpy(&(sa->iv),&row[i],IV_SIZE);continue;} @@ -449,9 +466,12 @@ static int32_t parse_sa_from_mysql_query(char *query, SecurityAssociation_t **se sa->iv = (uint8_t *)calloc(1, sa->shivf_len * sizeof(uint8_t)); sa->arc = (uint8_t *)calloc(1, sa->arc_len * sizeof(uint8_t)); sa->abm = (uint8_t *)calloc(1, sa->abm_len * sizeof(uint8_t)); + sa->ecs = calloc(1, sa->ecs_len * sizeof(uint8_t)); convert_hexstring_to_byte_array(iv_byte_str, sa->iv); convert_hexstring_to_byte_array(arc_byte_str, sa->arc); convert_hexstring_to_byte_array(abm_byte_str, sa->abm); + convert_hexstring_to_byte_array(ecs_byte_str, sa->ecs); + *security_association = sa; mysql_free_result(result); diff --git a/util/src_util/ut_crypto_config.c b/util/src_util/ut_crypto_config.c index 7ab4e07f..8f6895dd 100644 --- a/util/src_util/ut_crypto_config.c +++ b/util/src_util/ut_crypto_config.c @@ -146,13 +146,22 @@ UTEST(CRYPTO_CONFIG, CRYPTO_CONFIG_MDB) UTEST(CRYPTO_CONFIG, CRYPTO_CONFIG_KMC) { int32_t status = CRYPTO_LIB_ERROR; + char* protocol = "https"; char* hostname = "ITC_JPL"; int16_t port = 9999; - char* cert_path = "NONE"; - char* key_path = "NONE"; - uint8_t ssl_host_val = 123; - status = Crypto_Config_Kmc_Crypto_Service(hostname,port,cert_path,key_path,ssl_host_val); + char *kmc_crypto_app_uri = "crypto-service"; + char *mtls_client_cert_path = "/dev/null"; + char *mtls_client_cert_type = "PEM"; + char *mtls_client_key_path = "/dev/null"; + char *mtls_client_key_pass = "12345"; + char *mtls_ca_bundle = "/dev/null"; + char *mtls_ca_path = "/dev/null"; + char *mtls_issuer_cert = "/dev/null"; + uint8_t ignore_ssl_hostname_validation = CRYPTO_TRUE; + + status = Crypto_Config_Kmc_Crypto_Service(protocol,hostname,port,kmc_crypto_app_uri, mtls_client_cert_path,mtls_client_cert_type,mtls_client_key_path, + mtls_client_key_pass, mtls_ca_bundle,mtls_ca_path, mtls_issuer_cert, ignore_ssl_hostname_validation); ASSERT_EQ(CRYPTO_LIB_SUCCESS, status); } diff --git a/util/src_util/ut_kmc_crypto.c b/util/src_util/ut_kmc_crypto.c new file mode 100644 index 00000000..07db7f41 --- /dev/null +++ b/util/src_util/ut_kmc_crypto.c @@ -0,0 +1,364 @@ +/* Copyright (C) 2009 - 2022 National Aeronautics and Space Administration. + All Foreign Rights are Reserved to the U.S. Government. + + This software is provided "as is" without any warranty of any kind, either expressed, implied, or statutory, + including, but not limited to, any warranty that the software will conform to specifications, any implied warranties + of merchantability, fitness for a particular purpose, and freedom from infringement, and any warranty that the + documentation will conform to the program, or any warranty that the software will be error free. + + In no event shall NASA be liable for any damages, including, but not limited to direct, indirect, special or + consequential damages, arising out of, resulting from, or in any way connected with the software or its + documentation, whether or not based upon warranty, contract, tort or otherwise, and whether or not loss was sustained + from, or arose out of the results of, or use of, the software, documentation or services provided hereunder. + + ITC Team + NASA IV&V + jstar-development-team@mail.nasa.gov +*/ + +/** + * Unit Tests that make use of TC_ApplySecurity/TC_ProcessSecurity function on the data with KMC Crypto Service/MariaDB Functionality Enabled. + **/ +#include "crypto.h" +#include "crypto_error.h" +#include "sadb_routine.h" +#include "utest.h" + +#include "crypto.h" +#include "shared_util.h" +#include + +/** + * @brief Unit Test: Nominal Encryption with KMC Crypto Service && JPL Unit Test MariaDB + **/ +UTEST(KMC_CRYPTO, HAPPY_PATH_APPLY_SEC_ENC_AND_AUTH) +{ + // Setup & Initialize CryptoLib + Crypto_Config_CryptoLib(SADB_TYPE_MARIADB, CRYPTOGRAPHY_TYPE_KMCCRYPTO, CRYPTO_TC_CREATE_FECF_TRUE, TC_PROCESS_SDLS_PDUS_FALSE, TC_NO_PUS_HDR, + TC_IGNORE_SA_STATE_FALSE, TC_IGNORE_ANTI_REPLAY_TRUE, TC_UNIQUE_SA_PER_MAP_ID_FALSE, + TC_CHECK_FECF_TRUE, 0x3F); + Crypto_Config_MariaDB("sadb_user", "sadb_password", "localhost","sadb", 3306, CRYPTO_FALSE, NULL, NULL, NULL, NULL); + Crypto_Config_Kmc_Crypto_Service("https", "asec-cmdenc-srv1.jpl.nasa.gov", 8443, "crypto-service", "/home/isaleh/git/KMC/CryptoLib-IbraheemYSaleh/util/etc/local-test-cert.pem", "PEM","/home/isaleh/git/KMC/CryptoLib-IbraheemYSaleh/util/etc/local-test-key.pem",NULL,"/home/isaleh/git/KMC/CryptoLib-IbraheemYSaleh/util/etc/ammos-ca-bundle.crt", NULL, NULL, CRYPTO_FALSE); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 0, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 1, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 2, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 3, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + int32_t status = Crypto_Init(); + + char *raw_tc_jpl_mmt_scid44_vcid1= "202c0408000001bd37"; + char *raw_tc_jpl_mmt_scid44_vcid1_expect = NULL; + int raw_tc_jpl_mmt_scid44_vcid1_expect_len = 0; + + hex_conversion(raw_tc_jpl_mmt_scid44_vcid1, &raw_tc_jpl_mmt_scid44_vcid1_expect, &raw_tc_jpl_mmt_scid44_vcid1_expect_len); + + uint8_t *ptr_enc_frame = NULL; + uint16_t enc_frame_len = 0; + + ASSERT_EQ(CRYPTO_LIB_SUCCESS, status); + + printf("Frame before encryption:\n"); + for (int i=0; itc_pdu_len; i++) + { + printf("%02x ", tc_processed_frame->tc_pdu[i]); + } + printf("\n"); + + ASSERT_EQ(0x00,tc_processed_frame->tc_pdu[0]); + ASSERT_EQ( 0x01,tc_processed_frame->tc_pdu[1]); + + Crypto_Shutdown(); + free(enc_tc_jpl_mmt_scid44_vcid1_expect); + free(ptr_enc_frame); + ASSERT_EQ(CRYPTO_LIB_SUCCESS, status); +} +/** + * @brief Unit Test: Nominal Encryption with KMC Crypto Service && JPL Unit Test MariaDB + **/ +UTEST(KMC_CRYPTO, HAPPY_PATH_PROCESS_SEC_ENC_ONLY) +{ + // Setup & Initialize CryptoLib + Crypto_Config_CryptoLib(SADB_TYPE_MARIADB, CRYPTOGRAPHY_TYPE_KMCCRYPTO, CRYPTO_TC_CREATE_FECF_TRUE, TC_PROCESS_SDLS_PDUS_FALSE, TC_NO_PUS_HDR, + TC_IGNORE_SA_STATE_FALSE, TC_IGNORE_ANTI_REPLAY_TRUE, TC_UNIQUE_SA_PER_MAP_ID_FALSE, + TC_CHECK_FECF_TRUE, 0x3F); + Crypto_Config_MariaDB("sadb_user", "sadb_password", "localhost","sadb", 3306, CRYPTO_FALSE, NULL, NULL, NULL, NULL); + Crypto_Config_Kmc_Crypto_Service("https", "asec-cmdenc-srv1.jpl.nasa.gov", 8443, "crypto-service", "/home/isaleh/git/KMC/CryptoLib-IbraheemYSaleh/util/etc/local-test-cert.pem", "PEM","/home/isaleh/git/KMC/CryptoLib-IbraheemYSaleh/util/etc/local-test-key.pem",NULL,"/home/isaleh/git/KMC/CryptoLib-IbraheemYSaleh/util/etc/ammos-ca-bundle.crt", NULL, NULL, CRYPTO_FALSE); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 0, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 1, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 2, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 3, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + int32_t status = Crypto_Init(); + + char *enc_tc_jpl_mmt_scid44_vcid1= "202C0816000003000000000000000000000001669CD238"; + char *enc_tc_jpl_mmt_scid44_vcid1_expect = NULL; + int enc_tc_jpl_mmt_scid44_vcid1_expect_len = 0; + + // IV = 000000000000000000000001 + + TC_t *tc_processed_frame; + tc_processed_frame = malloc(sizeof(uint8_t) * TC_SIZE); + + hex_conversion(enc_tc_jpl_mmt_scid44_vcid1, &enc_tc_jpl_mmt_scid44_vcid1_expect, &enc_tc_jpl_mmt_scid44_vcid1_expect_len); + + uint8_t *ptr_enc_frame = NULL; + + ASSERT_EQ(CRYPTO_LIB_SUCCESS, status); + + printf("Encrypted Frame Before Processing:\n"); + for (int i=0; itc_pdu_len; i++) + for (int i=0; i<2; i++) + { + printf("%02x ", tc_processed_frame->tc_pdu[i]); + } + printf("\n"); + + // ASSERT_EQ(0x00,tc_processed_frame->tc_pdu[0]); + // ASSERT_EQ( 0x01,tc_processed_frame->tc_pdu[1]); + + Crypto_Shutdown(); + free(enc_tc_jpl_mmt_scid44_vcid1_expect); + free(ptr_enc_frame); + // ASSERT_EQ(CRYPTO_LIB_SUCCESS, status); +} +/** + * @brief Unit Test: Nominal Encryption with KMC Crypto Service && JPL Unit Test MariaDB + * This doesn't work -- Apply Security Auth Only doesn't return the proper tag. + **/ +UTEST(KMC_CRYPTO, HAPPY_PATH_PROCESS_SEC_AUTH_ONLY) +{ + // Setup & Initialize CryptoLib + Crypto_Config_CryptoLib(SADB_TYPE_MARIADB, CRYPTOGRAPHY_TYPE_KMCCRYPTO, CRYPTO_TC_CREATE_FECF_TRUE, TC_PROCESS_SDLS_PDUS_FALSE, TC_NO_PUS_HDR, + TC_IGNORE_SA_STATE_FALSE, TC_IGNORE_ANTI_REPLAY_TRUE, TC_UNIQUE_SA_PER_MAP_ID_FALSE, + TC_CHECK_FECF_TRUE, 0x3F); + Crypto_Config_MariaDB("sadb_user", "sadb_password", "localhost","sadb", 3306, CRYPTO_FALSE, NULL, NULL, NULL, NULL); + Crypto_Config_Kmc_Crypto_Service("https", "asec-cmdenc-srv1.jpl.nasa.gov", 8443, "crypto-service", "/home/isaleh/git/KMC/CryptoLib-IbraheemYSaleh/util/etc/local-test-cert.pem", "PEM","/home/isaleh/git/KMC/CryptoLib-IbraheemYSaleh/util/etc/local-test-key.pem",NULL,"/home/isaleh/git/KMC/CryptoLib-IbraheemYSaleh/util/etc/ammos-ca-bundle.crt", NULL, NULL, CRYPTO_FALSE); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 0, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 1, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 2, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x002C, 3, TC_HAS_FECF, TC_NO_SEGMENT_HDRS); + int32_t status = Crypto_Init(); + + char *enc_tc_jpl_mmt_scid44_vcid1= "202C0C26000004000000000000000000000001000100000000000000000000000000000000C4F4"; + char *enc_tc_jpl_mmt_scid44_vcid1_expect = NULL; + int enc_tc_jpl_mmt_scid44_vcid1_expect_len = 0; + + // Data=0001 + // IV=000000000000000000000001 + // AAD=00000000000000000000000000000000000000 + + + TC_t *tc_processed_frame; + tc_processed_frame = malloc(sizeof(uint8_t) * TC_SIZE); + + hex_conversion(enc_tc_jpl_mmt_scid44_vcid1, &enc_tc_jpl_mmt_scid44_vcid1_expect, &enc_tc_jpl_mmt_scid44_vcid1_expect_len); + + uint8_t *ptr_enc_frame = NULL; + + ASSERT_EQ(CRYPTO_LIB_SUCCESS, status); + + printf("Encrypted Frame Before Processing:\n"); + for (int i=0; itc_pdu_len; i++) + { + printf("%02x ", tc_processed_frame->tc_pdu[i]); + } + printf("\n"); + + // ASSERT_EQ(0x00,tc_processed_frame->tc_pdu[0]); + // ASSERT_EQ( 0x01,tc_processed_frame->tc_pdu[1]); + + Crypto_Shutdown(); + free(enc_tc_jpl_mmt_scid44_vcid1_expect); + free(ptr_enc_frame); + // ASSERT_EQ(CRYPTO_LIB_SUCCESS, status); +} + +UTEST_MAIN();