This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC3235SF: Generating ES256 Signature on CC3235SF

Part Number: CC3235SF
Other Parts Discussed in Thread: UNIFLASH

Hi,

I would like to generate an ES256 signature on the CC3235SF.  I have read this post here:

I would like to utilize the 0'th pre-programmed constant private ECC key to do so.  I have verified that my SHA256 is valid.  Is there somethign I am missing:

uint16_t ecc_signature_length = 0;

SlNetUtilCryptoCmdSignAttrib_t signAttrib;

uint8_t sha256_hash[32];
uint8_t ecc_buffer[512];

/* init crypto for SHA256 hashing of b64url(header).b64url(payload) */
memset(&hmac_params, 0, sizeof(CryptoCC32XX_HmacParams));

if (cryptoCC32XX_handle == NULL)
{
    CryptoCC32XX_init();
    cryptoCC32XX_handle = CryptoCC32XX_open(0, CryptoCC32XX_HMAC);
}

/* clear hash memory */
memset(&sha256_hash[0], 0, sizeof(sha256_hash));
CryptoCC32XX_HmacParams_init(&hmac_params);

hmac_params.moreData = 0;
/* generate the hash */
CryptoCC32XX_sign(cryptoCC32XX_handle,
                  CryptoCC32XX_HMAC_SHA256,
                  &encoded_header_and_encoded_payload[0],
                  strlen(&encoded_header_and_encoded_payload[0]),
                  &sha256_hash[0],
                  &hmac_params);

/* calculate ecc signature of hash */
signAttrib.Flags = 0;
signAttrib.ObjId = 0;
signAttrib.SigType = SL_NETUTIL_CRYPTO_SIG_SHA256wECDSA;
ecc_signature_length = 255;

memset(&ecc_buffer[0], 0, sizeof(ecc_buffer));

