From 77d4c5993c9a743fd24a1ad2f42d08427b557c59 Mon Sep 17 00:00:00 2001 From: Dmytro Zhuravlev Date: Tue, 8 Sep 2015 20:01:22 +0300 Subject: [PATCH] Add PKIX API for CA To support X.509 based DTLS in connectivity abstraction Change-Id: Icea2f13e8fe7be2179dfac5d45b70e9b762c7eef Signed-off-by: Dmytro Zhuravlev Reviewed-on: https://gerrit.iotivity.org/gerrit/2408 Tested-by: jenkins-iotivity Reviewed-by: Sachin Agrawal --- resource/csdk/connectivity/api/cainterface.h | 43 +++++ resource/csdk/connectivity/inc/caadapternetdtls.h | 7 + resource/csdk/connectivity/inc/pkix/pki.h | 7 +- .../src/adapter_util/caadapternetdtls.c | 191 ++++++++++++++++++++- 4 files changed, 246 insertions(+), 2 deletions(-) diff --git a/resource/csdk/connectivity/api/cainterface.h b/resource/csdk/connectivity/api/cainterface.h index 9499cf4..bc2dc98 100644 --- a/resource/csdk/connectivity/api/cainterface.h +++ b/resource/csdk/connectivity/api/cainterface.h @@ -35,6 +35,9 @@ #ifdef __WITH_DTLS__ #include "ocsecurityconfig.h" #endif +#ifdef __WITH_X509__ +#include "pki.h" +#endif //__WITH_X509__ #ifdef __cplusplus extern "C" @@ -87,6 +90,37 @@ typedef struct typedef void (*CAGetDTLSCredentialsHandler)(CADtlsPskCredsBlob_t **credInfo); #endif //__WITH_DTLS__ +#ifdef __WITH_X509__ +/** + * Binary structure containing certificate chain and certificate credentials + * for this device. + */ +typedef struct +{ + // certificate message for DTLS + unsigned char certificateChain[MAX_CERT_MESSAGE_LEN]; + // length of the certificate message + uint32_t certificateChainLen; + // number of certificates in certificate message + uint8_t chainLen; + // x component of EC public key + uint8_t rootPublicKeyX[PUBLIC_KEY_SIZE / 2]; + // y component of EC public key + uint8_t rootPublicKeyY[PUBLIC_KEY_SIZE / 2]; + // EC private key + uint8_t devicePrivateKey[PRIVATE_KEY_SIZE]; + +} CADtlsCertCreds_t; + +/** + * @brief Callback function type for getting certificate credentials. + * @param credInfo [OUT] Certificate credentials info. Handler has to allocate new memory for + * credInfo which is then freed by CA + * @return NONE + */ +typedef void (*CAGetCertCredentialsHandler)(CADtlsCertCreds_t *credInfo); +#endif //__WITH_X509__ + /** * Initialize the connectivity abstraction module. * It will initialize adapters, thread pool and other modules based on the platform @@ -139,6 +173,15 @@ void CARegisterHandler(CARequestCallback ReqHandler, CAResponseCallback RespHand CAResult_t CARegisterDTLSCredentialsHandler(CAGetDTLSCredentialsHandler GetDTLSCredentials); #endif //__WITH_DTLS__ +#ifdef __WITH_X509__ +/** + * @brief Register callback to get DTLS Cert credentials. + * @param GetCertCredentials [IN] GetCert Credetials callback + * @return #CA_STATUS_OK + */ +CAResult_t CARegisterCertCredentialsHandler(CAGetCertCredentialsHandler GetCertCredentials); +#endif //__WITH_X509__ + /** * Create an endpoint description. * @param[in] flags how the adapter should be used. diff --git a/resource/csdk/connectivity/inc/caadapternetdtls.h b/resource/csdk/connectivity/inc/caadapternetdtls.h index d766451..1d2c351 100644 --- a/resource/csdk/connectivity/inc/caadapternetdtls.h +++ b/resource/csdk/connectivity/inc/caadapternetdtls.h @@ -253,6 +253,13 @@ CAResult_t CAAdapterNetDtlsDecrypt(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t dataLen); +#ifdef __WITH_X509__ +/** + * @fn CADeInitX509 + * @brief Deinitializes certificate based credential + */ +void CADeInitX509(); +#endif //__WITH_X509__ #endif /* CA_ADAPTER_NET_DTLS_H_ */ diff --git a/resource/csdk/connectivity/inc/pkix/pki.h b/resource/csdk/connectivity/inc/pkix/pki.h index 23c6f50..221b6a9 100644 --- a/resource/csdk/connectivity/inc/pkix/pki.h +++ b/resource/csdk/connectivity/inc/pkix/pki.h @@ -33,10 +33,15 @@ extern "C" { #include "cert.h" /** - * Maximal lengths of certificate chain. + * Maximal number of certificates in trust chain. */ #define MAX_CHAIN_LEN (3) +/** + * Maximal length of the TLS certificate message. + */ +#define MAX_CERT_MESSAGE_LEN (2048) + #ifdef X509_DEBUG /** * Prints Certificate to console. diff --git a/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c b/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c index 780a6aa..bc2dbd0 100644 --- a/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c +++ b/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c @@ -26,6 +26,15 @@ #include "global.h" #include +#ifdef __WITH_X509__ +#include "pki.h" +#include "cainterface.h" +#include "credresource.h" +#undef VERIFY_SUCCESS +#define VERIFY_SUCCESS(op, successCode) { if ((op) != (successCode)) \ + {OIC_LOG_V(FATAL, NET_DTLS_TAG, "%s failed!!", #op); goto exit;} } +#endif + /** * @def NET_DTLS_TAG * @brief Logging tag for module name @@ -772,6 +781,176 @@ CAResult_t CADtlsGenerateOwnerPSK(const CAEndpoint_t *endpoint, return CA_STATUS_OK; } +#ifdef __WITH_X509__ +static CADtlsCertCreds_t g_X509Cred = {{0}, 0, 0, {0}, {0}, {0}}; + +static int g_IsX509Init = 0; + +int CAInitX509() +{ + OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CAInitX509"); + g_IsX509Init = (OC_STACK_OK == GetDtlsCertCredentials(&g_X509Cred)); + + OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CAInitX509"); + return !g_IsX509Init; +} + + +void CADeInitX509() +{ + g_IsX509Init = 0; +} + + +static int CAIsX509Active(struct dtls_context_t *ctx) +{ + (void)ctx; + return 0; +} + +static int CAGetDeviceKey(struct dtls_context_t *ctx, + const session_t *session, + const dtls_ecc_key_t **result) +{ + OIC_LOG(DEBUG, NET_DTLS_TAG, "CAGetDeviceKey"); + static dtls_ecc_key_t ecdsa_key = {DTLS_ECDH_CURVE_SECP256R1, NULL, NULL, NULL}; + + int ret = 1; + if (!g_IsX509Init) + { + VERIFY_SUCCESS(CAInitX509(), 0); + } + + ecdsa_key.priv_key = g_X509Cred.devicePrivateKey; + *result = &ecdsa_key; + + ret = 0; +exit: + return ret; +} + +static int +CAGetDeviceCertificate(struct dtls_context_t *ctx, + const session_t *session, + const unsigned char **cert, + size_t *cert_size) +{ + OIC_LOG(DEBUG, NET_DTLS_TAG, "CAGetDeviceCertificate"); + int ret = 1; + if (!g_IsX509Init) + { + VERIFY_SUCCESS(CAInitX509(), 0); + } + *cert = g_X509Cred.certificateChain; + *cert_size = g_X509Cred.certificateChainLen; +#ifdef X509_DEBUG + ByteArray ownCert = {g_X509Cred.certificateChain, g_X509Cred.certificateChainLen}; + PRINT_BYTE_ARRAY("OWN CERT: \n", ownCert); +#endif + + ret = 0; +exit: + return ret; +} +/** + * @fn CAGetRootKey + * @brief Gets x and y components of Root Certificate Autority public key + * + * @return 0 on success otherwise a positive error value. + * + */ +static int CAGetRootKey(const unsigned char **ca_pub_x, const unsigned char **ca_pub_y) +{ + OIC_LOG(DEBUG, NET_DTLS_TAG, "CAGetRootKey"); + int ret = 1; + if (!g_IsX509Init) + { + VERIFY_SUCCESS(CAInitX509(), 0); + } + *ca_pub_x = g_X509Cred.rootPublicKeyX; + *ca_pub_y = g_X509Cred.rootPublicKeyY; + + ret = 0; +exit: + return ret; +} + + +static int CAVerifyCertificate(struct dtls_context_t *ctx, const session_t *session, + const unsigned char *cert, size_t certLen, + const unsigned char *x, size_t xLen, + const unsigned char *y, size_t yLen) +{ + OIC_LOG(DEBUG, NET_DTLS_TAG, "Verify Certificate"); + + ByteArray crtChainDer[MAX_CHAIN_LEN]; + CertificateX509 crtChain[MAX_CHAIN_LEN]; + + uint8_t chainLength; + + int ret; + const unsigned char *ca_pub_x; + const unsigned char *ca_pub_y; + ByteArray certDerCode = BYTE_ARRAY_INITIALIZER; + ByteArray caPubKey = BYTE_ARRAY_INITIALIZER; + unsigned char ca_pub_key[PUBLIC_KEY_SIZE]; + + CAGetRootKey (&ca_pub_x, &ca_pub_y); + + certDerCode.data = (uint8_t *)cert; + certDerCode.len = certLen; + +#ifdef X509_DEBUG + PRINT_BYTE_ARRAY("CERT :\n", certDerCode); +#endif + + + caPubKey.len = PUBLIC_KEY_SIZE; + caPubKey.data = ca_pub_key; + + memcpy(caPubKey.data, ca_pub_x, PUBLIC_KEY_SIZE / 2); + memcpy(caPubKey.data + PUBLIC_KEY_SIZE / 2, ca_pub_y, PUBLIC_KEY_SIZE / 2); + + ret = (int) LoadCertificateChain (certDerCode, crtChainDer, &chainLength); + VERIFY_SUCCESS(ret, PKI_SUCCESS); + ret = (int) ParseCertificateChain (crtChainDer, crtChain, chainLength ); + VERIFY_SUCCESS(ret, PKI_SUCCESS); + ret = (int) CheckCertificateChain (crtChain, chainLength, caPubKey); + VERIFY_SUCCESS(ret, PKI_SUCCESS); + + INC_BYTE_ARRAY(crtChain[0].pubKey, 2); + + memcpy(x, crtChain[0].pubKey.data, xLen); + memcpy(y, crtChain[0].pubKey.data + PUBLIC_KEY_SIZE / 2, yLen); + + + if (NULL != ctx->peers && DTLS_SERVER == ctx->peers->role ) + { + stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session; + char peerAddr[MAX_ADDR_STR_SIZE_CA] = { 0 }; + uint16_t port = 0; + CAConvertAddrToName(&(addrInfo->addr.st), peerAddr, &port); + + CAResult_t result = CAAddIdToPeerInfoList(peerAddr, port, + crtChain[0].subject.data + crtChain[0].subject.len - sizeof(OicUuid_t), sizeof(OicUuid_t)); + if (CA_STATUS_OK != result ) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Fail to add peer id to gDtlsPeerInfoList"); + } + } + + +exit: + if (ret != 0) OIC_LOG(DEBUG, NET_DTLS_TAG, "Certificate verification FAILED\n"); + else OIC_LOG(DEBUG, NET_DTLS_TAG, "Certificate verification SUCCESS\n"); + return -ret; +} + +#endif + + + + CAResult_t CAAdapterNetDtlsInit() { OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); @@ -836,8 +1015,18 @@ CAResult_t CAAdapterNetDtlsInit() g_caDtlsContext->callbacks.write = CASendSecureData; g_caDtlsContext->callbacks.read = CAReadDecryptedPayload; g_caDtlsContext->callbacks.event = CAHandleSecureEvent; - g_caDtlsContext->callbacks.get_psk_info = CAGetPskCredentials; +#ifdef __WITH_X509__ + CAInitX509(); + if (g_IsX509Init == 0) +#endif //__WITH_X509__ + g_caDtlsContext->callbacks.get_psk_info = CAGetPskCredentials; +#ifdef __WITH_X509__ + g_caDtlsContext->callbacks.get_x509_key = CAGetDeviceKey; + g_caDtlsContext->callbacks.verify_x509_cert = CAVerifyCertificate; + g_caDtlsContext->callbacks.get_x509_cert = CAGetDeviceCertificate; + g_caDtlsContext->callbacks.is_x509_active = CAIsX509Active; +#endif //__WITH_X509__* dtls_set_handler(g_caDtlsContext->dtlsContext, &(g_caDtlsContext->callbacks)); ca_mutex_unlock(g_dtlsContextMutex); OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT"); -- 2.7.4