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!");
}
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.
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
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)
{
#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
}
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
/**
* 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
/**
* 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.
/**
* 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.
/**
* 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.
/**
* 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
/**
* 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.
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
* 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
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);
* 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
const OCProvisionDev_t *pDev2,\r
OCProvisionResultCB resultCallback);\r
\r
+/**\r
+ * API to provision a certificate to a device.\r
+ *\r
+ * @param[in] ctx Application context returned in result callback.\r
+ * @param[in] pDev Pointer to OCProvisionDev_t instance, respresenting the device to be provsioned.\r
+ * @param[in] pemCert Certificate to provision, encoded as PEM\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when\r
+ * provisioning request receives a response from first resource server.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCProvisionCertificate(void *ctx,\r
+ const OCProvisionDev_t *pDev,\r
+ const char* pemCert,\r
+ OCProvisionResultCB resultCallback);\r
+\r
#ifdef MULTIPLE_OWNER\r
/**\r
* API to provision preconfigured PIN to device(NOT LIST).\r
OCProvisionResultCB resultCallback);\r
\r
/**\r
-* Function to device revocation\r
-* This function will remove credential of target device from all devices in subnet.\r
-*\r
-* @param[in] ctx Application context would be returned in result callback\r
-* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)\r
-* @param[in] pTargetUuid Device information to be revoked.\r
-* @param[in] resultCallback callback provided by API user, callback will be called when\r
-* credential revocation is finished.\r
+ * Function to device revocation\r
+ * This function will remove credential of target device from all devices in subnet.\r
+ *\r
+ * @param[in] ctx Application context would be returned in result callback\r
+ * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)\r
+ * @param[in] pTargetUuid Device information to be revoked.\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when\r
+ * credential revocation is finished.\r
* @return OC_STACK_OK in case of success and other value otherwise.\r
-*/\r
+ */\r
OCStackResult OCRemoveDeviceWithUuid(void* ctx,\r
unsigned short waitTimeForOwnedDeviceDiscovery,\r
const OicUuid_t* pTargetUuid,\r
*/\r
OCStackResult OCSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,\r
OicEncodingType_t encodingType, uint16_t *credId);\r
+\r
+/**\r
+ * Function to save an identity certificate chain into Cred of SVR.\r
+ *\r
+ * @param[in] cert Certificate chain to be saved in Cred of SVR, PEM encoded, null terminated\r
+ * @param[in] key private key corresponding to the certificate, PEM encoded, null terminated\r
+ * @param[out] credId CredId of saved certificate chain in Cred of SVR.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCSaveOwnCertChain(char* cert, char* key, uint16_t *credId);\r
+\r
/**\r
* function to register callback, for getting notification for TrustCertChain change.\r
*\r
#include "mbedtls/config.h"
#include "mbedtls/pem.h"
#include "mbedtls/x509_csr.h"
+#include "occertutility.h"
#ifdef _MSC_VER
#include <io.h>
#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
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
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);
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)
{
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;
}
}
else
{
- size_t lst_cnt;
+ size_t lst_cnt;\r
for (lst_cnt = 0; nOfRes > lst_cnt; ++lst_cnt)
{
printf(" [%" PRIuPTR "] ", lst_cnt + 1);
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)
{
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. */\r
+ 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);
+ if (res != OC_STACK_OK)
+ {
+ OIC_LOG_V(ERROR, TAG, "OCGenerateRandomSerialNumber failed, error: %d", res);
+ goto exit;
+ }
+
+ OCUUIdentity deviceId = { 0 };
+ res = OCGetDeviceId(&deviceId);
+ if (res != OC_STACK_OK)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
+ goto exit;
+ }
+
+ OicUuid_t uuid = { 0 };
+ memcpy(uuid.id, deviceId.id, sizeof(uuid.id));
+
+ res = OCGenerateIdentityCertificate(
+ &uuid,
+ idPublicKey,
+ g_caCertPem,
+ g_caKeyPem,
+ serial,
+ TEST_CERT_NOT_BEFORE,
+ TEST_CERT_NOT_AFTER,
+ &idCert,
+ &idCertLen);
+ if (res != OC_STACK_OK)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to create identity cert for CA, error: %d", res);
+ goto exit;
+ }
+
+ uint16_t idCertCredId = 0;
+ res = OCSaveOwnCertChain(idCert, idKey, &idCertCredId);
+ if (res != OC_STACK_OK)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to save CA's identity cert & key, error: %d", res);
+ goto exit;
+ }
+
+exit:
+ OICFree(publicKey);
+ OICFree(serial);
+ OICFree(idPublicKey);
+ if (idKey != NULL)
+ {
+ OICClearMemory(idKey, idKeyLen);
+ OICFree(idKey);
+ }
+ OICFree(idCert);
+
+ if (res != OC_STACK_OK)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Create an identity certificate for a device, based on the information in its CSR.
+ * Assumes the csr has already been validated wtih OCVerifyCSRSignature.
+ */
+static int createIdentityCertFromCSR(const char* caKeyPem, const char* caCertPem, char* csr,
+ char** deviceCert)
+{
+ char* publicKey = NULL;
+ char* serial = NULL;
+ size_t serialLen;
+ OicUuid_t uuid = { 0 };
+ OCStackResult res = OC_STACK_ERROR;
+
+ res = OCGetUuidFromCSR(csr, &uuid);
+ if (res != OC_STACK_OK)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to get UUID from CSR, error: %d", res);
+ goto exit;
+ }
+ /* Note: a real OBT must make sure the UUID isn't already in use on the network. */
+
+ res = OCGetPublicKeyFromCSR(csr, &publicKey);
+ if (res != OC_STACK_OK)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to get public key from CSR, 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;
+ }
+
+ size_t deviceCertLen;
+ res = OCGenerateIdentityCertificate(
+ &uuid,
+ publicKey,
+ caCertPem,
+ caKeyPem,
+ serial,
+ TEST_CERT_NOT_BEFORE,
+ TEST_CERT_NOT_AFTER,
+ deviceCert,
+ &deviceCertLen);
+
+ if(res != OC_STACK_OK)
+ {
+ OIC_LOG_V(ERROR, TAG, "OCGenerateIdentityCertificate failed, error: %d", res);
+ goto exit;
+ }
+
+exit:
+ OICFree(publicKey);
+ OICFree(serial);
+
+ if (res != OC_STACK_OK)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int provisionCert(void)
+{
+ // make sure we own at least one device to provision
+ if (!g_own_list || g_own_cnt == 0)
+ {
+ printf(" > Owned Device List, to Provision Credentials, is Empty\n");
+ printf(" > Please Register Unowned Devices first, with [20] Menu\n");
+ return 0; // normal case
+ }
+
+ // select device for provisioning certificate
+ int dev_num = 0;
+ for (; ; )
+ {
+ printf(" > Enter Device Number, for certificate provisioning: ");
+ for (int ret = 0; 1 != ret; )
+ {
+ ret = scanf("%d", &dev_num);
+ for (; 0x20 <= getchar(); ); // for removing overflow garbages
+ // '0x20<=code' is character region
+ }
+ if (0<dev_num && g_own_cnt >= dev_num)
+ {
+ break;
+ }
+ printf(" Entered Wrong Number. Please Enter Again\n");
+ }
+
+ OCProvisionDev_t* targetDevice = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
+ if (targetDevice == NULL)
+ {
+ OIC_LOG(ERROR, TAG, "Error, invalid device %d");
+ return -1;
+ }
+
+ // Install the CA trust anchor
+ if (setupCA() != 0)
+ {
+ printf(" Failed to setup CA\n");
+ return -1;
+ }
+
+ // Provision the CA root cert to the target device
+ printf(" > Saving root certificate (trust anchor) to selected device..\n");
+ g_doneCB = false;
+ OicSecCredType_t type = SIGNED_ASYMMETRIC_KEY;
+
+ OCStackResult rst = OCProvisionTrustCertChain((void*)g_ctx, type, g_caCredId, targetDevice, &provisionTrustChainCB);
+ if (OC_STACK_OK != rst)
+ {
+ OIC_LOG_V(ERROR, TAG, "OCProvisionTrustCertChain returned error: %d", rst);
+ return -1;
+ }
+
+ if (waitCallbackRet()) // input |g_doneCB| flag implicitly
+ {
+ OIC_LOG(ERROR, TAG, "OCProvisionTrustCertChain callback error");
+ return -1;
+ }
+ if (!g_successCB)
+ {
+ return -1;
+ }
+
+ // Request a CSR from the device, check the CSR signature
+ printf(" > Getting CSR from device..\n");
+ g_doneCB = false;
+ rst = OCGetCSRResource((void*)g_ctx, targetDevice, getCsrForCertProvCB);
+ if (OC_STACK_OK != rst)
+ {
+ OIC_LOG_V(ERROR, TAG, "OCGetCSRResource API error: %d", rst);
+ return -1;
+ }
+ if (waitCallbackRet()) // input |g_doneCB| flag implicitly
+ {
+ OIC_LOG(ERROR, TAG, "OCGetCSRResource callback error");
+ return -1;
+ }
+ if (!g_successCB)
+ {
+ return -1;
+ }
+
+ rst = OCVerifyCSRSignature(g_csr);
+ if (OC_STACK_OK != rst)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to validate CSR signature");
+ OICFreeAndSetToNull(&g_csr);
+ return -1;
+ }
+
+ printf(" > Creating a certificate for the device..\n");
+ char* deviceCert;
+ int ret = createIdentityCertFromCSR(g_caKeyPem, g_caCertPem, g_csr, &deviceCert);
+ OICFreeAndSetToNull(&g_csr);
+ if (ret != 0)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to generate certificate");
+ OICFree(deviceCert);
+ return -1;
+ }
+
+ //Provision the new cert
+ printf(" > Provisioning certificate credential to selected device..\n");
+ g_doneCB = false;
+ rst = OCProvisionCertificate((void *)g_ctx, targetDevice, deviceCert, provisionCredCB);
+ if (OC_STACK_OK != rst)
+ {
+ OIC_LOG_V(ERROR, TAG, "OCProvisionCertificate returned error: %d", rst);
+ OICFree(deviceCert);
+ return -1;
+ }
+ if (waitCallbackRet()) // input |g_doneCB| flag implicitly
+ {
+ OIC_LOG(ERROR, TAG, "OCProvisionCertificate callback error");
+ OICFree(deviceCert);
+ return -1;
+ }
+ if (!g_successCB)
+ {
+ OICFree(deviceCert);
+ return -1;
+ }
+
+ printf(" > Provisioned certificate crendentials\n");
+ OICFree(deviceCert);
+
+ return 0;
+}
+
static int provisionAcl(void)
{
// check |own_list| for provisioning access control list
// for error checking, the return value saved and printed
g_doneCB = false;
printf(" Atempt Direct-Pairing Provisioning (PIN : [%s])..\n", (char*)pconf.pin.val);
-#if defined(_MSC_VER)
-#pragma warning(push)
- // Suppress C4028: formal parameter 2 different from declaration. getDevInst returns
- // OCProvisionDev_t *, which OCProvisionDirectPairing takes as its second parameter.
- // The compiler doesn't understand this.
-#pragma warning(disable:4028)
-#endif
OCStackResult rst = OCProvisionDirectPairing((void*) g_ctx,
- getDevInst((const OCProvisionDev_t *) g_own_list, dev_num),
+ getDevInst((const OCProvisionDev_t*) g_own_list, dev_num),
&pconf, provisionDPCB);
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
if(OC_STACK_OK != rst)
{
OIC_LOG_V(ERROR, TAG, "OCProvisionDirectPairing API error: %d", rst);
printf("** 32. Provision the Selected Access Control List(ACL)\n");
printf("** 33. Provision Direct-Pairing Configuration\n");
printf("** 34. Check Linked Status of the Selected Device on PRVN DB\n");
- printf("** 35. Save the Selected Access Control List(ACL) into local SVR DB\n\n");
+ printf("** 35. Save the Selected Access Control List(ACL) into local SVR DB\n");
+ printf("** 36. Provision certificate credential\n\n");
+
printf("** [D] UNLINK PAIRWISE THINGS\n");
printf("** 40. Unlink Pairwise Things\n\n");
OIC_LOG(ERROR, TAG, "_35_SAVE_ACL_: error");
}
break;
+ case _36_PROVIS_CERT_:
+ if (provisionCert())
+ {
+ OIC_LOG(ERROR, TAG, "_36_PROVIS_CERT_: error");
+ }
+ break;
case _40_UNLINK_PAIR_DEVS_:
if(unlinkPairwise())
{
OCProvisionResultCB resultCallback)
{
return SRPProvisionCredentials(ctx, type, keySize,
- pDev1, pDev2, resultCallback);
+ pDev1, pDev2, NULL, resultCallback);
}
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+/**\r
+* API to provision a certificate to a device.\r
+*\r
+* @param[in] ctx Application context returned in result callback.\r
+* @param[in] pDev Pointer to OCProvisionDev_t instance, respresenting the device to be provsioned.\r
+* @param[in] pemCert Certificate to provision, encoded as PEM\r
+* @param[in] resultCallback callback provided by API user, callback will be called when\r
+* provisioning request receives a response from first resource server.\r
+* @return OC_STACK_OK in case of success and other value otherwise.\r
+*/
+OCStackResult OCProvisionCertificate(void *ctx,\r
+ const OCProvisionDev_t *pDev,\r
+ const char* pemCert,\r
+ OCProvisionResultCB resultCallback)
+{
+ return SRPProvisionCredentials(ctx, SIGNED_ASYMMETRIC_KEY, 0,
+ pDev, NULL, pemCert, resultCallback);
+}
+#endif
+
/**
* this function sends Direct-Pairing Configuration to a device.
*
link->currentCountResults = 0;
link->resArr = (OCProvisionResult_t*) OICMalloc(sizeof(OCProvisionResult_t)*noOfResults);
res = SRPProvisionCredentials(link, type, keySize,
- pDev1, pDev2, &ProvisionCredsCB);
+ pDev1, pDev2, NULL, &ProvisionCredsCB);
if (res != OC_STACK_OK)
{
OICFree(link->resArr);
return SRPSaveTrustCertChain(trustCertChain, chainSize, encodingType, credId);
}
+/**\r
+ * Function to save an identity certificate chain into Cred of SVR.\r
+ *\r
+ * @param[in] cert Certificate chain to be saved in Cred of SVR, PEM encoded, null terminated\r
+ * @param[in] key key corresponding to the certificate, PEM encoded, null terminated\r
+ * @param[out] credId CredId of saved certificate chain in Cred of SVR.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCSaveOwnCertChain(char* cert, char* key, uint16_t *credId)
+{
+ OicSecKey_t ownCert = { 0 };
+ ownCert.data = (uint8_t*) cert;
+ ownCert.len = strlen(cert) + 1;
+ ownCert.encoding = OIC_ENCODING_PEM;
+
+ OicSecKey_t ownKey = { 0 };
+ ownKey.data = (uint8_t*) key;
+ ownKey.len = strlen(key) + 1;
+ ownKey.encoding = OIC_ENCODING_PEM;
+
+ return SRPSaveOwnCertChain(&ownCert, &ownKey, credId);
+}
+
/**
* function to register notifier for Trustcertchain change.
*
return OC_STACK_DELETE_TRANSACTION;
}
-
/**
* Internal function for handling credential generation and sending credential to resource server.
*
return OC_STACK_DELETE_TRANSACTION;
}
+static OCStackApplicationResult provisionIdentityCertCB(void *ctx, OCDoHandle UNUSED,
+ OCClientResponse *clientResponse)
+{
+ // Just call the callback provided to SRProvisionCredentials
+ VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
+ CredentialData_t* credData = (CredentialData_t *)ctx;
+ (void)UNUSED;
+ bool hasError;
+
+ // We expect OC_STACK_RESOURCE_CHANGED, anything else is an error
+ if (clientResponse && (OC_STACK_RESOURCE_CHANGED == clientResponse->result))
+ {
+ hasError = false;
+ }
+ else
+ {
+ hasError = true;
+ }
+
+ OCProvisionResultCB resultCallback = credData->resultCallback;
+ VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR, OC_STACK_DELETE_TRANSACTION);
+
+ ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
+ credData->resArr, hasError);
+
+ OICFree(credData);
+
+ return OC_STACK_DELETE_TRANSACTION;
+
+}
+
OCStackResult SRPProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16_t credId,
const OCProvisionDev_t *selectedDeviceInfo, OCProvisionResultCB resultCallback)
{
- OIC_LOG(INFO, TAG, "In SRPProvisionTrustCertChain");
+ OIC_LOG(INFO, TAG, "IN SRPProvisionTrustCertChain");
VERIFY_NOT_NULL_RETURN(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM);
VERIFY_NOT_NULL_RETURN(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
if (SIGNED_ASYMMETRIC_KEY != type)
return OC_STACK_NO_MEMORY;
}
secPayload->base.type = PAYLOAD_TYPE_SECURITY;
- int secureFlag = 0;
+ int secureFlag = 1; /* Don't send the private key to the device, if it happens to be present */
if(OC_STACK_OK != CredToCBORPayload(trustCertChainCred, &secPayload->securityData, &secPayload->payloadSize, secureFlag))
{
DeleteCredList(trustCertChainCred);
}
VERIFY_SUCCESS_RETURN(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
+
+ OIC_LOG(INFO, TAG, "OUT SRPProvisionTrustCertChain");
+
return OC_STACK_OK;
}
res = GetDoxmDeviceID(&cred->subject);
if (OC_STACK_OK != res)
{
- OIC_LOG(ERROR, TAG, "Cann't get the device id(GetDoxmDeviceID)");
+ OIC_LOG(ERROR, TAG, "Can't get the device id(GetDoxmDeviceID)");
DeleteCredList(cred);
return res;
}
- cred->credUsage= (char *)OICCalloc(1, strlen(TRUST_CA)+1 );
+ cred->credUsage= (char *)OICCalloc(1, strlen(TRUST_CA) + 1);
VERIFY_NOT_NULL_RETURN(TAG, cred->credUsage, ERROR, OC_STACK_NO_MEMORY);
OICStrcpy(cred->credUsage, strlen(TRUST_CA) + 1, TRUST_CA);
VERIFY_NOT_NULL_RETURN(TAG, cred->optionalData.data, ERROR, OC_STACK_NO_MEMORY);
cred->optionalData.len = chainSize + 1;
}
- else
+ else if (encodingType == OIC_ENCODING_DER)
{
cred->optionalData.data = (uint8_t *)OICCalloc(1, chainSize);
VERIFY_NOT_NULL_RETURN(TAG, cred->optionalData.data, ERROR, OC_STACK_NO_MEMORY);
cred->optionalData.len = chainSize;
}
+ else
+ {
+ OIC_LOG_V(ERROR, TAG, "Unknown encoding in %s", __func__);
+ DeleteCredList(cred);
+ return OC_STACK_INVALID_PARAM;
+ }
memcpy(cred->optionalData.data, trustCertChain, chainSize);
cred->optionalData.encoding = encodingType;
cred->optionalData.revstat = false;
return res;
}
-OCStackResult SRPSaveOwnCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_t *credId)
+static OCStackResult saveCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_t *credId, const char* usage)
{
- OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
+ OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
VERIFY_NOT_NULL_RETURN(TAG, cert, ERROR, OC_STACK_INVALID_PARAM);
VERIFY_NOT_NULL_RETURN(TAG, cert->data, ERROR, OC_STACK_INVALID_PARAM);
VERIFY_NOT_NULL_RETURN(TAG, key, ERROR, OC_STACK_INVALID_PARAM);
VERIFY_NOT_NULL_RETURN(TAG, key->data, ERROR, OC_STACK_INVALID_PARAM);
VERIFY_NOT_NULL_RETURN(TAG, credId, ERROR, OC_STACK_INVALID_PARAM);
+ VERIFY_NOT_NULL_RETURN(TAG, usage, ERROR, OC_STACK_INVALID_PARAM);
OCStackResult res = OC_STACK_ERROR;
return res;
}
- cred->credUsage= (char *)OICCalloc(1, strlen(PRIMARY_CERT)+1 );
+ cred->credUsage= (char *)OICCalloc(1, strlen(usage) + 1);
VERIFY_NOT_NULL_RETURN(TAG, cred->credUsage, ERROR, OC_STACK_NO_MEMORY);
- OICStrcpy(cred->credUsage, strlen(PRIMARY_CERT) + 1, PRIMARY_CERT) ;
+ OICStrcpy(cred->credUsage, strlen(usage) + 1, usage);
cred->credType = SIGNED_ASYMMETRIC_KEY;
}
*credId = cred->credId;
- OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
+ OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
return res;
}
+
+OCStackResult SRPSaveOwnCertChain(OicSecKey_t * cert, OicSecKey_t * key, uint16_t *credId)
+{
+ return saveCertChain(cert, key, credId, PRIMARY_CERT);
+}
+
#endif // __WITH_DTLS__ || __WITH_TLS__
OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
const OCProvisionDev_t *pDev1,
const OCProvisionDev_t *pDev2,
+ const char* pemCert,
OCProvisionResultCB resultCallback)
{
VERIFY_NOT_NULL_RETURN(TAG, pDev1, ERROR, OC_STACK_INVALID_PARAM);
}
if (!resultCallback)
{
- OIC_LOG(INFO, TAG, "SRPUnlinkDevices : NULL Callback");
+ OIC_LOG(INFO, TAG, "SRPProvisionCredentials: NULL Callback");
return OC_STACK_INVALID_CALLBACK;
}
if (SYMMETRIC_PAIR_WISE_KEY == type &&
0 == memcmp(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, sizeof(OicUuid_t)))
{
- OIC_LOG(INFO, TAG, "SRPUnlinkDevices : Same device ID");
+ OIC_LOG(INFO, TAG, "SRPProvisionCredentials : Same device ID");
return OC_STACK_INVALID_PARAM;
}
VERIFY_SUCCESS_RETURN(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
return res;
}
+ case SIGNED_ASYMMETRIC_KEY:
+ {
+ /* pDev1 is the device to be provisioned, checked non-null above */
+ /* pDev2 is not used, should be NULL */
+ /* size param is not used. */
+ /* pemCert is the cerficiate to be provisioned */
+ VERIFY_NOT_NULL_RETURN(TAG, pemCert, ERROR, OC_STACK_INVALID_PARAM);
+
+ OicSecKey_t deviceCert = { 0 };
+ deviceCert.data = (uint8_t*) pemCert; /* Casting away const is OK here */
+ deviceCert.len = strlen(pemCert) + 1;
+ deviceCert.encoding = OIC_ENCODING_PEM;
+
+ /* Create a credential object */
+ OicSecCred_t* cred = GenerateCredential(&pDev1->doxm->deviceID, SIGNED_ASYMMETRIC_KEY,
+ &deviceCert, NULL, // oic.sec.cred.publicdata = deviceCert, .privatedata = NULL
+ &provTooldeviceID, NULL); // rowner is the provisioning tool and no eowner
+ VERIFY_NOT_NULL_RETURN(TAG, cred, ERROR, OC_STACK_ERROR);
+
+ cred->publicData.encoding = OIC_ENCODING_PEM;
+ cred->credUsage = OICStrdup(PRIMARY_CERT);
+
+ /* Create credential data (used by the response handler provisionIdentityCertCB and freed there) */
+ CredentialData_t *credData = (CredentialData_t *)OICCalloc(1, sizeof(CredentialData_t));
+ if (NULL == credData)
+ {
+ DeleteCredList(cred);
+ OIC_LOG(ERROR, TAG, "Memory allocation problem");
+ return OC_STACK_NO_MEMORY;
+ }
+ credData->deviceInfo1 = pDev1;
+ credData->deviceInfo2 = NULL;
+ credData->credInfo = cred;
+ credData->ctx = ctx;
+ credData->credInfoFirst = cred;
+ credData->numOfResults = 0;
+ credData->resultCallback = resultCallback;
+ credData->resArr = NULL;
+
+ /* Note: the callback of type OCClientResponseHandler, thin wrapper that calls resultCallback */
+ OCStackResult res = provisionCredentials(cred, pDev1, credData, &provisionIdentityCertCB);
+ if (res != OC_STACK_OK)
+ {
+ OICFree(credData);
+ }
+
+ DeleteCredList(cred);
+ return OC_STACK_OK;
+ }
default:
{
OIC_LOG(ERROR, TAG, "Invalid option.");
* @return OC_STACK_DELETE_TRANSACTION to delete the transaction
* and OC_STACK_KEEP_TRANSACTION to keep it.
*/
-static OCStackApplicationResult SRPGetCSRResourceCB(void *ctx, OCDoHandle UNUSED,
- OCClientResponse *clientResponse)
-{
- OIC_LOG_V(INFO, TAG, "Inside SRPGetCSRResourceCB.");
- OC_UNUSED(UNUSED);
- VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
- GetCsrData_t *getCsrData = (GetCsrData_t*)ctx;
- OCGetCSRResultCB resultCallback = getCsrData->resultCallback;
-
- if (clientResponse)
- {
- if (OC_STACK_OK == clientResponse->result)
- {
- uint8_t *payload = ((OCSecurityPayload*)clientResponse->payload)->securityData;
- size_t size = ((OCSecurityPayload*)clientResponse->payload)->payloadSize;
-
- OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
-
- registerResultForGetCSRResourceCB(getCsrData, OC_STACK_OK, payload, size);
- }
- }
- else
- {
- registerResultForGetCSRResourceCB(getCsrData, OC_STACK_ERROR, NULL, 0);
- }
-
- resultCallback(getCsrData->ctx, getCsrData->numOfResults,
- getCsrData->resArr,
- false);
- OIC_LOG_V(ERROR, TAG, "SRPGetCSRResourceCB received Null clientResponse");
- for (size_t i = 0; i < getCsrData->numOfResults; i++)
- {
- OICFree(getCsrData->resArr[i].csr);
- }
- OICFree(getCsrData->resArr);
- OICFree(getCsrData);
-
- return OC_STACK_DELETE_TRANSACTION;
+static OCStackApplicationResult SRPGetCSRResourceCB(void *ctx, OCDoHandle UNUSED,\r
+ OCClientResponse *clientResponse)\r
+{\r
+ size_t i = 0;\r
+ OIC_LOG_V(INFO, TAG, "IN %s", __func__);\r
+ (void)UNUSED;\r
+ VERIFY_NOT_NULL_RETURN(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);\r
+ GetCsrData_t *getCsrData = (GetCsrData_t*)ctx;\r
+ OCGetCSRResultCB resultCallback = getCsrData->resultCallback;\r
+\r
+ if (clientResponse)\r
+ {\r
+ if (OC_STACK_OK == clientResponse->result)\r
+ {\r
+ uint8_t *payload = ((OCSecurityPayload*)clientResponse->payload)->securityData;\r
+ size_t size = ((OCSecurityPayload*)clientResponse->payload)->payloadSize;\r
+\r
+ OIC_LOG_BUFFER(DEBUG, TAG, payload, size);\r
+\r
+ registerResultForGetCSRResourceCB(getCsrData, OC_STACK_OK, payload, size);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ registerResultForGetCSRResourceCB(getCsrData, OC_STACK_ERROR, NULL, 0);\r
+ }\r
+\r
+ ((OCGetCSRResultCB)(resultCallback))(getCsrData->ctx, getCsrData->numOfResults,\r
+ getCsrData->resArr,\r
+ false);\r
+ OIC_LOG_V(ERROR, TAG, "%s: received Null clientResponse", __func__);\r
+ for (i = 0; i < getCsrData->numOfResults; i++)\r
+ {\r
+ OICFree(getCsrData->resArr[i].csr);\r
+ }\r
+ OICFree(getCsrData->resArr);\r
+ OICFree(getCsrData);\r
+ OIC_LOG_V(INFO, TAG, "OUT %s", __func__);\r
+\r
+ return OC_STACK_DELETE_TRANSACTION;\r
}
{
EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType,
OWNER_PSK_LENGTH_128, NULL,
- &pDev2, &provisioningCB));
+ &pDev2, NULL, &provisioningCB));
}
TEST(SRPProvisionCredentialsTest, SamelDeviceId)
{
EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType,
OWNER_PSK_LENGTH_128, &pDev1,
- &pDev1, &provisioningCB));
+ &pDev1, NULL, &provisioningCB));
}
TEST(SRPProvisionCredentialsTest, NullCallback)
{
EXPECT_EQ(OC_STACK_INVALID_CALLBACK, SRPProvisionCredentials(NULL, credType,
OWNER_PSK_LENGTH_128,
- &pDev1, &pDev2, NULL));
+ &pDev1, &pDev2, NULL, NULL));
}
TEST(SRPProvisionCredentialsTest, InvalidKeySize)
{
EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType,
- 0, &pDev1, &pDev2,
+ 0, &pDev1, &pDev2, NULL,
&provisioningCB));
}
#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
#include <mbedtls/ssl_ciphersuites.h>
+#include "mbedtls/pk.h"
#endif
#define TAG "OIC_SRM_CREDL"
return cborFindResult;
}
+/* Produce debugging output for all credentials, output metadata. */
+static void logCredMetadata()
+{
+#if defined(TB_LOG)
+ OicSecCred_t * temp = NULL;
+ size_t count = 0;
+ char uuidString[UUID_STRING_SIZE];
+ OicUuid_t ownUuid;
+
+ OIC_LOG_V(DEBUG, TAG, "IN %s:", __func__);
+
+ if (GetDoxmDeviceID(&ownUuid) == OC_STACK_OK && OCConvertUuidToString(ownUuid.id, uuidString))
+ {
+ OIC_LOG_V(DEBUG, TAG, "Own UUID: %s", uuidString);
+ }
+
+ LL_FOREACH(gCred, temp)
+ {
+ count++;
+ OIC_LOG(DEBUG, TAG, " ");
+ OIC_LOG_V(DEBUG, TAG, "Cred ID: %d", temp->credId);
+ if (OCConvertUuidToString(temp->subject.id, uuidString))
+ {
+ OIC_LOG_V(DEBUG, TAG, "Subject UUID: %s", uuidString);
+ }
+ OIC_LOG_V(DEBUG, TAG, "Cred Type: %d", temp->credType);
+ OIC_LOG_V(DEBUG, TAG, "privateData length: %d, encoding: %d", temp->privateData.len, temp->privateData.encoding);
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+ OIC_LOG_V(DEBUG, TAG, "publicData length: %d, encoding: %d", temp->publicData.len, temp->publicData.encoding);
+ if (temp->credUsage)
+ {
+ OIC_LOG_V(DEBUG, TAG, "credUsage: %s", temp->credUsage);
+ }
+
+ OIC_LOG_V(DEBUG, TAG, "optionalData length: %d, encoding: %d", temp->optionalData.len, temp->optionalData.encoding);
+#endif
+
+ }
+
+ OIC_LOG_V(DEBUG, TAG, "Found %d credentials.", count);
+
+ OIC_LOG_V(DEBUG, TAG, "OUT %s:", __func__);
+#endif
+}
+
+
OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload,
size_t *cborSize, int secureFlag)
{
+ OIC_LOG_V(DEBUG, TAG, "IN %s:", __func__);
if (NULL == credS || NULL == cborPayload || NULL != *cborPayload || NULL == cborSize)
{
return OC_STACK_INVALID_PARAM;
ret = OC_STACK_ERROR;
}
+ OIC_LOG_V(DEBUG, TAG, "OUT %s:", __func__);
+
return ret;
}
}
OIC_LOG(DEBUG, TAG, "OUT Cred UpdatePersistentStorage");
+
+ logCredMetadata();
+
return ret;
}
#endif//__WITH_DTLS__
}
- if (OC_EH_CHANGED != ret)
+ if (OC_EH_CHANGED != ret && cred != NULL)
{
if(OC_STACK_OK != RemoveCredential(&cred->subject))
{
cred->privateData.encoding = tmpCred->privateData.encoding;
}
#if defined(__WITH_X509__) || defined(__WITH_TLS__)
- else if (tmpCred->publicData.data)
+ if (tmpCred->publicData.data)
{
cred->publicData.data = (uint8_t *)OICCalloc(1, tmpCred->publicData.len);
VERIFY_NOT_NULL(TAG, cred->publicData.data, ERROR);
memcpy(cred->publicData.data, tmpCred->publicData.data, tmpCred->publicData.len);
cred->publicData.len = tmpCred->publicData.len;
+ cred->publicData.encoding = tmpCred->publicData.encoding;
}
- else if (tmpCred->optionalData.data)
+ if (tmpCred->optionalData.data)
{
cred->optionalData.data = (uint8_t *)OICCalloc(1, tmpCred->optionalData.len);
VERIFY_NOT_NULL(TAG, cred->optionalData.data, ERROR);
cred->optionalData.encoding = tmpCred->optionalData.encoding;
cred->optionalData.revstat= tmpCred->optionalData.revstat;
}
-
if (tmpCred->credUsage)
{
cred->credUsage = OICStrdup(tmpCred->credUsage);
LL_FOREACH(gCred, temp)
{
if ((SIGNED_ASYMMETRIC_KEY == temp->credType) &&
+ (temp->credUsage != NULL) &&
(0 == strcmp(temp->credUsage, usage)) && (false == temp->optionalData.revstat))
{
if(OIC_ENCODING_BASE64 == temp->optionalData.encoding)
LL_FOREACH(gCred, temp)
{
if (SIGNED_ASYMMETRIC_KEY == temp->credType &&
+ temp->credUsage != NULL &&
0 == strcmp(temp->credUsage, usage))
{
crt->data = OICRealloc(crt->data, crt->len + temp->publicData.len);
LL_FOREACH(gCred, temp)
{
if ((SIGNED_ASYMMETRIC_KEY == temp->credType || ASYMMETRIC_KEY == temp->credType) &&
- NULL != temp->credUsage &&
+ NULL != temp->credUsage &&
0 == strcmp(temp->credUsage, usage))
{
- key->data = OICRealloc(key->data, key->len + temp->privateData.len);
- memcpy(key->data + key->len, temp->privateData.data, temp->privateData.len);
- key->len += temp->privateData.len;
- OIC_LOG_V(DEBUG, TAG, "Key for %s found", usage);
+
+ if (temp->privateData.encoding == OIC_ENCODING_PEM)
+ {
+ /* Convert PEM to DER */
+ mbedtls_pk_context ctx;
+ mbedtls_pk_init(&ctx);
+
+ int ret = mbedtls_pk_parse_key(&ctx, temp->privateData.data, temp->privateData.len, NULL, 0);
+ if (ret != 0)
+ {
+ mbedtls_pk_free(&ctx);
+ OIC_LOG_V(ERROR, TAG, "Key for %s found, but failed to convert from PEM to DER (while reading PEM)", usage);
+ return;
+ }
+
+ key->data = OICRealloc(key->data, key->len + temp->privateData.len);
+ if (key->data == NULL)
+ {
+ mbedtls_pk_free(&ctx);
+ OIC_LOG(ERROR, TAG, "Realloc failed to increase key->data length");
+ return;
+ }
+
+ key->len += temp->privateData.len;
+ ret = mbedtls_pk_write_key_der(&ctx, key->data, key->len);
+ if (ret < 1) /* return value is the number of bytes written, or error */
+ {
+ mbedtls_pk_free(&ctx);
+ key->len = 0;
+ OIC_LOG_V(ERROR, TAG, "Key for %s found, but failed to convert from PEM to DER (while writing DER)", usage);
+ return;
+ }
+ key->data = OICRealloc(key->data, ret);
+ key->len = ret;
+ break;
+
+ }
+ else if(temp->privateData.encoding == OIC_ENCODING_DER)
+ {
+ key->data = OICRealloc(key->data, key->len + temp->privateData.len);
+ memcpy(key->data + key->len, temp->privateData.data, temp->privateData.len);
+ key->len += temp->privateData.len;
+ OIC_LOG_V(DEBUG, TAG, "Key for %s found", usage);
+ break;
+ }
+ else
+ {
+ OIC_LOG_V(WARNING, TAG, "Key for %s found, but it has an unknown encoding", usage);
+ }
}
}
if(0 == key->len)
}
case SIGNED_ASYMMETRIC_KEY:
{
- if (0 == strcmp(temp->credUsage, usage))
+ if (NULL != temp->credUsage && 0 == strcmp(temp->credUsage, usage))
{
list[1] = true;
OIC_LOG_V(DEBUG, TAG, "SIGNED_ASYMMETRIC_KEY found for %s", usage);
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/x509_csr.h"
+#include "mbedtls/oid.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/oid.h"
+#include "mbedtls/pem.h"
+#include "mbedtls/base64.h"
#ifndef NDEBUG
#include "mbedtls/debug.h"
return res;
}
+
+/* Verify the signature in a CSR is valid. */
+static int VerifyCSRSignature(mbedtls_x509_csr* csr)
+{
+ unsigned char hash[MBEDTLS_MD_MAX_SIZE];
+
+ if (csr->sig_md != MBEDTLS_MD_SHA256)
+ {
+ OIC_LOG(ERROR, TAG, "Unexpected digest used in CSR\n");
+ return -1;
+ }
+
+ if ((csr->cri.len == 0) || (csr->cri.p == NULL))
+ {
+ OIC_LOG(ERROR, TAG, "Missing CertificateRequestInfo field in CSR\n");
+ return -1;
+ }
+
+ if ((csr->sig.len == 0) || (csr->sig.p == NULL))
+ {
+ OIC_LOG(ERROR, TAG, "Missing signature field in CSR\n");
+ return -1;
+ }
+
+ if (MBEDTLS_OID_CMP(MBEDTLS_OID_ECDSA_SHA256, &csr->sig_oid) != 0)
+ {
+ char buf[256];
+ if (mbedtls_oid_get_numeric_string(buf, sizeof(buf), &csr->sig_oid) > 0)
+ {
+ OIC_LOG_V(ERROR, TAG, "Unexpected signature OID in CSR (got %s)\n", buf);
+ }
+ else
+ {
+ OIC_LOG(ERROR, TAG, "Unexpected signature OID in CSR\n");
+ }
+ return -1;
+ }
+
+ if (mbedtls_pk_get_type(&csr->pk) != MBEDTLS_PK_ECKEY)
+ {
+ OIC_LOG(ERROR, TAG, "Unexpected public key type in CSR\n");
+ return -1;
+ }
+
+ /* mbedtls_pk_get_bitlen returns the bit length of the curve */
+ if (mbedtls_pk_get_bitlen(&csr->pk) != 256)
+ {
+ OIC_LOG(ERROR, TAG, "Unexpected public length in CSR\n");
+ return -1;
+ }
+
+ mbedtls_ecp_keypair* ecKey = mbedtls_pk_ec(csr->pk);
+ if ((ecKey != NULL) && (ecKey->grp.id != MBEDTLS_ECP_DP_SECP256R1))
+ {
+ OIC_LOG(ERROR, TAG, "Unexpected curve parameters in CSR\n");
+ return -1;
+ }
+
+ /* Hash the CertificateRequestInfoField (https://tools.ietf.org/html/rfc2986#section-3) */
+ int ret = mbedtls_md(mbedtls_md_info_from_type(csr->sig_md), csr->cri.p, csr->cri.len, hash);
+ if (ret != 0)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to hash CertificateRequestInfoField\n");
+ return ret;
+ }
+
+ /* the length of hash is determined from csr->sig_md*/
+ ret = mbedtls_pk_verify(&csr->pk, csr->sig_md, hash, 0, csr->sig.p, csr->sig.len);
+
+ return ret;
+}
+
+OCStackResult OCVerifyCSRSignature(const char* csr)
+{
+ mbedtls_x509_csr csrObj;
+
+ mbedtls_x509_csr_init(&csrObj);
+ int ret = mbedtls_x509_csr_parse(&csrObj, (const unsigned char*)csr, strlen(csr) + 1);
+ if (ret < 0)
+ {
+ OIC_LOG_V(ERROR, TAG, "Couldn't parse CSR: %d", ret);
+ mbedtls_x509_csr_free(&csrObj);
+ return OC_STACK_ERROR;
+ }
+
+ ret = VerifyCSRSignature(&csrObj);
+
+ mbedtls_x509_csr_free(&csrObj);
+
+ if (ret != 0)
+ {
+ return OC_STACK_ERROR;
+ }
+
+ return OC_STACK_OK;
+}
+
+OCStackResult OCGetUuidFromCSR(const char* csr, OicUuid_t* uuid)
+{
+ mbedtls_x509_csr csrObj;
+
+ mbedtls_x509_csr_init(&csrObj);
+ int ret = mbedtls_x509_csr_parse(&csrObj, (const unsigned char*)csr, strlen(csr) + 1);
+ if (ret < 0)
+ {
+ OIC_LOG_V(ERROR, TAG, "Couldn't parse CSR: %d", ret);
+ mbedtls_x509_csr_free(&csrObj);
+ return OC_STACK_ERROR;
+ }
+
+ char uuidStr[UUID_STRING_SIZE + sizeof(SUBJECT_PREFIX) - 1] = { 0 }; // Both constants count NULL, subtract one
+ ret = mbedtls_x509_dn_gets(uuidStr, sizeof(uuidStr), &csrObj.subject);
+ if (ret != (sizeof(uuidStr) - 1))
+ {
+ OIC_LOG_V(ERROR, TAG, "mbedtls_x509_dn_gets returned length or error: %d, expected %d", ret, sizeof(uuidStr) - 1);
+ mbedtls_x509_csr_free(&csrObj);
+ return OC_STACK_ERROR;
+ }
+
+ if (!OCConvertStringToUuid(uuidStr + sizeof(SUBJECT_PREFIX) - 1, uuid->id))
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to convert UUID: '%s'", uuidStr);
+ mbedtls_x509_csr_free(&csrObj);
+ return OC_STACK_ERROR;
+ }
+
+ mbedtls_x509_csr_free(&csrObj);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCGetPublicKeyFromCSR(const char* csr, char** publicKey)
+{
+ mbedtls_x509_csr csrObj;
+
+ mbedtls_x509_csr_init(&csrObj);
+ int ret = mbedtls_x509_csr_parse(&csrObj, (const unsigned char*)csr, strlen(csr) + 1);
+ if (ret < 0)
+ {
+ OIC_LOG_V(ERROR, TAG, "Couldn't parse CSR: %d", ret);
+ mbedtls_x509_csr_free(&csrObj);
+ return OC_STACK_ERROR;
+ }
+
+ char subjectPublicKey[500] = { 0 };
+ ret = mbedtls_pk_write_pubkey_pem(&csrObj.pk, (unsigned char*)subjectPublicKey, sizeof(subjectPublicKey));
+ if (ret != 0)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to write subject public key as PEM: %d", ret);
+ mbedtls_x509_csr_free(&csrObj);
+ return OC_STACK_ERROR;
+ }
+
+ size_t pkLen = strlen(subjectPublicKey) + 1;
+ *publicKey = (char*) OICCalloc(1, pkLen);
+ if (*publicKey == NULL)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to allocate memory for public key");
+ mbedtls_x509_csr_free(&csrObj);
+ return OC_STACK_ERROR;
+ }
+
+ memcpy(*publicKey, subjectPublicKey, pkLen);
+ mbedtls_x509_csr_free(&csrObj);
+
+ return OC_STACK_OK;
+}
+
+OCStackResult OCConvertDerCSRToPem(const char* derCSR, size_t derCSRLen, char** pemCSR)
+{
+ const char* pemHeader = "-----BEGIN CERTIFICATE REQUEST-----\n";
+ const char* pemFooter = "-----END CERTIFICATE REQUEST-----\n";
+
+ /* Get the length required for output*/
+ size_t pemCSRLen;
+ int ret = mbedtls_pem_write_buffer(pemHeader,
+ pemFooter,
+ (const unsigned char*)derCSR,
+ derCSRLen,
+ NULL,
+ 0,
+ &pemCSRLen);
+ if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL)
+ {
+ OIC_LOG_V(ERROR, TAG, "Couldn't convert CSR into PEM, failed getting required length: %d", ret);
+ return OC_STACK_ERROR;
+ }
+
+ *pemCSR = OICCalloc(1, pemCSRLen + 1);
+ if (*pemCSR == NULL)
+ {
+ OIC_LOG(ERROR, TAG, "Failed to allocate memory for PEM CSR");
+ return OC_STACK_ERROR;
+ }
+
+ /* Try the conversion */
+ ret = mbedtls_pem_write_buffer(pemHeader, pemFooter,
+ (const unsigned char *)derCSR,
+ derCSRLen,
+ (unsigned char*) *pemCSR,
+ pemCSRLen,
+ &pemCSRLen);
+ if (ret < 0)
+ {
+ OIC_LOG_V(ERROR, TAG, "Couldn't convert CSR into PEM, failed getting required length: %d", ret);
+ OICFree(*pemCSR);
+ *pemCSR = NULL;
+ return OC_STACK_ERROR;
+ }
+
+ return OC_STACK_OK;
+}
+
#endif /* defined(__WITH_TLS__) || defined(__WITH_DTLS__) */
\ No newline at end of file
LoadSecretJustWorksCallback
OCConfigSelfOwnership
+OCConvertDerCSRToPem
OCDeleteACLList
OCDeleteDiscoveredDevices
OCDeletePdAclList
OCDiscoverSingleDevice
OCDiscoverUnownedDevices
OCDoOwnershipTransfer
-OCGenerateCACertificate
-OCGenerateIdentityCertificate
-OCGenerateKeyPair
-OCGenerateRandomSerialNumber
+OCGenerateCACertificate\r
+OCGenerateIdentityCertificate\r
+OCGenerateKeyPair\r
+OCGenerateRandomSerialNumber\r
OCGenerateRoleCertificate
OCGetACLResource
OCGetCredResource
OCGetCSRResource
OCGetDevInfoFromNetwork
OCGetLinkedStatus
+OCGetPublicKeyFromCSR
+OCGetUuidFromCSR
OCInitPM
OCProvisionACL
OCSaveACL
+OCProvisionCertificate
OCProvisionCredentials
OCProvisionDirectPairing
OCProvisionPairwiseDevices
OCResetDevice
OCResetSVRDB
OCSaveTrustCertChain
+OCSaveOwnCertChain
OCSetOwnerTransferCallbackData
OCUnlinkDevices
OCSetOxmAllowStatus
+OCVerifyCSRSignature
SetClosePinDisplayCB
SetDisplayPinWithContextCB