azurerestazure-iot-dps

Group enrollment in Azure Device Provisoning Service (DPS) not working through REST API: unauthorized 401002


I am trying to support DPS for my ESP32 firmware through HTTPS REST API using SAS.

My device registration ID is: xx-xx-8c4b14149ff4

I took the group enrollment from DPS primary key to generate the symmetric key from the registration ID.

I created the related SAS from that and forged the request, but the server returns "Unauthorized" with error code being 401002.

Here is my request (a curl version is provided for handiness ):

curl -L -i -X PUT \
-H 'Content-Type: application/json' \
-H 'Content-Encoding: utf-8' \
-H 'Authorization: SharedAccessSignature sr=0neXXXXXX22%2Fregistrations%xx-xx-8c4b14149ff4&sig=XXXXXXXXXXXXXXXXXXX%3D&skn=registration&se=1651482003' \
-d '{"registrationId": "xx-xx-8c4b14149ff4"}' \
https://global.azure-devices-provisioning.net/0neXXXXXX22/registrations/xx-xx-8c4b14149ff4/register?api-version=2021-06-01

Note that I replaced secret information with "xx".

The response body is as follows:

{
    "errorCode": 401002,
    "trackingId": "9fecada7-4e51-455e-9392-68522654a64a",
    "message": "Unauthorized",
    "timestampUtc": "2022-05-02T08:04:03.5761437Z"
}

Is there anything I must tweak to use the HTTPS REST API from the portal?

What should I look at beside the information themselves (which I already double-checked)?

References:


Solution

  • Actually my signature code had a small bug. I fixed it and now it works.

    Here is the (working) code for signing:

    #include <mbedtls/md.h>         // mbed tls lib used to sign SHA-256
    
    #include <base64.hpp>           // Densaugeo Base64 version 1.2.0 or 1.2.1
    
    
    /// Returns the SHA-256 signature of [dataToSign] with the key [enrollmentPrimaryKey]
    /// params[in]: dataToSign The data to sign (for our purpose, it is the registration ID (or the device ID if it is different)
    /// params[in]: enrollmentPrimaryKey The group enrollment primary key.
    /// returns The SHA-256 base-64 signature to present to DPS.
    /// Note: I use mbed to SHA-256 sign.
    String Sha256Sign(String dataToSign, String enrollmentPrimaryKey){
      /// Length of the dataToSign string
      const unsigned dataToSignLength = dataToSign.length();
      /// Buffer to hold the dataToSign as a char[] buffer from String.
      char dataToSignChar[dataToSignLength + 1];
      /// String to c-style string (char[])
      dataToSign.toCharArray(dataToSignChar, dataToSignLength + 1);
    
      /// The binary decoded key (from the base 64 definition)
      unsigned char decodedPSK[32];
    
      /// Encrypted binary signature
      unsigned char encryptedSignature[32];
    
      /// Base 64 encoded signature
      unsigned char encodedSignature[100];
      
      Serial.printf("Sha256Sign(): Registration Id to sign is: (%d bytes) %s\n", dataToSignLength, dataToSignChar);
      Serial.printf("Sha256Sign(): DPS group enrollment primary key is: (%d bytes) %s\n", enrollmentPrimaryKey.length(), enrollmentPrimaryKey.c_str());
    
    
      // Need to base64 decode the Preshared key and the length
      const unsigned base64DecodedDeviceLength = decode_base64((unsigned char*)enrollmentPrimaryKey.c_str(), decodedPSK);
      Serial.printf("Sha256Sign(): Decoded primary key is: (%d bytes) ", base64DecodedDeviceLength);
    
      for(int i= 0; i<base64DecodedDeviceLength; i++) {
        Serial.printf("%02x ", (int)decodedPSK[i]);
      }
      Serial.println();
      
      // Use mbed to sign
      mbedtls_md_type_t mdType = MBEDTLS_MD_SHA256;
      mbedtls_md_context_t hmacKeyContext;    
    
      mbedtls_md_init(&hmacKeyContext);
      mbedtls_md_setup(&hmacKeyContext, mbedtls_md_info_from_type(mdType), 1);
      mbedtls_md_hmac_starts(&hmacKeyContext, (const unsigned char *) decodedPSK, base64DecodedDeviceLength);
      mbedtls_md_hmac_update(&hmacKeyContext, (const unsigned char *) dataToSignChar, dataToSignLength);
      mbedtls_md_hmac_finish(&hmacKeyContext, encryptedSignature);
      mbedtls_md_free(&hmacKeyContext);
      
      Serial.print("Sha256Sign(): Computed hash is: ");
    
      for(int i= 0; i<sizeof(encryptedSignature); i++) {
        Serial.printf("%02x ", (int)encryptedSignature[i]);
      }
      Serial.println();
      // base64 decode the HMAC to a char
      encode_base64(encryptedSignature, sizeof(encryptedSignature), encodedSignature);
    
      Serial.printf("Sha256Sign(): Computed hash as base64: %s\n", encodedSignature);
    
      // creating the real SAS Token
      return String((char*)encodedSignature);
    }
    

    See it there: How to generate a symmetric key in C or C++ the same way this script does?