CST 3.3.2 encryption issue

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

CST 3.3.2 encryption issue

2,603 Views
isiora
Contributor II

Hello,

I'm signing and encrypting an image using CST 3.3.2. The target processor is an iMX8MM.
The signed and encrypted images don't work. If I use the CST only for signing, I have no problem. Only if I add encryption I have issue.
No issue at all I have with the CST 3.3.1, but I need to use the version 3.3.2 because later I must switch to the HSM via pkcs11 itf.
I have used with version 3.3.2 excatly the same .csf files and the same input image I used with version 3.3.1, so it seems a problem confined to version 3.3.2.
Is there anyone who can confirm this problem and tell me if she resolved it?
Thanks.

0 Kudos
Reply
19 Replies

1,931 Views
daescalona
Contributor I

Hello,

We are experiencing exactly the same issue. We have been using CST 3.3.1 to sign/encrypt our artifacts for the i.MX8M modules. However, with the update of the CST to version 3.3.2, the encrypted artifacts stopped working. For signed only artifacts there are no issues, they work perfectly.

We are wondering if the change that made the encrypted artifacts to stop working with the new version of CST is a design change and we need to update our software or it is indeed a bug and it will be fixed in the next CST revision. There is not anything in the documentation/release notes stating that there has been such a design change that requires some updates in our code to generate the encrypted artifacts in a proper way.

What is the recommendation meanwhile?

Thanks in advance.

0 Kudos
Reply

2,562 Views
Dhruvit
NXP TechSupport
NXP TechSupport

Hi @isiora,

I hope you are doing well.

Could you please describe more about the issue or share error/failed logs for further debugging?

Thanks & Regards,
Dhruvit Vasavada

0 Kudos
Reply

2,543 Views
isiora
Contributor II

Hi Dhruvit,

I'm fine, thank you.
Unfortunately I don't have much to add. There are no logs of the issue. The CST 3.3.2 terminate correctly all the phases up to build the final image, e.g. flash_sign_enc.bin. But when I upload the image to the target using the command:

 

uuu -b sd flash_sign_enc.bin

 

it hangs in step 1:

 

uuu (Universal Update Utility) for nxp imx chips -- libuuu_1.5.21-0-g1f42172

Success 0    Failure 0                                                                                                                       
                                                                                                                                              
                                                                                                                                              
1:3      1/ 1 [=================100%=================] SDP: boot -f flash_sign_enc.bin

 

Why the 'uuu' hangs is quite clear to me. The HAB code in rom try to decrypt the image without success, so returns to listen on serial download interface (SDP protocol) with no output on console.
If I replay exactly the same sequence in building the image, but using CST 3.3.1, everything works fine:

 

Success 1    Failure 0                                                                                                                       
                                                                                                                                              
                                                                                                                                              
1:3      5/ 5 [Done                                  ] FB: Done                                                                               
1:4      3/ 3 [=================100%=================] SDPV: jump

 

I remind you that signed only images, aka without encryption, work correctly using the CST 3.3.2.
The target board is a custom board with this imx8mini based som https://www.exorint.com/en/product/microsom-us04. The srk fuses are blown and the security configuration is closed.

Yesterday I have recompiled CST 3.3.2 and CST 3.3.1, but things remained unchanged: the CST 3.3.1 works, the CST 3.3.2 no. Now I'm trying to compare the code of the two versions, but I would like to know if I'm dealing with a bug in CST 3.3.2.

Thanks in advance!

0 Kudos
Reply

2,427 Views
Dhruvit
NXP TechSupport
NXP TechSupport

Hi @isiora,

I hope you are doing well.

Can you confirm whether you are using the PKCS11 backend when seeing the failure?

Have you tried the standard backend? 

Please provide me with CSF description files for further debugging.

Can you please mention which host OS is used to execute CST?

Thanks & Regards,
Dhruvit Vasavada

0 Kudos
Reply

2,415 Views
isiora
Contributor II

Hi Dhruvit,

