Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider reconstructing IDevID cert in Runtime #294

Closed
jhand2 opened this issue May 19, 2023 · 14 comments · Fixed by #709
Closed

Consider reconstructing IDevID cert in Runtime #294

jhand2 opened this issue May 19, 2023 · 14 comments · Fixed by #709

Comments

@jhand2
Copy link
Collaborator

jhand2 commented May 19, 2023

There are fuses for the vendor to program a signature over IDevID. It would be possible for Caliptra Runtime firmware to expose a mailbox command which takes some data (like the issuer name) and reconstructs the IDevID certificate.

A few things we would need to do for this to work:

  • Develop strict requirements for vendor CAs on the contents of the IDevID cert they produce
  • Pass some extra info in DataVault or DCCM from ROM to runtime
    • IDevID Public Key
    • IDevID Serial Number
    • IDevID UEID

cc @jameszhang-nvidia @mhatrevi @bluegate010

@jameszhang-nvidia
Copy link
Collaborator

Hi @jhand2
I filed chipsalliance/Caliptra#48 to update Caliptra spec to include the deterministic way of generating IDevID cert and that would be part of integration requirement if it needs some kind of HW register interface on Caliptra to do so. However my suggestion is to NOT do that and instead use a mailbox command to pass in the necessary fields.

I think the onlything that the ROM needs to pass to RT would be the IDevID Public Key and the IDevID Signature in FUSE if fuse is not accessible at that time. The serial number and issuer/subject are all items that needs to be passed in from the silicon vendor owned SOC manager from the call.

We also need to come up with a strict template that can be used. for example. the following

Serial Number: Need to define number of bytes (16?)
Issuer: needs to define number of bytes the string will take
Validity: Hard code a not before and not after?
Subject: Usually a combination of the serial number string then another string, need to determine bytes
Extension: What else other than the ones shown, AIA?
Extension: replace subject key and authority key identifier with proper hash of the relative keys (authority key identifier needs to be passed in from SOC manager)
Signature Value: from Caliptra fuse.

Certificate:

  • Data:
    • Version: 3 (0x2)
    • Serial Number:
      • xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
    • Signature Algorithm: ecdsa-with-SHA384
    • Issuer: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    • Validity
      • Not Before: Oct 17 00:00:00 2020 GMT
      • Not After : Dec 31 23:59:59 9999 GMT
    • Subject: serialNumber = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    • Subject Public Key Info:
      • Public Key Algorithm: id-ecPublicKey
        • Public-Key: (384 bit)
        • pub:
          • xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx: ...
        • ASN1 OID: secp384r1
        • NIST CURVE: P-384
    • X509v3 extensions:
      • X509v3 Basic Constraints: critical
        • CA:TRUE
      • X509v3 Key Usage: critical
        • Certificate Sign
      • X509v3 Subject Key Identifier:
        • xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
      • X509v3 Authority Key Identifier:
        • xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
    • Signature Algorithm: ecdsa-with-SHA384
    • Signature Value:
      • xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:x ...

@jhand2
Copy link
Collaborator Author

jhand2 commented May 19, 2023

One thing to note is that the issuer will be variable-length. But I think this is ok. The DPE implementation already does ~full X.509 serialization. So we just need to make that library a little more general purpose and it can be used for this.

@jameszhang-nvidia
Copy link
Collaborator

I think that works too Jordan, My original thought is that it might be more secure if we know exactly how many bytes the information being passed in is. If we create a more complicated mailbox command handler where the caliptra handler can also parse the input asn.1 object's length then that would be fine too.

Lets talk about it in the FW meeting a bit and if we can all agree with going this approach then we should write it up in as part of the spec.

@jhand2
Copy link
Collaborator Author

jhand2 commented May 19, 2023

Sounds good. I think it will be hard to place a restriction on exactly how many bytes the issuer is. The issuer must be the subject of the CA key, so it is highly dependent on the vendor PKI.

