Skip to content

Commit

Permalink
trust: implement the "edk2-cacerts" extractor
Browse files Browse the repository at this point in the history
Extract the DER-encoded X.509 certificates in the EFI_SIGNATURE_LIST
format that is

- defined by the UEFI 2.7 spec (using one inner EFI_SIGNATURE_DATA object
  per EFI_SIGNATURE_LIST, as specified for EFI_CERT_X509_GUID),

- and expected by edk2's HttpDxe when it configures the certificate list
  for HTTPS boot from EFI_TLS_CA_CERTIFICATE_VARIABLE (see the
  TlsConfigCertificate() function in "NetworkPkg/HttpDxe/HttpsSupport.c").

The intended command line is

  p11-kit extract \
    --format=edk2-cacerts \
    --filter=ca-anchors \
    --overwrite \
    --purpose=server-auth \
    $DEST/edk2/cacerts.bin

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1559580
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
  • Loading branch information
lersek authored and ueno committed Mar 30, 2018
1 parent 59054e4 commit ee27f91
Showing 1 changed file with 168 additions and 1 deletion.
169 changes: 168 additions & 1 deletion trust/extract-edk2.c
Expand Up @@ -34,11 +34,178 @@

#include "config.h"

#include "buffer.h" /* p11_buffer */
#include "debug.h" /* return_val_if_fail() */
#include "message.h" /* p11_message() */
#include "extract.h" /* p11_extract_edk2_cacerts() */

#include <stdint.h> /* UINT32_MAX */
#include <limits.h> /* SSIZE_MAX */

/* types from the UEFI 2.7 spec, section "31.4.1 Signature Database" */
typedef struct {
uint32_t data1;
uint16_t data2;
uint16_t data3;
uint8_t data4[8];
} efi_guid;

typedef struct {
efi_guid signature_type;
uint32_t signature_list_size;
uint32_t signature_header_size;
uint32_t signature_size;
} efi_signature_list;

typedef struct {
efi_guid signature_owner;
} efi_signature_data;

/*
* EFI_CERT_X509_GUID (A5C059A1-94E4-4AA7-87B5-AB155C2BF072) from the UEFI 2.7
* spec, in host byte order
*/
static const efi_guid efi_cert_x509_guid_host = {
0xa5c059a1,
0x94e4,
0x4aa7,
{ 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 }
};

/*
* the GUID identifying this extractor as "agent"
* (DCDD3B50-F405-43FD-96BE-BD33B1734776, generated with "uuidgen"), in host
* byte order
*/
static const efi_guid agent_guid_host = {
0xdcdd3b50,
0xf405,
0x43fd,
{ 0x96, 0xbe, 0xbd, 0x33, 0xb1, 0x73, 0x47, 0x76 }
};

/* serialization helpers */
static void
buffer_add_uint16 (p11_buffer *buffer,
uint16_t uint16)
{
uint8_t uint16_buf[2];

uint16_buf[0] = uint16;
uint16_buf[1] = uint16 >> 8;
p11_buffer_add (buffer, &uint16_buf, sizeof uint16_buf);
}

static void
buffer_add_uint32 (p11_buffer *buffer,
uint32_t uint32)
{
uint8_t uint32_buf[4];

uint32_buf[0] = uint32;
uint32_buf[1] = uint32 >> 8;
uint32_buf[2] = uint32 >> 16;
uint32_buf[3] = uint32 >> 24;
p11_buffer_add (buffer, &uint32_buf, sizeof uint32_buf);
}

static void
buffer_add_efi_guid (p11_buffer *buffer,
const efi_guid *guid)
{
buffer_add_uint32 (buffer, guid->data1);
buffer_add_uint16 (buffer, guid->data2);
buffer_add_uint16 (buffer, guid->data3);
p11_buffer_add (buffer, guid->data4, sizeof guid->data4);
}

static void
buffer_add_efi_signature_list (p11_buffer *buffer,
const efi_signature_list *siglist)
{
buffer_add_efi_guid (buffer, &siglist->signature_type);
buffer_add_uint32 (buffer, siglist->signature_list_size);
buffer_add_uint32 (buffer, siglist->signature_header_size);
buffer_add_uint32 (buffer, siglist->signature_size);
}

static void
buffer_add_efi_signature_data (p11_buffer *buffer,
const efi_signature_data *sigdata)
{
buffer_add_efi_guid (buffer, &sigdata->signature_owner);
}

/* main routine */
static bool
prepare_edk2_buffer (p11_enumerate *ex,
p11_buffer *buffer)
{
efi_signature_list siglist;
efi_signature_data sigdata;
CK_RV rv;
size_t size;

/*
* set "siglist.signature_type" and "sigdata.signature_owner" for reuse
* across all certificates
*/
siglist.signature_type = efi_cert_x509_guid_host;
sigdata.signature_owner = agent_guid_host;

/* also reuse a zero "siglist.signature_header_size" */
siglist.signature_header_size = 0;

/* for every certificate */
while ((rv = p11_kit_iter_next (ex->iter)) == CKR_OK) {
size = sizeof sigdata;

/*
* set the variable size fields in "siglist" while catching any
* (unlikely) integer overflows
*/
return_val_if_fail (ex->cert_len <= UINT32_MAX - size, false);
size += ex->cert_len;
siglist.signature_size = size;

return_val_if_fail (sizeof siglist <= UINT32_MAX - size, false);
size += sizeof siglist;
siglist.signature_list_size = size;

/* serialize the headers */
buffer_add_efi_signature_list (buffer, &siglist);
buffer_add_efi_signature_data (buffer, &sigdata);

/* serialize the DER encoding of the certificate */
return_val_if_fail (ex->cert_len <= SSIZE_MAX, false);
p11_buffer_add (buffer, ex->cert_der, ex->cert_len);
}

if (rv != CKR_CANCEL) {
p11_message ("failed to find certificate: %s",
p11_kit_strerror (rv));
return false;
}

return_val_if_fail (p11_buffer_ok (buffer), false);
return true;
}

bool
p11_extract_edk2_cacerts (p11_enumerate *ex,
const char *destination)
{
return false;
p11_buffer buffer;
p11_save_file *file;
bool ret;

p11_buffer_init (&buffer, 1024 * 10);
ret = prepare_edk2_buffer (ex, &buffer);
if (ret) {
file = p11_save_open_file (destination, NULL, ex->flags);
ret = p11_save_write_and_finish (file, buffer.data, buffer.len);
}

p11_buffer_uninit (&buffer);
return ret;
}

0 comments on commit ee27f91

Please sign in to comment.