no, not confirm. I see the failure using the standard openssl backend. I have not used the PKCS11 backend with the encryption, not yet. But it should be quite the same, because looking at the code I see that both the backend use openssl for encryption with a random key generated by cst (no hsm operation is involved). Incidentally, I would like to inform you that I always use the same key, using the '-d' and '-s' options.

I'm using a virtualbox VM with Ubuntu 18.04.6 LTS.
I attached the csf description files.

Thanks and kind regards

0 Kudos
Reply

2,492 Views
Dhruvit
NXP TechSupport
NXP TechSupport

Hi @isiora,

I am trying to reproduce this issue on my end.

I will update you on this ASAP.

Thanks & Regards,
Dhruvit Vasavada

0 Kudos
Reply

2,370 Views
isiora
Contributor II

Hi Dhruvit,

I confirm that the problem is the one I explained to you in my previous message.
In my software, I solved it by iterating over the tags in the binary csf, looking for the position of the HAB_TAG_MAC tag. By doing this I get the right offset of the nonce/MAC and the construction of the encrypted image is finally correct.
The fact remains that the procedures outlined in the guides and application notes are not consistent with the operation of version 3.3.2 of the CST.

Best regards,
Isidoro Orabona

0 Kudos
Reply

2,302 Views
Dhruvit
NXP TechSupport
NXP TechSupport


Hi @isiora,

Thank you very much for pointing out this issue.

I have informed our documentation team regarding this issue.

If there are no further questions, can I mark this case as closed?

Thanks & Regards,
Dhruvit Vasavada 

0 Kudos
Reply

2,291 Views
isiora
Contributor II

Hi Dhruvit,

yes, you can close this case. Thank you.

Kind regards,
Isidoro Orabona

0 Kudos
Reply

2,394 Views
isiora
Contributor II

Hi Dhruvit,

I think I've found what causes the problem.
In order to assemble the encrypted and signed image, I followed the guide in uboot, 'doc/imx/habv4/guides/mx8m_encrypted_boot.txt', and the application note AN12056. The uboot guide in paragraph 1.7.1 indicates to copy the Nonce/MAC from the binary csf relating to encryption into the binary csf relating to signature (see also A.3.1in AN12056). This is for obvious reasons, as the first csf performs a signature on the non-ciphered text, while the second performs the useful signature, the one on the ciphertext.
Now comes the problem. The step in §1.7.1 calculates the nonce offset starting from the end of the binary csf. In fact it assumes that the Nonce/MAC is the last element in the binary csf.
But this is no longer true in cst 3.3.2!!
If you look in cst.c, around line 1926, you will notice that cst 3.3.2 writes at the end of the binary csf the "AuthenticateCSF data", i.e. the signature, and not the Nonce/MAC. This makes the procedures outlined in the guides I mentioned unenforceable.
I don't know the reason for this change in the 3.3.2.
Now I'm looking for a solution to calculate the nonce offset, which is complicated by the fact that the size of the signature varies. One way could be to interpret the csf binary looking for the "Decrypt" command (the HAB_TAG_MAC tag) which contains the Nonce/MAC, but that's a bit tricky.
Hoping that this is the sole problem, can you help me to find a good solution?

Thanks and regards,
Isidoro Orabona

0 Kudos
Reply

1,925 Views
kef2
Senior Contributor V

Much simpler solution, independent of CCS version. Verified with HAB, not yet with AHAB.

In some docs NXP call strings in csf file like [blabla] as a commands. If [Authenticate Data] has to come prior to [Decrypt Data], then what about sequence of 3 commands

  1. authenticate IVT, DCD
  2. decrypt the rest
  3. authenticate decrypted the-rest

All this in single CSF file, no need to call ccs twice, no need to peek and poke parts of binary CSF. I even see advantage to such approach. Instead of authenticate encrypted binary, then decrypt and assume HAB can't decrypt it wrong way; I think it is better to authenticate IVT/DCD, decrypt, and then authenticate decrypted data, so that it fails if decryption fails for some reason.

 

