Support for signing EFI executable with certificate chain
edgrz opened this issue · 7 comments
Hello,
We are using go-uefi
library to generate UEFI executables in order to achieve Secure Boot on our systems. However, our UKI certificate we want to provide for creating the Signature is a certificate bundle/chain. However, as it is now it only supports to pass a single certificate object:
func CreateSignature(ctx *PECOFFSigningContext, Cert *x509.Certificate, Key crypto.Signer) ([]byte, error) {
// Tianocore demands that we pad to 8 bytes
// They also need to be added to the checksum file
// We move this out of the checksum function since this padding is
// only applied to the checksums used in the signature.
paddingBytes, _ := PaddingBytes(len(ctx.PEFile), 8)
ctx.PEFile = append(ctx.PEFile, paddingBytes...)
ctx.SigData.Write(paddingBytes)
sigCtx := &pkcs7.SigningContext{
Cert: Cert,
KeySigner: Key,
SigData: ctx.SigData.Bytes(),
Indirect: true,
}
sd, err := pkcs7.SignData(sigCtx)
if err != nil {
return nil, err
}
return sd, nil
}
Is there a way we could provide a certificate chain?
I've been reworking the signing code recently so the linked code is soon obsolete.
https://github.com/Foxboron/go-uefi/blob/master/authenticode/authenticode.go#L128
If you give a complete example on how you would like this to work, I can try and work something out. But I would need help to validate the behaviour.
Hi @Foxboron,
Thanks for the quick response. So basically, we want to generate an EFI executable providing the private key of a certificate for signing it and the certificate that needs to be embedded into the executable is not a self-signed one, so it means we need to provide the whole certificate chain (in my case just the cA and the certificate). So that, what we want is that the method for signing EFI executables (SignEFIExecutable
function in the past and now SignAuthenticode
) allow us to pass not a single cert *x509.Certificate
but a slice of certs (or any other way you think fits here to support certificate chain).
I see you even have already parseCertificates
function, so I think that if pkcs7.SignPKCS7
could support a slice or the bytes, would be already supporting it.
Regarding testing I do have baremetal hardware where i'm testing running Secure Boot system by generating my own ISOs, so I should be able to test it.
Are you expecting go-uefi
to validate the certificate chain, or is this an external process?
Not needed.
So here a useful schema of what we want to achieve (not UEFI): https://www.qualcomm.com/content/dam/qcomm-martech/dm-assets/documents/secure-boot-image-authentication_11.30.16.pdf (page 7)
We want to sign the UEFI executables with a certificate chain, where only the root cA is embedded into the signatureDB. So this would mean for validation that the other certificates of the chain must be embedded in the binary, so that UEFI can iterate over the chain to reach the root cA.
Unless there is an example of a properly signed binary I can compare against, or another form of example, I'm can't promise I'll look at it within any reasonable timeframe.
Hi @Foxboron
I just learned that sbsign
does support embedding multiple certificates into a signed binary... Would this help as a reference?
Usage: sbsign [options] --key <keyfile> --cert <certfile> <efi-boot-image>
Sign an EFI boot image for use with secure boot.
Options:
--engine <eng> use the specified engine to load the key
--key <keyfile> signing key (PEM-encoded RSA private key)
--cert <certfile> certificate (x509 certificate)
--addcert <addcertfile> additional intermediate certificates in a file
--detached write a detached signature, instead of
a signed binary
--output <file> write signed data to <file>
(default <efi-boot-image>.signed,
or <efi-boot-image>.pk7 for detached
signatures
Ah, yes. That makes things a lot easier. Should probably have checked that myself :)