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.

CCS/CC3220SF-LAUNCHXL: ECC key

Part Number: CC3220SF-LAUNCHXL

Tool/software: Code Composer Studio

Dear Sir,

I have an question about the ECC private key and public key. here I have to sign some payload and I have to send to cloud with public key (for the signature) so cloud side they will verification with the public key.

here I am using the SL_NETUTIL_CRYPTO_CMD_SIGN_MSG method for the signature and verification from the device side . please have a look my attachment that is function implementation for the signature and verification in device side.

Here I have following question.

1. As I see in NWP guidelines I can sign the payload using the private key at index zero (as per the document it is unique key). so SL_NETUTIL_CRYPTO_CMD_SIGN_MSG method does sign the payload using private key only? (I haven't install any other key pair to device so I am referring the index 0 only )

2. After sign the payload (in device), I do verification (in device) using the SL_NETUTIL_CRYPTO_CMD_VERIFY_MSG method with index0, so this verification will be done internally by the device Stack so by what key there are verifying the signature result.?

// Getting Public key from the input index
static int generate_public_key_from_index(uint32_t index, uint32_t configOpt, uint8_t *publicKey, uint16_t *keyLen)
{
    int rc = -1;

    rc = sl_NetUtilGet(configOpt, index, publicKey, keyLen);

    if (rc < 0)
    {
        ASSERT_ON_ERROR(rc, "sl_NetUtilCmd() failed");
    }

    return rc;
}

// Verify the signature using the given index
static int verify_sign_buffer_using_index(uint32_t index, uint8_t* buff , uint16_t buffLen , uint8_t* signBuff , uint16_t signBuffLen)
{
    int rc = -1;

    uint16_t resultLen = 0;

    if (1500 < (buffLen + signBuffLen))
    {
        SHOW_ERROR(rc, "buffer length is too large");
        return rc;
    }

    /* now verify the buffer */
    memcpy(base64encode, buff, buffLen);
    memcpy(base64encode + buffLen, signBuff, signBuffLen);

    SlNetUtilCryptoCmdVerifyAttrib_t verAttrib;

    verAttrib.Flags = 0;
    verAttrib.ObjId = 0;
    verAttrib.SigType = SL_NETUTIL_CRYPTO_SIG_SHAwECDSA; /* this is the only type supported */
    verAttrib.MsgLen = buffLen;
    verAttrib.SigLen = signBuffLen;

    resultLen = 4;

    int verifyResult = 0;

    rc = sl_NetUtilCmd(SL_NETUTIL_CRYPTO_CMD_VERIFY_MSG, (_u8 *) &verAttrib,
                       sizeof(SlNetUtilCryptoCmdVerifyAttrib_t), (const _u8 *) base64encode,
                       buffLen + signBuffLen, (_u8 *) &verifyResult, &resultLen);

    if (rc < 0)
    {
        ASSERT_ON_ERROR(rc, "sl_NetUtilCmd() failed");
    }
    else
    {
        WMDebugInfo(DEBUG_LOG, "sing buffer verification result %d ", verifyResult);
    }
    return verifyResult;
}

// Signing the buffer using given index
static int sing_buffer_using_index(uint32_t index, uint8_t* buff , uint16_t buffLen , uint8_t* signBuff , uint16_t *signBuffLen)
{
    int rc = -1;

    if(buff == NULL)
    {
        SHOW_ERROR(rc, "buffer is null");
        return rc;
    }

    if (buffLen >= 1500)
    {
        SHOW_ERROR(rc, "buffer length is too large");
        return rc;
    }

    SlNetUtilCryptoCmdSignAttrib_t signAttrib;

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

    rc = sl_NetUtilCmd(SL_NETUTIL_CRYPTO_CMD_SIGN_MSG, (uint8_t *) &signAttrib,
                       sizeof(SlNetUtilCryptoCmdSignAttrib_t), buff, buffLen, signBuff,
                       signBuffLen);

    if (rc < 0)
    {
        ASSERT_ON_ERROR(rc, "sl_NetUtilCmd() failed");
    }

    return rc;
}

// Process for Creating Public key, signing message and verifying 
int decription_method(WM_https_register_get_ts *WM_https_register_get)
{
    uint8_t buf[SL_NETUTIL_CMD_BUFFER_SIZE];

    int i = 0;

    uint16_t configLen = 255;

    if(generate_public_key_from_index(0, SL_NETUTIL_CRYPTO_PUBLIC_KEY, (uint8_t*)buf, (uint16_t*)&configLen) == 0)
    {
        WMDebugInfo(NO_CRLF, "\r\n\r\n");

        WMDebugInfo(NO_CRLF, "key result : ");

        for (i = 0; i < configLen; i++)
        {
            sprintf(&rawValueBuffer[i], "%02x", buf[i]);

            WMDebugInfo(NO_CRLF, "%02x", buf[i]);
        }

        WMDebugInfo(NO_CRLF, "\r\n\r\n");
    }

    configLen = 255;

    MQTTPayload_ts signaturePayload;

    uint16_t len = 0;

    len = Make_payload_for_signature(&signaturePayload);

    if (len == 0)
    {
        ASSERT_ON_ERROR(-1, "JSON packed creation failed");
    }

    WMDebugInfo(DEBUG_LOG, "signature payload %s", signaturePayload.jsonPayload);

    if(sing_buffer_using_index(0, (uint8_t*)signaturePayload.jsonPayload, signaturePayload.len, (uint8_t*)signatureBuffer, (uint16_t*)&configLen) == 0)
    {
        WMDebugInfo(NO_CRLF, "\r\n\r\n");

        WMDebugInfo(NO_CRLF, "signature result : ");

        for (i = 0; i < configLen; i++)
        {
            sprintf(&rawValueBuffer[i], "%x", signatureBuffer[i]);

            WMDebugInfo(NO_CRLF, "%x", signatureBuffer[i]);
        }

        WMDebugInfo(NO_CRLF, "\r\n\r\n");

        WMDebugInfo(NO_CRLF, "signature result : %s", rawValueBuffer);

        WMDebugInfo(NO_CRLF, "\r\n\r\n");

    }

    if(verify_sign_buffer_using_index(0, (uint8_t*)signaturePayload.jsonPayload, signaturePayload.len, (uint8_t*)signatureBuffer, configLen) == 0)
    {
        WMDebugInfo(DEBUG_LOG, "sing buffer verification passed");

    }
    else
    {
        WMDebugInfo(DEBUG_LOG, "sing buffer verification failed ");
    }

    return 0;
}

  • The CC3220 contains a unique key pair (i.e. private key and public key).

    As you mentioned, these device unique keys are in index 0 (other indexes can be used to install temporary keys by the host).

    The private key is used when you sign the image, the public key is used when you verify a signature.

    Only the public key can be read by the host.

    Br,

    Kobi

  • Dear Kobi,

    Thank you for the reply. how are you ?

    Here I read the public key but that is uncompressed and 130 byte long. how do I compress the public key  ?

    As i mention i have to send a signature data to the cloud using HTTPS, This sending process is fine but how do I singed data to the cloud using the index0 public key. which method I have to use for the verification on the cloud side.

  • The public key is in a x9.63 raw format. We don't support any compression in the NWP.

    Typically you will get the CSR for index 0 (see the , and use a CA to generate a certificate for the device. This certificate will be used at the cloud to verify the content you signed with the private key (ECDSA). 

    See "17.1.1.4 Certificate Creation" in the programmers guide (https://www.ti.com/lit/pdf/swru455).

    Br,

    Kobi

  • Dear Kobi,

    Thank you for the reply. 

    How do I generate the CSR at index 0?

    This CSR certificate I have to send to cloud ? if yes how do I send it to cloud.

    As a mentation that we can't read the private key so how do I send private key for the verification using CSR ?



  • See "17.1.1.4 Certificate Creation" in the programmers guide (https://www.ti.com/lit/pdf/swru455) - for details on CSR creation.

    CSR is used with a Certificate Authority to sign and generate your certificate. You may read the CSR at production time and use create the certificate using HSM or do some run-time registration to CA site. This is out of the scope for CC32xx. The cloud side typically defines the requirement on the device certificate.

    You don't need the private key for verification. The CSR contains the public key and this is all is needed to create the certificate that will verify the content signed by the device.

    If you are controlling the cloud side also, you can generate a self-signed certificate (instead of the CSR), that can be used to verify the content signed with index 0 private key. It is not recommended though as the self signed certificate will not be recognized as a valid certificate. 

    Br,

    Kobi

  • Dear kobi,

    I am not looking for the certificate signature method because I didn't  get any example for the signing and verification using that CSR certificate.

    So I change the logic here. here I explain the method 

    1. read the public key using key index0

    2. send this public key to cloud with uncompressed form.

    3.sing the payload and send it the signature data (signature data is generating in hex format by the TI )

    4. cloud side, using the nodjs script, verify the signature data using shared device public key( step2)

    this is the step I doing now but if I am doing sing and verification in the device it's fine but when I do cloud side using the node.js script I could not able to verify because of the signature data length. 

    Here approximately my signature length is 140 byte but expected was 64 byte only. I don't what is the issue here. 

  • The CSR needs to be signed by an external company (certificate authority). Check the Readme in the <sdk>\tools\cc32xx_tools\certificate-catalog\ for the full list of supported root CAs. This section cannot be introduced by an example as it depends on the selected certificate authority (and has a cost). Again, if you control the cloud side (i.e. the verifier), you can generate the certificate from the CSR using your own certificate.

    The signature should be ok. Ii thought the (binary) size is ~70B and not 140B (i guess you are referring to the hex representation). This was verified many times. Make sure you are using the script correctly.

    Br,

    Kobi

  • I think the extra bytes you are referring to are the ASN1 header. You can use the last 64 bytes (out of the expected 71-72 bytes) if your script requires just the signature.

    Br,

    Kobi

  • Dear sir,

    Thank you for the reply.

    Here as you told signature will have ANSI1 header so along with the header it is becoming the 140 byte around. how do i remove the ANSI header. ?

  • The 140B is strange. It should be half.

    Is this what you get as the signature length output params when the sl_NetUtilCmd returns?

  • Dear Sir,

    Have look on the signature output 

        retVal = sing_buffer_using_index(0, (uint8_t*) "QU1BTktFVEFO", strlen((const char*)"QU1BTktFVEFO"), (uint8_t*)signatureBuffer, (uint16_t*) &configLen);
    
        if (retVal < 0)
        {
            ASSERT_ON_ERROR(retVal, "sing_buffer_using_index() failed");
        }
        else
        {
    
            WMDebugInfo(NO_CRLF, "\r\n\r\n");
    
            WMDebugInfo(NO_CRLF, "signature result : ");
    
    
            memset((uint8_t*)&rawValueBuffer, 0x00, sizeof(rawValueBuffer));
    
            for (i = 0; i < configLen; i++)
            {
               sprintf(&rawValueBuffer[i], "%x", signatureBuffer[i]);
    
               WMDebugInfo(NO_CRLF, "%02x", signatureBuffer[i]);
            }
    
             WMDebugInfo(NO_CRLF, "\r\n\r\n");
    
             WMDebugInfo(NO_CRLF, "signature result : %s", rawValueBuffer);
    
             WMDebugInfo(NO_CRLF, "\r\n\r\n");
        }
    

    This is my signature and I am print down as %02x format .. have a look once

    [3045022100ad534a20925997179e84894bc69e1c379f0dd3adc3523c2c5f3c72588828dbe502203f85c3e0b2553745adc486a679a1a42eff5ef03259f8ee03144d1f09b344d332]


    and this is my sprintf format string format have a look once.

    [34220a54295919884c9139ddac532537582de2238ceb534ac8a7aa2f5f35fe31419b4d32]

    as I see this signature is in the DER format

  • The print seems alright.

    It is a 71B signature (each byte is represented by 2 hex number - so the string length is 142).

    The sprintf content is wrong because it tries to represent each byte (0-255) with a single hex number (0-15) which won't work (byte values are overriding each other, leading zeroes are skipped).

    Br,

    Kobi

  • Dear Kobi,

    Thank you for the reply.

    Here I decoded the DER format for signature data. here I have question about the signature data output.

    First have a look code for the signature component R and S

    </ 
    static int convert_DER_sign_to_rs_componet(uint8_t *hex_str)
    {
    //let's find the r and s value form the signature
    //this signature is in DER format so we need to find the signature integer
    //DER format is looks like the SEQUENCE| LEN| 02| len(r (32-33))| r| 02| len(s(32-33))| s| ht
    
    //so let's check signature contain the valid SEQUENCE number
    
    uint8_t offset = 0;
    
    uint8_t i = 0, j = 0;
    
    
    if (hex_str[offset] != 0x30)
    {
    ASSERT_ON_ERROR(-1, "hex_str[0] does not matched with 0x30 ");
    }
    
    offset += 2; //skip the SEQUENCE NUMBER | LEN
    
    for (i = 0; i < 2; i++)
    {
    
    if (hex_str[offset] != 0x02)
    {
    ASSERT_ON_ERROR(-1, "hex_str[] does not leaded by 0x02");
    }
    
    offset += 1; //skip the leaded by 0x02 value
    
    if (hex_str[offset] >= 0x21)
    {
    offset += 1; //skip the zero if found
    
    //check 4th index contain the 0x00
    
    if (hex_str[offset] == 0x00)
    {
    offset += 1; //start copy from the next byte
    
    if (i == 0)
    memcpy(initerger_rbuf, &hex_str[offset], 32);
    else
    memcpy(initerger_sbuf, &hex_str[offset], 32);
    }
    }
    else
    {
    offset += 1; //start copy from the next byte
    
    if (i == 0)
    memcpy(initerger_rbuf, &hex_str[offset], 32);
    else
    memcpy(initerger_sbuf, &hex_str[offset], 32);
    }
    
    offset += 32;
    
    for (j = 0; j < 32; j++)
    {
    if (i == 0)
    {
    WMDebugInfo(NO_CRLF, "%02x", initerger_rbuf[j]);
    }
    else
    {
    WMDebugInfo(NO_CRLF, "%02x", initerger_sbuf[j]);
    }
    }
    
    WMDebugInfo(NO_CRLF, "\r\n\r\n");
    }
    
    
    return offset;
    }
    
    />

    as per the google search DER format of data will be have sequence number and length as I explain as a comment in the function but here some extra byte is adding now. have a look down.

    [304502201de3662e573be7aaf850a467a15b8862090ee8dd5b5ee6df93652239a79e2ebf022100d775fb40faccf0d1b09acff528aab38aa39620dfcc67880d55e497f7692ec3d9]

    the above signature, I got some extra byte as 0x00. as per the format it should be the HT character at end of the signature (last byte) but i am getting starting of the R and S 

    [3046022100a567c52ce770bd03db6e85eb1472f2192990492c7041201237ccd96d14cc28ed022100c84352d29c047ea582dcdb4278714c9b3457bfaf0f2e76f15163e76327d7c480]

  • I'm not sure what is your concerns. Both signatures seem to satisfy the DER format definition. The "00" you mentioned, is part of the signature. .

    Where is the problem?

    Br,

    Kobi

  • Dear sir.

    If am not removing 0x00 then am not able to verify the signature using the script because including 0x00 it will become 65 byte but expect was 64 byte.. so why this 0x00 byte are Adding with staring of the R and S  components intended of the last byte as per the format..??..

    If I'll remove this 0x00 byte from the signature does cause any issue.. ?

  • You can try (Removing the leading 00).

    I'm not sure about it.

    Most tools / TLS stacks are ok getting the der format and i've not faced such issue before.

    I did a quick search for this and found the following: 

    https://stackoverflow.com/questions/34063694/fixed-length-64-bytes-ec-p-256-signature-with-jce

    br,

    Kobi

  • Dear kobi.

    I'll check it out. Anyway i already removed 0x00 byte from the signature.

    You can close the thread.