I don't think Caliptra needs to parse anything though. Caller passes a DER-encoded name field along with the size. Caliptra will just drop that into the cert it's constructing. If the caller passes something wrong, the signature will be wrong.

@flanfly
Copy link

flanfly commented May 31, 2023

Hello. I'm trying to understand what needs to be done here. I'm not a hardware guy so bear with me here. As far as I understand we don't want to put the device ID's X.509 certificate into the fuses (I guess fuse space is expensive). Instead only the certificate's public key and it's signature is fused, all other variable data like subject and issuer are sent by the ROM. The firmware receives these values from the ROM, pulls the signature and public key out of the fuses, pastes that into a hardcoded X.509 structure and sends it out via the mailbox interface.

In case this is roughly correct, would it be enough to use this certificate generation code in caliptra-x509 at runtime?

let bldr = cert::CertTemplateBuilder::<EcdsaSha384Algo>::new()
.add_basic_constraints_ext(true, 0)
.add_key_usage_ext(usage)
.add_ueid_ext(&[0xFF; 8]);

@jhand2
Copy link
Collaborator Author

jhand2 commented May 31, 2023

Some small clarifications

The signature is fused. The public key is deterministic, so can just be passed up by ROM.

all other variable data like subject and issuer are sent by the ROM

ROM doesn't have all of these details. Instead, the caller of the mailbox command will pass this information (at least the issuer).

The subject is chosen by ROM, so that could either be passed up or just hard-coded in Runtime.

In case this is roughly correct, would it be enough to use this certificate generation code in caliptra-x509 at runtime?

This code generates a template at build time. Then firmware would fill the variable fields at runtime.

However, one thing we discussed last week was a potentially simpler option:

  1. Caliptra exposes a mailbox command to give the IDevID Public key
  2. The mailbox caller stitches together the to-be-signed portion of the cert.
  3. Mailbox caller calls the mailbox command get generate the IDevID cert and passes the whole TBS portion. Caliptra just appends the signature from fuses.

This allows the SoC vendor to be more flexible with their IDevID certificate and not have to be constrained to the format Caliptra can reproduce.

I'll raise this this week and see if we can get more clarity on which route we want to take.

@jameszhang-nvidia
Copy link
Collaborator

Hi Jordan, just want to close on this. I believe we did discuss this topic a month ago and the general consensus is to follow your outlined 3 step above. Just want to ensure this is agreed and I'll close issue #48 in the main Caliptra github.

Thanks

@jhand2
Copy link
Collaborator Author

jhand2 commented Jun 30, 2023