[Authenticate Data]
    # Key slot index used to authenticate the image data
    Verification index = 2
    # IVT,DCD,..
    Blocks = 0x877ff400 0x400 0xc00 "u-boot-nand.imx"


[Install Secret Key]
    Verification index = 0
    Target index = 0
    # DEK file to create
    Key = "u-boot-nand.imx.dek"
    Key Length = 128
    Blob address = 0x878b7000

[Decrypt Data]
    Verification index = 0
    Mac Bytes = 16
    # Initially copy of u-boot-nand.imx. Data in file is going to be encrypted
    Blocks = 0x87800000 0x1000 0xb5000 "u-boot-nand.imx.signed"

# Authenticate decrypted data. Decrypted data is available in original file:
[Authenticate Data]
    Verification index = 2
    Blocks = 0x87800000 0x1000 0xb5000 "u-boot-nand.imx"

 

 

0 Kudos
Reply

1,894 Views
isiora
Contributor II

I too had thought that by reversing the operations I could use only one csf. In the end, however, not being able to carefully evaluate the security consequences, I preferred to maintain the suggested encrypt-then-sign sequence (swapping the order of operations is a sensitive issue in cryptography).

0 Kudos
Reply

1,886 Views
kef2
Senior Contributor V

It is not really swapping the order of auth and decrypt. It is authentication step split into two steps, one mandatory prior to decryption, and the second one after decryption. This allows using single cst run and avoid transplanting part of csf.bin's at undocumented locations! 

With transplanting, if your blob is wrong (or perhaps some other unknown cause of decypt failure), HAB will auth OK, decrypt "OK" producing garbage instead of real code, and then HAB ends jumping into the mess produced. Of course it won't boot, few chances it will break something, but who knows.

With auth-decrypt-auth and wrong blob, HAB will do first auth OK, decrypt "OK" producting garbage instead of real code, then 2nd auth will fail and HAB won't try executing unauthenticated code. As well I see locations zeroed due to 2nd auth pass failure.

I prefer auth-decrypt-auth. 

0 Kudos
Reply

1,852 Views
isiora
Contributor II
I want reply again to this to underline that what you say about bad blob is incorrect and I want to prevent this erroneous message of yours from passing through. The purpose of MAC is to check the integrity of the ciphertext. It is precisely the MAC verification that allows the HAB to give "decrypt KO" in case of alteration of the text or the blob.
0 Kudos
Reply

1,881 Views
isiora
Contributor II

Your proposal does not differ much from that reported in paragraph 4.3.1.3 "Signing and encrypting the signed image" of AN12056. Even in that case the procedure involves authentication and then encryption without transposition of the nounce/mac. The operations are identical to those you showed, even if accidentally divided into two csf, but even in this case they are equivalent. The fact that there is IVT authentication before encryption does not change things, it is still a "sign-then-encrypt" protocol. Pre-authentication of the IVT is obviously necessary, as this is a section that cannot be encrypted.
Instead, I want to use the encrypt-then-sign protocol in order to be "robust" even in the event of the DEK being compromised. And this issue concerns that topic.
Furthermore, I have implemented a safe and foolproof method based solely on the information provided by the HAB spec, which allows me to transpose the nuounce/mac. For this reason I have closed this issue. It is not important that operations are complicated by this peek and poke; they are performed by a computer ;-).

0 Kudos
Reply

1,874 Views
kef2
Senior Contributor V
  • Your proposal does not differ much from that reported in paragraph 4.3.1.3 "Signing and encrypting the signed image" of AN12056.

It is totally different. They suggest to auth only header (0xc00 bytes in their example) and decrypt data (0x55000 bytes), leaving data unauthenticated. Try encrypting kernel or something, load it to target, overwrite encrypted data anyhow, issue hab_auth_img, you will get no new HAB errors, though decrypted data is damaged.

  • The operations are identical to those you showed, even if accidentally divided into two csf, but even in this case they are equivalent.

