Securely Storing Product Information (Serial, Product Details, etc)

ericdaltman

New member
So I've been looking for a method to include a small, simple device in my products that can be factory written to store the product's serial number, product version, other details describing the product, and so on. The product runs on Linux, so I'd like something with data that is easily readable (either via some API command return, a stored text file on a simple FS, or something similar). The device should only be updatable by my company (which looks like it is quite possible via a locked Teensy).

The real question is: Is Teensy a good way to go here? I looked into TPM and not only is that overkill, it comes with some baggage for this utilization. Is Teensy easy to connect in a way Linux can reach without too much effort? Is it easy to have either a utility we release do a kind of 'firmware' update to the Teensy or something similar?

Thanks for your time if you got it to answer my question :)
-Eric
 
You can buy unique ID chips (often used for ethernet MAC addresses), and just log the ID at commissioning time in your database.- the chips are read-only and unique, often OneWire or I2C I think. Given a suitable driver that ought to be readable in /dev/<something-or-other>

If you want to write stuff (not just a unique id), an EEPROM chip perhaps, with the write-enable pin only going to a programming header?
 
Lockable Teensy can probably work here. Once locked into secure mode, you can update it, but only with programs created with your key. That ought to give you the plaform needed to build this sort of thing.

As for reading data in Linux, the easiest way which may or may not meet your security needs, would be to write startup code that alters the USB serial number string. On Linux the USB descriptors of all USB devices can be viewed with "lsusb -v". If you just put code on Teensy to alter that string early, before your Linux machine reads it, you can see it very easily on the Linux side.

However, anyone could create a custom USB device using another Teensy (not necessarily in locked mode) or any other programming USB chip which mimics that info. If someone physically replacing the Teensy with another USB device to get false info isn't a concern, that ought to be fairly simple.

If you do need to protect against replacement of the hardware with something that impersonates it, you'll need to do something more complex. RawHID is probably the simplest way. There is Linux example code to talk with it, where you can send 64 byte packets back and forth. This is more complicated since you need to write your own application. On Linux, to actually talk with interfaces like RawHID, you will also need to install a udev rule file. Once you can pass packets back and forth, you'll probably write your application to do a challenge-response. You'll create random or unique data and transit it to Teensy. Then Teensy will perform some algorithm on it and send you the result, maybe also with the product data. You'll check whether the result you got from Teensy was properly computed. The idea is an attacker who doesn't know the algorithm won't be able to impersonate your Teensy-based code, because you always transmit different data and expect the result for that unique data. A very secure algorithm would be use of digital signatures with a cipher like RSA2048, where you put the private key inside the secured code on Teensy and the public key on the Linux side. You send a block of random data, and Teensy signs it with the private key, and then you verify the signature back on the Linux side with the public key.

But you wanted simething "without too much effort", so maybe that's all getting a bit more complex than desired? Still, you should consider the fundamental question of whether you're willing to trust a simple fixed message that could be easily impersonated by someone who can replace the hardware, or go with some sort of challenge-response authentication where Teensy first proves to your Linux application that it truly is the hardware you installed and not an imposter someone has installed to cheat your system.
 
Thank you both for you suggestions. When I said simple, the Teensy fits my thinking. I guess I was thinking, "I don't need a Doctorate In Engineering" means "simple" to me. We have a dev team and access to our versatile and powerful custom APIs, so if it is The Right Fit, we'll code for it. As for MarkT's suggestion, it's something we can definitely /do/, but it SOUNDS complicated. I'd love to read more about it.

I guess I have to decide, and this is a conversation we've been having since 2015, what level of paranoia we want to have. Do we just want to make sure the average end user can't corrupt or cheat anything? Mostly, we use serials to identify the product and its capabilities. If someone modifies it, they generally just weaken their own experience. If they want to use our software in their own builds... that is definitely where we get the most concern. We've discussed having some kind of hardware key that must be present to unlock the software but then again, we have thousands of products out there WITHOUT such a key and don't want to lock them out of updates.

It's a tricky proposition. In the meantime, I think I'm going to get a Teensy or three for the lab and see what we can do with them.

Random follow up question, is there a way to tell (I guess just attempting to write to it) that a Teensy is locked?
 
