Blame trust/extract-edk2.c

Packit Service 3749ba
/*
Packit Service 3749ba
 * Copyright (c) 2018, Red Hat Inc.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Redistribution and use in source and binary forms, with or without
Packit Service 3749ba
 * modification, are permitted provided that the following conditions
Packit Service 3749ba
 * are met:
Packit Service 3749ba
 *
Packit Service 3749ba
 *     * Redistributions of source code must retain the above
Packit Service 3749ba
 *       copyright notice, this list of conditions and the
Packit Service 3749ba
 *       following disclaimer.
Packit Service 3749ba
 *     * Redistributions in binary form must reproduce the
Packit Service 3749ba
 *       above copyright notice, this list of conditions and
Packit Service 3749ba
 *       the following disclaimer in the documentation and/or
Packit Service 3749ba
 *       other materials provided with the distribution.
Packit Service 3749ba
 *     * The names of contributors to this software may not be
Packit Service 3749ba
 *       used to endorse or promote products derived from this
Packit Service 3749ba
 *       software without specific prior written permission.
Packit Service 3749ba
 *
Packit Service 3749ba
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit Service 3749ba
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit Service 3749ba
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
Packit Service 3749ba
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
Packit Service 3749ba
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit Service 3749ba
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
Packit Service 3749ba
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Packit Service 3749ba
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
Packit Service 3749ba
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Packit Service 3749ba
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
Packit Service 3749ba
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
Packit Service 3749ba
 * DAMAGE.
Packit Service 3749ba
 *
Packit Service 3749ba
 * Author: Laszlo Ersek <lersek@redhat.com>
Packit Service 3749ba
 */
Packit Service 3749ba
Packit Service 3749ba
#include "config.h"
Packit Service 3749ba
Packit Service 3749ba
#include "buffer.h"  /* p11_buffer */
Packit Service 3749ba
#include "debug.h"   /* return_val_if_fail() */
Packit Service 3749ba
#include "message.h" /* p11_message() */
Packit Service 3749ba
#include "extract.h" /* p11_extract_edk2_cacerts() */
Packit Service 3749ba
Packit Service 3749ba
#include <stdint.h>  /* UINT32_MAX */
Packit Service 3749ba
#include <limits.h>  /* SSIZE_MAX */
Packit Service 3749ba
Packit Service 3749ba
/* types from the UEFI 2.7 spec, section "31.4.1 Signature Database" */
Packit Service 3749ba
typedef struct {
Packit Service 3749ba
	uint32_t data1;
Packit Service 3749ba
	uint16_t data2;
Packit Service 3749ba
	uint16_t data3;
Packit Service 3749ba
	uint8_t data4[8];
Packit Service 3749ba
} efi_guid;
Packit Service 3749ba
Packit Service 3749ba
typedef struct {
Packit Service 3749ba
	efi_guid signature_type;
Packit Service 3749ba
	uint32_t signature_list_size;
Packit Service 3749ba
	uint32_t signature_header_size;
Packit Service 3749ba
	uint32_t signature_size;
Packit Service 3749ba
} efi_signature_list;
Packit Service 3749ba
Packit Service 3749ba
typedef struct {
Packit Service 3749ba
	efi_guid signature_owner;
Packit Service 3749ba
} efi_signature_data;
Packit Service 3749ba
Packit Service 3749ba
/*
Packit Service 3749ba
 * EFI_CERT_X509_GUID (A5C059A1-94E4-4AA7-87B5-AB155C2BF072) from the UEFI 2.7
Packit Service 3749ba
 * spec, in host byte order
Packit Service 3749ba
 */