I believe AMD folks were going to get back to us on whether option 3 is acceptable to them. If so, then I agree we can move forward with that (I've already made the ROM changes to pass up the IDevID public key to accomodate this).

cc @JohnTraverAmd, not sure who from your side should look at this.

@jhand2
Copy link
Collaborator Author

jhand2 commented Aug 2, 2023

To clarify, the current proposal is:

Goal: Reproduce the IDevID certificate that was created/signed during manufacturing.

  1. Caliptra implements a mailbox command GET_IDEV_INFO with the following request/response
// No inputs
struct GetIDevInfoReq{}

// Returns the IDevID public key
struct GetIDevInfoResp {
    idev_pub_x: [u8; 48],
    idev_pub_y: [u8; 48],
}
  1. Caliptra implements a mailbox command BUILD_IDEV_CERT with the following request/response
// Send the TBS
struct BuildIDevCert{
    pub tbs[u8; MAX_TBS_LEN];
}

// Returns IDevID cert, including the appended signature
struct GetIDevInfoResp {
    tbs: [u8; MAX_CERT_LEN],
}
  1. SoC is responsible for doing something like this
let idev_pub = get_idev_info();

// If is up to the SoC to have an IDevID TBS template. SoC can then populate that template
// with idev_pub

let cert = build_idev_cert(idev_pub);

@ArthurHeymans
Copy link
Contributor

I have some questions.

From the discussion suggests that the signature needs to be appended from the fuses. What does this mean? Is the signature something that can be fetched from the fuses and need to be appended to the cert, or does appended from fuses mean in this context that there is a mechanism in which the content of the fuses can generate a signature for the provided TBS cert?

How does getting the signature from fuses or signing from fuses work? I see similar code for the ldevid but I failed to find the equivalent for idevid.

@jhand2
Copy link
Collaborator Author

jhand2 commented Aug 17, 2023

@ArthurHeymans During manufactuing, the vendor will

  1. Provision the UDS in fuses (to give Caliptra an identity)
  2. Ask Caliptra for the self-signed IDevID CSR
  3. Verify the CSR and produce a signed IDevID certificate.

If the vendor chooses, they can then blow the IDevID cert signature into fuses, so that it is available to Caliptra for the lifetime of the chip. Caliptra can read those fuse values from this set of registers: https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.soc_ifc_reg.fuse_idevid_cert_attr%5B0%5D

We'll want to add the ability to read these registers from the soc_ifc driver, but it looks like that feature isn't present today.

The autogenerated register access code for the signature is here:

pub fn fuse_idevid_cert_attr(

@ArthurHeymans
Copy link
Contributor

@ArthurHeymans During manufactuing, the vendor will

1. Provision the UDS in fuses (to give Caliptra an identity)

2. Ask Caliptra for the self-signed IDevID CSR

3. Verify the CSR and produce a signed IDevID certificate.

If the vendor chooses, they can then blow the IDevID cert signature into fuses, so that it is available to Caliptra for the lifetime of the chip. Caliptra can read those fuse values from this set of registers: https://chipsalliance.github.io/caliptra-rtl/main/internal-regs/?p=clp.soc_ifc_reg.fuse_idevid_cert_attr%5B0%5D

We'll want to add the ability to read these registers from the soc_ifc driver, but it looks like that feature isn't present today.

The autogenerated register access code for the signature is here:

pub fn fuse_idevid_cert_attr(

Alright, I was confused. I somehow thought there was a requirement that things like serial number in the CERT can be chosen by the SoC calling the mailbox. That however is not true? They need to be exactly the same as the one in the CERT used to provision the fuses. Otherwise the signature won't be valid.

Is this true? Does this not defeat the purpose of being able to regenerate the IDevId CERT at runtime? The one calling the mailbox needs to know pretty much everything besides the public key when using the mailbox?

@jhand2
Copy link
Collaborator Author

jhand2 commented Aug 22, 2023

@ArthurHeymans

They need to be exactly the same as the one in the CERT used to provision the fuses. Otherwise the signature won't be valid.

Correct

The one calling the mailbox needs to know pretty much everything besides the public key when using the mailbox?

They also don't know the signature. It's true that Caliptra is doing very little here. In the future we may add another mechanism where Caliptra builds the whole cert, but that would require Caliptra to be much more opinionated about what the vendor puts in the certificate during manufacturing. So that is out of scope for Caliptra 1.0.

@ArthurHeymans
Copy link
Contributor

@ArthurHeymans

They need to be exactly the same as the one in the CERT used to provision the fuses. Otherwise the signature won't be valid.

Correct

The one calling the mailbox needs to know pretty much everything besides the public key when using the mailbox?

They also don't know the signature. It's true that Caliptra is doing very little here. In the future we may add another mechanism where Caliptra builds the whole cert, but that would require Caliptra to be much more opinionated about what the vendor puts in the certificate during manufacturing. So that is out of scope for Caliptra 1.0.

I see that a few things are being programmed in the sw-emulator fuses besides the CERT signature https://github.com/chipsalliance/caliptra-sw/blob/main/sw-emulator/app/src/main.rs#L314

What is the format of what needs to be programmed into fuses?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants