diff options
author | Laszlo Ersek <lersek@redhat.com> | 2018-03-27 17:28:11 +0200 |
---|---|---|
committer | Daiki Ueno <ueno@gnu.org> | 2018-03-30 08:45:49 +0200 |
commit | ee27f9153a14d0c6d75f8745a8c1879a6e4bb2e8 (patch) | |
tree | e519b7a0c031cd8cfedbabb289d2feefcd32b057 /trust | |
parent | 59054e4f9fe3e95f8db881973901ab59a0b1ef8a (diff) |
trust: implement the "edk2-cacerts" extractor
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>
Diffstat (limited to 'trust')
-rw-r--r-- | trust/extract-edk2.c | 169 |
1 files changed, 168 insertions, 1 deletions
diff --git a/trust/extract-edk2.c b/trust/extract-edk2.c index 5bde060..d989346 100644 --- a/trust/extract-edk2.c +++ b/trust/extract-edk2.c @@ -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; } |