Packit Service 3749ba
static const efi_guid efi_cert_x509_guid_host = {
Packit Service 3749ba
	0xa5c059a1,
Packit Service 3749ba
	0x94e4,
Packit Service 3749ba
	0x4aa7,
Packit Service 3749ba
	{ 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 }
Packit Service 3749ba
};
Packit Service 3749ba
Packit Service 3749ba
/*
Packit Service 3749ba
 * the GUID identifying this extractor as "agent"
Packit Service 3749ba
 * (DCDD3B50-F405-43FD-96BE-BD33B1734776, generated with "uuidgen"), in host
Packit Service 3749ba
 * byte order
Packit Service 3749ba
 */
Packit Service 3749ba
static const efi_guid agent_guid_host = {
Packit Service 3749ba
	0xdcdd3b50,
Packit Service 3749ba
	0xf405,
Packit Service 3749ba
	0x43fd,
Packit Service 3749ba
	{ 0x96, 0xbe, 0xbd, 0x33, 0xb1, 0x73, 0x47, 0x76 }
Packit Service 3749ba
};
Packit Service 3749ba
Packit Service 3749ba
/* serialization helpers */
Packit Service 3749ba
static void
Packit Service 3749ba
buffer_add_uint16 (p11_buffer *buffer,
Packit Service 3749ba
                   uint16_t uint16)