sl_NetUtilCmd(SL_NETUTIL_CRYPTO_CMD_SIGN_MSG,
              (uint8_t *)&signAttrib,
              sizeof(SlNetUtilCryptoCmdSignAttrib_t),
              &sha256_hash[0],
              sizeof(sha256_hash),
              &ecc_buffer[0],
              &ecc_signature_length);

  • The sl_NetUtilCmd(SL_NETUTIL_CRYPTO_CMD_SIGN_MSG,...) works on the original buffer (rather than on the digest).

    The NetUtil command calculates the digest (using SHA2) before signing it with EC.

    Br,

    Kobi

  • Hi Kobi,

    Thanks for the reply!  Ultimately, this is for use with a JWT to connect to Google's MQTT platform.  I have a couple questions while I continue working on this in tandem:

    Since we're using the ECC key pair from silicon, I have written code to extract the x9.63 public ECC key to the host.  This key is then converted to a public.pem format, and placed on Google's Cloud Platform for that specific device.  Is this feasible?

    Secondly, would you mind briefly looking at my code to see if I am creating the signature correctly?

    /*
     * This file was based on source code from Google's IOT Core SDK.
     */

    #include <stdio.h>
    #include <string.h>
    #include <stdbool.h>
    #include <stdint.h>
    /* TI-DRIVERS Header files */
    #include <ti/drivers/net/wifi/simplelink.h>
    #include <ti/drivers/net/wifi/netutil.h>
    #include <net/utils/str_mpl.h>

    #include "jwt.h"

    #define JWT_HEADER_BUF_SIZE     40
    #define JWT_PAYLOAD_BUF_SIZE    256
    #define JWT_MAX_SIGNATURE_SIZE  132
    #define JWT_PROJECTID_MAX_LEN   200

    static char jwt[256];

    static void jwt_url_base64_encode_buffer(uint8_t* data_to_encode,
                                             size_t data_to_encode_size,
                                             char* encoded_data_destination,
                                             size_t* encoded_data_size)
    {
        *encoded_data_size = sizeof(jwt) - strlen(&jwt[0]);

        StrMpl_encodeBase64(data_to_encode,
                            data_to_encode_size,
                            (uint8_t*) encoded_data_destination,
                            encoded_data_size);

        size_t i;

        for (i = 0; i < *encoded_data_size; i++)
        {
            switch (encoded_data_destination[i])
            {
                case '+':
                    encoded_data_destination[i] = '-';
                    break;
                case '/':
                    encoded_data_destination[i] = '_';
                    break;
                case '=':
                    encoded_data_destination[i] = 0;
                    *encoded_data_size--;
                    break;
                default:
                    break;
            }
        }
    }


    static void jwt_create_b64h_b64p(const char* project_id, uint32_t expiration_period_sec)
    {
      size_t bytes_written = 0;
      size_t index = 0;

      /* create header */
      char header[JWT_HEADER_BUF_SIZE];
      memset(&header[0], 0, JWT_HEADER_BUF_SIZE);
      memcpy(&header[0], "{\"alg\":\"ES256\",\"typ\":\"JWT\"}", strlen("{\"alg\":\"ES256\",\"typ\":\"JWT\"}"));

      /* create payload */
      //todo, as of now set to today's date, time = 12:00PM UTC
      uint32_t current_time_in_sec = 1587470400;
      char payload[JWT_PAYLOAD_BUF_SIZE];
      memset(&payload[0], 0, JWT_PAYLOAD_BUF_SIZE);

      snprintf(payload,
               JWT_PAYLOAD_BUF_SIZE,
               "{\"iat\":%ld,\"exp\":%ld,\"aud\":\"%s\"}",
               current_time_in_sec,
               current_time_in_sec + expiration_period_sec,
               project_id);

      /* base64 encode header */
      jwt_url_base64_encode_buffer((uint8_t*) &header[0],
                                   strlen(header),
                                   &jwt[index],
                                   &bytes_written);
      index += bytes_written;
      /* add first dot separating b64(h) and b64(p) */
      jwt[index++] = '.';

      jwt_url_base64_encode_buffer((uint8_t*) &payload[0],
                                   strlen(payload),
                                   &jwt[index],
                                   &bytes_written);
    }

    // create the JWT: b64(h).b64(p).b64(ecc(sha256(b64(h).b64(p))))
    // h = header
    // p = payload
    // b64 = base64
    // sha = Secure Hash Algorithm
    // ecc = Elliptic Curve Cryptography
    void jwt_create(const char* project_id, uint32_t expiration_period_sec)
    {
        size_t bytes_written = 0;
        size_t index = 0;

        /* clear JWT */
        memset(&jwt[0], 0, sizeof(jwt));

        /* create base64 encoded header and payload: b64(h).b64(p) */
        jwt_create_b64h_b64p(project_id, expiration_period_sec);

        /* create es256 signature of b64(h).b64(p): sha256(b64(h).b64(p)) */
        uint16_t bytes_written_ecc_signature = 255;
        uint8_t ecc_signature[JWT_MAX_SIGNATURE_SIZE];
        memset(&ecc_signature[0], 0, JWT_MAX_SIGNATURE_SIZE);

        SlNetUtilCryptoCmdSignAttrib_t signAttrib;
        signAttrib.Flags = 0;
        signAttrib.ObjId = 0;
        signAttrib.SigType = SL_NETUTIL_CRYPTO_SIG_SHA256wECDSA; /* this is the only type supported */

        sl_NetUtilCmd(SL_NETUTIL_CRYPTO_CMD_SIGN_MSG,
                      (uint8_t *)&signAttrib,
                      sizeof(SlNetUtilCryptoCmdSignAttrib_t),
                      (const uint8_t *) &jwt[0],
                      strlen(&jwt[0]),
                      &ecc_signature[0],
                      &bytes_written_ecc_signature);

      /* add second dot separating b64(h).b64(p) and b64(eccsignature) */
      index = strlen(&jwt[0]);
      jwt[index++] = '.';

      jwt_url_base64_encode_buffer(&ecc_signature[0],
                                   bytes_written_ecc_signature,
                                   &jwt[index],
                                   &bytes_written);
    }

    const char* jwt_get()
    {
        return &jwt[0];
    }

  • Hi Ben,

    The standard way of working with the device key, is to read the CSR (Certificate Signing Request) and use it to generate the device certificate.

    You can get the device CSR using the uniflash Tools (you will need to enable CSR in the DeviceIdenity menu) , using the "Certificate_Signing_Request_CC3235SF_LAUNCHXL_nortos_ccs" example from the SDK (see http://dev.ti.com/tirex/explore/node?node=AMpkGCJkwCqQ.cWUJcYKJA__fc2e6sr__LATEST) or directly from the code (see the use of SL_NETUTIL_CRYPTO_CSR_SIGN_AND_SAVE in the Certificate Signing Request example).

    The CSR (that includes the device public key) will then be than use a valid certificate authority (a root CA that is acceptable by Google) to sign the public key and create the device certificate. 

    I'm not familiar with the the Google MQTT requirements but they will probably describe the required procedure.

    You can also create a self signed certificate from the device but this is not the typical method.

    You can also read about it in http://www.ti.com/lit/ug/swpu332a/swpu332a.pdf.

    Regarding your code, I can only verify that the slNetUTilCmd part seems ok. I can't help in regards to the JWT creation and assumes that the base64 utilities you are using are ok and that the buffer sizes works.

    br,

    Kobi  

  • Hi Kobi,

    I have already connected to Google by loading Google's root CA's via Uniflash.  I hardcoded the JWT to successfully do this.

    I guess, in your opinion, is the crypto library capable of creating an ES256 signature using it's constant key pair's private x9.63 raw private key?  I'm quite certain this is where my issue lies.

    I'm good on all the certificate stuff, it was actually pretty intuitive; nonetheless, thank you for your time!

    -Ben

  • if you sign the JWT with the device private key how does the server verifies the signature? how do you provide the public key to the server?

    See chapter 17.1 of http://www.ti.com/lit/ug/swru455j/swru455j.pdf for more details on the NetUtil command. I think it fits the ES256 requirements,

  • I'm pretty familiar with that document.  I think you have answered my question.  This is a pretty complex integration and I've been at it for quite some time, so my apologies if I seem as if I was grasping for straws.

    The device public key is sent to google at time of manufacturing.  I have code that reads the ECC public key (x9.63 format) and converts it to .pem format.

    There is a root CA from google loaded on the filesystem.

    The JWT contains an ES256 signature created using the ECC private key.

    I am starting to think that maybe the conversion of the x9.63 public key might have gone awry.

    Thanks,

    Ben