Skip to content

Commit

Permalink
Merge pull request aws#10 from aws/feat/add-token-support-and-update-…
Browse files Browse the repository at this point in the history
…error-parsing

Update Foundry SDK to support token-based authentication for provisioning device with new requesred certificate. Also, parse client ID parameter provided by Foundry service after successful provisioning
  • Loading branch information
aggarw13 authored Nov 15, 2019
2 parents f1db49a + 3dbf4c9 commit 0fdb56f
Show file tree
Hide file tree
Showing 11 changed files with 711 additions and 188 deletions.
88 changes: 65 additions & 23 deletions demos/src/aws_iot_demo_onboarding.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,17 @@
#define NUM_OF_PROVISIONING_PARAMS 1u

/**
* @brief Type for the callback context for the #AwsIotOnboarding_GetDeviceCredentials API.
* It will be used for storing the received Certificate ID string that will be provided in the callback.
* @brief Type for the context parameter for the #AwsIotOnboarding_DeviceCredentialsCallbackInfo_t callback.
* It will be used for storing the received Certificate ID and the ownership token data received from the server through
* the callback, so that can be used for provisioning the demo application.
*/
typedef struct _demoProvisionDeviceCallbackContext
typedef struct _demoDeviceCredentialsCallbackContext
{
char * pCertificateIdBuffer;
size_t certificateIdLength;
} _demoProvisionDeviceCallbackContext_t;
char * pCertificateOwnershipToken;
size_t tokenLength;
} _demoDeviceCredentialsCallbackContext_t;

/*-----------------------------------------------------------*/