Packit Service 3749ba
{
Packit Service 3749ba
	uint8_t uint16_buf[2];
Packit Service 3749ba
Packit Service 3749ba
	uint16_buf[0] = uint16;
Packit Service 3749ba
	uint16_buf[1] = uint16 >> 8;
Packit Service 3749ba
	p11_buffer_add (buffer, &uint16_buf, sizeof uint16_buf);
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
static void
Packit Service 3749ba
buffer_add_uint32 (p11_buffer *buffer,
Packit Service 3749ba
                   uint32_t uint32)
Packit Service 3749ba
{
Packit Service 3749ba
	uint8_t uint32_buf[4];
Packit Service 3749ba
Packit Service 3749ba
	uint32_buf[0] = uint32;
Packit Service 3749ba
	uint32_buf[1] = uint32 >> 8;
Packit Service 3749ba
	uint32_buf[2] = uint32 >> 16;
Packit Service 3749ba
	uint32_buf[3] = uint32 >> 24;
Packit Service 3749ba
	p11_buffer_add (buffer, &uint32_buf, sizeof uint32_buf);
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
static void
Packit Service 3749ba
buffer_add_efi_guid (p11_buffer *buffer,
Packit Service 3749ba
                     const efi_guid *guid)
Packit Service 3749ba
{
Packit Service 3749ba
	buffer_add_uint32 (buffer, guid->data1);
Packit Service 3749ba
	buffer_add_uint16 (buffer, guid->data2);
Packit Service 3749ba
	buffer_add_uint16 (buffer, guid->data3);
Packit Service 3749ba
	p11_buffer_add (buffer, guid->data4, sizeof guid->data4);
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
static void
Packit Service 3749ba
buffer_add_efi_signature_list (p11_buffer *buffer,
Packit Service 3749ba
                               const efi_signature_list *siglist)
Packit Service 3749ba
{
Packit Service 3749ba
	buffer_add_efi_guid (buffer, &siglist->signature_type);
Packit Service 3749ba
	buffer_add_uint32 (buffer, siglist->signature_list_size);
Packit Service 3749ba
	buffer_add_uint32 (buffer, siglist->signature_header_size);
Packit Service 3749ba
	buffer_add_uint32 (buffer, siglist->signature_size);
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
static void
Packit Service 3749ba
buffer_add_efi_signature_data (p11_buffer *buffer,
Packit Service 3749ba
                               const efi_signature_data *sigdata)
Packit Service 3749ba
{
Packit Service 3749ba
	buffer_add_efi_guid (buffer, &sigdata->signature_owner);
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
/* main routine */
Packit Service 3749ba
static bool
Packit Service 3749ba
prepare_edk2_buffer (p11_enumerate *ex,
Packit Service 3749ba
                     p11_buffer *buffer)
Packit Service 3749ba
{
Packit Service 3749ba
	efi_signature_list siglist;
Packit Service 3749ba
	efi_signature_data sigdata;
Packit Service 3749ba
	CK_RV rv;
Packit Service 3749ba
	size_t size;
Packit Service 3749ba
Packit Service 3749ba
	/*
Packit Service 3749ba
	 * set "siglist.signature_type" and "sigdata.signature_owner" for reuse
Packit Service 3749ba
	 * across all certificates
Packit Service 3749ba
	 */
Packit Service 3749ba
	siglist.signature_type = efi_cert_x509_guid_host;
Packit Service 3749ba
	sigdata.signature_owner = agent_guid_host;
Packit Service 3749ba
Packit Service 3749ba
	/* also reuse a zero "siglist.signature_header_size" */
Packit Service 3749ba
	siglist.signature_header_size = 0;
Packit Service 3749ba
Packit Service 3749ba
	/* for every certificate */
Packit Service 3749ba
	while ((rv = p11_kit_iter_next (ex->iter)) == CKR_OK) {
Packit Service 3749ba
		size = sizeof sigdata;
Packit Service 3749ba
Packit Service 3749ba
		/*
Packit Service 3749ba
		 * set the variable size fields in "siglist" while catching any
Packit Service 3749ba
		 * (unlikely) integer overflows
Packit Service 3749ba
		 */
Packit Service 3749ba
		return_val_if_fail (ex->cert_len <= UINT32_MAX - size, false);
Packit Service 3749ba
		size += ex->cert_len;
Packit Service 3749ba
		siglist.signature_size = size;
Packit Service 3749ba
Packit Service 3749ba
		return_val_if_fail (sizeof siglist <= UINT32_MAX - size, false);
Packit Service 3749ba
		size += sizeof siglist;
Packit Service 3749ba
		siglist.signature_list_size = size;
Packit Service 3749ba
Packit Service 3749ba
		/* serialize the headers */
Packit Service 3749ba
		buffer_add_efi_signature_list (buffer, &siglist);
Packit Service 3749ba
		buffer_add_efi_signature_data (buffer, &sigdata);
Packit Service 3749ba
Packit Service 3749ba
		/* serialize the DER encoding of the certificate */
Packit Service 3749ba
		return_val_if_fail (ex->cert_len <= SSIZE_MAX, false);
Packit Service 3749ba
		p11_buffer_add (buffer, ex->cert_der, ex->cert_len);
Packit Service 3749ba
	}
Packit Service 3749ba
Packit Service 3749ba
	if (rv != CKR_CANCEL) {
Packit Service 3749ba
		p11_message ("failed to find certificate: %s",
Packit Service 3749ba
		             p11_kit_strerror (rv));
Packit Service 3749ba
		return false;
Packit Service 3749ba
	}
Packit Service 3749ba
Packit Service 3749ba
	return_val_if_fail (p11_buffer_ok (buffer), false);
Packit Service 3749ba
	return true;
Packit Service 3749ba
}
Packit Service 3749ba
Packit Service 3749ba
bool
Packit Service 3749ba
p11_extract_edk2_cacerts (p11_enumerate *ex,
Packit Service 3749ba
                          const char *destination)
Packit Service 3749ba
{
Packit Service 3749ba
	p11_buffer buffer;
Packit Service 3749ba
	p11_save_file *file;
Packit Service 3749ba
	bool ret;
Packit Service 3749ba
Packit Service 3749ba
	p11_buffer_init (&buffer, 1024 * 10);
Packit Service 3749ba
	ret = prepare_edk2_buffer (ex, &buffer);
Packit Service 3749ba
	if (ret) {
Packit Service 3749ba
		file = p11_save_open_file (destination, NULL, ex->flags);
Packit Service 3749ba
		ret = p11_save_write_and_finish (file, buffer.data, buffer.len);
Packit Service 3749ba
	}
Packit Service 3749ba
Packit Service 3749ba
	p11_buffer_uninit (&buffer);
Packit Service 3749ba
	return ret;
Packit Service 3749ba
}