Add certificate verification
authorDmytro Zhuravlev <d.zhuravlev@samsung.com>
Wed, 2 Sep 2015 12:04:21 +0000 (15:04 +0300)
committerSachin Agrawal <sachin.agrawal@intel.com>
Tue, 8 Sep 2015 21:20:40 +0000 (21:20 +0000)
Used to parse and check certificate by CA

Change-Id: I19277c2ea633e3e79f13a7934d835cfdd0b31f8b
Signed-off-by: Dmytro Zhuravlev <d.zhuravlev@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2355
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Sachin Agrawal <sachin.agrawal@intel.com>
14 files changed:
resource/csdk/connectivity/inc/pkix/byte_array.h [new file with mode: 0644]
resource/csdk/connectivity/inc/pkix/cert.h [new file with mode: 0644]
resource/csdk/connectivity/inc/pkix/crl.h [new file with mode: 0644]
resource/csdk/connectivity/inc/pkix/crypto_adapter.h [new file with mode: 0644]
resource/csdk/connectivity/inc/pkix/der_dec.h [new file with mode: 0644]
resource/csdk/connectivity/inc/pkix/pki.h [new file with mode: 0644]
resource/csdk/connectivity/inc/pkix/pki_errors.h [new file with mode: 0644]
resource/csdk/connectivity/inc/pkix/sn_store.h [new file with mode: 0644]
resource/csdk/connectivity/src/adapter_util/pkix/cert.c [new file with mode: 0644]
resource/csdk/connectivity/src/adapter_util/pkix/crl.c [new file with mode: 0644]
resource/csdk/connectivity/src/adapter_util/pkix/der_const.c [new file with mode: 0644]
resource/csdk/connectivity/src/adapter_util/pkix/der_dec.c [new file with mode: 0644]
resource/csdk/connectivity/src/adapter_util/pkix/pki.c [new file with mode: 0644]
resource/csdk/connectivity/src/adapter_util/pkix/sn_store.c [new file with mode: 0644]

diff --git a/resource/csdk/connectivity/inc/pkix/byte_array.h b/resource/csdk/connectivity/inc/pkix/byte_array.h
new file mode 100644 (file)
index 0000000..22892cd
--- /dev/null
@@ -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 <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+/**
+ * @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 (file)
index 0000000..03c6f7c
--- /dev/null
@@ -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 (file)
index 0000000..a3e5a32
--- /dev/null
@@ -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 (file)
index 0000000..3fda0cf
--- /dev/null
@@ -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 (file)
index 0000000..b26938a
--- /dev/null
@@ -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 (file)
index 0000000..23c6f50
--- /dev/null
@@ -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 (file)
index 0000000..0d7477f
--- /dev/null
@@ -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 <stdio.h>  // <printf>
+#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 (file)
index 0000000..50d8ff2
--- /dev/null
@@ -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 (file)
index 0000000..4a02949
--- /dev/null
@@ -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 (file)
index 0000000..91a7608
--- /dev/null
@@ -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 (file)
index 0000000..b342918
--- /dev/null
@@ -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 (file)
index 0000000..a1c5bba
--- /dev/null
@@ -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 (file)
index 0000000..8d32cc9
--- /dev/null
@@ -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 <time.h>
+#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 (file)
index 0000000..b393fbb
--- /dev/null
@@ -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 <string.h>
+#include <stdlib.h>
+
+//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