Commit 07b430ed authored by Greg Zaverucha's avatar Greg Zaverucha Committed by Kevin Kane

[IOT-1785] Support for Certificate Provisioning

- Shell script to create IoTivity identity certificates using
OpenSSL command line tools.
- Partial unit test for providing credentails to the CA adapter
layer.  Tests loading of PEM cert and key.
- Misc changes and fixes to the cred resource
- updated provisioning client to provision certs
- helper code to create certs from CSRs

Change-Id: I7d3ab4810c7f7d6247ed90420cb97cbdb5f829a4
Signed-off-by: default avatarGreg Zaverucha <gregz@microsoft.com>
Signed-off-by: default avatarKevin Kane <kkane@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/17509Reviewed-by: default avatarAlex Kelley <alexke@microsoft.com>
Tested-by: default avatarjenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: default avatarDan Mihai <Daniel.Mihai@microsoft.com>
parent 4de03691
......@@ -1334,7 +1334,7 @@ static void SetupCipher(mbedtls_ssl_config * config, CATransportAdapter_t adapte
g_getCredentialTypesCallback(g_caSslContext->cipherFlag);
// Retrieve the PSK credential from SRM
if (0 != InitPskIdentity(config))
if (true == g_caSslContext->cipherFlag[0] && 0 != InitPskIdentity(config))
{
OIC_LOG(ERROR, NET_SSL_TAG, "PSK identity initialization failed!");
}
......
......@@ -100,7 +100,6 @@ static const uint16_t PORT = 4545;
static const char NORMAL_INFO_DATA[] =
"{\"oc\":[{\"href\":\"%s\",\"prop\":{\"rt\":[\"core.led\"],"
"\"if\":[\"oc.mi.def\"],\"obs\":1}}]}";
#ifdef __WITH_DTLS__
// Iotivity Device Identity.
......@@ -164,6 +163,74 @@ int32_t CAGetDtlsPskCredentials( CADtlsPskCredType_t type,
printf("CAGetDtlsPskCredentials OUT\n");
return ret;
}
const char* our_cert = "-----BEGIN CERTIFICATE-----\n"
"MIIBhTCCASugAwIBAgIJAPZ5mB94RwYHMAoGCCqGSM49BAMCMCUxIzAhBgNVBAoM\n"
"GklvVGl2aXR5VGVzdFNlbGZTaWduZWROYW1lMB4XDTE2MTIxNjIxMjcyMVoXDTMw\n"
"MDgyNTIxMjcyMVowITEfMB0GA1UECgwWSW9UaXZpdHlUZXN0Q2xpZW50TmFtZTBZ\n"
"MBMGByqGSM49AgEGCCqGSM49AwEHA0IABF8OxpJNe01ZPEFpXUUhjUV5uwJM1TF3\n"
"ZSt0tJ71lQiRZ9cbl5z31acRpsZM+fXiR+wkR4xoP7iIyDdTHHVHtkSjSDBGMBUG\n"
"A1UdJQQOMAwGCisGAQQBgt58AQYwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQH\n"
"EWLwaDfA+o6U4wmQKVoK9I3B/DAKBggqhkjOPQQDAgNIADBFAiAbDHQHzSjNiDeQ\n"
"OaJYRMLIW2dIlabiQ5pxkW/jEaRszAIhAPzuoNdrQTRbnqCy0hmS9hFt8MxDrrBh\n"
"7jHARQm/5pko\n"
"-----END CERTIFICATE-----\n";
const char* our_key = "-----BEGIN EC PRIVATE KEY-----\n"
"MHcCAQEEIOV0iG5CndNK6JhB8nDcqQjNjgRWe/LQWPNPua3w7nHToAoGCCqGSM49\n"
"AwEHoUQDQgAEXw7Gkk17TVk8QWldRSGNRXm7AkzVMXdlK3S0nvWVCJFn1xuXnPfV\n"
"pxGmxkz59eJH7CRHjGg/uIjIN1McdUe2RA==\n"
"-----END EC PRIVATE KEY-----\n";
const char* our_ca = "-----BEGIN CERTIFICATE-----\n"
"MIIBlzCCATygAwIBAgIJALxGf3YRERn1MAoGCCqGSM49BAMCMCUxIzAhBgNVBAoM\n"
"GklvVGl2aXR5VGVzdFNlbGZTaWduZWROYW1lMB4XDTE2MTIxNjIxMjcyMVoXDTMw\n"
"MDgyNTIxMjcyMVowJTEjMCEGA1UECgwaSW9UaXZpdHlUZXN0U2VsZlNpZ25lZE5h\n"
"bWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATo/zp8PXaA/drJQKSG3TlerO0F\n"
"eHkpRkmXMeLFLrImqo1w9OyLfVmrpBrCDjf83BkwLYp19bkYizL2Yk9zIQ4Do1Uw\n"
"UzAhBgNVHSUEGjAYBgorBgEEAYLefAEGBgorBgEEAYLefAEHMA8GA1UdEwEB/wQF\n"
"MAMBAf8wHQYDVR0OBBYEFAcRYvBoN8D6jpTjCZApWgr0jcH8MAoGCCqGSM49BAMC\n"
"A0kAMEYCIQCuZb1LMTthWy9rPgy2FQgoFHB2LXUJlgRLJeO/gTFqgQIhANRvr1Py\n"
"5Bp6asye5FK4VUj6tARxmRNeNLvwonLrqp2w\n"
"-----END CERTIFICATE-----\n";
// Invoked by the CA stack to retrieve credentials from this module
void provide_x509_cert_and_key(PkiInfo_t* inf)
{
/* PEM data must end in newline and be null terminated for IoTivity */
inf->crt.data = (uint8_t*) our_cert;
inf->crt.len = strlen(our_cert) + 1;
inf->key.data = (uint8_t*) our_key;
inf->key.len = strlen(our_key) + 1;
inf->ca.data = (uint8_t*) our_ca;
inf->ca.len = strlen(our_ca) + 1;
// CRL not provided
inf->crl.data = NULL;
inf->crl.len = 0;
return;
}
// Empty version, for testing.
void badPkixInfoHandler(PkiInfo_t* inf)
{
return;
}
void provide_supported_credential_types(bool* list)
{
list[1] = true;
/*
* Note: there is a default implementation of this in credresource.c, exposed by
* pkix_interface.h, called InitManufacturerCipherSuiteList. If the cred resource
* has a credential of the required type, it updates list accordingly.
*
* In a separate test, we could use the cred resource and APIs (credresource.h).
*/
return;
}
#endif //__WITH_DTLS__
// CAInitialize TC
......@@ -293,6 +360,43 @@ TEST_F(CATests, SendRequestTestWithInvalidAddress)
tempRep = NULL;
}
#if defined(__WITH_DTLS__)
TEST_F(CATests, DISABLED_PkiTest)
{
// @todo: this test is disabled for now, it crashes with an invalid write. Cert data
// provided by the provide_x509_cert_and_key is stored as const char, but ParseChain()
// (in ca_adapter_net_ssl.c) writes to it while reading. We could change the test to
// provide data on the heap, but the CA stack should not be changing data provided to it
// by callbacks.
char* local_addr = "127.0.0.1";
uint16_t local_port = 5503;
CAEndpoint_t* serverAddr = NULL;
CARegisterHandler(request_handler, response_handler, error_handler);
EXPECT_EQ(CA_STATUS_OK, CASelectNetwork(CA_ADAPTER_IP));
CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, local_addr, local_port, &serverAddr);
ASSERT_TRUE(serverAddr != NULL);
// Register a credential types handler (tells the CA layer which creds are supported)
EXPECT_EQ(CA_STATUS_OK, CAregisterGetCredentialTypesHandler(provide_supported_credential_types));
// Limit ourselves to 0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 since it's non-PSK
EXPECT_EQ(CA_STATUS_OK, CASelectCipherSuite(0xC0AE, serverAddr->adapter));
// Register an empty callback to provide the keys, expect failure when initializing the handshake.
EXPECT_EQ(CA_STATUS_OK, CAregisterPkixInfoHandler(badPkixInfoHandler));
EXPECT_EQ(CA_STATUS_FAILED, CAInitiateHandshake(serverAddr));
// Register a working callback to provide the keys, expect success.
EXPECT_EQ(CA_STATUS_OK, CAregisterPkixInfoHandler(provide_x509_cert_and_key));
EXPECT_EQ(CA_STATUS_OK, CAInitiateHandshake(serverAddr));
CADestroyEndpoint(serverAddr);
}
#endif /* defined(__WITH_DTLS__) */
// CASendRequest TC
// check return value when a NULL is passed instead of a valid CARequestInfo_t address
TEST_F(CATests, SendRequestTestWithNullAddr)
......@@ -481,6 +585,8 @@ TEST_F(CATests, RegisterDTLSCredentialsHandlerTest)
{
#ifdef __WITH_DTLS__
EXPECT_EQ(CA_STATUS_OK, CAregisterPskCredentialsHandler(CAGetDtlsPskCredentials));
EXPECT_EQ(CA_STATUS_OK, CAregisterPkixInfoHandler(provide_x509_cert_and_key));
EXPECT_EQ(CA_STATUS_OK, CAregisterGetCredentialTypesHandler(provide_supported_credential_types));
#endif
}
......
......@@ -170,6 +170,50 @@ OCStackResult OCGenerateRoleCertificate(
char **certificate,
size_t *certificateLen);
/**
* Extract a UUID from a CSR.
*
* @param[in] csr The CSR containing the UUID as null-terminated PEM.
* @param[out] uuid The UUID in the CSR
*
* @return 0 on success, nonzero otherwise
*/
OCStackResult OCGetUuidFromCSR(const char* csr, OicUuid_t* uuid);
/**
* Extract a public key from a CSR.
*
* @param[in] csr The CSR containing the public key, as null-terminated PEM.
* @param[out] publicKey The public key is output here as null-terminated PEM.
* Callers must call OICFree when finished.
*
* @return 0 on success, nonzero otherwise
*/
OCStackResult OCGetPublicKeyFromCSR(const char* csr, char** publicKey);
/**
* Verify the signature in a CSR is valid.
*
* @param[in] csr The CSR to check, as null-terminated PEM.
*
* @returns 0 on success, nonzero otherwise
*
* @remark Requires that ECDSA with SHA-256 be used for the signature.
*/
OCStackResult OCVerifyCSRSignature(const char* csr);
/**
* Convert a CSR from DER encoding to PEM encoding.
*
* @param[in] derCSR The CSR to convert, encoded as DER
* @param[in] derCSRLen Then number of bytes in derCSR
* @param[out] pemCSR The output, PEM encoded, null-terminated CSR. Callers
* call OICFree when finished.
*
* @returns 0 on success, nonzero otherwise
*/
OCStackResult OCConvertDerCSRToPem(const char* derCSR, size_t derCSRLen, char** pemCSR);
#ifdef __cplusplus
}
#endif
......
......@@ -35,7 +35,7 @@ extern "C"
/**
* API to send ACL information to resource.
*
* @param[in] ctx Application context would be returned in result callback.
* @param[in] ctx Application context to be returned in result callback.
* @param[in] selectedDeviceInfo Selected target device.
* @param[in] acl ACL to provision.
* @param[in] resultCallback callback provided by API user, callback will be called when
......@@ -56,7 +56,7 @@ OCStackResult SRPSaveACL(const OicSecAcl_t *acl);
/**
* API to request CRED information to resource.
*
* @param[in] ctx Application context would be returned in result callback.
* @param[in] ctx Application context to be returned in result callback.
* @param[in] selectedDeviceInfo Selected target device.
* @param[in] resultCallback callback provided by API user, callback will be called when
* provisioning request recieves a response from resource server.
......@@ -68,7 +68,7 @@ OCStackResult SRPGetCredResource(void *ctx, const OCProvisionDev_t *selectedDevi
/**
* API to request ACL information to resource.
*
* @param[in] ctx Application context would be returned in result callback.
* @param[in] ctx Application context to be returned in result callback.
* @param[in] selectedDeviceInfo Selected target device.
* @param[in] resultCallback callback provided by API user, callback will be called when
* provisioning request recieves a response from resource server.
......@@ -93,7 +93,7 @@ OCStackResult SRPGetCSRResource(void *ctx, const OCProvisionDev_t *selectedDevic
/**
* function to provision Trust certificate chain to devices.
*
* @param[in] ctx Application context would be returned in result callback.
* @param[in] ctx Application context to be returned in result callback.
* @param[in] type Type of credentials to be provisioned to the device.
* @param[in] credId CredId of trust certificate chain to be provisioned to the device.
* @param[in] selectedDeviceInfo Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
......@@ -145,7 +145,7 @@ void SRPRemoveTrustCertChainNotifier(void);
/**
* API to send Direct-Pairing Configuration to a device.
*
* @param[in] ctx Application context would be returned in result callback.
* @param[in] ctx Application context to be returned in result callback.
* @param[in] selectedDeviceInfo Selected target device.
* @param[in] pconf PCONF pointer.
* @param[in] resultCallback callback provided by API user, callback will be called when
......@@ -170,11 +170,13 @@ OCStackResult SRPProvisionDirectPairing(void *ctx, const OCProvisionDev_t *selec
/**
* API to provision credential to devices.
*
* @param[in] ctx Application context would be returned in result callback.
* @param[in] ctx Application context to be returned in result callback.
* @param[in] type Type of credentials to be provisioned to the device.
* @param[in] keySize size of key
* @param[in] pDev1 Pointer to PMOwnedDeviceInfo_t instance,respresenting resource to be provsioned.
@param[in] pDev2 Pointer to PMOwnedDeviceInfo_t instance,respresenting resource to be provsioned.
* @param[in] pDev1 Pointer to PMOwnedDeviceInfo_t instance, respresenting resource to be provsioned.
* @param[in] pDev2 Pointer to PMOwnedDeviceInfo_t instance, respresenting resource to be provsioned.
* @param[in] pemCert When provisioning a certificate (type is SIGNED_ASYMMETRIC_KEY), this is the
* certificate, encoded as PEM.
* @param[in] resultCallback callback provided by API user, callback will be called when
* provisioning request recieves a response from first resource server.
* @return OC_STACK_OK in case of success and other value otherwise.
......@@ -182,13 +184,14 @@ OCStackResult SRPProvisionDirectPairing(void *ctx, const OCProvisionDev_t *selec
OCStackResult SRPProvisionCredentials(void *ctx,OicSecCredType_t type, size_t keySize,
const OCProvisionDev_t *pDev1,
const OCProvisionDev_t *pDev2,
const char* pemCert,
OCProvisionResultCB resultCallback);
/**
* Function to unlink devices.
* This function will remove the credential & relationship between the two devices.
*
* @param[in] ctx Application context would be returned in result callback
* @param[in] ctx Application context to be returned in result callback
* @param[in] pTargetDev1 first device information to be unlinked.
* @param[in] pTargetDev2 second device information to be unlinked.
* @param[in] resultCallback callback provided by API user, callback will be called when
......@@ -205,7 +208,7 @@ OCStackResult SRPUnlinkDevices(void* ctx,
* Function to device revocation.
* This function will remove credential of target device from all devices in subnet.
*
* @param[in] ctx Application context would be returned in result callback
* @param[in] ctx Application context to be returned in result callback
* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
* @param[in] pTargetDev Device information to be revoked.
* @param[in] resultCallback callback provided by API user, callback will be called when
......@@ -221,18 +224,18 @@ OCStackResult SRPRemoveDevice(void* ctx,
OCProvisionResultCB resultCallback);
/**
* Function to device revocation
* This function will remove credential of target device from all devices in subnet.
*
* @param[in] ctx Application context would be returned in result callback
* @param[in] pOwnedDevList List of owned devices
* @param[in] pTargetDev Device information to be revoked.
* @param[in] resultCallback callback provided by API user, callback will be called when
* credential revocation is finished.
* @return OC_STACK_OK in case of success and other value otherwise.
* If OC_STACK_OK is returned, the caller of this API should wait for callback.
* OC_STACK_CONTINUE means operation is success but no request is need to be initiated.
*/
* Function to device revocation
* This function will remove credential of target device from all devices in subnet.
*
* @param[in] ctx Application context to be returned in result callback
* @param[in] pOwnedDevList List of owned devices
* @param[in] pTargetDev Device information to be revoked.
* @param[in] resultCallback callback provided by API user, callback will be called when
* credential revocation is finished.
* @return OC_STACK_OK in case of success and other value otherwise.
* If OC_STACK_OK is returned, the caller of this API should wait for callback.
* OC_STACK_CONTINUE means operation is success but no request is need to be initiated.
*/
OCStackResult SRPRemoveDeviceWithoutDiscovery(void* ctx, const OCProvisionDev_t* pOwnedDevList,
const OCProvisionDev_t* pTargetDev, OCProvisionResultCB resultCallback);
......@@ -240,7 +243,7 @@ OCStackResult SRPRemoveDeviceWithoutDiscovery(void* ctx, const OCProvisionDev_t*
* Function to sync-up credential and ACL of the target device.
* This function will remove credential and ACL of target device from all devices in subnet.
*
* @param[in] ctx Application context would be returned in result callback
* @param[in] ctx Application context to be returned in result callback
* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
* @param[in] pTargetDev Device information to be revoked.
* @param[in] resultCallback callback provided by API user, callback will be called when
......
......@@ -295,6 +295,21 @@ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t ke
const OCProvisionDev_t *pDev2,
OCProvisionResultCB resultCallback);
/**
* API to provision a certificate to a device.
*
* @param[in] ctx Application context returned in result callback.
* @param[in] pDev Pointer to OCProvisionDev_t instance, respresenting the device to be provsioned.
* @param[in] pemCert Certificate to provision, encoded as PEM
* @param[in] resultCallback callback provided by API user, callback will be called when
* provisioning request receives a response from first resource server.
* @return OC_STACK_OK in case of success and other value otherwise.
*/
OCStackResult OCProvisionCertificate(void *ctx,
const OCProvisionDev_t *pDev,
const char* pemCert,
OCProvisionResultCB resultCallback);
#ifdef MULTIPLE_OWNER
/**
* API to provision preconfigured PIN to device(NOT LIST).
......@@ -388,16 +403,16 @@ OCStackResult OCRemoveDevice(void* ctx,
OCProvisionResultCB resultCallback);
/**
* Function to device revocation
* This function will remove credential of target device from all devices in subnet.
*
* @param[in] ctx Application context would be returned in result callback
* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
* @param[in] pTargetUuid Device information to be revoked.
* @param[in] resultCallback callback provided by API user, callback will be called when
* credential revocation is finished.
* Function to device revocation
* This function will remove credential of target device from all devices in subnet.
*
* @param[in] ctx Application context would be returned in result callback
* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
* @param[in] pTargetUuid Device information to be revoked.
* @param[in] resultCallback callback provided by API user, callback will be called when
* credential revocation is finished.
* @return OC_STACK_OK in case of success and other value otherwise.
*/
*/
OCStackResult OCRemoveDeviceWithUuid(void* ctx,
unsigned short waitTimeForOwnedDeviceDiscovery,
const OicUuid_t* pTargetUuid,
......@@ -531,6 +546,17 @@ OCStackResult OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16
*/
OCStackResult OCSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
OicEncodingType_t encodingType, uint16_t *credId);
/**
* Function to save an identity certificate chain into Cred of SVR.
*
* @param[in] cert Certificate chain to be saved in Cred of SVR, PEM encoded, null terminated
* @param[in] key private key corresponding to the certificate, PEM encoded, null terminated
* @param[out] credId CredId of saved certificate chain in Cred of SVR.
* @return OC_STACK_OK in case of success and other value otherwise.
*/
OCStackResult OCSaveOwnCertChain(char* cert, char* key, uint16_t *credId);
/**
* function to register callback, for getting notification for TrustCertChain change.
*
......
......@@ -40,6 +40,7 @@
#include "mbedtls/config.h"
#include "mbedtls/pem.h"
#include "mbedtls/x509_csr.h"
#include "occertutility.h"
#ifdef _MSC_VER
#include <io.h>
......@@ -69,6 +70,7 @@ extern "C"
#define _33_PROVIS_DP_ 33
#define _34_CHECK_LINK_STATUS_ 34
#define _35_SAVE_ACL_ 35
#define _36_PROVIS_CERT_ 36
#define _40_UNLINK_PAIR_DEVS_ 40
#define _50_REMOVE_SELEC_DEV_ 50
#define _51_REMOVE_DEV_WITH_UUID_ 51
......@@ -105,6 +107,9 @@ static const OicSecPrm_t SUPPORTED_PRMS[1] =
PRM_PRE_CONFIGURED,
};
static char* TEST_CERT_NOT_BEFORE = "20170101000000"; // Not before field for certificates, in format YYYYMMDDhhmmss
static char* TEST_CERT_NOT_AFTER = "20270101000000"; // + ten years
// |g_ctx| means provision manager application context and
// the following, includes |un/own_list|, could be variables, which |g_ctx| has,
// for accessing all function(s) for these, they are declared on global domain
......@@ -119,8 +124,13 @@ static int g_unown_cnt;
static OCProvisionDev_t* g_mot_enable_list;
static int g_mot_enable_cnt;
#endif //MULTIPLE_OWNER
char* g_caKeyPem; /* Test CA private key */
char* g_caCertPem; /* Test CA certificate */
uint16_t g_caCredId = 0; /* ID of CA's OCF identity cert */
char* g_csr; /* Certificate signing request from device */
static bool g_doneCB;
static bool g_doneCB; /* Set to true by the callback to indicate it completed. */
static bool g_successCB; /* Set to true by the callback to indicate success. */
#ifdef __WITH_TLS__
static int secure_protocol = 1;
static void setDevProtocol(OCProvisionDev_t* dev_lst);
......@@ -138,6 +148,11 @@ static FILE* fopen_prvnMng(const char*, const char*);
static int waitCallbackRet(void);
static int selectTwoDiffNum(int*, int*, const int, const char*);
/* At a few places in this file, warning 4028 is incorrectly produced, disable it for the whole file. */
#ifdef _MSC_VER
#pragma warning( disable : 4028)
#endif
// callback function(s) for provisioning client using C-level provisioning API
static void ownershipTransferCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
{
......@@ -172,11 +187,30 @@ static void provisionCredCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr,
if(!hasError)
{
OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*) ctx);
g_successCB = true;
}
else
{
OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*) ctx);
printResultList((const OCProvisionResult_t*) arr, nOfRes);
g_successCB = false;
}
g_doneCB = true;
}
/* Function of type OCProvisionResultCB from \resource\csdk\security\provisioning\include\pmtypes.h */
void provisionTrustChainCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
{
if (!hasError)
{
OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*)ctx);
g_successCB = true;
}
else
{
OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*)ctx);
printResultList((const OCProvisionResult_t*)arr, nOfRes);
g_successCB = false;
}
g_doneCB = true;
}
......@@ -291,7 +325,7 @@ static void getCsrCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* arr, bool has
}
else
{
size_t lst_cnt;
size_t lst_cnt;
for (lst_cnt = 0; nOfRes > lst_cnt; ++lst_cnt)
{
printf(" [%" PRIuPTR "] ", lst_cnt + 1);
......@@ -304,6 +338,56 @@ static void getCsrCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* arr, bool has
g_doneCB = true;
}
static void getCsrForCertProvCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* arr, bool hasError)
{
g_successCB = false;
if (!hasError)
{
if (nOfRes != 1)
{
OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED - ctx: %s", (char*)ctx);
goto exit;
}
if (arr[0].encoding == OIC_ENCODING_DER)
{
OCStackResult res = OCConvertDerCSRToPem((char*)arr[0].csr, arr[0].csrLen, &g_csr);
if (res != OC_STACK_OK)
{
OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED (CSR re-encoding failed) - error: %d, ctx: %s", res, (char*)ctx);
goto exit;
}
g_successCB = true;
}
else if(arr[0].encoding == OIC_ENCODING_PEM)
{
g_csr = (char*)OICCalloc(1, arr[0].csrLen);
if (g_csr == NULL)
{
OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED (memory allocation) - ctx: %s", (char*)ctx);
goto exit;
}
memcpy(g_csr, arr[0].csr, arr[0].csrLen);
OIC_LOG(INFO, TAG, "getCsrForCertProvCB success");
g_successCB = true;
}
else
{
OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED (unknown encoding) - ctx: %s", (char*)ctx);
goto exit;
}
}
else
{
OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED - ctx: %s", (char*)ctx);
}
exit:
g_doneCB = true;
}
static void provisionDPCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
{
......@@ -783,6 +867,345 @@ static int provisionCred(void)
return 0;
}
/*
* Initialize the provisioning client for certificate provisioning.
* This function:
* 1. Generates a root key pair for a CA.
* 2. Generates a self-signed root certificate for the CA public key.
* 3. Saves this root as a trust anchor locally.
* 4. Generate and store an IoTivity key and cert (issued from the CA root cert).
* This is an EE cert the CA/OBT will use in DTLS.
*
* @param[out] credid parameter for the ID of the CA credential
*/
static int setupCA()
{
char* publicKey = NULL;
size_t publicKeyLen = 0;
size_t caKeyLen = 0;
char* serial = NULL;
size_t serialLen = 0;
size_t caCertLen = 0;
char* idPublicKey = NULL;
char* idKey = NULL;
char* idCert = NULL;
size_t idCertLen = 0;
size_t idKeyLen = 0;
if (g_caCredId == 0)
{
printf("Setting up CA for certificate provisioning\n");
}
else
{
printf("Skipping CA setup, already done\n");
return 0;
}
/* Create CA keypair, serial number */
OCStackResult res = OCGenerateKeyPair(&publicKey, &publicKeyLen, &g_caKeyPem, &caKeyLen);
if (res != OC_STACK_OK)
{
OIC_LOG_V(ERROR, TAG, "OCGenerateKeyPair failed, error: %d", res);
goto exit;
}
res = OCGenerateRandomSerialNumber(&serial, &serialLen);
if (res != OC_STACK_OK)
{
OIC_LOG_V(ERROR, TAG, "OCGenerateRandomSerialNumber failed, error: %d", res);
goto exit;
}
/* Create a CA certificate */
res = OCGenerateCACertificate(
"C=US, O=Open Connectivity Foundation, CN=IoTivity test code CA", // subject
publicKey,
NULL, // Issuer private key is null
g_caKeyPem, // use CA's own key to create self-signed cert
serial,
TEST_CERT_NOT_BEFORE,
TEST_CERT_NOT_AFTER,
&g_caCertPem,
&caCertLen);
if (res != OC_STACK_OK)
{
OIC_LOG_V(ERROR, TAG, "OCGenerateCACertificate failed, error: %d", res);
goto exit;
}
/* Set our own trust anchor so that we trust certs we've issued. */
res = OCSaveTrustCertChain((uint8_t*) g_caCertPem, caCertLen, OIC_ENCODING_PEM, &g_caCredId);
if (OC_STACK_OK != res)
{
OIC_LOG_V(ERROR, TAG, "OCSaveTrustCertChain error: %d", res);
goto exit;
}
/* Create identity certificate for use by the CA. */
res = OCGenerateKeyPair(&idPublicKey, &publicKeyLen, &idKey, &idKeyLen);
if (res != OC_STACK_OK)
{
OIC_LOG_V(ERROR, TAG, "OCGenerateKeyPair failed, error: %d", res);
goto exit;
}
res = OCGenerateRandomSerialNumber(&serial, &serialLen);