nounce/mac transplantation doesn't protect from bad blob. Authentication is made for whole encrypted imaged. After decryption, which succeeds always, no decrypted data authentication is performed. HAB will be happy if you insert bad blob. 

 

  • The fact that there is IVT authentication before encryption does not change things, it is still a "sign-then-encrypt" protocol. Pre-authentication of the IVT is obviously necessary, as this is a section that cannot be encrypted.

You just didn't try with data and/or blob overwrite. Try it and see. I tried. Since nounce peek-poke didn't succeed with CST 3.3.2, I didn't really try it. But since those commands in CSF are performed sequentially, and transformer CSF is auth first, then decrypt, I'm sure it doesn't protect from bad blob or decrypt failures caused by other reasons.

  •  
0 Kudos
Reply

1,865 Views
isiora
Contributor II

I no longer have problems copying the MAC/nounce and using the cst 3.3.2. I don't need to try. I'm not interested in the "sign-then-encrypt" protocol. The encrypt-then-sign protocol works correctly. I have tested all major scenarios on closed devices. NXP just needs to update the AN.
What you say about their example, "... leaving the data unauthenticated" is not right. The data is signed by the first csf ("CSF to sign the boot image (CSF-Sign)"), see block of size 0x55c00 bytes. The second csf ("CSF to encrypt signed image (CSF-Enc-Sign)") is used to sign only the IVT&co, the block of size 0xc00, and to encrypt the data, the block of size 0x55000 bytes .
Compared to your proposal it is just more difficult to assemble the final image, which however is structurally the same as the one you obtained, i.e. auth-decrypt-auth using your terms. So it is simpler if someone wants to use the "sign-then-encrypt" protocol, which is not what I'm interested in though.

  • nounce/mac transplantation doesn't protect from bad blob. Authentication is made for whole encrypted imaged. After decryption, which succeeds always, no decrypted data authentication is performed. HAB will be happy if you insert bad blob. 

Regarding this your point, the purpose of the MAC is precisely to check the integrity of the ciphertext. So what you say cannot happen. Any alteration to the ciphertext or to the dek causes the integrity check to fail and the HAB stops. The use of the MAC in transmitting a chipertext for integrity verification is common practice and a basic notion in applied cryptography.

Have you an Happy New Year,
I.

0 Kudos
Reply

1,845 Views
kef2
Senior Contributor V

This is final my comment, no more coming

  •  I'm not interested in the "sign-then-encrypt" protocol. The encrypt-then-sign protocol works correctly. I have tested all major scenarios on closed devices. NXP just needs to update the AN.

You are using weird terms indeed. HAB process, what you have encoded by CST in CSF binary is a set of HAB commands. What comes first is executed first. Simple encryption example form AN was authenticate header, then decrypt the rest of data. So at least it is sign(header)-then-decrypt(data). This simple example is not in particular single chapter of AN12056, but starts at 4.3.1 and ends in 4.3.1.2. Such simple csf example is enough to create encrypted image in single CST run. Let it call [A]

Example with peek poke lets to create two CSF files, one that does [A], second one that repeats [A] with authentication range extended for whole image, but output dek and encrypted image are to be ignored. This 2nd CSF binary is tuned to replace, eee, undocumented something at offset depending on CST version, from one binary CSF to another binary CSF. Whatever it replaces, both CSF's contain single auth command, which happens first, then single decrypt command, which happens next.  So in theiry this [B] case should auth whole image, including encrypted part, and then decrypt data if auth pass succeeds. Looking at a sequence of suggested shell commands, it looks like resulting sign-enc CSF auths original decrypted data, then peek-poke replaces what? Auth range and auth "checksum" from [A]? Perhaps decryption stuff like dek used? Then hm, it should auth against encrypted image produced in [A], but according to commands it auths against plain image. Uff, clearly AN politely speaking is not really perfect... BTW, if you say [A] is enough and it is perfectly robust, then what for did they use those two CST pass with peek-poke??? Perhaps [A] is not enough?