Expand All @@ -125,7 +128,7 @@ static void _printRejectedResponse( const AwsIotOnboardingRejectedResponse_t * p

/**
* @brief Callback for displaying the credentials sent by the server (if server is successful), and
* copying the Certificate ID data obtained from the server issued with the new device credentials.
* copying the Certificate ID and ownership token data obtained from the server issued with the new device credentials.
*
* @param[in] contextParam The context of the callback containing buffers to copy the credentials to.
* @param[in] pResponseInfo The device credentials information obtained from the server that will be copied into the
Expand All @@ -134,35 +137,56 @@ static void _printRejectedResponse( const AwsIotOnboardingRejectedResponse_t * p
static void _demoDeviceCredentialsCallback( void * contextParam,
const AwsIotOnboardingGetDeviceCredentialsResponse_t * pResponseInfo )
{
_demoProvisionDeviceCallbackContext_t * certificateIdContext = ( _demoProvisionDeviceCallbackContext_t * ) contextParam;
_demoDeviceCredentialsCallbackContext_t * certificateIdTokenContext =
( _demoDeviceCredentialsCallbackContext_t * ) contextParam;

IotLogInfo( "Received StatusCode={%d}", pResponseInfo->statusCode );

if( pResponseInfo->statusCode == AWS_IOT_ONBOARDING_SERVER_STATUS_ACCEPTED )
{
/* Allocate buffer space for storing the certificate ID obtained from the server. */
certificateIdContext->pCertificateIdBuffer = Iot_DefaultMalloc( pResponseInfo->u.acceptedResponse.certificateIdLength + 1 );
certificateIdTokenContext->pCertificateIdBuffer =
Iot_DefaultMalloc( pResponseInfo->u.acceptedResponse.certificateIdLength + 1 );

/* Copy the certificate ID into the buffer. */
if( certificateIdContext->pCertificateIdBuffer != NULL )
if( certificateIdTokenContext->pCertificateIdBuffer != NULL )
{
/* Copy the size of the Certificate ID string. */
certificateIdContext->certificateIdLength = pResponseInfo->u.acceptedResponse.certificateIdLength;
certificateIdTokenContext->certificateIdLength = pResponseInfo->u.acceptedResponse.certificateIdLength;

memcpy( certificateIdContext->pCertificateIdBuffer,
memcpy( certificateIdTokenContext->pCertificateIdBuffer,
pResponseInfo->u.acceptedResponse.pCertificateId,
pResponseInfo->u.acceptedResponse.certificateIdLength );
/* Add a NULL terminator to the buffer (to treat the buffer as a string!) */
*( certificateIdContext->pCertificateIdBuffer + pResponseInfo->u.acceptedResponse.certificateIdLength ) = '\0';
*( certificateIdTokenContext->pCertificateIdBuffer + pResponseInfo->u.acceptedResponse.certificateIdLength ) = '\0';
}

/* Print the certificate Pem and private key data received. This is ONLY for the demo purpose, STORE THE
/* Allocate buffer space for storing the ownership token string obtained from the server. */
certificateIdTokenContext->pCertificateOwnershipToken =
Iot_DefaultMalloc( pResponseInfo->u.acceptedResponse.ownershipTokenLength + 1 );

/* Copy the ownership token into the buffer. */
if( certificateIdTokenContext->pCertificateOwnershipToken != NULL )
{
/* Copy the size of the ownership token string. */
certificateIdTokenContext->tokenLength = pResponseInfo->u.acceptedResponse.ownershipTokenLength;

memcpy( certificateIdTokenContext->pCertificateOwnershipToken,
pResponseInfo->u.acceptedResponse.pCertificateOwnershipToken,
pResponseInfo->u.acceptedResponse.ownershipTokenLength );
/* Add a NULL terminator to the buffer (to treat the buffer as a string!) */
*( certificateIdTokenContext->pCertificateOwnershipToken + pResponseInfo->u.acceptedResponse.ownershipTokenLength ) = '\0';
}

/* Print the received credentials information. This is ONLY for the demonstration purpose, STORE THE
* PRIVATE KEY SECURELY! */
IotLogInfo( "\n Certificate PEM = %.*s \n Certificate ID = %.*s \n DREADED PRIVATE KEY = %.*s \n",
IotLogInfo( "\n Certificate PEM = %.*s\n Certificate ID = %.*s\n Ownership Token = %.*s\n DREADED PRIVATE KEY = %.*s\n",
pResponseInfo->u.acceptedResponse.deviceCertificateLength,
pResponseInfo->u.acceptedResponse.pDeviceCertificate,
pResponseInfo->u.acceptedResponse.certificateIdLength,
pResponseInfo->u.acceptedResponse.pCertificateId,
pResponseInfo->u.acceptedResponse.ownershipTokenLength,
pResponseInfo->u.acceptedResponse.pCertificateOwnershipToken,
pResponseInfo->u.acceptedResponse.privateKeyLength,
pResponseInfo->u.acceptedResponse.pPrivateKey );
}
Expand Down Expand Up @@ -190,6 +214,13 @@ static void _demoOnboardDeviceCallback( void * contextParam,

if( pResponseInfo->statusCode == AWS_IOT_ONBOARDING_SERVER_STATUS_ACCEPTED )
{
if( pResponseInfo->u.acceptedResponse.pClientId != NULL )
{
IotLogInfo( "ClientID = %.*s",
pResponseInfo->u.acceptedResponse.clientIdLength,
pResponseInfo->u.acceptedResponse.pClientId );
}

if( pResponseInfo->u.acceptedResponse.pThingName != NULL )
{
IotLogInfo( "ThingName = %.*s",
Expand Down Expand Up @@ -379,10 +410,12 @@ int RunOnboardingDemo( bool awsIotMqttMode,

/* Represents memory that will be allocated to store the Certificate ID that will be provided by the credential
* requesting API through the callback. */
_demoProvisionDeviceCallbackContext_t newCertificateIdDataContext;
_demoDeviceCredentialsCallbackContext_t newCertificateDataContext;

newCertificateIdDataContext.pCertificateIdBuffer = NULL;
newCertificateIdDataContext.certificateIdLength = 0;
newCertificateDataContext.pCertificateIdBuffer = NULL;
newCertificateDataContext.certificateIdLength = 0;
newCertificateDataContext.pCertificateOwnershipToken = NULL;
newCertificateDataContext.tokenLength = 0;

/* Request data for onboarding the demo application. */
AwsIotOnboardingOnboardDeviceRequestInfo_t requestInfo;
Expand Down Expand Up @@ -445,7 +478,7 @@ int RunOnboardingDemo( bool awsIotMqttMode,
connectionEstablished = true;

/* Set the certificate ID pointer as context parameter to the credentials response processing callback. */
deviceCredentialsCallback.userParam = &newCertificateIdDataContext;
deviceCredentialsCallback.userParam = &newCertificateDataContext;

/* Set the callback function for handling device credentials that the server will send. */
deviceCredentialsCallback.function = _demoDeviceCredentialsCallback;
Expand All @@ -463,9 +496,10 @@ int RunOnboardingDemo( bool awsIotMqttMode,
IotLogError( "Request to get new credentials failed, error %s ",
AwsIotOnboarding_strerror( requestStatus ) );
}
else if( newCertificateIdDataContext.pCertificateIdBuffer == NULL )
else if( ( newCertificateDataContext.pCertificateIdBuffer == NULL ) ||
( newCertificateDataContext.pCertificateOwnershipToken == NULL ) )
{
IotLogInfo( "Don 't have the Certificate ID to proceed for onboarding. So exiting...!" );
IotLogInfo( "Don't have either the Certificate ID OR the Certificate Ownership Token (or both) to proceed with provisioning. So exiting...!" );
}
else
{
Expand All @@ -476,8 +510,10 @@ int RunOnboardingDemo( bool awsIotMqttMode,
if( status == EXIT_SUCCESS )
{
/* Set the parameters for requesting onboarding. */
requestInfo.pDeviceCertificateId = newCertificateIdDataContext.pCertificateIdBuffer;
requestInfo.deviceCertificateIdLength = newCertificateIdDataContext.certificateIdLength;
requestInfo.pDeviceCertificateId = newCertificateDataContext.pCertificateIdBuffer;
requestInfo.deviceCertificateIdLength = newCertificateDataContext.certificateIdLength;
requestInfo.pCertificateOwnershipToken = newCertificateDataContext.pCertificateOwnershipToken;
requestInfo.ownershipTokenLength = newCertificateDataContext.tokenLength;
requestInfo.pTemplateName = PROVISIONING_TEMPLATE_NAME;
requestInfo.templateNameLength = sizeof( PROVISIONING_TEMPLATE_NAME ) - 1;
requestInfo.pParametersStart = &provisioningParameters;
Expand Down Expand Up @@ -518,9 +554,15 @@ int RunOnboardingDemo( bool awsIotMqttMode,
}

/* Release the Certificate ID buffer, if memory was allocated for it. */
if( newCertificateIdDataContext.pCertificateIdBuffer != NULL )
if( newCertificateDataContext.pCertificateIdBuffer != NULL )
{
Iot_DefaultFree( newCertificateDataContext.pCertificateIdBuffer );
}

/* Release the ownership token buffer, if memory was allocated for it. */
if( newCertificateDataContext.pCertificateOwnershipToken != NULL )
{
Iot_DefaultFree( newCertificateIdDataContext.pCertificateIdBuffer );
Iot_DefaultFree( newCertificateDataContext.pCertificateOwnershipToken );
}

return status;
Expand Down
48 changes: 34 additions & 14 deletions libraries/aws/onboarding/include/types/aws_iot_onboarding_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,17 @@ typedef struct AwsIotOnboardingOnboardDeviceRequestInfo
*/
size_t deviceCertificateIdLength;

/**
* @brief The ownership token for the certificate being requested for provisioning the device with.
* This token should have been issued by AWS IoT for the same certificate ID being passed.
*/
const char * pCertificateOwnershipToken;

/**
* @brief The length of the ownership token string.
*/
size_t ownershipTokenLength;

/**
* @brief The list of parameter entries to send to the server for onboarding the device.
*/
Expand Down Expand Up @@ -281,8 +292,8 @@ typedef struct AwsIotOnboardingRejectedResponse

/**
* @ingroup onboarding_datatypes_paramstructs
* @brief Parameter that encapsulates the server response to the callback function for the
* #AwsIotOnboarding_GetDeviceCredentials API.
* @brief Encapsulates the server response data sent for the request to generate new key-pair and
* certificate for the device.
*
* @paramfor Onboarding server accepted response callback functions
*
Expand All @@ -299,14 +310,17 @@ typedef struct AwsIotOnboardingGetDeviceCredentialsResponse
/* Represents the successful/accepted response of device credentials received from the server. */
struct
{
const char * pDeviceCertificate; /**< The new certificate for the device.*/
size_t deviceCertificateLength; /**< The size of the device certificate.*/
const char * pCertificateId; /**< The certificate ID associated with the new certificate,
* @p pDeviceCertificate.*/
size_t certificateIdLength; /**< The length of the certificate ID.*/
const char * pPrivateKey; /**< The private key associated with the new certificate,
* @p pDeviceCertificate.*/
size_t privateKeyLength; /**< The size of the private key.*/
const char * pDeviceCertificate; /**< The new certificate for the device.*/
size_t deviceCertificateLength; /**< The size of the device certificate.*/
const char * pCertificateId; /**< The certificate ID associated with the new certificate,
* @p pDeviceCertificate.*/
size_t certificateIdLength; /**< The length of the certificate ID.*/
const char * pPrivateKey; /**< The private key associated with the new certificate,
* @p pDeviceCertificate.*/
size_t privateKeyLength; /**< The size of the private key.*/
const char * pCertificateOwnershipToken; /**< The token that represents ownership of certificate and
* associated private key that the device.*/
size_t ownershipTokenLength; /**< The size of the ownership token.*/
} acceptedResponse;

/* Represents the rejected response information received from the server. */
Expand Down Expand Up @@ -348,13 +362,13 @@ typedef struct AwsIotOnboardingGetDeviceCredentialsCallbackInfo

/**
* @ingroup onboarding_datatypes_paramstructs
* @brief Parameter that encapsulates the server response to the callback function for the
* #AwsIotOnboarding_OnboardDevice API.
* @brief Encpasulates the server response data sent for the request to provision device with an AWS IoT issued
* certificate.
*
* @paramfor Onboarding server accepted response callback functions
*
* The #AwsIotOnboarding_OnboardDevice library API passes this object to a user-provided callback function whenever
* the operation completes with a response from the server.
* The #AwsIotOnboarding_OnboardDevice library API passes this object as a parameter to a user-provided callback
* function whenever the operation completes with a response from the server.
*/
typedef struct AwsIotOnboardingOnboardDeviceResponse
{
Expand All @@ -372,6 +386,12 @@ typedef struct AwsIotOnboardingOnboardDeviceResponse
/**< The length of the Thing resource name. */
size_t thingNameLength;

/**< The client ID used in the connection to the AWS IoT server for provisioning the device.*/
const char * pClientId;

/**< The length of the client ID text. */
size_t clientIdLength;

/**< A list of device configuration data that is received from the server. */
const AwsIotOnboardingResponseDeviceConfigurationEntry_t * pDeviceConfigList;

Expand Down
8 changes: 8 additions & 0 deletions libraries/aws/onboarding/src/aws_iot_onboarding_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,14 @@ AwsIotOnboardingError_t AwsIotOnboarding_OnboardDevice( IotMqttConnection_t onbo
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_ONBOARDING_BAD_PARAMETER );
}

if( ( pRequestData->pCertificateOwnershipToken == NULL ) ||
( pRequestData->ownershipTokenLength == 0 ) )
{
IotLogError( "Invalid certificate ownership token data passed for device onboarding request." );

IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_ONBOARDING_BAD_PARAMETER );
}

/* Check that the provided template name is valid. */
if( ( pRequestData->pTemplateName == NULL ) ||
( pRequestData->templateNameLength == 0 ) ||
Expand Down
Loading

0 comments on commit 0fdb56f

Please sign in to comment.