From the Arduino IDE (I use version 1.8.19), click on Tools > Teensy 4 Security. Clicking the "Fuse Write Sketch" loads a new IDE windows with the "FuseWrite" sketch. Building, loading, and running this sketch actually locks the T4. After the appropriate locations are written to install the Public Key hash value, to install the decryption key, & to lock/set/reset appropriate fuses, specific code is executed to verify that the T4 is actually locked . . . you could execute something similar (note that this snippet may depend upon values obtained/set earlier in the sketch, so you will want to reference the full sketch to make sure that you have a fully operational check):

Code:
  IMXRTfuseReload();
  const uint32_t lockbits = HW_OCOTP_LOCK;
  const uint32_t configbits = HW_OCOTP_CFG5;
  if ((configbits & 0x3000) != 0x3000) {
    Serial.println("Error: decryption can not be used on this Teensy");
    ok = false;
  }
  if ((lockbits & 0x800000) != 0x800000) {
    Serial.printf("Error: Key is not locked! %x", lockbits);
    ok = false;
  }
  Serial.println();
  if ((IOMUXC_GPR_GPR11 & 0xF00) == 0) {
    Serial.println("Testing Bus Encryption Engine");
    if (memcmp(plaintext, ciphertext, sizeof(ciphertext)) == 0) {
      Serial.println("Error: ciphertext matches without decryption?!");
      ok = false;
    }
    unsigned char cipher[4];
    memcpy(cipher, ciphertext, sizeof(cipher));
    CCM_CCGR4 |= CCM_CCGR4_BEE(3);
    BEE_CTRL = 0x06;
    IOMUXC_GPR_GPR18 = (uint32_t)ciphertext;
    IOMUXC_GPR_GPR19 = (uint32_t)ciphertext + 1024;
    IOMUXC_GPR_GPR11 = 0x100;
    BEE_ADDR_OFFSET0 = 0;
    BEE_CTRL |= 0x11;
    arm_dcache_delete((void *)plaintext, sizeof(plaintext));
    arm_dcache_delete((void *)ciphertext, sizeof(ciphertext));
    if (memcmp(plaintext, ciphertext, sizeof(ciphertext)) == 0) {
        Serial.println("Success: ciphertext decryption test passed :-)");
    } else {
      Serial.println("Error: ciphertext decryption did not match plaintext!");
      Serial.printf("  plain:  %02X %02X %02X %02X\n",
        plaintext[0], plaintext[1], plaintext[2], plaintext[3]);
      Serial.printf("  cipher: %02X %02X %02X %02X\n",
        cipher[0], cipher[1], cipher[2], cipher[3]);
      Serial.printf("  dcrypt: %02X %02X %02X %02X\n",
        ciphertext[0], ciphertext[1], ciphertext[2], ciphertext[3]);
        ok = false;
    }
  } else {
    Serial.println("Bus Encryption Engine is active (this program is encrypted)");
    Serial.println("  Encryption is assumed to be working if this program runs.");
    if ((configbits & 0x02) == 0) {
      Serial.println("  To run the explicit decryption test, delete the .EHEX");
      Serial.println("  file and press the button on Teensy to upload again");
      Serial.println("  with only the .HEX file.  Clicking Verify or Upload in");
      Serial.println("  Arduino rebuilds both .HEX and .EHEX files.");
    }
  }
  if ((configbits & 0x00C00000) == 0 || (configbits & 0x04000000) == 0) {
    Serial.println();
    if ((lockbits & 4) == 4) {
      Serial.println("Error: JTAG can not be disabled");
      ok = false;
    } else {
      Serial.println("Notice: JTAG is still enabled");
    }
  }
  if ((configbits & 2) != 2) {
    Serial.println();
    if ((lockbits & 4) == 4) {
      Serial.println("Error: Secure mode can not be set");
      ok = false;
    } else {
      Serial.println("Notice: Secure mode is not yet set, unencrypted");
      Serial.println("        programs are still allowed to run");
    }
  }

Additionally, from the same Teensy 4 Security dialog, clicking on the "Lock Security Sketch" button opens the "LockSecureMode" sketch which includes the following to verify that the T4 is locked:

Code:
        if ((HW_OCOTP_CFG5 & 0x04C00002) == 0x04C00002) {
          Serial.println("Success: Secure mode set");
          ok = true;
        } else {
          Serial.println("Fail: Unable to set secure mode");
        }

