From: Dmytro Zhuravlev Date: Wed, 2 Sep 2015 12:04:21 +0000 (+0300) Subject: Add certificate verification X-Git-Tag: 1.2.0+RC1~999^2^2~10 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1204d785fd06cc3af53ff4bef96cef42c297f54b;p=platform%2Fupstream%2Fiotivity.git Add certificate verification Used to parse and check certificate by CA Change-Id: I19277c2ea633e3e79f13a7934d835cfdd0b31f8b Signed-off-by: Dmytro Zhuravlev Reviewed-on: https://gerrit.iotivity.org/gerrit/2355 Tested-by: jenkins-iotivity Reviewed-by: Sachin Agrawal --- diff --git a/resource/csdk/connectivity/inc/pkix/byte_array.h b/resource/csdk/connectivity/inc/pkix/byte_array.h new file mode 100644 index 0000000..22892cd --- /dev/null +++ b/resource/csdk/connectivity/inc/pkix/byte_array.h @@ -0,0 +1,116 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + + +#ifndef _BYTE_ARRAY_H_ +#define _BYTE_ARRAY_H_ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#include +#include +#include + +/** + * @struct ByteArray + * + * General purpose byte array structure. + * + * Contains pointer to array of bytes and it's length. + */ + +typedef struct +{ + uint8_t *data; /**< Pointer to the byte array */ + size_t len; /**< Data size */ +} ByteArray; + + +/**@def BYTE_ARRAY_INITIALIZER + * + * Initializes of existing byte array pointer to \a NULL. + */ +#undef BYTE_ARRAY_INITIALIZER +#define BYTE_ARRAY_INITIALIZER {NULL, 0} + +/**@def INIT_BYTE_ARRAY(array) + * + * Initializes of existing byte array \a array. + * + * @param array ByteArray + */ +#undef INIT_BYTE_ARRAY +#define INIT_BYTE_ARRAY(array) do{ \ + (array).data = NULL; \ + (array).len = 0; \ + }while(0) + +/**@def PRINT_BYTE_ARRAY(msg, array) + * + * Prints out byte array \a array in hex representation with message \a msg. + * + * @param msg string of characters + * @param array byte array + */ +#undef PRINT_BYTE_ARRAY +#define PRINT_BYTE_ARRAY(msg, array) do{ \ + size_t i; \ + printf("%10s", msg); \ + for( i=0; i< (array).len; i++) { \ + if( (i!=0) && ((i%16)==0) ) putchar('\n'); \ + printf("%02X ", (array).data[i]); \ + } \ + putchar('\n'); \ + }while(0) + +/**@def INC_BYTE_ARRAY_PTR(array, size) + * + * Increments byte array pointer \a array by \a size. + * + * @param array byte array pointer + * @param size number of positions + */ +#undef INC_BYTE_ARRAY_PTR +#define INC_BYTE_ARRAY_PTR(array, size) do{ \ + (array)->data += size; \ + (array)->len -= size; \ + }while(0) + +/**@def INC_BYTE_ARRAY(array, size) + * + * Increments byte array \a array by \a size. + * + * @param array byte array + * @param size number of positions + */ +#undef INC_BYTE_ARRAY +#define INC_BYTE_ARRAY(array, size) do{ \ + (array).data += size; \ + (array).len -= size; \ + }while(0) + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif // _BYTE_ARRAY_H_ diff --git a/resource/csdk/connectivity/inc/pkix/cert.h b/resource/csdk/connectivity/inc/pkix/cert.h new file mode 100644 index 0000000..03c6f7c --- /dev/null +++ b/resource/csdk/connectivity/inc/pkix/cert.h @@ -0,0 +1,78 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + +#ifndef _CERT_H_ +#define _CERT_H_ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#include "byte_array.h" +#include "pki_errors.h" + +/** + * @struct CertificateX509 + * + * Certificate structure. + * + * Structure fields contain byte arrays pointed to relative DER certificate positions. + */ +typedef struct +{ + ByteArray tbs; /**< TBS certificate.*/ + ByteArray serNum; /**< Serial number.*/ + ByteArray pubKey; /**< Public key.*/ + + ByteArray signR; /**< Signature r value.*/ + ByteArray signS; /**< Signature s value.*/ + + ByteArray issuer; /**< Issuer name.*/ + ByteArray subject; /**< Subject name.*/ + + ByteArray validFrom; /**< Start time of certificate validity. */ + ByteArray validTo; /**< End time of certificate validity. */ + +} CertificateX509; + +/** + * Reads certificate from byte array and write it into certificate structure. + * + * @param[in] code Byte array with DER encoded certificate + * @param[out] crt Pointer to certificate structure + * @return PKI_SUCCESS if successful + */ +PKIError DecodeCertificate(ByteArray code, CertificateX509 *crt); + +/** + * Parse ECDSA public key, remove ASN.1 extra bytes. + * + * @param ByteArray structure which contains public key + * @return PKI_SUCCESS if public key is correct, error code in case of invalid key + */ +PKIError ParsePublicKey(ByteArray *caPublicKey); + +#ifdef __cplusplus +} +#endif //__cplusplus + + +#endif //_CERT_H_ diff --git a/resource/csdk/connectivity/inc/pkix/crl.h b/resource/csdk/connectivity/inc/pkix/crl.h new file mode 100644 index 0000000..a3e5a32 --- /dev/null +++ b/resource/csdk/connectivity/inc/pkix/crl.h @@ -0,0 +1,78 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + + +#ifndef _CRL_H_ +#define _CRL_H_ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#include "byte_array.h" +#include "pki_errors.h" + +/// Maximal number of revoked certificates in list +#ifdef WITH_ARDUINO +#define CRL_MAX_LEN (256) +#else +#define CRL_MAX_LEN (1024) +#endif // WITH_ARDUINO +/** + * @struct CertificateList + * + * CRL structure. + * + * Structure fields contain byte arrays pointed to relative DER certificate positions. + */ +typedef struct +{ + ByteArray tbs; /**< TBS sequence of CRL.*/ + ByteArray issuer; /**< Issuer name.*/ + ByteArray date; /**< The issue-date for CRL.*/ + ByteArray signR; /**< Signature r value.*/ + ByteArray signS; /**< Signature s value.*/ +} CertificateList; + +#ifdef X509_DEBUG +/** + * Prints Certificate List to console. + * + * @param crl - pointer to certificate list structure + * @return PKI_SUCCESS if success, error code otherwise + */ +PKIError PrintCRL(const CertificateList *const crl); +#endif + +/** + * Decodes and checks Certificate List. + * + * @param code - certificate list structure in DER format + * @param crl - pointer to certificate list structure + * @param caPubKey - ByteArray structure contains CA public key + * @return PKI_SUCCESS if success, error code otherwise + */ +PKIError DecodeCertificateList(ByteArray code, CertificateList *crl, ByteArray caPubKey); + +#ifdef __cplusplus +} +#endif //__cplusplus +#endif //_CRL_H_ diff --git a/resource/csdk/connectivity/inc/pkix/crypto_adapter.h b/resource/csdk/connectivity/inc/pkix/crypto_adapter.h new file mode 100644 index 0000000..3fda0cf --- /dev/null +++ b/resource/csdk/connectivity/inc/pkix/crypto_adapter.h @@ -0,0 +1,83 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + + +#ifndef _CRYPTO_ADAPTER_H_ +#define _CRYPTO_ADAPTER_H_ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#include "ecc.h" +#include "sha2.h" + +/// Sizes for ECDSA prime256v1 elliptic curve +#define PUBLIC_KEY_SIZE (64) +#define SIGN_R_LEN (32) +#define SIGN_S_LEN (32) +#define SIGN_FULL_SIZE (64) +#define PRIVATE_KEY_SIZE (32) + +/// Length of SHA 256 hash +#define SHA_256_HASH_LEN (32) + +#define uECC_SIGN_VERIFICATION_SUCCESS (1) + +/** + * @def GET_SHA_256(tbs, sha256) + * + * A macro that compute sha-256 hash of tbs part. + * + * @param[in] tbs "to be signed" part + * @param[out] sha256 hash of tbs + */ +#undef GET_SHA_256 +#define GET_SHA_256(tbs, sha256) do{ \ + SHA256_CTX ctx256; \ + SHA256_Init(&ctx256); \ + SHA256_Update(&ctx256, tbs.data, tbs.len); \ + SHA256_Final(sha256, &ctx256); \ + }while(0) + +/**@def CHECK_SIGN(structure, caPubKey) + * Checks the sign of ASN.1 structure. + * + * @param structure ASN.1 stucture + * @param caPubKey public key of CA + */ +#undef CHECK_SIGN +#define CHECK_SIGN(structure, caPubKey) do{ \ + int err; \ + uint8_t sha256[SHA_256_HASH_LEN]; \ + uint8_t fullSignature[SIGN_FULL_SIZE]; \ + GET_SHA_256((structure).tbs, sha256); \ + memcpy(fullSignature, (structure).signR.data, SIGN_R_LEN); \ + memcpy((fullSignature + SIGN_R_LEN), (structure).signS.data, SIGN_S_LEN);\ + err = uECC_verify(caPubKey.data, sha256, fullSignature); \ + CHECK_EQUAL(err, uECC_SIGN_VERIFICATION_SUCCESS, PKI_SIG_MISMATCH); \ + }while(0) + + +#ifdef __cplusplus +} +#endif //__cplusplus +#endif //_CRYPTO_ADAPTER_H_ diff --git a/resource/csdk/connectivity/inc/pkix/der_dec.h b/resource/csdk/connectivity/inc/pkix/der_dec.h new file mode 100644 index 0000000..b26938a --- /dev/null +++ b/resource/csdk/connectivity/inc/pkix/der_dec.h @@ -0,0 +1,144 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ +#ifndef _DER_DEC_H_ +#define _DER_DEC_H_ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#include "byte_array.h" +#include "pki_errors.h" +#include "crypto_adapter.h" + +/// Maximal octet number in certificate's serial number +#define SERIAL_NUMBER_MAX_LEN (20) +/** + * @name DER constants + * These constants comply with DER encoded the ANS.1 type tags. + * DER encoding uses hexadecimal representation. + */ +#define DER_UNIVERSAL (0x00) +#define DER_SEQUENCE (0x30) +#define DER_OBJECT_IDENTIFIER (0x06) +#define DER_BIT_STRING (0x03) +#define DER_INTEGER (0x02) +#define DER_UTC_TIME (0x17) +#define DER_VERSION (0xa0) + +/* The first octet of the OCTET STRING indicates whether the key is +compressed or uncompressed. The uncompressed form is indicated by 0x04 +and the compressed form is indicated by either 0x02 or 0x03 (RFC 5480)*/ +#define ASN1_UNCOMPRESSED_KEY (0x04) +/// ASN.1 UTC time length +#define UTC_TIME_LEN (13) +/// Length Octet ASN.1 +#define LEN_LONG (128) +/// Size of byte +#define SIZE_OF_BYTE (8) + +#define ECDSA_WITH_SHA256_OID_LEN (8) +#define EC_PUBLIC_KEY_OID_LEN (7) +#define PRIME_256_V1_OID_LEN (8) + +/**@def SKIP_DER_FIELD(array, type, length) + * Skips the field in the ASN.1 structure. + * + * @param array pointer to ASN.1 stucture + * @param type type of ASN.1 field + * @param length length of ASN.1 field + */ +#undef SKIP_DER_FIELD +#define SKIP_DER_FIELD(array, type, length) do{ \ + CHECK_EQUAL(*((array).data), type, PKI_INVALID_FORMAT); \ + CHECK_CALL(DecodeLength , &(array), &(length)); \ + INC_BYTE_ARRAY(array, length); \ + }while(0) + +/**@def COPY_DER_FIELD(array, str, field, type, length) + * Copies the field from the ASN.1 structure. + * + * @param array pointer to ASN.1 stucture + * @param str structure in which the array is copied + * @param field field of the structure in which the array is copied + * @param type type of ASN.1 field + * @param length length of ASN.1 field + */ +#undef COPY_DER_FIELD +#define COPY_DER_FIELD(array, crt, field, type, length) do{ \ + CHECK_EQUAL(*((array).data), type, PKI_INVALID_FORMAT); \ + CHECK_CALL(DecodeLength , &(array), &(length)); \ + ((crt)->field).data = (array).data; \ + ((crt)->field).len = length; \ + INC_BYTE_ARRAY(array, length); \ + }while(0) + + +/**@def CHECK_DER_OID(array, oid, length) + * Checks the field from the ASN.1 structure. + * + * @param array pointer to ASN.1 stucture + * @param oid type of DER object + * @param oidLen length of DER array + * @param length length of ASN.1 field + */ +#undef CHECK_DER_OID +#undef CHECK_DER_OID +#define CHECK_DER_OID(array, oid, oidLen, length) do{ \ + int ret = 0; \ + CHECK_EQUAL(*((array).data), DER_OBJECT_IDENTIFIER, PKI_INVALID_FORMAT); \ + CHECK_CALL(DecodeLength , &(array), &(length)); \ + CHECK_EQUAL(length, oidLen, PKI_UNKNOWN_OID); \ + ret = memcmp ((array).data, oid, oidLen); \ + CHECK_EQUAL(ret, 0, PKI_UNKNOWN_OID); \ + }while(0) + +/**@def PARSE_SIGNATURE(structure) + * Parse signature of ASN.1 structure , remove ASN.1 extra bytes. + * + * @param structure Certificate or CertificateList structure + */ +#undef PARSE_SIGNATURE +#define PARSE_SIGNATURE(structure) do{ \ + if (((structure)->signR.len == SIGN_R_LEN + 1) && ((structure)->signR.data[0] == 0)) \ + INC_BYTE_ARRAY((structure)->signR, 1); \ + else if ((structure)->signR.len != SIGN_R_LEN) \ + CHECK_NULL(NULL, PKI_WRONG_ARRAY_LEN); \ + if (((structure)->signS.len == SIGN_S_LEN + 1) && ((structure)->signS.data[0] == 0)) \ + INC_BYTE_ARRAY((structure)->signS, 1); \ + else if ((structure)->signS.len != SIGN_S_LEN) \ + CHECK_NULL(NULL, PKI_WRONG_ARRAY_LEN); \ + }while(0) + +/** + * Computes length of ASN.1 object in DER format. + * + * @param[in] code array with DER encoded ASN.1 structure + * @return PKI_SUCCESS if success, error code otherwise + */ +PKIError DecodeLength(ByteArray *code, size_t *length); + +#ifdef __cplusplus +} +#endif //__cplusplus + + +#endif //_X509_PARSE_H_ diff --git a/resource/csdk/connectivity/inc/pkix/pki.h b/resource/csdk/connectivity/inc/pkix/pki.h new file mode 100644 index 0000000..23c6f50 --- /dev/null +++ b/resource/csdk/connectivity/inc/pkix/pki.h @@ -0,0 +1,102 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + + +#ifndef _PKI_H_ +#define _PKI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "byte_array.h" +#include "pki_errors.h" +#include "crypto_adapter.h" +#include "cert.h" + +/** + * Maximal lengths of certificate chain. + */ +#define MAX_CHAIN_LEN (3) + +#ifdef X509_DEBUG +/** + * Prints Certificate to console. + * + * @param crt - pointer to Certificate structure + * @return PKI_SUCCESS if success, error code otherwise + */ +PKIError PrintCertificate(const CertificateX509 *const crt); +#endif + +/** + * Checks certificate validity period. + * + * @param dateFrom - array with not before field + * @param dateTo - array with not after field + * @return PKI_SUCCESS if valid, error code otherwise + */ +PKIError CheckValidity(ByteArray dateFrom, ByteArray dateTo); + +/** + * Checks certificate date and sign. + * + * @param[in] certDerCode - Byte array with DER encoded certificate + * @param[in] caPublicKey - CA public key + * @return 0 if successful + */ +PKIError CheckCertificate(ByteArray certDerCode, ByteArray caPublicKey); + +/** + * Parses each certificates from list. + * + * @param[in] chainDerCode Array of DER encoded certificates + * @param[out] chainCrt Array of parsed certificates + * @param[in] chainLen Lengths of array + * @returns PKI_SUCCESS if no error is occurred + */ +PKIError ParseCertificateChain (ByteArray *chainDerCode, CertificateX509 *chainCrt, + uint8_t chainLen); + +/** + * Loads certificates in DER format from TLS message to array. + * + * @param[in] msg TLS message with certificate's chain + * @param[out] chain Array of DER encoded certificates + * @param[out] chainLen Lengths of array + * @returns PKI_SUCCESS if no error is occurred + */ +PKIError LoadCertificateChain (ByteArray msg, ByteArray *chain, uint8_t *chainLength); + +/** + * Checks the signature of each certificate in chain. + * + * @param[in] chainCrt Chain of certificates structures + * @param[in] chainLen Number of certificates in the chain + * @param[in] caPubKey Public key which sign the last certificate from chain + * @returns PKI_SUCCESS if no error is occurred + */ +PKIError CheckCertificateChain (CertificateX509 *chainCrt, uint8_t chainLen, ByteArray caPubKey); + +#ifdef __cplusplus +} +#endif //__cplusplus +#endif // _PKI_H_ diff --git a/resource/csdk/connectivity/inc/pkix/pki_errors.h b/resource/csdk/connectivity/inc/pkix/pki_errors.h new file mode 100644 index 0000000..0d7477f --- /dev/null +++ b/resource/csdk/connectivity/inc/pkix/pki_errors.h @@ -0,0 +1,320 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + + +#ifndef _PKI_ERRORS_H_ +#define _PKI_ERRORS_H_ + + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#ifdef X509_DEBUG +#warning "DEBUG is enabled" +#include // +#endif + +/** + * @enum PKIError + * + * The enumeration of error codes. + */ + +typedef enum +{ + PKI_SUCCESS = 0, /**< No error occurred. */ + PKI_UNKNOWN_ERROR, /**< Unknown error occurred. */ + PKI_NULL_PASSED, /**< NULL passed to function. */ + PKI_CERT_DATE_INVALID, /**< Certificate date expired. */ + PKI_BUFFER_OVERFLOW, /**< Array out of range. */ + PKI_WRONG_OCTET_LEN, /**< Wrong length of octet. */ + PKI_UNKNOWN_OID, /**< Requested OID is unknown. */ + PKI_INVALID_FORMAT, /**< The CRT/CRL/CSR format is invalid. */ + PKI_INVALID_DATE_FORMAT, /**< The date tag or value is invalid. */ + PKI_INVALID_SIGNATURE, /**< The signature tag or value invalid. */ + PKI_SIG_MISMATCH, /**< Signature algorithms do not match. */ + PKI_CERT_VERIFY_FAILED, /**< Certificate verification failed*/ + PKI_CERT_REVOKED, /**< Certificate is revoked. */ + PKI_WRONG_ARRAY_LEN, /**< Wrong length of input array*/ + PKI_MEMORY_ALLOC_FAILED, /**< Failed to allocate memory */ + PKI_BASE64_ERROR, /**< Base64 convertion error occurred. */ + PKI_JSON_ERROR, /**< JSON convertion error occurred. */ + PKI_JSON_NOT_FOUND, /**< JSON object not found. */ + + ISSUER_CA_STORAGE_FILE_READ_ERROR, /**< File read error in CA storage */ + ISSUER_CA_STORAGE_FILE_WRITE_ERROR, /**< File write error in CA storage */ + ISSUER_CA_STORAGE_CRL_READ_ERROR, /**< CRL file read error in CA storage */ + ISSUER_CA_STORAGE_CRL_WRITE_ERROR, /**< CRL file write error in CA storage */ + ISSUER_CA_STORAGE_CRT_READ_ERROR, /**< Certificate file read error in CA storage */ + ISSUER_CA_STORAGE_CRT_WRITE_ERROR, /**< Certificate file write error in CA storage */ + ISSUER_CA_STORAGE_MEMORY_ALLOC_FAILED, /**< Failed to allocate memory in CA storage */ + ISSUER_CA_STORAGE_WRONG_SERIAL_NUMBER, /**< Wrong serial number passed to CA storage */ + ISSUER_CA_STORAGE_SN_UNDEFINED, /**< Serial number is not defined in CA storage */ + ISSUER_CA_STORAGE_WRONG_CRL_SERIAL_NUMBER, /**< Wrong CRL serial number passed to CA + storage */ + ISSUER_CA_STORAGE_CRL_SN_UNDEFINED, /**< CRL serial number is not defined in CA + storage */ + ISSUER_CA_STORAGE_WRONG_PRIVATE_KEY_LEN, /**< Passed private key length not equal to + PRIVATE_KEY_SIZE*/ + ISSUER_CA_STORAGE_PRIVATE_KEY_UNDEFINED, /**< CA private key is not defined in CA storage */ + ISSUER_CA_STORAGE_WRONG_PUBLIC_KEY_LEN, /**< Passed public key length not equal to + PUBLIC_KEY_SIZE*/ + ISSUER_CA_STORAGE_PUBLIC_KEY_UNDEFINED, /**< CA public key is not defined in CA storage */ + ISSUER_CA_STORAGE_CA_CHAIN_LENGTH_UNDEFINED,/**< CA certificate chain length is not defined in + CA storage */ + ISSUER_CA_STORAGE_WRONG_CA_NAME_LEN, /**< CA name length is bigger than + ISSUER_MAX_NAME_SIZE */ + ISSUER_CA_STORAGE_CA_NAME_UNDEFINED, /**< CA name is not defined in CA storage */ + ISSUER_CA_STORAGE_CRL_UNDEFINED, /**< CRL is not defined in CA storage */ + ISSUER_CA_STORAGE_NULL_PASSED, /**< NULL passed to function in CA storage */ + CKM_INFO_IS_NOT_INIT, /**< CKM info storage was not init */ + ISSUER_CA_STORAGE_WRONG_BYTE_ARRAY_LEN, /**< ByteArray with wrong lenth passed into + CA storage */ + + ISSUER_MAKE_KEY_ERROR, /**< Error during uECC_make_key() */ + ISSUER_MEMORY_ALLOC_FAILED, /**< Failed to allocate memory in issuer */ + ISSUER_FILE_WRITE_ERROR, /**< File write error in issuer */ + ISSUER_WRONG_SERIAL_NUMBER, /**< Wrong serial number passed to issuer */ + ISSUER_WRONG_ROOT_NAME_LEN, /**< CA name length is bigger than ISSUER_MAX_NAME_SIZE */ + ISSUER_NULL_PASSED, /**< NULL passed to function in issuer */ + ISSUER_WRONG_BYTE_ARRAY_LEN,/**< ByteArray with wrong length passed into issuer */ + + ISSUER_CRL_ENCODER_MEMORY_ALLOC_FAILED, /**< Failed to allocate memory in CRL encoder */ + ISSUER_CRL_ENCODER_DER_ENCODE_FAIL, /**< Failed to encode structure into DER + in CRL encoder */ + ISSUER_CRL_ENCODER_SIGNATURE_FAIL, /**< Failed to sign TBS in CRL encoder */ + ISSUER_CRL_NULL_PASSED, /**< NULL passed to function in CRL encoder */ + ISSUER_CRL_WRONG_BYTE_ARRAY_LEN, /**< ByteArray with wrong length passed into + CRL encoder */ + + ISSUER_CSR_MEMORY_ALLOC_FAILED, /**< Failed to allocate memory in CSR unit */ + ISSUER_CSR_DER_ENCODE_FAIL, /**< Failed to encode structure into DER in CSR unit */ + ISSUER_CSR_SIGNATURE_FAIL, /**< Failed to sign TBS in CSR unit */ + ISSUER_CSR_DER_DECODE_FAIL, /**< Failed to decode structure from DER in CSR unit */ + ISSUER_CSR_INVALID_SIGNATURE, /**< Signature check fail in CSR unit. */ + ISSUER_CSR_TOO_LONG_NAME, /**< CSR subject name length is bigger than CSR_MAX_NAME_SIZE */ + ISSUER_CSR_INVALID_KEY_FORMAT, /**< Public key format is invalid in CSR unit. */ + ISSUER_CSR_NULL_PASSED, /**< NULL passed to function in CSR unit */ + ISSUER_CSR_WRONG_BYTE_ARRAY_LEN,/**< ByteArray with wrong length passed into CSR unit */ + + ISSUER_X509_MEMORY_ALLOC_FAILED, /**< Failed to allocate memory in X.509 encoder */ + ISSUER_X509_DER_ENCODE_FAIL, /**< Failed to encode structure into DER in X.509 encoder */ + ISSUER_X509_SIGNATURE_FAIL, /**< Failed to sign TBS in X.509 encoder */ + ISSUER_X509_NULL_PASSED, /**< NULL passed to function in X.509 encoder */ + ISSUER_X509_WRONG_BYTE_ARRAY_LEN /**< ByteArray with wrong length passed into X.509 encoder */ +} PKIError; + + +/** @def CHECK_PRINT(err_code, ...) + * + * Prints debug information \a err_code and __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__ values. + * + * @param[in] err_code Error code +*/ +#ifdef X509_DEBUG +#define CHECK_PRINT(err_code) \ +fprintf(stderr, "%s() in %s, line %i: %d\n",__func__, __FILE__, __LINE__, err_code); +#else +# define CHECK_PRINT(...) +#endif + +/** + * @def CHECK_NULL(param, error) + * A macro that checks whether \a param is not NULL. + * + * If \a (param = NULL) it goes to error processing with \a error code. + * + * @param[in] param Parameter to check + * @param[in] error Error code + */ +#define CHECK_NULL(param, error) do { \ + if (!(param)) { \ + error_value = error; \ + CHECK_PRINT(error); \ + goto ERROR_PROC; \ + } } while(0) + +/** @def CHECK_EQUAL(param, checker, err_code) + * + * A macro that checks whether \a param equal to \a checker. + * + * If \a (param != checker) it goes to error processing with \a err_code error code. + * + * @param[in] param Parameter to check + * @param[in] error Error code + */ +#define CHECK_EQUAL(param, checker, err_code) do { \ + if ((param) != (checker)) { \ + error_value = err_code; \ + CHECK_PRINT(err_code); \ + goto ERROR_PROC; \ + } } while(0) + +/** @def CHECK_NOT_EQUAL(param, checker, err_code) + * A macro that checks whether \a param not equal to \a checker. + * + * If \a (param == checker) it goes to error processing with \a err_code error code. + * + * @param[in] param Parameter to check + * @param[in] error Error code + */ +#define CHECK_NOT_EQUAL(param, checker, err_code) do { \ + if ((param) == (checker)) { \ + error_value = err_code; \ + CHECK_PRINT(err_code); \ + goto ERROR_PROC; \ + } } while(0) + +/** @def CHECK_LESS(param, checker, err_code) + * A macro that checks whether \a param less then \a checker. + * + * If \a (param > checker) it goes to error processing with \a err_code error code. + * + * @param[in] param Parameter to check + * @param[in] error error code + */ +#define CHECK_LESS(param, checker, err_code) do { \ + if ((param) >= (checker)) { \ + error_value = err_code; \ + CHECK_PRINT(err_code); \ + goto ERROR_PROC; \ + } } while(0) + +/** @def CHECK_COND(param, err_code) + * + * A macro that checks whether condition \a param is true. + * + * If \a (param != true) it goes to error processing with \a err_code error code. + * + * @param[in] param Parameter to check + * @param[in] error error code + */ +#define CHECK_COND(param, err_code) do { \ + if (!(param)) { \ + error_value = err_code; \ + CHECK_PRINT(err_code); \ + goto ERROR_PROC; \ + } } while(0) + +/** @def CHECK_LESS_EQUAL(param, checker, err_code) +* +* A macro that checks whether \a param <= \a checker. +* +* If \a (param < checker) it goes to error processing with \a err_code error code. +* +* @param[in] param Parameter to check +* @param[in] error error code +*/ +#define CHECK_LESS_EQUAL(param, checker, err_code) do { \ + if ((param) > (checker)) { \ + error_value = err_code; \ + CHECK_PRINT(err_code); \ + goto ERROR_PROC; \ + } } while(0) + +/** @def CHECK_NULL_BYTE_ARRAY_PTR(param, err_code) + * + * A macro that checks whether pointer to ByteArray \a param is not NULL and contains a valid pointer. + * + * If \a (param != checker) it goes to error processing with \a err_code error code. + * + * @param[in] param Parameter to check + * @param[in] err_code Error code + */ +#define CHECK_NULL_BYTE_ARRAY_PTR(param, err_code) do { \ + CHECK_NULL(param, err_code); \ + CHECK_NULL((param)->data, err_code); \ + CHECK_NULL((param)->len, err_code); \ + } while(0) + +/** @def FUNCTION_INIT(...) + * A macro for initializations function variables. + * + * If error occurs it goes to error processing. + */ +#define FUNCTION_INIT(...) \ + PKIError error_value = PKI_UNKNOWN_ERROR; \ + __VA_ARGS__; + +/** @def FUNCTION_CLEAR(...) + * + * A macro for freeing function variables. + * + * @return 0 if successful + */ +#define FUNCTION_CLEAR(...) \ + error_value = PKI_SUCCESS; \ + ERROR_PROC: \ + __VA_ARGS__ \ + return error_value; + +/** @def CHECK_CALL(fn, ...) + * A macro that checks \a fn function return code + * + * If function return error code it goes to error processing. + * + * @param[in] fn Function to call + */ +#define CHECK_CALL(fn, ...) do { \ + error_value = fn(__VA_ARGS__); \ + if ((int)error_value != (int)PKI_SUCCESS) { \ + CHECK_PRINT(error_value); \ + goto ERROR_PROC; \ + } } while(0) + +/** @def CHECK_INC_BYTE_ARRAY_PTR(array, size) + * + * Increments byte array pointer \a array by \a size with bound checking. + * + * @param array byte array pointer + * @param size number of positions + */ +#undef CHECK_INC_BYTE_ARRAY_PTR +#define CHECK_INC_BYTE_ARRAY_PTR(array, size) do{ \ + if (size > ((array)->len)){ \ + error_value = PKI_BUFFER_OVERFLOW; \ + CHECK_PRINT(error_value); \ + goto ERROR_PROC; } \ + INC_BYTE_ARRAY_PTR(array, size); \ + }while(0) + +/** @def CHECK_INC_BYTE_ARRAY(array, size) + * + * Increments byte array \a array by \a size with bound checking. + * + * @param array byte array pointer + * @param size number of positions + */ +#undef CHECK_INC_BYTE_ARRAY +#define CHECK_INC_BYTE_ARRAY(array, size) do{ \ + if (size > ((array).len)) { \ + error_value = PKI_BUFFER_OVERFLOW; \ + CHECK_PRINT(error_value); \ + goto ERROR_PROC; } \ + INC_BYTE_ARRAY(array, size); \ + }while(0) + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif // _PKI_ERRORS_H_ diff --git a/resource/csdk/connectivity/inc/pkix/sn_store.h b/resource/csdk/connectivity/inc/pkix/sn_store.h new file mode 100644 index 0000000..50d8ff2 --- /dev/null +++ b/resource/csdk/connectivity/inc/pkix/sn_store.h @@ -0,0 +1,67 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ +#ifndef _SN_STORE_H_ +#define _SN_STORE_H_ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#include "pki_errors.h" +#include "byte_array.h" + + +/** + * Stores serial number to SN storage. + * + * @param[in] serNum certificate serial number to be stored + * @return PKI_SUCCESS if success, error code otherwise + */ +PKIError StoreSerialNumber(const ByteArray serNum); + +/** + * Check whether there is \a serNum in SN storage. + * + * @param[in] serNum certificate serial number to be stored + * @return PKI_SUCCESS if \a not belongs SN storage, error code otherwise + */ +PKIError CheckSerialNumber(const ByteArray serNum); + + +#ifdef X509_DEBUG +/** + * Prints all serial numbers from SN storage. + */ +void PrintSNStore(void); +#endif + + +/** + * Frees memory occupied by SN storage. + */ +void FreeSNStore(void); + + +#ifdef __cplusplus +} +#endif //__cplusplus +#endif //_SN_STORE_H_ + diff --git a/resource/csdk/connectivity/src/adapter_util/pkix/cert.c b/resource/csdk/connectivity/src/adapter_util/pkix/cert.c new file mode 100644 index 0000000..4a02949 --- /dev/null +++ b/resource/csdk/connectivity/src/adapter_util/pkix/cert.c @@ -0,0 +1,171 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + + +#include "byte_array.h" +#include "cert.h" +#include "der_dec.h" + + +extern const uint8_t g_ECDSA_WITH_SHA256_OID[]; +extern const uint8_t g_EC_PUBLIC_KEY_OID[]; +extern const uint8_t g_PRIME_256_V1_OID[]; + +/** + * Decodes TBSCertificate. + */ +static PKIError DecodeTbs(CertificateX509 *const crt) +{ + FUNCTION_INIT( + size_t length, temp_len; + ByteArray tbs = crt->tbs, temp; + CHECK_NULL(crt, PKI_NULL_PASSED); + ); + //skip version + SKIP_DER_FIELD(tbs, DER_VERSION, length); + //serial number + COPY_DER_FIELD(tbs, crt, serNum, DER_INTEGER, length); + + CHECK_EQUAL(*(tbs.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &tbs, &length); + //copy to temp + temp = tbs; // OPTIONAL + INC_BYTE_ARRAY(tbs, length); // skip algorithm identifier + //check_signature_algorithm + //1.2.840.10045.4.3.2 + CHECK_DER_OID(temp, g_ECDSA_WITH_SHA256_OID, ECDSA_WITH_SHA256_OID_LEN, temp_len); + //copy issuer X.500 name + COPY_DER_FIELD(tbs, crt, issuer, DER_SEQUENCE, length); + CHECK_EQUAL(*(tbs.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &tbs, &length); + + //copy valid period + COPY_DER_FIELD(tbs, crt, validFrom, DER_UTC_TIME, length); + COPY_DER_FIELD(tbs, crt, validTo, DER_UTC_TIME, length); + + //copy subject X.500 name + COPY_DER_FIELD(tbs, crt, subject, DER_SEQUENCE, length); + //public key + CHECK_EQUAL(*(tbs.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &tbs, &length); + CHECK_EQUAL(*(tbs.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &tbs, &length); + //check public key type + //1.2.840.10045.2.1 + CHECK_DER_OID(tbs, g_EC_PUBLIC_KEY_OID, EC_PUBLIC_KEY_OID_LEN, length); + INC_BYTE_ARRAY(tbs, length); + //check curve + //1.2.840.10045.3.1.7 + CHECK_DER_OID(tbs, g_PRIME_256_V1_OID, PRIME_256_V1_OID_LEN, length); + INC_BYTE_ARRAY(tbs, length); + //copy public key + COPY_DER_FIELD(tbs, crt, pubKey, DER_BIT_STRING, length); + FUNCTION_CLEAR(); +} + + +/** + * Decodes certificate in DER format. + */ +PKIError DecodeCertificate(ByteArray code, CertificateX509 *crt) +{ + FUNCTION_INIT( + size_t length, tempLen; + ByteArray temp; + CHECK_NULL(crt, PKI_NULL_PASSED); + CHECK_NULL(code.data, PKI_NULL_PASSED); + ); + CHECK_EQUAL(*(code.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &code, &length); + //store sequence position + temp = code; + //TODO check length of TBS + //copy tbs + COPY_DER_FIELD(code, crt, tbs, DER_SEQUENCE, length); + //decode tbs + CHECK_CALL(DecodeTbs, crt); + //include sequense and len to tbs + crt->tbs.len += crt->tbs.data - temp.data; + crt->tbs.data = temp.data; + //printf("DATA %02X\n", *(code.data)); + CHECK_EQUAL(*(code.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &code, &length); + //copy to temp + temp = code; + INC_BYTE_ARRAY(code, length); // skip algorithm identifier + //check_signature_algorithm + //1.2.840.10045.4.3.2 + CHECK_DER_OID(temp, g_ECDSA_WITH_SHA256_OID, ECDSA_WITH_SHA256_OID_LEN, tempLen); + //decode_signature_value + CHECK_EQUAL(*(code.data), DER_BIT_STRING, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &code, &length); + //skip DER_UNIVERSAL + CHECK_EQUAL(*(code.data), DER_UNIVERSAL, PKI_INVALID_FORMAT); + CHECK_INC_BYTE_ARRAY(code, 1); + CHECK_EQUAL(*(code.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &code, &length); + //copy sign r value + COPY_DER_FIELD(code, crt, signR, DER_INTEGER, length); + //copy sign s value + COPY_DER_FIELD(code, crt, signS, DER_INTEGER, length); + + PARSE_SIGNATURE(crt); + + FUNCTION_CLEAR(); +} + +#ifdef X509_DEBUG +/** + * Prints certificate to console. + */ +PKIError PrintCertificate(const CertificateX509 *const crt) +{ + FUNCTION_INIT( + CHECK_NULL(crt, PKI_NULL_PASSED); + ); + printf("\n-----BEGIN CERTIFICATE-----\n"); + PRINT_BYTE_ARRAY("SER NUM:\n", crt->serNum); + PRINT_BYTE_ARRAY("ISSUER:\n", crt->issuer); + PRINT_BYTE_ARRAY("SUBJECT:\n", crt->subject); + PRINT_BYTE_ARRAY("PUB KEY:\n", crt->pubKey); + PRINT_BYTE_ARRAY("SIGN R VALUE:\n", crt->signR); + PRINT_BYTE_ARRAY("SIGN S VALUE:\n", crt->signS); + PRINT_BYTE_ARRAY("TBS:\n", crt->tbs); + printf("-----END CERTIFICATE-----\n"); + FUNCTION_CLEAR( + ); +} +#endif + +PKIError ParsePublicKey(ByteArray *caPublicKey) +{ + FUNCTION_INIT( + CHECK_NULL(caPublicKey, PKI_NULL_PASSED); + ); + + if ((caPublicKey->len == PUBLIC_KEY_SIZE + 2) && (caPublicKey->data[0] == 0) + && (caPublicKey->data[1] == ASN1_UNCOMPRESSED_KEY)) + INC_BYTE_ARRAY(*caPublicKey, 2); + else if (caPublicKey->len != PUBLIC_KEY_SIZE) + CHECK_NULL(NULL, PKI_WRONG_ARRAY_LEN); + + FUNCTION_CLEAR(); +} diff --git a/resource/csdk/connectivity/src/adapter_util/pkix/crl.c b/resource/csdk/connectivity/src/adapter_util/pkix/crl.c new file mode 100644 index 0000000..91a7608 --- /dev/null +++ b/resource/csdk/connectivity/src/adapter_util/pkix/crl.c @@ -0,0 +1,170 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + + +#include "crl.h" +#include "byte_array.h" +#include "der_dec.h" +#include "sn_store.h" +#include "der_dec.h" +#include "crypto_adapter.h" + + +extern const uint8_t g_ECDSA_WITH_SHA256_OID[ECDSA_WITH_SHA256_OID_LEN]; +extern const uint8_t g_EC_PUBLIC_KEY_OID[EC_PUBLIC_KEY_OID_LEN]; +extern const uint8_t g_PRIME_256_V1_OID[PRIME_256_V1_OID_LEN]; + +/* + * TBSCertList ::= SEQUENCE { + * version Version OPTIONAL, + * -- if present, MUST be v2 + * signature AlgorithmIdentifier, + * issuer Name, + * thisUpdate Time, + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time + * } OPTIONAL, + * } +*/ + + +/** + * Decodes TBS of CRL. + */ +static PKIError DecodeTbs(CertificateList *const crl) +{ + FUNCTION_INIT( + size_t length; + ByteArray tbs = crl->tbs, temp; + CHECK_NULL(crl, PKI_NULL_PASSED); + ByteArray sn = BYTE_ARRAY_INITIALIZER; + FreeSNStore(); + ); + + CHECK_EQUAL(*(tbs.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &tbs, &length); + + INC_BYTE_ARRAY(tbs, length); // skip algorithm identifier + //1.2.840.10045.4.3.2 + //copy issuer X.500 name + COPY_DER_FIELD(tbs, crl, issuer, DER_SEQUENCE, length); + //copy date + COPY_DER_FIELD(tbs, crl, date, DER_UTC_TIME, length); + //COPY_DER_FIELD(tbs, crl, date, DER_UTC_TIME, length); // optional + // copy serial numbers + CHECK_EQUAL(*(tbs.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &tbs, &length); + temp.data = tbs.data; + temp.len = length; + while (tbs.data < temp.data + temp.len) + { + CHECK_EQUAL(*(tbs.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &tbs, &length); + //serial number + CHECK_EQUAL(*(tbs.data), DER_INTEGER, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &tbs, &length); + sn.data = tbs.data; + sn.len = length; + CHECK_CALL(StoreSerialNumber, sn); + INC_BYTE_ARRAY(tbs, length); + SKIP_DER_FIELD(tbs, DER_UTC_TIME, length); + } + FUNCTION_CLEAR(); +} + +/* + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } +*/ + +/** + * Decodes certificate in DER format. + */ +PKIError DecodeCertificateList(ByteArray code, CertificateList *crl, ByteArray caPubKey) +{ + FUNCTION_INIT( + size_t length, tempLen; + ByteArray temp; + CHECK_NULL(crl, PKI_NULL_PASSED); + CHECK_NULL(code.data, PKI_NULL_PASSED); + ); + CHECK_EQUAL(*(code.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &code, &length); + //store sequence position + temp = code; + //TODO check length of TBS + //copy tbs + COPY_DER_FIELD(code, crl, tbs, DER_SEQUENCE, length); + //decode tbs + CHECK_CALL(DecodeTbs, crl); //TODO + //include sequense and len to tbs + crl->tbs.len += crl->tbs.data - temp.data; + crl->tbs.data = temp.data; + + CHECK_EQUAL(*(code.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &code, &length); + //copy to temp + temp = code; + INC_BYTE_ARRAY(code, length); // skip algorithm identifier + //check_signature_algorithm + //1.2.840.10045.4.3.2 + CHECK_DER_OID(temp, g_ECDSA_WITH_SHA256_OID, ECDSA_WITH_SHA256_OID_LEN, tempLen); + //decode_signature_value + CHECK_EQUAL(*(code.data), DER_BIT_STRING, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &code, &length); + //skip DER_UNIVERSAL + CHECK_EQUAL(*(code.data), DER_UNIVERSAL, PKI_INVALID_FORMAT); + CHECK_INC_BYTE_ARRAY(code, 1); + CHECK_EQUAL(*(code.data), DER_SEQUENCE, PKI_INVALID_FORMAT); + CHECK_CALL(DecodeLength , &code, &length); + //copy sign r value + COPY_DER_FIELD(code, crl, signR, DER_INTEGER, length); + //copy sign s value + COPY_DER_FIELD(code, crl, signS, DER_INTEGER, length); + if (caPubKey.data != NULL) + { + PARSE_SIGNATURE(crl); + CHECK_SIGN(*crl, caPubKey); + } + FUNCTION_CLEAR(); +} + +#ifdef X509_DEBUG +/** + * Prints CRL to console. + */ +PKIError PrintCRL(const CertificateList *const crl) +{ + FUNCTION_INIT( + CHECK_NULL(crl, PKI_NULL_PASSED); + ); + printf("\n-----BEGIN CRL-----\n"); + PRINT_BYTE_ARRAY("ISSUER:\n", crl->issuer); + PRINT_BYTE_ARRAY("DATE:\n", crl->date); + PRINT_BYTE_ARRAY("TBS:\n", crl->tbs); + printf("-----END CRL-----\n"); + FUNCTION_CLEAR( + ); +} +#endif diff --git a/resource/csdk/connectivity/src/adapter_util/pkix/der_const.c b/resource/csdk/connectivity/src/adapter_util/pkix/der_const.c new file mode 100644 index 0000000..b342918 --- /dev/null +++ b/resource/csdk/connectivity/src/adapter_util/pkix/der_const.c @@ -0,0 +1,27 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ +#include "stdint.h" + +const uint8_t g_ECDSA_WITH_SHA256_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02}; +const uint8_t g_EC_PUBLIC_KEY_OID[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01}; +const uint8_t g_PRIME_256_V1_OID[] = {0x2A, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; + + diff --git a/resource/csdk/connectivity/src/adapter_util/pkix/der_dec.c b/resource/csdk/connectivity/src/adapter_util/pkix/der_dec.c new file mode 100644 index 0000000..a1c5bba --- /dev/null +++ b/resource/csdk/connectivity/src/adapter_util/pkix/der_dec.c @@ -0,0 +1,57 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + +#include "der_dec.h" + +/** + * Computes length. + */ +PKIError DecodeLength(ByteArray *code, size_t *length) +{ + FUNCTION_INIT( + CHECK_NULL_BYTE_ARRAY_PTR(code, PKI_NULL_PASSED); + ); + CHECK_INC_BYTE_ARRAY_PTR(code, 1); + + if ((*(code->data)) < LEN_LONG) + { + *length = *(code->data); + CHECK_INC_BYTE_ARRAY_PTR(code, 1); + } + else + { + uint8_t i = 0; + uint8_t blocksNum = *(code->data) - LEN_LONG; + CHECK_INC_BYTE_ARRAY_PTR(code, 1); + CHECK_LESS(blocksNum, 5, PKI_WRONG_OCTET_LEN); + *length = 0; + + for (i = 0; i < blocksNum; ++i) + { + *length |= *(code->data) << ((blocksNum - i - 1) * SIZE_OF_BYTE); + CHECK_INC_BYTE_ARRAY_PTR(code, 1); + } + } + + //should be: length <= array size + CHECK_LESS_EQUAL(*length, code->len, PKI_WRONG_OCTET_LEN); + FUNCTION_CLEAR(); +} diff --git a/resource/csdk/connectivity/src/adapter_util/pkix/pki.c b/resource/csdk/connectivity/src/adapter_util/pkix/pki.c new file mode 100644 index 0000000..8d32cc9 --- /dev/null +++ b/resource/csdk/connectivity/src/adapter_util/pkix/pki.c @@ -0,0 +1,225 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ +#include "pki.h" +#include "cert.h" +#include "sn_store.h" +#include "der_dec.h" +#include "crypto_adapter.h" + +#ifndef WITH_ARDUINO +#include +#endif + + +/** + * Check: notBefore <= now <= notAfter. + */ +PKIError CheckValidity(ByteArray dateFrom, ByteArray dateTo) +{ + FUNCTION_INIT( + struct tm t = {0}; + struct tm lnow = {0}; + time_t now; + int i; + ByteArray date; + CHECK_EQUAL(dateFrom.len, UTC_TIME_LEN, PKI_INVALID_DATE_FORMAT); + CHECK_EQUAL(dateTo.len, UTC_TIME_LEN, PKI_INVALID_DATE_FORMAT); + ); + /* Get the current time */ + now = time(NULL); + gmtime_r( &now, &lnow); + for (i = 0; i < 2; i ++) + { + date = (i == 0 ? dateFrom : dateTo); + t.tm_year = (date.data[0] - '0') * 10 + date.data[1] - '0'; + /* It is considered date from 1950 to 2050 */ + if (t.tm_year < 50) + { + t.tm_year += 100; + } + t.tm_mon = (date.data[2] - '0') * 10 + date.data[3] - '0' - 1; + t.tm_mday = (date.data[4] - '0') * 10 + date.data[5] - '0'; + t.tm_hour = (date.data[6] - '0') * 10 + date.data[7] - '0'; + t.tm_min = (date.data[8] - '0') * 10 + date.data[9] - '0'; + t.tm_sec = (date.data[10] - '0') * 10 + date.data[11] - '0'; + if (i == 0) + { + CHECK_LESS_EQUAL(t.tm_year, lnow.tm_year, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year) + CHECK_LESS_EQUAL(t.tm_mon, lnow.tm_mon, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year && t.tm_mon == lnow.tm_mon) + CHECK_LESS_EQUAL(t.tm_mday, lnow.tm_mday, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year && t.tm_mon == lnow.tm_mon && t.tm_mday == lnow.tm_mday) + CHECK_LESS_EQUAL(t.tm_hour, lnow.tm_hour, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year && t.tm_mon == lnow.tm_mon && t.tm_mday == lnow.tm_mday + && t.tm_hour == lnow.tm_hour) + CHECK_LESS_EQUAL(t.tm_min, lnow.tm_min, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year && t.tm_mon == lnow.tm_mon && t.tm_mday == lnow.tm_mday + && t.tm_hour == lnow.tm_hour && t.tm_min == lnow.tm_min) + CHECK_LESS_EQUAL(t.tm_sec, lnow.tm_sec, PKI_CERT_DATE_INVALID); + } + else + { + CHECK_LESS_EQUAL(lnow.tm_year, t.tm_year, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year) + CHECK_LESS_EQUAL(lnow.tm_mon, t.tm_mon, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year && t.tm_mon == lnow.tm_mon) + CHECK_LESS_EQUAL(lnow.tm_mday, t.tm_mday, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year && t.tm_mon == lnow.tm_mon && t.tm_mday == lnow.tm_mday) + CHECK_LESS_EQUAL(lnow.tm_hour, t.tm_hour, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year && t.tm_mon == lnow.tm_mon && t.tm_mday == lnow.tm_mday + && t.tm_hour == lnow.tm_hour) + CHECK_LESS_EQUAL(lnow.tm_min, t.tm_min, PKI_CERT_DATE_INVALID); + if (t.tm_year == lnow.tm_year && t.tm_mon == lnow.tm_mon && t.tm_mday == lnow.tm_mday + && t.tm_hour == lnow.tm_hour && t.tm_min == lnow.tm_min) + CHECK_LESS_EQUAL(lnow.tm_sec, t.tm_sec, PKI_CERT_DATE_INVALID); + } + } + FUNCTION_CLEAR(); +} + +/** + * Decode certDerCode certificate and performs verification. + * + * @param[in] certDerCode Byte array with DER encoded certificate + * @param[in] caPublicKey Byte array with CA public key + * @return PKI_SUCCESS if success, error code otherwise + */ +PKIError CheckCertificate(ByteArray certDerCode, ByteArray caPublicKey) +{ + FUNCTION_INIT( + CertificateX509 crt; + INIT_BYTE_ARRAY(crt.tbs); + INIT_BYTE_ARRAY(crt.signR); + INIT_BYTE_ARRAY(crt.signS); + INIT_BYTE_ARRAY(crt.pubKey); + INIT_BYTE_ARRAY(crt.issuer); + INIT_BYTE_ARRAY(crt.subject); + ); + + CHECK_CALL(DecodeCertificate, certDerCode, &crt); + CHECK_CALL(CheckValidity, crt.validFrom, crt.validTo); + CHECK_CALL(ParsePublicKey, &caPublicKey); + CHECK_SIGN(crt, caPublicKey); + CHECK_CALL(CheckSerialNumber, crt.serNum); + + FUNCTION_CLEAR(); +} + +/* + * https://tools.ietf.org/html/rfc5246 + * This is a sequence (chain) of certificates. The sender's certificate MUST come first + * in the list. Each following certificate MUST directly certify the one preceding it. + */ + + +/* + * Handshake Message: certificate consist of the list of certificates. + * Certificate length (3 bytes) + * DER encoded certificate + * The first is server’s certificate + * Other certificates are optional + * Usually intermediate CA certificates + */ + +// Parses each certificate from list. +PKIError ParseCertificateChain (ByteArray *chainDerCode, CertificateX509 *chainCrt, + uint8_t chainLen) +{ + FUNCTION_INIT( + int i; + CHECK_NULL(chainDerCode, PKI_NULL_PASSED); + CHECK_NULL(chainCrt, PKI_NULL_PASSED); + CHECK_LESS_EQUAL(chainLen, MAX_CHAIN_LEN, PKI_WRONG_ARRAY_LEN); + ); + for (i = 0; i < chainLen; i++) + { + CHECK_CALL(DecodeCertificate, (*chainDerCode), chainCrt); +#ifdef X509_DEBUG + PrintCertificate(chainCrt); +#endif + chainDerCode++; + chainCrt++; + } + FUNCTION_CLEAR(); +} + +// Loads certificates from TLS message +PKIError LoadCertificateChain (ByteArray msg, ByteArray *chain, uint8_t *chainLength) +{ + FUNCTION_INIT( + CHECK_NULL(msg.data, PKI_NULL_PASSED); + CHECK_LESS_EQUAL(3, msg.len, PKI_WRONG_ARRAY_LEN); + CHECK_NULL(chain, PKI_NULL_PASSED); + CHECK_NULL(chainLength, PKI_NULL_PASSED); + uint32_t tmpLengthChain = 0; + *chainLength = 0; + ); + + CHECK_COND(msg.data[0] != 0 || msg.data[1] != 0 || msg.data[2] != 3, PKI_SUCCESS); +#ifdef X509_DEBUG + printf("start chain parsing\n"); +#endif + while (msg.len > 0) + { +#ifdef X509_DEBUG + printf("chain parsing: %d\n", msg.len); +#endif + CHECK_LESS_EQUAL(3, msg.len, PKI_WRONG_ARRAY_LEN); + tmpLengthChain = (((uint32_t) msg.data[0]) << 16) | (((uint32_t) msg.data[1]) << 8) | msg.data[2]; + CHECK_INC_BYTE_ARRAY(msg, 3); + (*chain).data = msg.data; + (*chain).len = tmpLengthChain; + chain ++; + (*chainLength) ++; + CHECK_LESS_EQUAL((*chainLength), MAX_CHAIN_LEN, PKI_WRONG_ARRAY_LEN); + CHECK_INC_BYTE_ARRAY(msg, tmpLengthChain); // Check this + } + FUNCTION_CLEAR(); +} + +/* + * Certificate validation requires that root keys be distributed independently, + * the self-signed certificate that specifies the root certificate authority MAY be omitted + * from the chain, under the assumption that the remote end must already possess it in order to + * validate it in any case. + */ + +// Verifies each certificate from list using next public key from list +PKIError CheckCertificateChain (CertificateX509 *chainCrt, uint8_t chainLen, ByteArray caPubKey) +{ + FUNCTION_INIT( + int i; + CHECK_NULL(chainCrt, PKI_NULL_PASSED); + CHECK_LESS_EQUAL(chainLen, MAX_CHAIN_LEN, PKI_WRONG_ARRAY_LEN); + ); + for (i = 0; i < chainLen - 1; i++) + { + ParsePublicKey(&(chainCrt + 1)->pubKey); + CHECK_SIGN(*chainCrt, (chainCrt + 1)->pubKey); + CHECK_CALL(CheckSerialNumber, chainCrt->serNum); + chainCrt++; + } + CHECK_SIGN(*chainCrt, caPubKey); + CHECK_CALL(CheckSerialNumber, chainCrt->serNum); + FUNCTION_CLEAR(); +} + diff --git a/resource/csdk/connectivity/src/adapter_util/pkix/sn_store.c b/resource/csdk/connectivity/src/adapter_util/pkix/sn_store.c new file mode 100644 index 0000000..b393fbb --- /dev/null +++ b/resource/csdk/connectivity/src/adapter_util/pkix/sn_store.c @@ -0,0 +1,118 @@ +/****************************************************************** + * + * Copyright 2015 Samsung Electronics All Rights Reserved. + * + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + + ******************************************************************/ + +#include "sn_store.h" +#include +#include + +//Size of initial memory +#define CRL_BLOCK_LEN 20 + + +/** + * @struct SNStore + * + * General structure for storing serial numbers. + * + * Contains pointer to array of bytes and it's length. + */ +typedef struct +{ + ByteArray array; /**< Byte array with data*/ + size_t blockNumber; /**< Number of used memory blocks */ +} SNStore; + + +/** + * Internal storage for serial numbers. + */ +static SNStore Store = {{NULL, 0}, 1}; + +// Frees memory occupied by SN storage. +void FreeSNStore(void) +{ + free(Store.array.data); + INIT_BYTE_ARRAY(Store.array); + Store.blockNumber = 1; +} + +// Stores serial number to SN storage. +PKIError StoreSerialNumber(const ByteArray sn) +{ + FUNCTION_INIT( + CHECK_NULL(sn.data, PKI_NULL_PASSED); + uint8_t *temp = NULL; + ); + if (Store.array.len == 0 || Store.array.len + sn.len + 1 > CRL_BLOCK_LEN * Store.blockNumber) + { + temp = (uint8_t *) realloc(Store.array.data, + sizeof(uint8_t) * CRL_BLOCK_LEN * Store.blockNumber * 2); + CHECK_NULL(temp, PKI_MEMORY_ALLOC_FAILED); + Store.array.data = temp; + Store.blockNumber *= 2; + } + Store.array.data[Store.array.len] = sn.len; + memcpy(&Store.array.data[Store.array.len + 1], sn.data, sn.len); + Store.array.len += sn.len + 1; + FUNCTION_CLEAR( + if (error_value != PKI_SUCCESS) free(temp); + ); +} + + +// Checks whether there is serial number in SN storage +PKIError CheckSerialNumber(const ByteArray sn) +{ + FUNCTION_INIT( + int i, res; + CHECK_NULL(sn.data, PKI_NULL_PASSED); + ); + CHECK_NULL(Store.array.data, PKI_SUCCESS); + for ( i = 0; i < Store.array.len; i += Store.array.data[i] + 1) + { + if (sn.len == Store.array.data[i]) + { + res = memcmp(&Store.array.data[i + 1], sn.data, sn.len); + CHECK_NOT_EQUAL(res, 0, PKI_CERT_REVOKED); + } + } + FUNCTION_CLEAR(); +} + +#ifdef X509_DEBUG +//Prints store content +void PrintSNStore(void) +{ + ByteArray curr; + int i, count = 0; + if (Store.array.data != NULL) + { + for ( i = 0; i < Store.array.len; i += Store.array.data[i] + 1) + { + curr.len = Store.array.data[i]; + curr.data = &Store.array.data[i + 1]; + PRINT_BYTE_ARRAY("", curr); + count++; + } + } + printf("\nSN STORE CONTAINS %d ELEMENTS\n", count); +} +#endif //DEBUG