Skip to content

Commit

Permalink
Add support for DPS symmetric key attestation (#767)
Browse files Browse the repository at this point in the history
Summary: The changes here implement the client code needed to register with DPS in order for DPS to resolve the Edge device to the configured IoT Hub. More about this capability in DPS can be learned here: https://docs.microsoft.com/en-us/azure/iot-dps/quick-create-simulated-device-symm-key

Overall the changes deal with parsing the config.yaml to obtain the device's symmetric key and an attestation test is performed with DPS using a SAS token. The changes are primarily relegated to the dps and provisioning crates and come along with tests.

**Note:** While the feature implementation is done via this PR, it should be noted that the DPS service has not enabled provisioning devices with Edge capabilities. As a result, best effort testing has taken place and it was observed that the device that DPS registration at the destination IoT Hub took place but it did not have the Edge capability enabled. A true E2E test can take place when DPS enables this in the service.
  • Loading branch information
mrohera committed Feb 6, 2019
1 parent 925b1fb commit b7adfff
Show file tree
Hide file tree
Showing 17 changed files with 773 additions and 117 deletions.
1 change: 1 addition & 0 deletions edgelet/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions edgelet/contrib/config/linux/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
# manual - using an iothub connection string
# dps - using dps for provisioning
#
# DPS Settings
# scope_id - Required. Value of a specific DPS instance's ID scope
# registration_id - Required. Registration ID of a specific device in DPS
# symmetric_key - Optional. This entry should only be specified when
# provisioning devices configured for symmetric key
# attestation
###############################################################################

provisioning:
Expand All @@ -30,6 +36,7 @@ provisioning:
# global_endpoint: "https://global.azure-devices-provisioning.net"
# scope_id: "{scope_id}"
# registration_id: "{registration_id}"
# symmetric_key: "{symmetric_key}"

###############################################################################
# Certificate settings
Expand Down
7 changes: 7 additions & 0 deletions edgelet/contrib/config/linux/debian/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
# manual - using an iothub connection string
# dps - using dps for provisioning
#
# DPS Settings
# scope_id - Required. Value of a specific DPS instance's ID scope
# registration_id - Required. Registration ID of a specific device in DPS
# symmetric_key - Optional. This entry should only be specified when
# provisioning devices configured for symmetric key
# attestation
###############################################################################

provisioning:
Expand All @@ -30,6 +36,7 @@ provisioning:
# global_endpoint: "https://global.azure-devices-provisioning.net"
# scope_id: "{scope_id}"
# registration_id: "{registration_id}"
# symmetric_key: "{symmetric_key}"

###############################################################################
# Certificate settings
Expand Down
7 changes: 7 additions & 0 deletions edgelet/contrib/config/windows/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
# manual - using an iothub connection string
# dps - using dps for provisioning
#
# DPS Settings
# scope_id - Required. Value of a specific DPS instance's ID scope
# registration_id - Required. Registration ID of a specific device in DPS
# symmetric_key - Optional. This entry should only be specified when
# provisioning devices configured for symmetric key
# attestation
###############################################################################

provisioning:
Expand All @@ -30,6 +36,7 @@ provisioning:
# global_endpoint: "https://global.azure-devices-provisioning.net"
# scope_id: "{scope_id}"
# registration_id: "{registration_id}"
# symmetric_key: "{symmetric_key}"

###############################################################################
# Certificate settings
Expand Down
3 changes: 3 additions & 0 deletions edgelet/dps/src/dps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Copyright (c) Microsoft. All rights reserved.

pub const DPS_API_VERSION: &str = "2018-11-01";
15 changes: 12 additions & 3 deletions edgelet/dps/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ pub enum ErrorKind {
#[fail(display = "Could not get operation status")]
GetOperationStatus,

#[fail(display = "Could not get symmetric key attestation operation status")]
GetOperationStatusForSymmetricKey,

#[fail(display = "Could not get symmetric challenge key")]
GetSymmetricChallengeKey,

#[fail(display = "Could not get token")]
GetToken,

Expand All @@ -32,14 +38,17 @@ pub enum ErrorKind {
#[fail(display = "Could not get TPM challenge key because the TPM token is invalid")]
InvalidTpmToken,

#[fail(display = "DPS registration succeeded but returned an empty response")]
RegisterWithAuthUnexpectedlySucceeded,

#[fail(display = "DPS registration failed")]
RegisterWithAuthUnexpectedlyFailed,

#[fail(display = "DPS registration failed because the DPS operation is not assigned")]
RegisterWithAuthUnexpectedlyFailedOperationNotAssigned,

#[fail(display = "DPS registration succeeded but returned an empty response")]
RegisterWithAuthUnexpectedlySucceeded,

#[fail(display = "Symmetric key registration failed")]
RegisterWithSymmetricChallengeKey,
}

impl Fail for Error {
Expand Down
3 changes: 3 additions & 0 deletions edgelet/dps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ extern crate url;
extern crate edgelet_core;
extern crate edgelet_http;

pub mod dps;
pub mod error;
mod model;
pub mod registration;
Expand All @@ -35,3 +36,5 @@ pub use model::{
TpmRegistrationResult,
};
pub use registration::{DpsClient, DpsTokenSource};

pub const DPS_API_VERSION: &str = "2018-11-01";
147 changes: 126 additions & 21 deletions edgelet/dps/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Copyright (c) Microsoft. All rights reserved.

/*
* DeviceProvisioningService_DeviceRuntimeClient
* ProvisioningDeviceClient
*
* API for device runtime operations with the Azure IotHub Device Provisioning Service
* API for device runtime operations with the Azure IoT Hub Device Provisioning Service
*
* OpenAPI spec version: 2017-11-15
* OpenAPI spec version: 2018-11-01
*
* Generated by: https://github.com/swagger-api/swagger-codegen.git
*/
Expand Down Expand Up @@ -165,6 +165,46 @@ impl Default for TpmRegistrationResult {
}
}

/// [`SymmetricKeyRegistrationResult`] : Registration result returned when using `SymmetricKey` attestation

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SymmetricKeyRegistrationResult {
#[serde(rename = "enrollmentGroupId")]
enrollment_group_id: Option<String>,
}

impl SymmetricKeyRegistrationResult {
/// Registration result returned when using SymmetricKey attestation
pub fn new() -> SymmetricKeyRegistrationResult {
SymmetricKeyRegistrationResult {
enrollment_group_id: None,
}
}

pub fn set_enrollment_group_id(&mut self, enrollment_group_id: String) {
self.enrollment_group_id = Some(enrollment_group_id);
}

pub fn with_enrollment_group_id(mut self, enrollment_group_id: String) -> Self {
self.enrollment_group_id = Some(enrollment_group_id);
self
}

pub fn enrollment_group_id(&self) -> Option<&str> {
self.enrollment_group_id.as_ref().map(AsRef::as_ref)
}

pub fn reset_enrollment_group_id(&mut self) {
self.enrollment_group_id = None;
}
}

impl Default for SymmetricKeyRegistrationResult {
fn default() -> Self {
SymmetricKeyRegistrationResult::new()
}
}

/// [`RegistrationOperationStatus`] : Registration operation status.

#[derive(Debug, Serialize, Deserialize, Clone)]
Expand Down Expand Up @@ -238,17 +278,22 @@ impl RegistrationOperationStatus {
}
}

/// [`DeviceRegistrationResult`] : Device registration result.

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct DeviceRegistrationResult {
/// TPM registration result.
/// Registration result returned when using TPM attestation
#[serde(rename = "tpm", skip_serializing_if = "Option::is_none")]
tpm: Option<TpmRegistrationResult>,
/// X509 registration result.
/// Registration result returned when using X509 attestation
#[serde(skip_deserializing)]
x509: Option<String>,
/// Registration ID.
#[serde(rename = "registrationId")]
registration_id: String,
/// Registration result returned when using SymmetricKey attestation
#[serde(rename = "symmetricKey", skip_serializing_if = "Option::is_none")]
symmetric_key: Option<SymmetricKeyRegistrationResult>,
/// The registration ID is alphanumeric, lowercase, and may contain hyphens.
#[serde(rename = "registrationId", skip_serializing_if = "Option::is_none")]
registration_id: Option<String>,
/// Registration create date time (in UTC).
#[serde(rename = "createdDateTimeUtc", skip_serializing_if = "Option::is_none")]
created_date_time_utc: Option<String>,
Expand All @@ -259,8 +304,18 @@ pub struct DeviceRegistrationResult {
#[serde(rename = "deviceId", skip_serializing_if = "Option::is_none")]
device_id: Option<String>,
/// Enrollment status.
#[serde(rename = "status")]
status: String,
#[serde(rename = "status", skip_serializing_if = "Option::is_none")]
status: Option<String>,
/// Substatus for 'Assigned' devices. Possible values include -
/// 'initialAssignment': Device has been assigned to an IoT hub for the first time,
/// 'deviceDataMigrated': Device has been assigned to a different IoT hub and its
/// device data was migrated from the previously assigned IoT hub.
/// Device data was removed from the previously assigned IoT hub,
/// 'deviceDataReset': Device has been assigned to a different IoT hub and its device
/// data was populated from the initial state stored in the enrollment.
/// Device data was removed from the previously assigned IoT hub.
#[serde(rename = "substatus", skip_serializing_if = "Option::is_none")]
substatus: Option<String>,
/// Error code.
#[serde(rename = "errorCode", skip_serializing_if = "Option::is_none")]
error_code: Option<i32>,
Expand All @@ -280,15 +335,17 @@ pub struct DeviceRegistrationResult {

impl DeviceRegistrationResult {
/// Device registration result.
pub fn new(registration_id: String, status: String) -> Self {
pub fn new() -> Self {
DeviceRegistrationResult {
tpm: None,
x509: None,
registration_id,
symmetric_key: None,
registration_id: None,
created_date_time_utc: None,
assigned_hub: None,
device_id: None,
status,
status: None,
substatus: None,
error_code: None,
error_message: None,
last_updated_date_time_utc: None,
Expand All @@ -313,17 +370,38 @@ impl DeviceRegistrationResult {
self.tpm = None;
}

pub fn set_symmetric_key(&mut self, symmetric_key: SymmetricKeyRegistrationResult) {
self.symmetric_key = Some(symmetric_key);
}

pub fn with_symmetric_key(mut self, symmetric_key: SymmetricKeyRegistrationResult) -> Self {
self.symmetric_key = Some(symmetric_key);
self
}

pub fn symmetric_key(&self) -> Option<&SymmetricKeyRegistrationResult> {
self.symmetric_key.as_ref()
}

pub fn reset_symmetric_key(&mut self) {
self.symmetric_key = None;
}

pub fn set_registration_id(&mut self, registration_id: String) {
self.registration_id = registration_id;
self.registration_id = Some(registration_id);
}

pub fn with_registration_id(mut self, registration_id: String) -> Self {
self.registration_id = registration_id;
self.registration_id = Some(registration_id);
self
}

pub fn registration_id(&self) -> &String {
&self.registration_id
pub fn registration_id(&self) -> Option<&str> {
self.registration_id.as_ref().map(AsRef::as_ref)
}

pub fn reset_registration_id(&mut self) {
self.registration_id = None;
}

pub fn set_created_date_time_utc(&mut self, created_date_time_utc: String) {
Expand Down Expand Up @@ -378,16 +456,37 @@ impl DeviceRegistrationResult {
}

pub fn set_status(&mut self, status: String) {
self.status = status;
self.status = Some(status);
}

pub fn with_status(mut self, status: String) -> Self {
self.status = status;
self.status = Some(status);
self
}

pub fn status(&self) -> Option<&str> {
self.status.as_ref().map(AsRef::as_ref)
}

pub fn reset_status(&mut self) {
self.status = None;
}

pub fn set_substatus(&mut self, substatus: String) {
self.substatus = Some(substatus);
}

pub fn with_substatus(mut self, substatus: String) -> Self {
self.substatus = Some(substatus);
self
}

pub fn status(&self) -> &String {
&self.status
pub fn substatus(&self) -> Option<&str> {
self.substatus.as_ref().map(AsRef::as_ref)
}

pub fn reset_substatus(&mut self) {
self.substatus = None;
}

pub fn set_error_code(&mut self, error_code: i32) {
Expand Down Expand Up @@ -458,3 +557,9 @@ impl DeviceRegistrationResult {
self.etag = None;
}
}

impl Default for DeviceRegistrationResult {
fn default() -> Self {
DeviceRegistrationResult::new()
}
}
Loading

0 comments on commit b7adfff

Please sign in to comment.