I thought to repeat and post exact steps, which proved for me in the past necessity to use either two pass CST + peek-poke or single CST pass with 2nd auth command after decrypt step. Well, I'm unable to reproduce my observations. Plain [A] seems being robust and doesn't allow to alter encrypted part of loaded image or to replace blob. I thought perhaps I used old hardware like SS variant of Vybrid, which is known having HAB issues. Now even Vybrid seems being immune.. But I clearly saw:

1. load [A] like image, overwrite any byte in encrypted part using mw command, run hab_auth_image. As a result no HAB errors, decrypted part looks perfect except of overwritten mw location. 

2. Issuing 2nd time hab_auth_image with data not reloaded and thus decrypted, I was getting again encrypted image like it was originally after load. Since now 1. leads to two new HAB errors, 2nd hab_auth_image call leads to more HAB errors and zeroed data. Hm, looks like [A] is enough. But I clearly saw it having issues.

3. since unable to reproduce above two, not sure regarding bad blob. But I think it led as well to garbage decryption with no HAB errors. 

These observations and inability to peek-poke right let me thinking about two auth commands, which clearly fixed all 3 on the same hardware and the same image data with IVT. It's bad I didn't notice something that doesn't allow to reproduce odd behavior now. Perhaps u-boot was not signed at all, perhaps something regarding PROBLOB, I don't know.

Happy New Year

0 Kudos
Reply

1,768 Views
isiora
Contributor II

I agree on "AN politely speaking is not really perfect". In fact, I found the description in the uboot documentation clearer (doc/imx/habv4/).

I decided to describe in quite some detail why we need to use two CSFs to generate an encrypt-then-sign image (that is the protocol that I use) and why we need to transcribe the nonce/MAC from one binary CSF to the other. I know you already know a lot of what I'm going to describe, but I hope to clarify some aspects and I hope it's useful for someone else.

I have attached two CSFs (spl_enc.csf and spl_sign_enc.csf) and the corresponding binary csf dumps interpreted by hab_csf_parser (spl_enc.bin.tags, spl_sign_enc.bin.tags) that reports the HAB commands present in the binary CSF. Note, they report only the commands and values part of the commands, not the indirect data like signatures and certificates.

The general scheme involves, to simplify, using the first csf to sign and then encrypt the image, then discarding the signature; and the second csf to sign the encrypted image, discarding the encryption produced (the encryption of the already encrypted image).
This strange sequence is forced by the fact that the HAB executes the commands in the CSF in the order they appear. And since for the chosen protocol I want to first authenticate the encrypted image and then decrypt it, it is necessary that in the binary CSF the image authentication command comes before the decryption one.
If you take a look at the two .csf and the two .tags using diff, you will see that they are very very similar. In particular the two .tags differ only for the nonce/MAC HAB tag values.

In the following, we first execute "cst -i spl_enc.csf -o spl_enc.bin" and then "cst -i spl_sign_enc.csf -o spl_sign_enc.bin".
We suppose to have in input a "flash.bin" image produced by mkimage and to know the useful offsets in the image (csf and blob offsets).

The CST program reads and executes the command in the input spl_enc.csf:

  1. [Install SRK] generates the HAB command that indicates where the SRK table, inserted by the CST itself, is into the binary CSF.
  2. [Install CSFK] generates the HAB command that indicates where the CSF1_1 certificate, inserted by the CST itself, is into the binary CSF.
  3. [Authenticate CSF] generates the HAB command (HAB_CMD_AUT_DAT). The command also indicates where the CSF signature is into the binary CSF. Because the CST is building the CSF, the CST delays the generation of the CSF signature.
  4. [Install Key] Reads the certificate IMG1_1. Generates the HAB command to assign the verification index and where the IMG1_1 certificate is into the binary CSF.
  5. [Authenticate Data] Uses the IMG1_1 private key to sign the specified block(s) from "flash.bin" file and generate the HAB command (HAB_CMD_AUT_DAT with PCL=HAB_PCL_CMS) and the computed signature.
  6. [Install Secret Key] Generates a random symmetric key dek.bin and notes the address where the blob will be put, and generates the related HAB command to install the key.
  7. [Decrypt Data] Applies the AEAD scheme. Using the dek key encrypts the specified block(s) read from "flash-spl-enc.bin" calculating also the MAC, and generates the authenticated-decrypt HAB command (HAB_CMD_AUT_DAT with PCL=HAB_PCL_AEAD). "flash-spl-enc.bin" is initially a copy of "flash.bin". After this command the "flash-spl-enc.bin" has these block(s) ciphered. These blocks are a subset of the blocks in the previous [Authenticate Data] command.
  8. At end, the CST inserts the certificates, as a series of HAB_TAG_CSF commands, then generates the HAB_TAG_SIG command that represents the image signature followed by the HAB_TAG_MAC command that indicates the nonce and MAC values, and finally inserts the HAB_TAG_SIG command for the CSF signature.