Hope that helps . . .

Mark J Culross
KD5RXT
 
Last edited:
Mark's answer is correct.

You can also see it in Teensy Loader's Verbose Information window, which is in the Help menu.

Random follow up question, is there a way to tell (I guess just attempting to write to it) that a Teensy is locked?

You can still load new programs after locked into secure mode, if they were created using your key. The loading process is pretty much the same as normal. It does take an extra second or two for an initial step to gain access. During that second you might notice Teensy Loader displays a picture of the main chip and a lock icon. But other than that brief moment, attempting to write new firmware to your locked Teensy works the same as before locked.

Of course, if you try without a .ehex file created by your key, you'll notice difference right away! To test, you could find and delete the .ehex file (but leave the .hex file so Teensy Loader has unencypted data to use), or try with a different PC that doesn't have your key so it can only create a .hex file.

But in the normal course of usage, every time you compile with Arduino IDE both .hex and .ehex are automatically created, if the software finds your key.pem file in the correct location. Everything works pretty much the same way as normal. If you're not looking at that little Teensy Loader window during the brief second while it shows the chip+lock icon, you might not ever notice you're doing anything differently. A lot of work when into making is very simple and easy and as similar to normal as possible.

By far the most important thing with lockable Teensy is to make backup copies of your key.pem file. If you lose that key file, you won't be able to create new .ehex files capable of running on every Teensy you locked with that key. Lockable Teensy doesn't change much about how you write, but it absolutely imposes a requirement that the files you write are .ehex created with the correct key. Make extra backups of your key.pem file, as there is absolutely no way to ever recover it (other than backups) if your PC is lost or damaged!
 
Thank you all so much! I was curious about being able to quickly tell if a Teensy has been locked because I'm curious about using the very state of it being locked to make sure it's an accepted chip... and the ability to utilize a known key to access it, to verify legitimacy.
 
and the ability to utilize a known key to access it, to verify legitimacy.

I'm not 100% certain I understand. But here are some basic guidelines to keep in mind, which may or may not be relevant to your plans.

You should not put any copy of your key.pem file on hardware or software you distribute to customers or the general public. Your key.pem file should be kept secret. Many plenty of backup copies, but keep them all secret.

The key.pem file is used to create the .ehex file when you compile. It is not used to actually load the .ehex file onto Teensy. So you could verify whether a locked Teensy has your key by loading one of your .ehex files onto it. But consider if someone wanted to create an imposter device, and they're willing to go to considerable effort to do so. They could make a USB device that isn't even Teensy, but pretends to be. It could receive all your .ehex file but just ignore the data and lie to you that wrote it into flash memory.

In other words, the process of loading a .ehex file is designed for security of only specific goals. These are the main 2 goals:

1: Confidentiality of the original .hex data
2: Prevent booting or running if the .ehex uses the wrong key

Like so many security protocols, other goals aren't necessarily secure. Teensy Loader does have some checking to prevent writing incompatible .ehex files, but those checks are not designed for strong security. The confirmation of data written isn't done with a secure protocol. Anyone (with significant effort) could craft software that writes the wrong .ehex file to a locked Teensy. They could also create a non-Teensy device that pretends to be Teensy and says .ehex data was written. The process of loading the .ehex file isn't secured. A wrong .ehex can be loaded, but it won't be able to boot.

What an imposter device can't do (or would need to break strong encryption or somehow steal your key to accomplish) is actually running your .ehex program, or extracting the original .hex data from it. Those are the only 2 things lockable Teensy really secures.

As I tried to explain earlier, if you want to design this well, you should strive to create a program which runs on Teensy and can't be easily impersonated. Lockable Teensy's 2 security goals gives you the platform to keep attackers from gaining the unencrypted code. It also prevents them from being able to run it on any other Teensy, and they are prevented from running any program of their making on your lockable Teensy.

There are many ways you could do this, but as far as I know, to have good security for your goal you really need 2 way communication. You'll need to transmit a message of unique data, and have your .ehex code compute an answer that can't be easily guessed. It's important to use unique data, so an attacker who seeks to impersonate your ID hardware can't simply capture the communication on the USB cable and replay it later to impersonate your device.
 
Back
Top