The CST produces a file ("spl_enc.bin") that is the binary CSF containing these HAB commands that has generated. The attached "spl_enc.bin.tags" is a human readable dump of the commands present in the file.

NOTE: it seems that the binary CSF ends with the CSF signature in CST3.3.2, while ends with nonce/MAC in the CST3.3.1. The current NXP documentation assumes that nonce/MAC is at the end of binary CSF.

After producing the blob from the dek, we put the blob and the spl_enc.bin into flash-spl-enc.bin at the calculated offsets, obtaining a final image.

If we fed this image to the HAB, it will execute the commands as given in the exact order in which they were generated by the CST. But it will fail. In fact the HAB (simplifying):

  • Autenticates the CSF. It is OK, the CSF is in plaintext.
  • Autenticates the image. It fails, because the CST signed the blocks as dictated by the [Authenticate Data] above, before crypting a subset of the same blocks, as directed by the [Decrypt Data] command.

At this point we have a correctly ciphered image with a wrong signature.

To get a correct image we need the signature calculated including the encrypted blocks. To achieve this we can run the CST once again passing it an identical CSF, but replacing "flash.bin" with "flash-spl-enc.bin", and replacing "flash-spl-enc.bin" with a dummy copy ("flash-spl-enc-dummy.bin"). So we have the CST calculate the signature on an image that includes the encrypted blocks. We are also careful not to overwrite the dek already generated, indicating in the new CSF "dek_dummy.bin". See the attached spl_sign_enc.csf.

Now the CST generates the same sequence but the signature value is now calculated including the encrypted blocks. In this way, the generated binary csf (spl_sign_enc.bin) should be identical to the spl_enc.bin, except for the signature value.

We now put this spl_sign_enc.bin into flash-spl-enc.bin at usual offset, obtaining a new final image.

We feed this new image to the HAB and ... it fails again!
In fact the "HAB" (always simplifying):

  • Autenticates the CSF. It is OK, the CSF is in plaintext.
  • Autenticates the image. It is OK, now the signature is computed over the correct dataset.
  • Decrypt Data. Applies the AEAD scheme. Uses the dek in the blob to compute the MAC over encrypted blocks. Uses the dek to decrypt the blocks. Check the MAC. The check fails for mismatch on the MAC and the ROM will not executes the code.

NOTE: the HAB maybe always decrypts the blocks regardless of MAC mismatch, to avoid oracle attacks. I don't know if it does that, I have not tested it.

What is happening is that the MAC in the spl_sign_enc.bin is incorrect because it has been calculated over the already ciphered blocks and not on the original blocks, and moreover with a different random nonce. (Incidentally this means that the MAC is doing its job). Thus, the spl_sign_enc.bin contains a correct signature but a wrong nonce/MAC.

At this point we have a correctly encrypted image (done by first CSF) with a correct signature (done by the second) but with a bad MAC because this is the MAC calculated during the second encryption that we discarded and is not related to the first, right encryption, done by the first CSF.

To fix this, we just need to copy the original nonce/MAC from spl_enc.bin into spl_sign_enc.bin, and assemble the image again. To know the position of the nonce/MAC we can search the HAB_TAG_MAC in the binary csf generated by the CST, independently by the CST version.

Done. Now the HAB will authenticate and decrypt the image correctly.

I wish you happy holidays,
I.