Move sources to src/ subdirectory
We have a number of source files now, so move them from the top level to src/ Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
This commit is contained in:
parent
5466f381dd
commit
c7ee585439
22 changed files with 47 additions and 46 deletions
32
src/Makefile.am
Normal file
32
src/Makefile.am
Normal file
|
@ -0,0 +1,32 @@
|
|||
|
||||
bin_PROGRAMS = sbsign sbverify sbattach sbvarsign sbsiglist
|
||||
|
||||
coff_headers = coff/external.h coff/pe.h
|
||||
AM_CFLAGS = -Wall -Wextra --std=gnu99
|
||||
|
||||
common_SOURCES = idc.c idc.h image.c image.h fileio.c fileio.h \
|
||||
efivars.h $(coff_headers)
|
||||
common_LDADD = ../lib/ccan/libccan.a $(libcrypto_LIBS)
|
||||
common_CFLAGS = -I$(top_srcdir)/lib/ccan/
|
||||
|
||||
sbsign_SOURCES = sbsign.c $(common_SOURCES)
|
||||
sbsign_LDADD = $(common_LDADD)
|
||||
sbsign_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS)
|
||||
|
||||
sbverify_SOURCES = sbverify.c $(common_SOURCES)
|
||||
sbverify_LDADD = $(common_LDADD)
|
||||
sbverify_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS)
|
||||
|
||||
sbattach_SOURCES = sbattach.c $(common_SOURCES)
|
||||
sbattach_LDADD = $(common_LDADD)
|
||||
sbattach_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS)
|
||||
|
||||
sbvarsign_SOURCES = sbvarsign.c $(common_SOURCES)
|
||||
sbvarsign_LDADD = $(common_LDADD) $(uuid_LIBS)
|
||||
sbvarsign_CPPFLAGS = $(EFI_CPPFLAGS)
|
||||
sbvarsign_CFLAGS = $(AM_CFLAGS) $(uuid_CFLAGS) $(common_CFLAGS)
|
||||
|
||||
sbsiglist_SOURCES = sbsiglist.c $(common_SOURCES)
|
||||
sbsiglist_LDADD = $(common_LDADD) $(uuid_LIBS)
|
||||
sbsiglist_CPPFLAGS = $(EFI_CPPFLAGS)
|
||||
sbsiglist_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS)
|
269
src/coff/external.h
Normal file
269
src/coff/external.h
Normal file
|
@ -0,0 +1,269 @@
|
|||
/* external.h -- External COFF structures
|
||||
|
||||
Copyright 2001, 2006, 2010 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
MA 02110-1301, USA. */
|
||||
|
||||
#ifndef COFF_EXTERNAL_H
|
||||
#define COFF_EXTERNAL_H
|
||||
|
||||
#ifndef DO_NOT_DEFINE_FILHDR
|
||||
/********************** FILE HEADER **********************/
|
||||
|
||||
struct external_filehdr
|
||||
{
|
||||
char f_magic[2]; /* magic number */
|
||||
char f_nscns[2]; /* number of sections */
|
||||
char f_timdat[4]; /* time & date stamp */
|
||||
char f_symptr[4]; /* file pointer to symtab */
|
||||
char f_nsyms[4]; /* number of symtab entries */
|
||||
char f_opthdr[2]; /* sizeof(optional hdr) */
|
||||
char f_flags[2]; /* flags */
|
||||
};
|
||||
|
||||
#define FILHDR struct external_filehdr
|
||||
#define FILHSZ 20
|
||||
#endif
|
||||
|
||||
#ifndef DO_NOT_DEFINE_AOUTHDR
|
||||
/********************** AOUT "OPTIONAL HEADER" **********************/
|
||||
|
||||
typedef struct external_aouthdr
|
||||
{
|
||||
char magic[2]; /* type of file */
|
||||
char vstamp[2]; /* version stamp */
|
||||
char tsize[4]; /* text size in bytes, padded to FW bdry*/
|
||||
char dsize[4]; /* initialized data " " */
|
||||
char bsize[4]; /* uninitialized data " " */
|
||||
char entry[4]; /* entry pt. */
|
||||
char text_start[4]; /* base of text used for this file */
|
||||
char data_start[4]; /* base of data used for this file */
|
||||
} ATTRIBUTE_PACKED
|
||||
AOUTHDR;
|
||||
|
||||
#define AOUTHDRSZ 28
|
||||
#define AOUTSZ 28
|
||||
|
||||
typedef struct external_aouthdr64
|
||||
{
|
||||
char magic[2]; /* Type of file. */
|
||||
char vstamp[2]; /* Version stamp. */
|
||||
char tsize[4]; /* Text size in bytes, padded to FW bdry*/
|
||||
char dsize[4]; /* Initialized data " ". */
|
||||
char bsize[4]; /* Uninitialized data " ". */
|
||||
char entry[4]; /* Entry pt. */
|
||||
char text_start[4]; /* Base of text used for this file. */
|
||||
}
|
||||
AOUTHDR64;
|
||||
#define AOUTHDRSZ64 24
|
||||
|
||||
#endif /* not DO_NOT_DEFINE_AOUTHDR */
|
||||
|
||||
#ifndef DO_NOT_DEFINE_SCNHDR
|
||||
/********************** SECTION HEADER **********************/
|
||||
|
||||
struct external_scnhdr
|
||||
{
|
||||
char s_name[8]; /* section name */
|
||||
char s_paddr[4]; /* physical address, aliased s_nlib */
|
||||
char s_vaddr[4]; /* virtual address */
|
||||
char s_size[4]; /* section size */
|
||||
char s_scnptr[4]; /* file ptr to raw data for section */
|
||||
char s_relptr[4]; /* file ptr to relocation */
|
||||
char s_lnnoptr[4]; /* file ptr to line numbers */
|
||||
char s_nreloc[2]; /* number of relocation entries */
|
||||
char s_nlnno[2]; /* number of line number entries */
|
||||
char s_flags[4]; /* flags */
|
||||
};
|
||||
|
||||
#define SCNHDR struct external_scnhdr
|
||||
#define SCNHSZ 40
|
||||
|
||||
/* Names of "special" sections. */
|
||||
|
||||
#define _TEXT ".text"
|
||||
#define _DATA ".data"
|
||||
#define _BSS ".bss"
|
||||
#define _COMMENT ".comment"
|
||||
#define _LIB ".lib"
|
||||
#endif /* not DO_NOT_DEFINE_SCNHDR */
|
||||
|
||||
#ifndef DO_NOT_DEFINE_LINENO
|
||||
|
||||
/********************** LINE NUMBERS **********************/
|
||||
|
||||
#ifndef L_LNNO_SIZE
|
||||
#error L_LNNO_SIZE needs to be defined
|
||||
#endif
|
||||
|
||||
/* 1 line number entry for every "breakpointable" source line in a section.
|
||||
Line numbers are grouped on a per function basis; first entry in a function
|
||||
grouping will have l_lnno = 0 and in place of physical address will be the
|
||||
symbol table index of the function name. */
|
||||
struct external_lineno
|
||||
{
|
||||
union
|
||||
{
|
||||
char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
|
||||
char l_paddr[4]; /* (physical) address of line number */
|
||||
} l_addr;
|
||||
|
||||
char l_lnno[L_LNNO_SIZE]; /* line number */
|
||||
};
|
||||
|
||||
#define LINENO struct external_lineno
|
||||
#define LINESZ (4 + L_LNNO_SIZE)
|
||||
|
||||
#if L_LNNO_SIZE == 4
|
||||
#define GET_LINENO_LNNO(abfd, ext) H_GET_32 (abfd, (ext->l_lnno))
|
||||
#define PUT_LINENO_LNNO(abfd, val, ext) H_PUT_32 (abfd, val, (ext->l_lnno))
|
||||
#endif
|
||||
#if L_LNNO_SIZE == 2
|
||||
#define GET_LINENO_LNNO(abfd, ext) H_GET_16 (abfd, (ext->l_lnno))
|
||||
#define PUT_LINENO_LNNO(abfd, val, ext) H_PUT_16 (abfd, val, (ext->l_lnno))
|
||||
#endif
|
||||
|
||||
#endif /* not DO_NOT_DEFINE_LINENO */
|
||||
|
||||
#ifndef DO_NOT_DEFINE_SYMENT
|
||||
/********************** SYMBOLS **********************/
|
||||
|
||||
#define E_SYMNMLEN 8 /* # characters in a symbol name */
|
||||
#ifndef E_FILNMLEN
|
||||
#define E_FILNMLEN 14
|
||||
#endif
|
||||
#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
|
||||
|
||||
struct external_syment
|
||||
{
|
||||
union
|
||||
{
|
||||
char e_name[E_SYMNMLEN];
|
||||
|
||||
struct
|
||||
{
|
||||
char e_zeroes[4];
|
||||
char e_offset[4];
|
||||
} e;
|
||||
} e;
|
||||
|
||||
char e_value[4];
|
||||
char e_scnum[2];
|
||||
char e_type[2];
|
||||
char e_sclass[1];
|
||||
char e_numaux[1];
|
||||
} ATTRIBUTE_PACKED ;
|
||||
|
||||
#define SYMENT struct external_syment
|
||||
#define SYMESZ 18
|
||||
|
||||
#ifndef N_BTMASK
|
||||
#define N_BTMASK 0xf
|
||||
#endif
|
||||
|
||||
#ifndef N_TMASK
|
||||
#define N_TMASK 0x30
|
||||
#endif
|
||||
|
||||
#ifndef N_BTSHFT
|
||||
#define N_BTSHFT 4
|
||||
#endif
|
||||
|
||||
#ifndef N_TSHIFT
|
||||
#define N_TSHIFT 2
|
||||
#endif
|
||||
|
||||
#endif /* not DO_NOT_DEFINE_SYMENT */
|
||||
|
||||
#ifndef DO_NOT_DEFINE_AUXENT
|
||||
|
||||
union external_auxent
|
||||
{
|
||||
struct
|
||||
{
|
||||
char x_tagndx[4]; /* str, un, or enum tag indx */
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
char x_lnno[2]; /* declaration line number */
|
||||
char x_size[2]; /* str/union/array size */
|
||||
} x_lnsz;
|
||||
|
||||
char x_fsize[4]; /* size of function */
|
||||
|
||||
} x_misc;
|
||||
|
||||
union
|
||||
{
|
||||
struct /* if ISFCN, tag, or .bb */
|
||||
{
|
||||
char x_lnnoptr[4]; /* ptr to fcn line # */
|
||||
char x_endndx[4]; /* entry ndx past block end */
|
||||
} x_fcn;
|
||||
|
||||
struct /* if ISARY, up to 4 dimen. */
|
||||
{
|
||||
char x_dimen[E_DIMNUM][2];
|
||||
} x_ary;
|
||||
|
||||
} x_fcnary;
|
||||
|
||||
char x_tvndx[2]; /* tv index */
|
||||
|
||||
} x_sym;
|
||||
|
||||
union
|
||||
{
|
||||
char x_fname[E_FILNMLEN];
|
||||
|
||||
struct
|
||||
{
|
||||
char x_zeroes[4];
|
||||
char x_offset[4];
|
||||
} x_n;
|
||||
|
||||
} x_file;
|
||||
|
||||
struct
|
||||
{
|
||||
char x_scnlen[4]; /* section length */
|
||||
char x_nreloc[2]; /* # relocation entries */
|
||||
char x_nlinno[2]; /* # line numbers */
|
||||
#ifdef INCLUDE_COMDAT_FIELDS_IN_AUXENT
|
||||
char x_checksum[4]; /* section COMDAT checksum */
|
||||
char x_associated[2]; /* COMDAT associated section index */
|
||||
char x_comdat[1]; /* COMDAT selection number */
|
||||
#endif
|
||||
} x_scn;
|
||||
|
||||
struct
|
||||
{
|
||||
char x_tvfill[4]; /* tv fill value */
|
||||
char x_tvlen[2]; /* length of .tv */
|
||||
char x_tvran[2][2]; /* tv range */
|
||||
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
|
||||
} ATTRIBUTE_PACKED ;
|
||||
|
||||
#define AUXENT union external_auxent
|
||||
#define AUXESZ 18
|
||||
|
||||
#define _ETEXT "etext"
|
||||
|
||||
#endif /* not DO_NOT_DEFINE_AUXENT */
|
||||
|
||||
#endif /* COFF_EXTERNAL_H */
|
512
src/coff/pe.h
Normal file
512
src/coff/pe.h
Normal file
|
@ -0,0 +1,512 @@
|
|||
/* pe.h - PE COFF header information
|
||||
|
||||
Copyright 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2009, 2010
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of BFD, the Binary File Descriptor library.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
#ifndef _PE_H
|
||||
#define _PE_H
|
||||
|
||||
/* NT specific file attributes. */
|
||||
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
|
||||
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
|
||||
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
|
||||
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
|
||||
#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
|
||||
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
|
||||
#define IMAGE_FILE_16BIT_MACHINE 0x0040
|
||||
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
|
||||
#define IMAGE_FILE_32BIT_MACHINE 0x0100
|
||||
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
|
||||
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
|
||||
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
|
||||
#define IMAGE_FILE_SYSTEM 0x1000
|
||||
#define IMAGE_FILE_DLL 0x2000
|
||||
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
|
||||
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
|
||||
|
||||
/* DllCharacteristics flag bits. The inconsistent naming may seem
|
||||
odd, but that is how they are defined in the PE specification. */
|
||||
#define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040
|
||||
#define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080
|
||||
#define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100
|
||||
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200
|
||||
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400
|
||||
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
|
||||
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
|
||||
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
|
||||
|
||||
/* Additional flags to be set for section headers to allow the NT loader to
|
||||
read and write to the section data (to replace the addresses of data in
|
||||
dlls for one thing); also to execute the section in .text's case. */
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
|
||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
||||
#define IMAGE_SCN_MEM_READ 0x40000000
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||
|
||||
/* Section characteristics added for ppc-nt. */
|
||||
|
||||
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */
|
||||
|
||||
#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */
|
||||
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */
|
||||
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */
|
||||
|
||||
#define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */
|
||||
#define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */
|
||||
#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */
|
||||
#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */
|
||||
|
||||
#define IMAGE_SCN_MEM_FARDATA 0x00008000
|
||||
|
||||
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
|
||||
#define IMAGE_SCN_MEM_16BIT 0x00020000
|
||||
#define IMAGE_SCN_MEM_LOCKED 0x00040000
|
||||
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
|
||||
|
||||
/* Bit position in the s_flags field where the alignment values start. */
|
||||
#define IMAGE_SCN_ALIGN_POWER_BIT_POS 20
|
||||
#define IMAGE_SCN_ALIGN_POWER_BIT_MASK 0x00f00000
|
||||
#define IMAGE_SCN_ALIGN_POWER_NUM(val) \
|
||||
(((val) >> IMAGE_SCN_ALIGN_POWER_BIT_POS) - 1)
|
||||
#define IMAGE_SCN_ALIGN_POWER_CONST(val) \
|
||||
(((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS)
|
||||
|
||||
#define IMAGE_SCN_ALIGN_1BYTES IMAGE_SCN_ALIGN_POWER_CONST (0)
|
||||
#define IMAGE_SCN_ALIGN_2BYTES IMAGE_SCN_ALIGN_POWER_CONST (1)
|
||||
#define IMAGE_SCN_ALIGN_4BYTES IMAGE_SCN_ALIGN_POWER_CONST (2)
|
||||
#define IMAGE_SCN_ALIGN_8BYTES IMAGE_SCN_ALIGN_POWER_CONST (3)
|
||||
/* Default alignment if no others are specified. */
|
||||
#define IMAGE_SCN_ALIGN_16BYTES IMAGE_SCN_ALIGN_POWER_CONST (4)
|
||||
#define IMAGE_SCN_ALIGN_32BYTES IMAGE_SCN_ALIGN_POWER_CONST (5)
|
||||
#define IMAGE_SCN_ALIGN_64BYTES IMAGE_SCN_ALIGN_POWER_CONST (6)
|
||||
#define IMAGE_SCN_ALIGN_128BYTES IMAGE_SCN_ALIGN_POWER_CONST (7)
|
||||
#define IMAGE_SCN_ALIGN_256BYTES IMAGE_SCN_ALIGN_POWER_CONST (8)
|
||||
#define IMAGE_SCN_ALIGN_512BYTES IMAGE_SCN_ALIGN_POWER_CONST (9)
|
||||
#define IMAGE_SCN_ALIGN_1024BYTES IMAGE_SCN_ALIGN_POWER_CONST (10)
|
||||
#define IMAGE_SCN_ALIGN_2048BYTES IMAGE_SCN_ALIGN_POWER_CONST (11)
|
||||
#define IMAGE_SCN_ALIGN_4096BYTES IMAGE_SCN_ALIGN_POWER_CONST (12)
|
||||
#define IMAGE_SCN_ALIGN_8192BYTES IMAGE_SCN_ALIGN_POWER_CONST (13)
|
||||
|
||||
/* Encode alignment power into IMAGE_SCN_ALIGN bits of s_flags */
|
||||
#define COFF_ENCODE_ALIGNMENT(SECTION, ALIGNMENT_POWER) \
|
||||
((SECTION).s_flags |= IMAGE_SCN_ALIGN_POWER_CONST ((ALIGNMENT_POWER)))
|
||||
|
||||
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */
|
||||
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */
|
||||
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */
|
||||
#define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */
|
||||
|
||||
/* COMDAT selection codes. */
|
||||
|
||||
#define IMAGE_COMDAT_SELECT_NODUPLICATES (1) /* Warn if duplicates. */
|
||||
#define IMAGE_COMDAT_SELECT_ANY (2) /* No warning. */
|
||||
#define IMAGE_COMDAT_SELECT_SAME_SIZE (3) /* Warn if different size. */
|
||||
#define IMAGE_COMDAT_SELECT_EXACT_MATCH (4) /* Warn if different. */
|
||||
#define IMAGE_COMDAT_SELECT_ASSOCIATIVE (5) /* Base on other section. */
|
||||
|
||||
/* Machine numbers. */
|
||||
|
||||
#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000
|
||||
#define IMAGE_FILE_MACHINE_ALPHA 0x0184
|
||||
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284
|
||||
#define IMAGE_FILE_MACHINE_AM33 0x01d3
|
||||
#define IMAGE_FILE_MACHINE_AMD64 0x8664
|
||||
#define IMAGE_FILE_MACHINE_ARM 0x01c0
|
||||
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
|
||||
#define IMAGE_FILE_MACHINE_CEE 0xc0ee
|
||||
#define IMAGE_FILE_MACHINE_CEF 0x0cef
|
||||
#define IMAGE_FILE_MACHINE_EBC 0x0ebc
|
||||
#define IMAGE_FILE_MACHINE_I386 0x014c
|
||||
#define IMAGE_FILE_MACHINE_IA64 0x0200
|
||||
#define IMAGE_FILE_MACHINE_M32R 0x9041
|
||||
#define IMAGE_FILE_MACHINE_M68K 0x0268
|
||||
#define IMAGE_FILE_MACHINE_MIPS16 0x0266
|
||||
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366
|
||||
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466
|
||||
#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
|
||||
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
|
||||
#define IMAGE_FILE_MACHINE_R10000 0x0168
|
||||
#define IMAGE_FILE_MACHINE_R3000 0x0162
|
||||
#define IMAGE_FILE_MACHINE_R4000 0x0166
|
||||
#define IMAGE_FILE_MACHINE_SH3 0x01a2
|
||||
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
|
||||
#define IMAGE_FILE_MACHINE_SH3E 0x01a4
|
||||
#define IMAGE_FILE_MACHINE_SH4 0x01a6
|
||||
#define IMAGE_FILE_MACHINE_SH5 0x01a8
|
||||
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
|
||||
#define IMAGE_FILE_MACHINE_TRICORE 0x0520
|
||||
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
|
||||
#define IMAGE_FILE_MACHINE_AMD64 0x8664
|
||||
|
||||
#define IMAGE_SUBSYSTEM_UNKNOWN 0
|
||||
#define IMAGE_SUBSYSTEM_NATIVE 1
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
|
||||
#define IMAGE_SUBSYSTEM_POSIX_CUI 7
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
|
||||
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
|
||||
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
|
||||
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
|
||||
#define IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13
|
||||
#define IMAGE_SUBSYSTEM_XBOX 14
|
||||
|
||||
/* Magic values that are true for all dos/nt implementations. */
|
||||
#define DOSMAGIC 0x5a4d
|
||||
#define NT_SIGNATURE 0x00004550
|
||||
|
||||
/* NT allows long filenames, we want to accommodate this.
|
||||
This may break some of the bfd functions. */
|
||||
#undef FILNMLEN
|
||||
#define FILNMLEN 18 /* # characters in a file name. */
|
||||
|
||||
struct external_PEI_DOS_hdr
|
||||
{
|
||||
/* DOS header fields - always at offset zero in the EXE file. */
|
||||
char e_magic[2]; /* Magic number, 0x5a4d. */
|
||||
char e_cblp[2]; /* Bytes on last page of file, 0x90. */
|
||||
char e_cp[2]; /* Pages in file, 0x3. */
|
||||
char e_crlc[2]; /* Relocations, 0x0. */
|
||||
char e_cparhdr[2]; /* Size of header in paragraphs, 0x4. */
|
||||
char e_minalloc[2]; /* Minimum extra paragraphs needed, 0x0. */
|
||||
char e_maxalloc[2]; /* Maximum extra paragraphs needed, 0xFFFF. */
|
||||
char e_ss[2]; /* Initial (relative) SS value, 0x0. */
|
||||
char e_sp[2]; /* Initial SP value, 0xb8. */
|
||||
char e_csum[2]; /* Checksum, 0x0. */
|
||||
char e_ip[2]; /* Initial IP value, 0x0. */
|
||||
char e_cs[2]; /* Initial (relative) CS value, 0x0. */
|
||||
char e_lfarlc[2]; /* File address of relocation table, 0x40. */
|
||||
char e_ovno[2]; /* Overlay number, 0x0. */
|
||||
char e_res[4][2]; /* Reserved words, all 0x0. */
|
||||
char e_oemid[2]; /* OEM identifier (for e_oeminfo), 0x0. */
|
||||
char e_oeminfo[2]; /* OEM information; e_oemid specific, 0x0. */
|
||||
char e_res2[10][2]; /* Reserved words, all 0x0. */
|
||||
char e_lfanew[4]; /* File address of new exe header, usually 0x80. */
|
||||
char dos_message[16][4]; /* Other stuff, always follow DOS header. */
|
||||
};
|
||||
|
||||
struct external_PEI_IMAGE_hdr
|
||||
{
|
||||
char nt_signature[4]; /* required NT signature, 0x4550. */
|
||||
|
||||
/* From standard header. */
|
||||
char f_magic[2]; /* Magic number. */
|
||||
char f_nscns[2]; /* Number of sections. */
|
||||
char f_timdat[4]; /* Time & date stamp. */
|
||||
char f_symptr[4]; /* File pointer to symtab. */
|
||||
char f_nsyms[4]; /* Number of symtab entries. */
|
||||
char f_opthdr[2]; /* Sizeof(optional hdr). */
|
||||
char f_flags[2]; /* Flags. */
|
||||
};
|
||||
|
||||
struct external_PEI_filehdr
|
||||
{
|
||||
/* DOS header fields - always at offset zero in the EXE file. */
|
||||
char e_magic[2]; /* Magic number, 0x5a4d. */
|
||||
char e_cblp[2]; /* Bytes on last page of file, 0x90. */
|
||||
char e_cp[2]; /* Pages in file, 0x3. */
|
||||
char e_crlc[2]; /* Relocations, 0x0. */
|
||||
char e_cparhdr[2]; /* Size of header in paragraphs, 0x4. */
|
||||
char e_minalloc[2]; /* Minimum extra paragraphs needed, 0x0. */
|
||||
char e_maxalloc[2]; /* Maximum extra paragraphs needed, 0xFFFF. */
|
||||
char e_ss[2]; /* Initial (relative) SS value, 0x0. */
|
||||
char e_sp[2]; /* Initial SP value, 0xb8. */
|
||||
char e_csum[2]; /* Checksum, 0x0. */
|
||||
char e_ip[2]; /* Initial IP value, 0x0. */
|
||||
char e_cs[2]; /* Initial (relative) CS value, 0x0. */
|
||||
char e_lfarlc[2]; /* File address of relocation table, 0x40. */
|
||||
char e_ovno[2]; /* Overlay number, 0x0. */
|
||||
char e_res[4][2]; /* Reserved words, all 0x0. */
|
||||
char e_oemid[2]; /* OEM identifier (for e_oeminfo), 0x0. */
|
||||
char e_oeminfo[2]; /* OEM information; e_oemid specific, 0x0. */
|
||||
char e_res2[10][2]; /* Reserved words, all 0x0. */
|
||||
char e_lfanew[4]; /* File address of new exe header, usually 0x80. */
|
||||
char dos_message[16][4]; /* Other stuff, always follow DOS header. */
|
||||
|
||||
/* Note: additional bytes may be inserted before the signature. Use
|
||||
the e_lfanew field to find the actual location of the NT signature. */
|
||||
|
||||
char nt_signature[4]; /* required NT signature, 0x4550. */
|
||||
|
||||
/* From standard header. */
|
||||
char f_magic[2]; /* Magic number. */
|
||||
char f_nscns[2]; /* Number of sections. */
|
||||
char f_timdat[4]; /* Time & date stamp. */
|
||||
char f_symptr[4]; /* File pointer to symtab. */
|
||||
char f_nsyms[4]; /* Number of symtab entries. */
|
||||
char f_opthdr[2]; /* Sizeof(optional hdr). */
|
||||
char f_flags[2]; /* Flags. */
|
||||
};
|
||||
|
||||
#ifdef COFF_IMAGE_WITH_PE
|
||||
|
||||
/* The filehdr is only weird in images. */
|
||||
|
||||
#undef FILHDR
|
||||
#define FILHDR struct external_PEI_filehdr
|
||||
#undef FILHSZ
|
||||
#define FILHSZ 152
|
||||
|
||||
#endif /* COFF_IMAGE_WITH_PE */
|
||||
|
||||
/* 32-bit PE a.out header: */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AOUTHDR standard;
|
||||
|
||||
/* NT extra fields; see internal.h for descriptions. */
|
||||
char ImageBase[4];
|
||||
char SectionAlignment[4];
|
||||
char FileAlignment[4];
|
||||
char MajorOperatingSystemVersion[2];
|
||||
char MinorOperatingSystemVersion[2];
|
||||
char MajorImageVersion[2];
|
||||
char MinorImageVersion[2];
|
||||
char MajorSubsystemVersion[2];
|
||||
char MinorSubsystemVersion[2];
|
||||
char Reserved1[4];
|
||||
char SizeOfImage[4];
|
||||
char SizeOfHeaders[4];
|
||||
char CheckSum[4];
|
||||
char Subsystem[2];
|
||||
char DllCharacteristics[2];
|
||||
char SizeOfStackReserve[4];
|
||||
char SizeOfStackCommit[4];
|
||||
char SizeOfHeapReserve[4];
|
||||
char SizeOfHeapCommit[4];
|
||||
char LoaderFlags[4];
|
||||
char NumberOfRvaAndSizes[4];
|
||||
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
|
||||
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars. */
|
||||
} PEAOUTHDR;
|
||||
|
||||
#undef AOUTSZ
|
||||
#define AOUTSZ (AOUTHDRSZ + 196)
|
||||
|
||||
/* Like PEAOUTHDR, except that the "standard" member has no BaseOfData
|
||||
(aka data_start) member and that some of the members are 8 instead
|
||||
of just 4 bytes long. */
|
||||
typedef struct
|
||||
{
|
||||
#ifdef AOUTHDRSZ64
|
||||
AOUTHDR64 standard;
|
||||
#else
|
||||
AOUTHDR standard;
|
||||
#endif
|
||||
/* NT extra fields; see internal.h for descriptions. */
|
||||
char ImageBase[8];
|
||||
char SectionAlignment[4];
|
||||
char FileAlignment[4];
|
||||
char MajorOperatingSystemVersion[2];
|
||||
char MinorOperatingSystemVersion[2];
|
||||
char MajorImageVersion[2];
|
||||
char MinorImageVersion[2];
|
||||
char MajorSubsystemVersion[2];
|
||||
char MinorSubsystemVersion[2];
|
||||
char Reserved1[4];
|
||||
char SizeOfImage[4];
|
||||
char SizeOfHeaders[4];
|
||||
char CheckSum[4];
|
||||
char Subsystem[2];
|
||||
char DllCharacteristics[2];
|
||||
char SizeOfStackReserve[8];
|
||||
char SizeOfStackCommit[8];
|
||||
char SizeOfHeapReserve[8];
|
||||
char SizeOfHeapCommit[8];
|
||||
char LoaderFlags[4];
|
||||
char NumberOfRvaAndSizes[4];
|
||||
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
|
||||
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars. */
|
||||
} PEPAOUTHDR;
|
||||
|
||||
#ifdef AOUTHDRSZ64
|
||||
#define PEPAOUTSZ (AOUTHDRSZ64 + 196 + 5 * 4) /* = 240 */
|
||||
#else
|
||||
#define PEPAOUTSZ 240
|
||||
#endif
|
||||
|
||||
#undef E_FILNMLEN
|
||||
#define E_FILNMLEN 18 /* # characters in a file name. */
|
||||
|
||||
/* Import Tyoes fot ILF format object files.. */
|
||||
#define IMPORT_CODE 0
|
||||
#define IMPORT_DATA 1
|
||||
#define IMPORT_CONST 2
|
||||
|
||||
/* Import Name Tyoes for ILF format object files. */
|
||||
#define IMPORT_ORDINAL 0
|
||||
#define IMPORT_NAME 1
|
||||
#define IMPORT_NAME_NOPREFIX 2
|
||||
#define IMPORT_NAME_UNDECORATE 3
|
||||
|
||||
/* Weak external characteristics. */
|
||||
#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
|
||||
#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
|
||||
#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
|
||||
|
||||
/* .pdata/.xdata defines and structures for x64 PE+ for exception handling. */
|
||||
|
||||
/* .pdata in exception directory. */
|
||||
|
||||
struct pex64_runtime_function
|
||||
{
|
||||
bfd_vma rva_BeginAddress;
|
||||
bfd_vma rva_EndAddress;
|
||||
bfd_vma rva_UnwindData;
|
||||
unsigned int isChained : 1;
|
||||
};
|
||||
|
||||
struct external_pex64_runtime_function
|
||||
{
|
||||
bfd_byte rva_BeginAddress[4];
|
||||
bfd_byte rva_EndAddress[4];
|
||||
bfd_byte rva_UnwindData[4];
|
||||
};
|
||||
|
||||
/* If the lowest significant bit is set for rva_UnwindData RVA, it
|
||||
means that the unified RVA points to another pex64_runtime_function
|
||||
that this entry shares the unwind_info block with. */
|
||||
#define PEX64_IS_RUNTIME_FUNCTION_CHAINED(PTR_RTF) \
|
||||
(((PTR_RTF)->rva_UnwindData & 1) != 0)
|
||||
#define PEX64_GET_UNWINDDATA_UNIFIED_RVA(PTR_RTF) \
|
||||
((PTR_RTF)->rva_UnwindData & ~1)
|
||||
|
||||
/* The unwind codes. */
|
||||
#define UWOP_PUSH_NONVOL 0
|
||||
#define UWOP_ALLOC_LARGE 1
|
||||
#define UWOP_ALLOC_SMALL 2
|
||||
#define UWOP_SET_FPREG 3
|
||||
#define UWOP_SAVE_NONVOL 4
|
||||
#define UWOP_SAVE_NONVOL_FAR 5
|
||||
#define UWOP_SAVE_XMM 6
|
||||
#define UWOP_SAVE_XMM_FAR 7
|
||||
#define UWOP_SAVE_XMM128 8
|
||||
#define UWOP_SAVE_XMM128_FAR 9
|
||||
#define UWOP_PUSH_MACHFRAME 10
|
||||
|
||||
struct pex64_unwind_code
|
||||
{
|
||||
bfd_vma prologue_offset;
|
||||
/* Contains Frame offset, or frame allocation size. */
|
||||
bfd_vma frame_addr;
|
||||
unsigned int uwop_code : 4;
|
||||
/* xmm, mm, or standard register from 0 - 15. */
|
||||
unsigned int reg : 4;
|
||||
/* Used for UWOP_PUSH_MACHFRAME to indicate optional errorcode stack
|
||||
argument. */
|
||||
unsigned int has_errorcode : 1;
|
||||
};
|
||||
|
||||
struct external_pex64_unwind_code
|
||||
{
|
||||
bfd_byte dta[2];
|
||||
};
|
||||
|
||||
#define PEX64_UNWCODE_CODE(VAL) ((VAL) & 0xf)
|
||||
#define PEX64_UNWCODE_INFO(VAL) (((VAL) >> 4) & 0xf)
|
||||
|
||||
/* The unwind info. */
|
||||
#define UNW_FLAG_NHANDLER 0
|
||||
#define UNW_FLAG_EHANDLER 1
|
||||
#define UNW_FLAG_UHANDLER 2
|
||||
#define UNW_FLAG_FHANDLER 3
|
||||
#define UNW_FLAG_CHAININFO 4
|
||||
|
||||
#define UNW_FLAG_MASK 0x1f
|
||||
|
||||
struct pex64_unwind_info
|
||||
{
|
||||
bfd_vma SizeOfBlock;
|
||||
bfd_byte Version; /* Values from 0 up to 7 are possible. */
|
||||
bfd_byte Flags; /* Values from 0 up to 31 are possible. */
|
||||
bfd_vma SizeOfPrologue;
|
||||
bfd_vma CountOfCodes; /* Amount of pex64_unwind_code elements. */
|
||||
/* 0 = CFA, 1..15 are index of integer registers. */
|
||||
unsigned int FrameRegister : 4;
|
||||
bfd_vma FrameOffset;
|
||||
bfd_vma sizeofUnwindCodes;
|
||||
bfd_byte *rawUnwindCodes;
|
||||
/* Valid for UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER. */
|
||||
bfd_vma CountOfScopes;
|
||||
bfd_byte *rawScopeEntries;
|
||||
bfd_vma rva_ExceptionHandler; /* UNW_EHANDLER. */
|
||||
bfd_vma rva_TerminationHandler; /* UNW_FLAG_UHANDLER. */
|
||||
bfd_vma rva_FrameHandler; /* UNW_FLAG_FHANDLER. */
|
||||
bfd_vma FrameHandlerArgument; /* UNW_FLAG_FHANDLER. */
|
||||
bfd_vma rva_FunctionEntry; /* UNW_FLAG_CHAININFO. */
|
||||
};
|
||||
|
||||
struct external_pex64_unwind_info
|
||||
{
|
||||
bfd_byte Version_Flags;
|
||||
bfd_byte SizeOfPrologue;
|
||||
bfd_byte CountOfCodes;
|
||||
bfd_byte FrameRegisterOffset;
|
||||
/* external_pex64_unwind_code array. */
|
||||
/* bfd_byte handler[4]; */
|
||||
/* Optional language specific data. */
|
||||
};
|
||||
|
||||
struct external_pex64_scope
|
||||
{
|
||||
bfd_vma Count;
|
||||
};
|
||||
|
||||
struct pex64_scope
|
||||
{
|
||||
bfd_byte Count[4];
|
||||
};
|
||||
|
||||
struct pex64_scope_entry
|
||||
{
|
||||
bfd_vma rva_BeginAddress;
|
||||
bfd_vma rva_EndAddress;
|
||||
bfd_vma rva_HandlerAddress;
|
||||
bfd_vma rva_JumpAddress;
|
||||
};
|
||||
#define PEX64_SCOPE_ENTRY_SIZE 16
|
||||
|
||||
struct external_pex64_scope_entry
|
||||
{
|
||||
bfd_byte rva_BeginAddress[4];
|
||||
bfd_byte rva_EndAddress[4];
|
||||
bfd_byte rva_HandlerAddress[4];
|
||||
bfd_byte rva_JumpAddress[4];
|
||||
};
|
||||
|
||||
#define PEX64_UWI_VERSION(VAL) ((VAL) & 7)
|
||||
#define PEX64_UWI_FLAGS(VAL) (((VAL) >> 3) & 0x1f)
|
||||
#define PEX64_UWI_FRAMEREG(VAL) ((VAL) & 0xf)
|
||||
#define PEX64_UWI_FRAMEOFF(VAL) (((VAL) >> 4) & 0xf)
|
||||
#define PEX64_UWI_SIZEOF_UWCODE_ARRAY(VAL) \
|
||||
((((VAL) + 1) & ~1) * 2)
|
||||
|
||||
#define PEX64_OFFSET_TO_UNWIND_CODE 0x4
|
||||
|
||||
#define PEX64_OFFSET_TO_HANDLER_RVA (COUNTOFUNWINDCODES) \
|
||||
(PEX64_OFFSET_TO_UNWIND_CODE + \
|
||||
PEX64_UWI_SIZEOF_UWCODE_ARRAY(COUNTOFUNWINDCODES))
|
||||
|
||||
#define PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) \
|
||||
(PEX64_OFFSET_TO_HANDLER_RVA(COUNTOFUNWINDCODES) + 4)
|
||||
|
||||
#define PEX64_SCOPE_ENTRY(COUNTOFUNWINDCODES, IDX) \
|
||||
(PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \
|
||||
PEX64_SCOPE_ENTRY_SIZE * (IDX))
|
||||
|
||||
#endif /* _PE_H */
|
73
src/efivars.h
Normal file
73
src/efivars.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#ifndef EFI_VARAUTH_H
|
||||
#define EFI_VARAUTH_H
|
||||
|
||||
#include <efi/efi.h>
|
||||
|
||||
#define EFI_CERT_TYPE_PKCS7_GUID \
|
||||
{0x4aafd29d, 0x68df, 0x49ee, \
|
||||
{0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7}}
|
||||
|
||||
typedef struct {
|
||||
UINT32 dwLength;
|
||||
UINT16 wRevision;
|
||||
UINT16 wCertificateType;
|
||||
UINT8 bCertificate[];
|
||||
} WIN_CERTIFICATE;
|
||||
|
||||
typedef struct {
|
||||
WIN_CERTIFICATE Hdr;
|
||||
EFI_GUID CertType;
|
||||
UINT8 CertData[];
|
||||
} WIN_CERTIFICATE_UEFI_GUID;
|
||||
|
||||
typedef struct {
|
||||
EFI_TIME TimeStamp;
|
||||
WIN_CERTIFICATE_UEFI_GUID AuthInfo;
|
||||
} EFI_VARIABLE_AUTHENTICATION_2;
|
||||
|
||||
|
||||
typedef struct {
|
||||
EFI_GUID SignatureOwner;
|
||||
UINT8 SignatureData[];
|
||||
} EFI_SIGNATURE_DATA;
|
||||
|
||||
typedef struct {
|
||||
EFI_GUID SignatureType;
|
||||
UINT32 SignatureListSize;
|
||||
UINT32 SignatureHeaderSize;
|
||||
UINT32 SignatureSize;
|
||||
} EFI_SIGNATURE_LIST;
|
||||
|
||||
#endif /* EFI_VARAUTH_H */
|
||||
|
157
src/fileio.c
Normal file
157
src/fileio.c
Normal file
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <ccan/talloc/talloc.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
|
||||
#include "fileio.h"
|
||||
|
||||
EVP_PKEY *fileio_read_pkey(const char *filename)
|
||||
{
|
||||
EVP_PKEY *key = NULL;
|
||||
BIO *bio;
|
||||
|
||||
bio = BIO_new_file(filename, "r");
|
||||
if (!bio)
|
||||
goto out;
|
||||
|
||||
key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
|
||||
|
||||
out:
|
||||
BIO_free_all(bio);
|
||||
if (!key) {
|
||||
fprintf(stderr, "Can't load key from file '%s'\n", filename);
|
||||
ERR_print_errors_fp(stderr);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
X509 *fileio_read_cert(const char *filename)
|
||||
{
|
||||
X509 *cert = NULL;
|
||||
BIO *bio;
|
||||
|
||||
bio = BIO_new_file(filename, "r");
|
||||
if (!bio)
|
||||
goto out;
|
||||
|
||||
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
|
||||
out:
|
||||
BIO_free_all(bio);
|
||||
if (!cert) {
|
||||
fprintf(stderr, "Can't load certificate from file '%s'\n",
|
||||
filename);
|
||||
ERR_print_errors_fp(stderr);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
int fileio_read_file(void *ctx, const char *filename,
|
||||
uint8_t **out_buf, size_t *out_len)
|
||||
{
|
||||
struct stat statbuf;
|
||||
uint8_t *buf;
|
||||
size_t len;
|
||||
int fd, rc;
|
||||
|
||||
rc = -1;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = fstat(fd, &statbuf);
|
||||
if (rc) {
|
||||
perror("fstat");
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = statbuf.st_size;
|
||||
|
||||
buf = talloc_array(ctx, uint8_t, len);
|
||||
if (!buf) {
|
||||
perror("talloc");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!read_all(fd, buf, len)) {
|
||||
perror("read_all");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Error reading file %s\n", filename);
|
||||
} else {
|
||||
*out_buf = buf;
|
||||
*out_len = len;
|
||||
}
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
int fileio_write_file(const char *filename, uint8_t *buf, size_t len)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!write_all(fd, buf, len)) {
|
||||
perror("write_all");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
48
src/fileio.h
Normal file
48
src/fileio.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#ifndef FILEIO_H
|
||||
#define FILEIO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
EVP_PKEY *fileio_read_pkey(const char *filename);
|
||||
X509 *fileio_read_cert(const char *filename);
|
||||
|
||||
int fileio_read_file(void *ctx, const char *filename,
|
||||
uint8_t **out_buf, size_t *out_len);
|
||||
int fileio_write_file(const char *filename, uint8_t *buf, size_t len);
|
||||
|
||||
#endif /* FILEIO_H */
|
||||
|
216
src/gen-keyfiles.c
Normal file
216
src/gen-keyfiles.c
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <endian.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
|
||||
#include "ccan/talloc/talloc.h"
|
||||
|
||||
struct efi_guid {
|
||||
uint32_t data1;
|
||||
uint16_t data2;
|
||||
uint16_t data3;
|
||||
uint8_t data4[8];
|
||||
};
|
||||
|
||||
#if __BYTE_ORDER != __LITTLE_ENDIAN
|
||||
#error Only little-endian machines are supported currently
|
||||
#endif
|
||||
|
||||
const struct efi_guid x509_guid = { 0xa5c059a1, 0x94e4, 0x4aa7, \
|
||||
{ 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 } };
|
||||
|
||||
struct efi_signature_data {
|
||||
struct efi_guid SignatureOwner;
|
||||
uint8_t SignatureData[];
|
||||
};
|
||||
|
||||
struct efi_signature_list {
|
||||
struct efi_guid SignatureType;
|
||||
uint32_t SignatureListSize;
|
||||
uint32_t SignatureHeaderSize;
|
||||
uint32_t SignatureSize;
|
||||
/* this can follow directly, as we don't have a header */
|
||||
struct efi_signature_data Signatures[];
|
||||
};
|
||||
|
||||
struct keydata {
|
||||
void *buf;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
static void uuid_to_efi_guid(uuid_t u, struct efi_guid *e)
|
||||
{
|
||||
/* The UUID is in raw format, so no byte-swapping is required */
|
||||
memcpy(e, u, sizeof(*e));
|
||||
}
|
||||
|
||||
static struct keydata *slurp_file(const char *filename)
|
||||
{
|
||||
unsigned int bytes_read;
|
||||
struct stat statbuf;
|
||||
struct keydata *keydata;
|
||||
int rc, fd;
|
||||
|
||||
keydata = talloc(NULL, struct keydata);
|
||||
if (!keydata) {
|
||||
perror("talloc(keydata)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
rc = fstat(fd, &statbuf);
|
||||
if (rc) {
|
||||
perror("fstat");
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
keydata->size = statbuf.st_size;
|
||||
|
||||
keydata->buf = talloc_size(keydata, keydata->size);
|
||||
if (!keydata->buf) {
|
||||
perror("talloc(buf)");
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
for (bytes_read = 0; bytes_read < keydata->size; bytes_read += rc) {
|
||||
rc = read(fd, keydata->buf + bytes_read,
|
||||
keydata->size - bytes_read);
|
||||
if (rc < 0) {
|
||||
perror("read");
|
||||
break;
|
||||
}
|
||||
if (rc == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes_read < keydata->size) {
|
||||
fprintf(stderr, "error reading input file\n");
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return keydata;
|
||||
|
||||
err_close:
|
||||
close(fd);
|
||||
err_free:
|
||||
talloc_free(keydata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int write_file(const char *filename, void *buf, unsigned int size)
|
||||
{
|
||||
int fd, rc;
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT, 0644);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = write(fd, buf, size);
|
||||
if (rc != (int)size) {
|
||||
perror("write");
|
||||
rc = -1;
|
||||
} else
|
||||
rc = 0;
|
||||
|
||||
close(fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int write_output(const char *basename,
|
||||
struct efi_signature_list *siglist)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
/* write list */
|
||||
filename = talloc_asprintf(NULL, "%s.siglist", basename);
|
||||
write_file(filename, siglist, siglist->SignatureListSize);
|
||||
talloc_free(filename);
|
||||
|
||||
/* write single entry data */
|
||||
filename = talloc_asprintf(NULL, "%s.sigdata", basename);
|
||||
write_file(filename, siglist->Signatures, siglist->SignatureSize);
|
||||
talloc_free(filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct efi_signature_list *siglist;
|
||||
struct efi_signature_data *sigdata;
|
||||
struct keydata *keydata;
|
||||
const char *filename;
|
||||
int rc, siglist_size;
|
||||
uuid_t owner_uuid;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s <owner-uuid> <keyfile>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
rc = uuid_parse(argv[1], owner_uuid);
|
||||
if (rc) {
|
||||
fprintf(stderr, "failed to parse uuid '%s'\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
filename = argv[2];
|
||||
|
||||
keydata = slurp_file(filename);
|
||||
if (!keydata)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
siglist_size =
|
||||
sizeof(struct efi_signature_list) +
|
||||
sizeof(struct efi_signature_data) +
|
||||
keydata->size;
|
||||
|
||||
siglist = talloc_size(keydata, siglist_size);
|
||||
|
||||
siglist->SignatureType = x509_guid;
|
||||
siglist->SignatureListSize = siglist_size;
|
||||
siglist->SignatureHeaderSize = 0;
|
||||
siglist->SignatureSize = sizeof(struct efi_signature_data) +
|
||||
keydata->size;
|
||||
sigdata = siglist->Signatures;
|
||||
uuid_to_efi_guid(owner_uuid, &sigdata->SignatureOwner);
|
||||
memcpy(sigdata->SignatureData, keydata->buf, keydata->size);
|
||||
|
||||
write_output(filename, siglist);
|
||||
|
||||
return 0;
|
||||
}
|
301
src/idc.c
Normal file
301
src/idc.c
Normal file
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <ccan/talloc/talloc.h>
|
||||
|
||||
#include "idc.h"
|
||||
|
||||
typedef struct idc_type_value {
|
||||
ASN1_OBJECT *type;
|
||||
ASN1_TYPE *value;
|
||||
} IDC_TYPE_VALUE;
|
||||
|
||||
ASN1_SEQUENCE(IDC_TYPE_VALUE) = {
|
||||
ASN1_SIMPLE(IDC_TYPE_VALUE, type, ASN1_OBJECT),
|
||||
ASN1_OPT(IDC_TYPE_VALUE, value, ASN1_ANY),
|
||||
} ASN1_SEQUENCE_END(IDC_TYPE_VALUE);
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(IDC_TYPE_VALUE);
|
||||
|
||||
typedef struct idc_string {
|
||||
int type;
|
||||
union {
|
||||
ASN1_BMPSTRING *unicode;
|
||||
ASN1_IA5STRING *ascii;
|
||||
} value;
|
||||
} IDC_STRING;
|
||||
|
||||
ASN1_CHOICE(IDC_STRING) = {
|
||||
ASN1_IMP(IDC_STRING, value.unicode, ASN1_BMPSTRING, 0),
|
||||
ASN1_IMP(IDC_STRING, value.ascii, ASN1_IA5STRING, 1),
|
||||
} ASN1_CHOICE_END(IDC_STRING);
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(IDC_STRING);
|
||||
|
||||
typedef struct idc_link {
|
||||
int type;
|
||||
union {
|
||||
ASN1_NULL *url;
|
||||
ASN1_NULL *moniker;
|
||||
IDC_STRING *file;
|
||||
} value;
|
||||
} IDC_LINK;
|
||||
|
||||
ASN1_CHOICE(IDC_LINK) = {
|
||||
ASN1_IMP(IDC_LINK, value.url, ASN1_NULL, 0),
|
||||
ASN1_IMP(IDC_LINK, value.moniker, ASN1_NULL, 1),
|
||||
ASN1_EXP(IDC_LINK, value.file, IDC_STRING, 2),
|
||||
} ASN1_CHOICE_END(IDC_LINK);
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(IDC_LINK);
|
||||
|
||||
typedef struct idc_pe_image_data {
|
||||
ASN1_BIT_STRING *flags;
|
||||
IDC_LINK *file;
|
||||
} IDC_PEID;
|
||||
|
||||
ASN1_SEQUENCE(IDC_PEID) = {
|
||||
ASN1_SIMPLE(IDC_PEID, flags, ASN1_BIT_STRING),
|
||||
ASN1_EXP(IDC_PEID, file, IDC_LINK, 0),
|
||||
} ASN1_SEQUENCE_END(IDC_PEID);
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(IDC_PEID);
|
||||
|
||||
typedef struct idc_digest {
|
||||
X509_ALGOR *alg;
|
||||
ASN1_OCTET_STRING *digest;
|
||||
} IDC_DIGEST;
|
||||
|
||||
ASN1_SEQUENCE(IDC_DIGEST) = {
|
||||
ASN1_SIMPLE(IDC_DIGEST, alg, X509_ALGOR),
|
||||
ASN1_SIMPLE(IDC_DIGEST, digest, ASN1_OCTET_STRING),
|
||||
} ASN1_SEQUENCE_END(IDC_DIGEST)
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(IDC_DIGEST)
|
||||
|
||||
typedef struct idc {
|
||||
IDC_TYPE_VALUE *data;
|
||||
IDC_DIGEST *digest;
|
||||
} IDC;
|
||||
|
||||
ASN1_SEQUENCE(IDC) = {
|
||||
ASN1_SIMPLE(IDC, data, IDC_TYPE_VALUE),
|
||||
ASN1_SIMPLE(IDC, digest, IDC_DIGEST),
|
||||
} ASN1_SEQUENCE_END(IDC)
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(IDC)
|
||||
|
||||
static int type_set_sequence(void *ctx, ASN1_TYPE *type,
|
||||
void *s, const ASN1_ITEM *it)
|
||||
{
|
||||
uint8_t *seq_data, *tmp;
|
||||
ASN1_OCTET_STRING *os;
|
||||
ASN1_STRING *seq = s;
|
||||
int len;
|
||||
|
||||
os = ASN1_STRING_new();
|
||||
|
||||
len = ASN1_item_i2d((ASN1_VALUE *)seq, NULL, it);
|
||||
tmp = seq_data = talloc_array(ctx, uint8_t, len);
|
||||
ASN1_item_i2d((ASN1_VALUE *)seq, &tmp, it);
|
||||
|
||||
ASN1_STRING_set(os, seq_data, len);
|
||||
ASN1_TYPE_set(type, V_ASN1_SEQUENCE, os);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char obsolete[] = {
|
||||
0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62,
|
||||
0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74,
|
||||
0x00, 0x65, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e
|
||||
};
|
||||
|
||||
const char *sha256_str(const uint8_t *hash)
|
||||
{
|
||||
static char s[SHA256_DIGEST_LENGTH * 2 + 1];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
|
||||
snprintf(s + i * 2, 3, "%02x", hash[i]);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image)
|
||||
{
|
||||
uint8_t *buf, *tmp, sha[SHA256_DIGEST_LENGTH];
|
||||
int idc_nid, peid_nid, len, rc;
|
||||
IDC_PEID *peid;
|
||||
ASN1_STRING *s;
|
||||
ASN1_TYPE *t;
|
||||
BIO *sigbio;
|
||||
IDC *idc;
|
||||
|
||||
idc_nid = OBJ_create("1.3.6.1.4.1.311.2.1.4",
|
||||
"spcIndirectDataContext",
|
||||
"Indirect Data Context");
|
||||
peid_nid = OBJ_create("1.3.6.1.4.1.311.2.1.15",
|
||||
"spcPEImageData",
|
||||
"PE Image Data");
|
||||
|
||||
image_hash_sha256(image, sha);
|
||||
|
||||
idc = IDC_new();
|
||||
peid = IDC_PEID_new();
|
||||
|
||||
peid->file = IDC_LINK_new();
|
||||
peid->file->type = 2;
|
||||
peid->file->value.file = IDC_STRING_new();
|
||||
peid->file->value.file->type = 0;
|
||||
peid->file->value.file->value.unicode = ASN1_STRING_new();
|
||||
ASN1_STRING_set(peid->file->value.file->value.unicode,
|
||||
obsolete, sizeof(obsolete));
|
||||
|
||||
idc->data->type = OBJ_nid2obj(peid_nid);
|
||||
idc->data->value = ASN1_TYPE_new();
|
||||
type_set_sequence(image, idc->data->value, peid, &IDC_PEID_it);
|
||||
|
||||
idc->digest->alg->parameter = ASN1_TYPE_new();
|
||||
idc->digest->alg->algorithm = OBJ_nid2obj(NID_sha256);
|
||||
idc->digest->alg->parameter->type = V_ASN1_NULL;
|
||||
ASN1_OCTET_STRING_set(idc->digest->digest, sha, sizeof(sha));
|
||||
|
||||
len = i2d_IDC(idc, NULL);
|
||||
tmp = buf = talloc_array(image, uint8_t, len);
|
||||
i2d_IDC(idc, &tmp);
|
||||
|
||||
/* Add the contentType authenticated attribute */
|
||||
PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT,
|
||||
OBJ_nid2obj(idc_nid));
|
||||
|
||||
/* Because the PKCS7 lib has a hard time dealing with non-standard
|
||||
* data types, we create a temporary BIO to hold the signed data, so
|
||||
* that the top-level PKCS7 object calculates the correct hash...
|
||||
*/
|
||||
sigbio = PKCS7_dataInit(p7, NULL);
|
||||
BIO_write(sigbio, buf+2, len-2);
|
||||
|
||||
/* ... then we finalise the p7 content, which does the actual
|
||||
* signing ... */
|
||||
rc = PKCS7_dataFinal(p7, sigbio);
|
||||
if (!rc) {
|
||||
fprintf(stderr, "dataFinal failed\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ... and we replace the content with the actual IDC ASN type. */
|
||||
t = ASN1_TYPE_new();
|
||||
s = ASN1_STRING_new();
|
||||
ASN1_STRING_set(s, buf, len);
|
||||
ASN1_TYPE_set(t, V_ASN1_SEQUENCE, s);
|
||||
PKCS7_set0_type_other(p7->d.sign->contents, idc_nid, t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct idc *IDC_get(PKCS7 *p7, BIO *bio)
|
||||
{
|
||||
const unsigned char *buf, *idcbuf;
|
||||
ASN1_STRING *str;
|
||||
IDC *idc;
|
||||
|
||||
/* extract the idc from the signed PKCS7 'other' data */
|
||||
str = p7->d.sign->contents->d.other->value.asn1_string;
|
||||
idcbuf = buf = ASN1_STRING_data(str);
|
||||
idc = d2i_IDC(NULL, &buf, ASN1_STRING_length(str));
|
||||
|
||||
/* If we were passed a BIO, write the idc data, minus type and length,
|
||||
* to the BIO. This can be used to PKCS7_verify the idc */
|
||||
if (bio) {
|
||||
uint32_t idclen;
|
||||
uint8_t tmp;
|
||||
|
||||
tmp = idcbuf[1];
|
||||
|
||||
if (!(tmp & 0x80)) {
|
||||
idclen = tmp & 0x7f;
|
||||
idcbuf += 2;
|
||||
} else if ((tmp & 0x82) == 0x82) {
|
||||
idclen = (idcbuf[2] << 8) +
|
||||
idcbuf[3];
|
||||
idcbuf += 4;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid ASN.1 data in "
|
||||
"IndirectDataContext?\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BIO_write(bio, idcbuf, idclen);
|
||||
}
|
||||
|
||||
return idc;
|
||||
}
|
||||
|
||||
int IDC_check_hash(struct idc *idc, struct image *image)
|
||||
{
|
||||
unsigned char sha[SHA256_DIGEST_LENGTH];
|
||||
const unsigned char *buf;
|
||||
ASN1_STRING *str;
|
||||
|
||||
image_hash_sha256(image, sha);
|
||||
|
||||
/* check hash algorithm sanity */
|
||||
if (OBJ_cmp(idc->digest->alg->algorithm, OBJ_nid2obj(NID_sha256))) {
|
||||
fprintf(stderr, "Invalid algorithm type\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
str = idc->digest->digest;
|
||||
if (ASN1_STRING_length(str) != sizeof(sha)) {
|
||||
fprintf(stderr, "Invalid algorithm length\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check hash against the one we calculated from the image */
|
||||
buf = ASN1_STRING_data(str);
|
||||
if (memcmp(buf, sha, sizeof(sha))) {
|
||||
fprintf(stderr, "Hash doesn't match image\n");
|
||||
fprintf(stderr, " got: %s\n", sha256_str(buf));
|
||||
fprintf(stderr, " expecting: %s\n", sha256_str(sha));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
46
src/idc.h
Normal file
46
src/idc.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#ifndef IDC_H
|
||||
#define IDC_H
|
||||
|
||||
#include "image.h"
|
||||
|
||||
#include <openssl/pkcs7.h>
|
||||
|
||||
struct idc;
|
||||
|
||||
int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image);
|
||||
struct idc *IDC_get(PKCS7 *p7, BIO *bio);
|
||||
int IDC_check_hash(struct idc *idc, struct image *image);
|
||||
|
||||
#endif /* IDC_H */
|
||||
|
526
src/image.c
Normal file
526
src/image.c
Normal file
|
@ -0,0 +1,526 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ccan/talloc/talloc.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "fileio.h"
|
||||
#include "image.h"
|
||||
|
||||
#define DATA_DIR_CERT_TABLE 4
|
||||
|
||||
#define CERT_TABLE_TYPE_PKCS 0x0002 /* PKCS signedData */
|
||||
#define CERT_TABLE_REVISION 0x0200 /* revision 2 */
|
||||
|
||||
/**
|
||||
* The PE/COFF headers export struct fields as arrays of chars. So, define
|
||||
* a couple of accessor functions that allow fields to be deferenced as their
|
||||
* native types, to allow strict aliasing. This also allows for endian-
|
||||
* neutral behaviour.
|
||||
*/
|
||||
static uint32_t __pehdr_u32(char field[])
|
||||
{
|
||||
uint8_t *ufield = (uint8_t *)field;
|
||||
return (ufield[3] << 24) +
|
||||
(ufield[2] << 16) +
|
||||
(ufield[1] << 8) +
|
||||
ufield[0];
|
||||
}
|
||||
|
||||
static uint16_t __pehdr_u16(char field[])
|
||||
{
|
||||
uint8_t *ufield = (uint8_t *)field;
|
||||
return (ufield[1] << 8) +
|
||||
ufield[0];
|
||||
}
|
||||
|
||||
/* wrappers to ensure type correctness */
|
||||
#define pehdr_u32(f) __pehdr_u32(f + BUILD_ASSERT_OR_ZERO(sizeof(f) == 4))
|
||||
#define pehdr_u16(f) __pehdr_u16(f + BUILD_ASSERT_OR_ZERO(sizeof(f) == 2))
|
||||
|
||||
/* Machine-specific PE/COFF parse functions. These parse the relevant a.out
|
||||
* header for the machine type, and set the following members of struct image:
|
||||
* - aouthdr_size
|
||||
* - file_alignment
|
||||
* - header_size
|
||||
* - data_dir
|
||||
* - checksum
|
||||
*
|
||||
* These functions require image->aouthdr to be set by the caller.
|
||||
*/
|
||||
static int image_pecoff_parse_32(struct image *image)
|
||||
{
|
||||
if (image->aouthdr.aout_32->standard.magic[0] != 0x0b ||
|
||||
image->aouthdr.aout_32->standard.magic[1] != 0x01) {
|
||||
fprintf(stderr, "Invalid a.out machine type\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
image->aouthdr_size = sizeof(*image->aouthdr.aout_32);
|
||||
|
||||
image->file_alignment =
|
||||
pehdr_u32(image->aouthdr.aout_32->FileAlignment);
|
||||
image->header_size =
|
||||
pehdr_u32(image->aouthdr.aout_32->SizeOfHeaders);
|
||||
|
||||
image->data_dir = (void *)image->aouthdr.aout_32->DataDirectory;
|
||||
image->checksum = (uint32_t *)image->aouthdr.aout_32->CheckSum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int image_pecoff_parse_64(struct image *image)
|
||||
{
|
||||
if (image->aouthdr.aout_64->standard.magic[0] != 0x0b ||
|
||||
image->aouthdr.aout_64->standard.magic[1] != 0x02) {
|
||||
fprintf(stderr, "Invalid a.out machine type\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
image->aouthdr_size = sizeof(*image->aouthdr.aout_64);
|
||||
|
||||
image->file_alignment =
|
||||
pehdr_u32(image->aouthdr.aout_64->FileAlignment);
|
||||
image->header_size =
|
||||
pehdr_u32(image->aouthdr.aout_64->SizeOfHeaders);
|
||||
|
||||
image->data_dir = (void *)image->aouthdr.aout_64->DataDirectory;
|
||||
image->checksum = (uint32_t *)image->aouthdr.aout_64->CheckSum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int image_pecoff_parse(struct image *image)
|
||||
{
|
||||
struct cert_table_header *cert_table;
|
||||
char nt_sig[] = {'P', 'E', 0, 0};
|
||||
size_t size = image->size;
|
||||
void *buf = image->buf;
|
||||
uint16_t magic;
|
||||
uint32_t addr;
|
||||
int rc;
|
||||
|
||||
/* sanity checks */
|
||||
if (size < sizeof(*image->doshdr)) {
|
||||
fprintf(stderr, "file is too small for DOS header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
image->doshdr = buf;
|
||||
|
||||
if (image->doshdr->e_magic[0] != 0x4d
|
||||
|| image->doshdr->e_magic[1] != 0x5a) {
|
||||
fprintf(stderr, "Invalid DOS header magic\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr = pehdr_u32(image->doshdr->e_lfanew);
|
||||
if (addr >= image->size) {
|
||||
fprintf(stderr, "pehdr is beyond end of file [0x%08x]\n",
|
||||
addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr + sizeof(*image->pehdr) > image->size) {
|
||||
fprintf(stderr, "File not large enough to contain pehdr\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
image->pehdr = buf + addr;
|
||||
if (memcmp(image->pehdr->nt_signature, nt_sig, sizeof(nt_sig))) {
|
||||
fprintf(stderr, "Invalid PE header signature\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* a.out header directly follows PE header */
|
||||
image->aouthdr.addr = image->pehdr + 1;
|
||||
magic = pehdr_u16(image->pehdr->f_magic);
|
||||
|
||||
if (magic == IMAGE_FILE_MACHINE_AMD64) {
|
||||
rc = image_pecoff_parse_64(image);
|
||||
|
||||
} else if (magic == IMAGE_FILE_MACHINE_I386) {
|
||||
rc = image_pecoff_parse_32(image);
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "Invalid PE header magic\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "Error parsing a.out header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we have the data_dir now, from parsing the a.out header */
|
||||
image->data_dir_sigtable = &image->data_dir[DATA_DIR_CERT_TABLE];
|
||||
|
||||
if (pehdr_u16(image->pehdr->f_opthdr) != image->aouthdr_size) {
|
||||
fprintf(stderr, "Invalid a.out header size\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (image->size < sizeof(*image->doshdr) + sizeof(*image->pehdr)
|
||||
+ image->aouthdr_size) {
|
||||
fprintf(stderr, "file is too small for a.out header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
image->cert_table_size = image->data_dir_sigtable->size;
|
||||
if (image->cert_table_size)
|
||||
cert_table = buf + image->data_dir_sigtable->addr;
|
||||
else
|
||||
cert_table = NULL;
|
||||
|
||||
image->cert_table = cert_table;
|
||||
|
||||
/* if we have a valid cert table header, populate sigbuf as a shadow
|
||||
* copy of the cert table */
|
||||
if (cert_table && cert_table->revision == CERT_TABLE_REVISION &&
|
||||
cert_table->type == CERT_TABLE_TYPE_PKCS &&
|
||||
cert_table->size < size) {
|
||||
image->sigsize = cert_table->size;
|
||||
image->sigbuf = talloc_memdup(image, cert_table + 1,
|
||||
image->sigsize);
|
||||
}
|
||||
|
||||
image->sections = pehdr_u16(image->pehdr->f_nscns);
|
||||
image->scnhdr = image->aouthdr.addr + image->aouthdr_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int align_up(int size, int align)
|
||||
{
|
||||
return (size + align - 1) & ~(align - 1);
|
||||
}
|
||||
|
||||
static int cmp_regions(const void *p1, const void *p2)
|
||||
{
|
||||
const struct region *r1 = p1, *r2 = p2;
|
||||
|
||||
if (r1->data < r2->data)
|
||||
return -1;
|
||||
if (r1->data > r2->data)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_region_from_range(struct region *region, void *start, void *end)
|
||||
{
|
||||
region->data = start;
|
||||
region->size = end - start;
|
||||
}
|
||||
|
||||
static int image_find_regions(struct image *image)
|
||||
{
|
||||
struct region *regions, *r;
|
||||
void *buf = image->buf;
|
||||
int i, gap_warn;
|
||||
size_t bytes;
|
||||
|
||||
gap_warn = 0;
|
||||
|
||||
/* now we know where the checksum and cert table data is, we can
|
||||
* construct regions that need to be signed */
|
||||
bytes = 0;
|
||||
image->n_checksum_regions = 0;
|
||||
image->checksum_regions = NULL;
|
||||
|
||||
image->n_checksum_regions = 3;
|
||||
image->checksum_regions = talloc_zero_array(image,
|
||||
struct region,
|
||||
image->n_checksum_regions);
|
||||
|
||||
/* first region: beginning to checksum field */
|
||||
regions = image->checksum_regions;
|
||||
set_region_from_range(®ions[0], buf, image->checksum);
|
||||
regions[0].name = "begin->cksum";
|
||||
bytes += regions[0].size;
|
||||
|
||||
bytes += sizeof(*image->checksum);
|
||||
|
||||
/* second region: end of checksum to certificate table entry */
|
||||
set_region_from_range(®ions[1],
|
||||
image->checksum + 1,
|
||||
image->data_dir_sigtable
|
||||
);
|
||||
regions[1].name = "cksum->datadir[CERT]";
|
||||
bytes += regions[1].size;
|
||||
|
||||
bytes += sizeof(struct data_dir_entry);
|
||||
/* third region: end of checksum to end of headers */
|
||||
set_region_from_range(®ions[2],
|
||||
(void *)image->data_dir_sigtable
|
||||
+ sizeof(struct data_dir_entry),
|
||||
buf + image->header_size);
|
||||
regions[2].name = "datadir[CERT]->headers";
|
||||
bytes += regions[2].size;
|
||||
|
||||
/* add COFF sections */
|
||||
for (i = 0; i < image->sections; i++) {
|
||||
uint32_t file_offset, file_size;
|
||||
|
||||
file_offset = pehdr_u32(image->scnhdr[i].s_scnptr);
|
||||
file_size = pehdr_u32(image->scnhdr[i].s_size);
|
||||
|
||||
if (!file_size)
|
||||
continue;
|
||||
|
||||
image->n_checksum_regions++;
|
||||
image->checksum_regions = talloc_realloc(image,
|
||||
image->checksum_regions,
|
||||
struct region,
|
||||
image->n_checksum_regions);
|
||||
regions = image->checksum_regions;
|
||||
|
||||
regions[i + 3].data = buf + file_offset;
|
||||
regions[i + 3].size = align_up(file_size,
|
||||
image->file_alignment);
|
||||
regions[i + 3].name = talloc_strndup(image->checksum_regions,
|
||||
image->scnhdr[i].s_name, 8);
|
||||
bytes += regions[i + 3].size;
|
||||
|
||||
if (regions[i+2].data + regions[i+2].size
|
||||
!= regions[i+3].data) {
|
||||
fprintf(stderr, "warning: gap in section table:\n");
|
||||
fprintf(stderr, " %-8s: 0x%08tx - 0x%08tx,\n",
|
||||
regions[i+2].name,
|
||||
regions[i+2].data - buf,
|
||||
regions[i+2].data +
|
||||
regions[i+2].size - buf);
|
||||
fprintf(stderr, " %-8s: 0x%08tx - 0x%08tx,\n",
|
||||
regions[i+3].name,
|
||||
regions[i+3].data - buf,
|
||||
regions[i+3].data +
|
||||
regions[i+3].size - buf);
|
||||
|
||||
|
||||
gap_warn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (gap_warn)
|
||||
fprintf(stderr, "gaps in the section table may result in "
|
||||
"different checksums\n");
|
||||
|
||||
qsort(image->checksum_regions, image->n_checksum_regions,
|
||||
sizeof(struct region), cmp_regions);
|
||||
|
||||
if (bytes + image->cert_table_size != image->size) {
|
||||
int n = image->n_checksum_regions++;
|
||||
struct region *r;
|
||||
|
||||
image->checksum_regions = talloc_realloc(image,
|
||||
image->checksum_regions,
|
||||
struct region,
|
||||
image->n_checksum_regions);
|
||||
r = &image->checksum_regions[n];
|
||||
r->name = "endjunk";
|
||||
r->data = image->buf + bytes;
|
||||
r->size = image->size - bytes - image->cert_table_size;
|
||||
|
||||
fprintf(stderr, "warning: data remaining[%zd vs %zd]: gaps "
|
||||
"between PE/COFF sections?\n",
|
||||
bytes + image->cert_table_size, image->size);
|
||||
}
|
||||
|
||||
/* record the size of non-signature data */
|
||||
r = &image->checksum_regions[image->n_checksum_regions - 1];
|
||||
image->data_size = (r->data - (void *)image->buf) + r->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct image *image_load(const char *filename)
|
||||
{
|
||||
struct image *image;
|
||||
int rc;
|
||||
|
||||
image = talloc(NULL, struct image);
|
||||
if (!image) {
|
||||
perror("talloc(image)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = fileio_read_file(image, filename, &image->buf, &image->size);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = image_pecoff_parse(image);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = image_find_regions(image);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
return image;
|
||||
err:
|
||||
talloc_free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int image_hash_sha256(struct image *image, uint8_t digest[])
|
||||
{
|
||||
struct region *region;
|
||||
SHA256_CTX ctx;
|
||||
int rc, i, n;
|
||||
|
||||
rc = SHA256_Init(&ctx);
|
||||
if (!rc)
|
||||
return -1;
|
||||
|
||||
n = 0;
|
||||
|
||||
for (i = 0; i < image->n_checksum_regions; i++) {
|
||||
region = &image->checksum_regions[i];
|
||||
n += region->size;
|
||||
#if 0
|
||||
printf("sum region: 0x%04lx -> 0x%04lx [0x%04x bytes]\n",
|
||||
region->data - image->buf,
|
||||
region->data - image->buf - 1 + region->size,
|
||||
region->size);
|
||||
|
||||
#endif
|
||||
rc = SHA256_Update(&ctx, region->data, region->size);
|
||||
if (!rc)
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = SHA256_Final(digest, &ctx);
|
||||
|
||||
return !rc;
|
||||
}
|
||||
|
||||
int image_add_signature(struct image *image, void *sig, int size)
|
||||
{
|
||||
/* we only support one signature at present */
|
||||
if (image->sigbuf) {
|
||||
fprintf(stderr, "warning: overwriting existing signature\n");
|
||||
talloc_free(image->sigbuf);
|
||||
}
|
||||
image->sigbuf = sig;
|
||||
image->sigsize = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void image_remove_signature(struct image *image)
|
||||
{
|
||||
if (image->sigbuf)
|
||||
talloc_free(image->sigbuf);
|
||||
image->sigbuf = NULL;
|
||||
image->sigsize = 0;
|
||||
}
|
||||
|
||||
int image_write(struct image *image, const char *filename)
|
||||
{
|
||||
struct cert_table_header cert_table_header;
|
||||
int fd, rc, len, padlen;
|
||||
bool is_signed;
|
||||
uint8_t pad[8];
|
||||
|
||||
is_signed = image->sigbuf && image->sigsize;
|
||||
padlen = 0;
|
||||
|
||||
/* optionally update the image to contain signature data */
|
||||
if (is_signed) {
|
||||
cert_table_header.size = image->sigsize +
|
||||
sizeof(cert_table_header);
|
||||
cert_table_header.revision = CERT_TABLE_REVISION;
|
||||
cert_table_header.type = CERT_TABLE_TYPE_PKCS;
|
||||
|
||||
len = sizeof(cert_table_header) + image->sigsize;
|
||||
|
||||
/* pad to sizeof(pad)-byte boundary */
|
||||
padlen = align_up(len, sizeof(pad)) - len;
|
||||
|
||||
image->data_dir_sigtable->addr = image->size;
|
||||
image->data_dir_sigtable->size = len + padlen;
|
||||
} else {
|
||||
image->data_dir_sigtable->addr = 0;
|
||||
image->data_dir_sigtable->size = 0;
|
||||
}
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = write_all(fd, image->buf, image->data_size);
|
||||
if (!rc)
|
||||
goto out;
|
||||
if (!is_signed)
|
||||
goto out;
|
||||
|
||||
rc = write_all(fd, &cert_table_header, sizeof(cert_table_header));
|
||||
if (!rc)
|
||||
goto out;
|
||||
|
||||
rc = write_all(fd, image->sigbuf, image->sigsize);
|
||||
if (!rc)
|
||||
goto out;
|
||||
|
||||
if (padlen) {
|
||||
memset(pad, 0, sizeof(pad));
|
||||
rc = write_all(fd, pad, padlen);
|
||||
}
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
return !rc;
|
||||
}
|
||||
|
||||
int image_write_detached(struct image *image, const char *filename)
|
||||
{
|
||||
int fd, rc;
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = write_all(fd, image->sigbuf, image->sigsize);
|
||||
|
||||
close(fd);
|
||||
return !rc;
|
||||
}
|
111
src/image.h
Normal file
111
src/image.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#ifndef IMAGE_H
|
||||
#define IMAGE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <bfd.h>
|
||||
#define DO_NOT_DEFINE_LINENO
|
||||
|
||||
#include "coff/external.h"
|
||||
#include "coff/pe.h"
|
||||
|
||||
struct region {
|
||||
void *data;
|
||||
int size;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct image {
|
||||
uint8_t *buf;
|
||||
size_t size;
|
||||
|
||||
/* size of the image, without signature */
|
||||
size_t data_size;
|
||||
|
||||
/* Pointers to interesting parts of the image */
|
||||
uint32_t *checksum;
|
||||
struct external_PEI_DOS_hdr *doshdr;
|
||||
struct external_PEI_IMAGE_hdr *pehdr;
|
||||
union {
|
||||
PEPAOUTHDR *aout_64;
|
||||
PEAOUTHDR *aout_32;
|
||||
void *addr;
|
||||
} aouthdr;
|
||||
unsigned int aouthdr_size;
|
||||
struct data_dir_entry *data_dir;
|
||||
struct data_dir_entry *data_dir_sigtable;
|
||||
struct external_scnhdr *scnhdr;
|
||||
int sections;
|
||||
|
||||
void *cert_table;
|
||||
int cert_table_size;
|
||||
|
||||
/* We cache a few values from the aout header, so we don't have to
|
||||
* keep checking whether to use the 32- or 64-bit version */
|
||||
uint32_t file_alignment;
|
||||
uint32_t header_size;
|
||||
|
||||
/* Regions that are included in the image hash: populated
|
||||
* during image parsing, then used during the hash process.
|
||||
*/
|
||||
struct region *checksum_regions;
|
||||
int n_checksum_regions;
|
||||
|
||||
/* Generated signature */
|
||||
void *sigbuf;
|
||||
size_t sigsize;
|
||||
|
||||
};
|
||||
|
||||
struct data_dir_entry {
|
||||
uint32_t addr;
|
||||
uint32_t size;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cert_table_header {
|
||||
uint32_t size;
|
||||
uint16_t revision;
|
||||
uint16_t type;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct image *image_load(const char *filename);
|
||||
|
||||
int image_hash_sha256(struct image *image, uint8_t digest[]);
|
||||
int image_add_signature(struct image *, void *sig, int size);
|
||||
void image_remove_signature(struct image *image);
|
||||
int image_write(struct image *image, const char *filename);
|
||||
int image_write_detached(struct image *image, const char *filename);
|
||||
|
||||
#endif /* IMAGE_H */
|
||||
|
958
src/libcoff.h
Normal file
958
src/libcoff.h
Normal file
|
@ -0,0 +1,958 @@
|
|||
/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically
|
||||
generated from "libcoff-in.h" and "coffcode.h".
|
||||
Run "make headers" in your build bfd/ to regenerate. */
|
||||
|
||||
/* BFD COFF object file private structure.
|
||||
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
|
||||
Free Software Foundation, Inc.
|
||||
Written by Cygnus Support.
|
||||
|
||||
This file is part of BFD, the Binary File Descriptor library.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
MA 02110-1301, USA. */
|
||||
|
||||
#include "bfdlink.h"
|
||||
|
||||
/* Object file tdata; access macros. */
|
||||
|
||||
#define coff_data(bfd) ((bfd)->tdata.coff_obj_data)
|
||||
#define obj_pe(bfd) (coff_data (bfd)->pe)
|
||||
#define obj_symbols(bfd) (coff_data (bfd)->symbols)
|
||||
#define obj_sym_filepos(bfd) (coff_data (bfd)->sym_filepos)
|
||||
#define obj_relocbase(bfd) (coff_data (bfd)->relocbase)
|
||||
#define obj_raw_syments(bfd) (coff_data (bfd)->raw_syments)
|
||||
#define obj_raw_syment_count(bfd) (coff_data (bfd)->raw_syment_count)
|
||||
#define obj_convert(bfd) (coff_data (bfd)->conversion_table)
|
||||
#define obj_conv_table_size(bfd) (coff_data (bfd)->conv_table_size)
|
||||
#define obj_coff_external_syms(bfd) (coff_data (bfd)->external_syms)
|
||||
#define obj_coff_keep_syms(bfd) (coff_data (bfd)->keep_syms)
|
||||
#define obj_coff_strings(bfd) (coff_data (bfd)->strings)
|
||||
#define obj_coff_keep_strings(bfd) (coff_data (bfd)->keep_strings)
|
||||
#define obj_coff_sym_hashes(bfd) (coff_data (bfd)->sym_hashes)
|
||||
#define obj_coff_strings_written(bfd) (coff_data (bfd)->strings_written)
|
||||
#define obj_coff_local_toc_table(bfd) (coff_data (bfd)->local_toc_sym_map)
|
||||
|
||||
/* `Tdata' information kept for COFF files. */
|
||||
|
||||
typedef struct coff_tdata
|
||||
{
|
||||
struct coff_symbol_struct *symbols; /* Symtab for input bfd. */
|
||||
unsigned int *conversion_table;
|
||||
int conv_table_size;
|
||||
file_ptr sym_filepos;
|
||||
|
||||
struct coff_ptr_struct *raw_syments;
|
||||
unsigned long raw_syment_count;
|
||||
|
||||
/* These are only valid once writing has begun. */
|
||||
long int relocbase;
|
||||
|
||||
/* These members communicate important constants about the symbol table
|
||||
to GDB's symbol-reading code. These `constants' unfortunately vary
|
||||
from coff implementation to implementation... */
|
||||
unsigned local_n_btmask;
|
||||
unsigned local_n_btshft;
|
||||
unsigned local_n_tmask;
|
||||
unsigned local_n_tshift;
|
||||
unsigned local_symesz;
|
||||
unsigned local_auxesz;
|
||||
unsigned local_linesz;
|
||||
|
||||
/* The unswapped external symbols. May be NULL. Read by
|
||||
_bfd_coff_get_external_symbols. */
|
||||
void * external_syms;
|
||||
/* If this is TRUE, the external_syms may not be freed. */
|
||||
bfd_boolean keep_syms;
|
||||
|
||||
/* The string table. May be NULL. Read by
|
||||
_bfd_coff_read_string_table. */
|
||||
char *strings;
|
||||
/* If this is TRUE, the strings may not be freed. */
|
||||
bfd_boolean keep_strings;
|
||||
/* If this is TRUE, the strings have been written out already. */
|
||||
bfd_boolean strings_written;
|
||||
|
||||
/* Is this a PE format coff file? */
|
||||
int pe;
|
||||
/* Used by the COFF backend linker. */
|
||||
struct coff_link_hash_entry **sym_hashes;
|
||||
|
||||
/* Used by the pe linker for PowerPC. */
|
||||
int *local_toc_sym_map;
|
||||
|
||||
struct bfd_link_info *link_info;
|
||||
|
||||
/* Used by coff_find_nearest_line. */
|
||||
void * line_info;
|
||||
|
||||
/* A place to stash dwarf2 info for this bfd. */
|
||||
void * dwarf2_find_line_info;
|
||||
|
||||
/* The timestamp from the COFF file header. */
|
||||
long timestamp;
|
||||
|
||||
/* Copy of some of the f_flags bits in the COFF filehdr structure,
|
||||
used by ARM code. */
|
||||
flagword flags;
|
||||
|
||||
/* coff-stgo32 EXE stub header after BFD tdata has been allocated. Its data
|
||||
is kept in internal_filehdr.go32stub beforehand. */
|
||||
char *go32stub;
|
||||
} coff_data_type;
|
||||
|
||||
/* Tdata for pe image files. */
|
||||
typedef struct pe_tdata
|
||||
{
|
||||
coff_data_type coff;
|
||||
struct internal_extra_pe_aouthdr pe_opthdr;
|
||||
int dll;
|
||||
int has_reloc_section;
|
||||
int dont_strip_reloc;
|
||||
bfd_boolean (*in_reloc_p) (bfd *, reloc_howto_type *);
|
||||
flagword real_flags;
|
||||
} pe_data_type;
|
||||
|
||||
#define pe_data(bfd) ((bfd)->tdata.pe_obj_data)
|
||||
|
||||
/* Tdata for XCOFF files. */
|
||||
|
||||
struct xcoff_tdata
|
||||
{
|
||||
/* Basic COFF information. */
|
||||
coff_data_type coff;
|
||||
|
||||
/* TRUE if this is an XCOFF64 file. */
|
||||
bfd_boolean xcoff64;
|
||||
|
||||
/* TRUE if a large a.out header should be generated. */
|
||||
bfd_boolean full_aouthdr;
|
||||
|
||||
/* TOC value. */
|
||||
bfd_vma toc;
|
||||
|
||||
/* Index of section holding TOC. */
|
||||
int sntoc;
|
||||
|
||||
/* Index of section holding entry point. */
|
||||
int snentry;
|
||||
|
||||
/* .text alignment from optional header. */
|
||||
int text_align_power;
|
||||
|
||||
/* .data alignment from optional header. */
|
||||
int data_align_power;
|
||||
|
||||
/* modtype from optional header. */
|
||||
short modtype;
|
||||
|
||||
/* cputype from optional header. */
|
||||
short cputype;
|
||||
|
||||
/* maxdata from optional header. */
|
||||
bfd_vma maxdata;
|
||||
|
||||
/* maxstack from optional header. */
|
||||
bfd_vma maxstack;
|
||||
|
||||
/* Used by the XCOFF backend linker. */
|
||||
asection **csects;
|
||||
long *debug_indices;
|
||||
unsigned int *lineno_counts;
|
||||
unsigned int import_file_id;
|
||||
};
|
||||
|
||||
#define xcoff_data(abfd) ((abfd)->tdata.xcoff_obj_data)
|
||||
|
||||
/* We take the address of the first element of an asymbol to ensure that the
|
||||
macro is only ever applied to an asymbol. */
|
||||
#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd)))
|
||||
|
||||
/* The used_by_bfd field of a section may be set to a pointer to this
|
||||
structure. */
|
||||
|
||||
struct coff_section_tdata
|
||||
{
|
||||
/* The relocs, swapped into COFF internal form. This may be NULL. */
|
||||
struct internal_reloc *relocs;
|
||||
/* If this is TRUE, the relocs entry may not be freed. */
|
||||
bfd_boolean keep_relocs;
|
||||
/* The section contents. This may be NULL. */
|
||||
bfd_byte *contents;
|
||||
/* If this is TRUE, the contents entry may not be freed. */
|
||||
bfd_boolean keep_contents;
|
||||
/* Information cached by coff_find_nearest_line. */
|
||||
bfd_vma offset;
|
||||
unsigned int i;
|
||||
const char *function;
|
||||
/* Optional information about a COMDAT entry; NULL if not COMDAT. */
|
||||
struct coff_comdat_info *comdat;
|
||||
int line_base;
|
||||
/* A pointer used for .stab linking optimizations. */
|
||||
void * stab_info;
|
||||
/* Available for individual backends. */
|
||||
void * tdata;
|
||||
};
|
||||
|
||||
/* An accessor macro for the coff_section_tdata structure. */
|
||||
#define coff_section_data(abfd, sec) \
|
||||
((struct coff_section_tdata *) (sec)->used_by_bfd)
|
||||
|
||||
/* Tdata for sections in XCOFF files. This is used by the linker. */
|
||||
|
||||
struct xcoff_section_tdata
|
||||
{
|
||||
/* Used for XCOFF csects created by the linker; points to the real
|
||||
XCOFF section which contains this csect. */
|
||||
asection *enclosing;
|
||||
/* The lineno_count field for the enclosing section, because we are
|
||||
going to clobber it there. */
|
||||
unsigned int lineno_count;
|
||||
/* The first and last symbol indices for symbols used by this csect. */
|
||||
unsigned long first_symndx;
|
||||
unsigned long last_symndx;
|
||||
};
|
||||
|
||||
/* An accessor macro the xcoff_section_tdata structure. */
|
||||
#define xcoff_section_data(abfd, sec) \
|
||||
((struct xcoff_section_tdata *) coff_section_data ((abfd), (sec))->tdata)
|
||||
|
||||
/* Tdata for sections in PE files. */
|
||||
|
||||
struct pei_section_tdata
|
||||
{
|
||||
/* The virtual size of the section. */
|
||||
bfd_size_type virt_size;
|
||||
/* The PE section flags. */
|
||||
long pe_flags;
|
||||
};
|
||||
|
||||
/* An accessor macro for the pei_section_tdata structure. */
|
||||
#define pei_section_data(abfd, sec) \
|
||||
((struct pei_section_tdata *) coff_section_data ((abfd), (sec))->tdata)
|
||||
|
||||
/* COFF linker hash table entries. */
|
||||
|
||||
struct coff_link_hash_entry
|
||||
{
|
||||
struct bfd_link_hash_entry root;
|
||||
|
||||
/* Symbol index in output file. Set to -1 initially. Set to -2 if
|
||||
there is a reloc against this symbol. */
|
||||
long indx;
|
||||
|
||||
/* Symbol type. */
|
||||
unsigned short type;
|
||||
|
||||
/* Symbol class. */
|
||||
unsigned char symbol_class;
|
||||
|
||||
/* Number of auxiliary entries. */
|
||||
char numaux;
|
||||
|
||||
/* BFD to take auxiliary entries from. */
|
||||
bfd *auxbfd;
|
||||
|
||||
/* Pointer to array of auxiliary entries, if any. */
|
||||
union internal_auxent *aux;
|
||||
|
||||
/* Flag word; legal values follow. */
|
||||
unsigned short coff_link_hash_flags;
|
||||
/* Symbol is a PE section symbol. */
|
||||
#define COFF_LINK_HASH_PE_SECTION_SYMBOL (01)
|
||||
};
|
||||
|
||||
/* COFF linker hash table. */
|
||||
|
||||
struct coff_link_hash_table
|
||||
{
|
||||
struct bfd_link_hash_table root;
|
||||
/* A pointer to information used to link stabs in sections. */
|
||||
struct stab_info stab_info;
|
||||
};
|
||||
|
||||
/* Look up an entry in a COFF linker hash table. */
|
||||
|
||||
#define coff_link_hash_lookup(table, string, create, copy, follow) \
|
||||
((struct coff_link_hash_entry *) \
|
||||
bfd_link_hash_lookup (&(table)->root, (string), (create), \
|
||||
(copy), (follow)))
|
||||
|
||||
/* Traverse a COFF linker hash table. */
|
||||
|
||||
#define coff_link_hash_traverse(table, func, info) \
|
||||
(bfd_link_hash_traverse \
|
||||
(&(table)->root, \
|
||||
(bfd_boolean (*) (struct bfd_link_hash_entry *, void *)) (func), \
|
||||
(info)))
|
||||
|
||||
/* Get the COFF linker hash table from a link_info structure. */
|
||||
|
||||
#define coff_hash_table(p) ((struct coff_link_hash_table *) ((p)->hash))
|
||||
|
||||
/* Functions in coffgen.c. */
|
||||
extern const bfd_target *coff_object_p
|
||||
(bfd *);
|
||||
extern struct bfd_section *coff_section_from_bfd_index
|
||||
(bfd *, int);
|
||||
extern long coff_get_symtab_upper_bound
|
||||
(bfd *);
|
||||
extern long coff_canonicalize_symtab
|
||||
(bfd *, asymbol **);
|
||||
extern int coff_count_linenumbers
|
||||
(bfd *);
|
||||
extern struct coff_symbol_struct *coff_symbol_from
|
||||
(bfd *, asymbol *);
|
||||
extern bfd_boolean coff_renumber_symbols
|
||||
(bfd *, int *);
|
||||
extern void coff_mangle_symbols
|
||||
(bfd *);
|
||||
extern bfd_boolean coff_write_symbols
|
||||
(bfd *);
|
||||
extern bfd_boolean coff_write_linenumbers
|
||||
(bfd *);
|
||||
extern alent *coff_get_lineno
|
||||
(bfd *, asymbol *);
|
||||
extern asymbol *coff_section_symbol
|
||||
(bfd *, char *);
|
||||
extern bfd_boolean _bfd_coff_get_external_symbols
|
||||
(bfd *);
|
||||
extern const char *_bfd_coff_read_string_table
|
||||
(bfd *);
|
||||
extern bfd_boolean _bfd_coff_free_symbols
|
||||
(bfd *);
|
||||
extern struct coff_ptr_struct *coff_get_normalized_symtab
|
||||
(bfd *);
|
||||
extern long coff_get_reloc_upper_bound
|
||||
(bfd *, sec_ptr);
|
||||
extern asymbol *coff_make_empty_symbol
|
||||
(bfd *);
|
||||
extern void coff_print_symbol
|
||||
(bfd *, void * filep, asymbol *, bfd_print_symbol_type);
|
||||
extern void coff_get_symbol_info
|
||||
(bfd *, asymbol *, symbol_info *ret);
|
||||
extern bfd_boolean _bfd_coff_is_local_label_name
|
||||
(bfd *, const char *);
|
||||
extern asymbol *coff_bfd_make_debug_symbol
|
||||
(bfd *, void *, unsigned long);
|
||||
extern bfd_boolean coff_find_nearest_line
|
||||
(bfd *, asection *, asymbol **, bfd_vma, const char **,
|
||||
const char **, unsigned int *);
|
||||
extern bfd_boolean coff_find_inliner_info
|
||||
(bfd *, const char **, const char **, unsigned int *);
|
||||
extern int coff_sizeof_headers
|
||||
(bfd *, struct bfd_link_info *);
|
||||
extern bfd_boolean bfd_coff_reloc16_relax_section
|
||||
(bfd *, asection *, struct bfd_link_info *, bfd_boolean *);
|
||||
extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents
|
||||
(bfd *, struct bfd_link_info *, struct bfd_link_order *,
|
||||
bfd_byte *, bfd_boolean, asymbol **);
|
||||
extern bfd_vma bfd_coff_reloc16_get_value
|
||||
(arelent *, struct bfd_link_info *, asection *);
|
||||
extern void bfd_perform_slip
|
||||
(bfd *, unsigned int, asection *, bfd_vma);
|
||||
|
||||
/* Functions and types in cofflink.c. */
|
||||
|
||||
#define STRING_SIZE_SIZE 4
|
||||
|
||||
/* We use a hash table to merge identical enum, struct, and union
|
||||
definitions in the linker. */
|
||||
|
||||
/* Information we keep for a single element (an enum value, a
|
||||
structure or union field) in the debug merge hash table. */
|
||||
|
||||
struct coff_debug_merge_element
|
||||
{
|
||||
/* Next element. */
|
||||
struct coff_debug_merge_element *next;
|
||||
|
||||
/* Name. */
|
||||
const char *name;
|
||||
|
||||
/* Type. */
|
||||
unsigned int type;
|
||||
|
||||
/* Symbol index for complex type. */
|
||||
long tagndx;
|
||||
};
|
||||
|
||||
/* A linked list of debug merge entries for a given name. */
|
||||
|
||||
struct coff_debug_merge_type
|
||||
{
|
||||
/* Next type with the same name. */
|
||||
struct coff_debug_merge_type *next;
|
||||
|
||||
/* Class of type. */
|
||||
int type_class;
|
||||
|
||||
/* Symbol index where this type is defined. */
|
||||
long indx;
|
||||
|
||||
/* List of elements. */
|
||||
struct coff_debug_merge_element *elements;
|
||||
};
|
||||
|
||||
/* Information we store in the debug merge hash table. */
|
||||
|
||||
struct coff_debug_merge_hash_entry
|
||||
{
|
||||
struct bfd_hash_entry root;
|
||||
|
||||
/* A list of types with this name. */
|
||||
struct coff_debug_merge_type *types;
|
||||
};
|
||||
|
||||
/* The debug merge hash table. */
|
||||
|
||||
struct coff_debug_merge_hash_table
|
||||
{
|
||||
struct bfd_hash_table root;
|
||||
};
|
||||
|
||||
/* Initialize a COFF debug merge hash table. */
|
||||
|
||||
#define coff_debug_merge_hash_table_init(table) \
|
||||
(bfd_hash_table_init (&(table)->root, _bfd_coff_debug_merge_hash_newfunc, \
|
||||
sizeof (struct coff_debug_merge_hash_entry)))
|
||||
|
||||
/* Free a COFF debug merge hash table. */
|
||||
|
||||
#define coff_debug_merge_hash_table_free(table) \
|
||||
(bfd_hash_table_free (&(table)->root))
|
||||
|
||||
/* Look up an entry in a COFF debug merge hash table. */
|
||||
|
||||
#define coff_debug_merge_hash_lookup(table, string, create, copy) \
|
||||
((struct coff_debug_merge_hash_entry *) \
|
||||
bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
|
||||
|
||||
/* Information we keep for each section in the output file when doing
|
||||
a relocatable link. */
|
||||
|
||||
struct coff_link_section_info
|
||||
{
|
||||
/* The relocs to be output. */
|
||||
struct internal_reloc *relocs;
|
||||
/* For each reloc against a global symbol whose index was not known
|
||||
when the reloc was handled, the global hash table entry. */
|
||||
struct coff_link_hash_entry **rel_hashes;
|
||||
};
|
||||
|
||||
/* Information that we pass around while doing the final link step. */
|
||||
|
||||
struct coff_final_link_info
|
||||
{
|
||||
/* General link information. */
|
||||
struct bfd_link_info *info;
|
||||
/* Output BFD. */
|
||||
bfd *output_bfd;
|
||||
/* Used to indicate failure in traversal routine. */
|
||||
bfd_boolean failed;
|
||||
/* If doing "task linking" set only during the time when we want the
|
||||
global symbol writer to convert the storage class of defined global
|
||||
symbols from global to static. */
|
||||
bfd_boolean global_to_static;
|
||||
/* Hash table for long symbol names. */
|
||||
struct bfd_strtab_hash *strtab;
|
||||
/* When doing a relocatable link, an array of information kept for
|
||||
each output section, indexed by the target_index field. */
|
||||
struct coff_link_section_info *section_info;
|
||||
/* Symbol index of last C_FILE symbol (-1 if none). */
|
||||
long last_file_index;
|
||||
/* Contents of last C_FILE symbol. */
|
||||
struct internal_syment last_file;
|
||||
/* Symbol index of first aux entry of last .bf symbol with an empty
|
||||
endndx field (-1 if none). */
|
||||
long last_bf_index;
|
||||
/* Contents of last_bf_index aux entry. */
|
||||
union internal_auxent last_bf;
|
||||
/* Hash table used to merge debug information. */
|
||||
struct coff_debug_merge_hash_table debug_merge;
|
||||
/* Buffer large enough to hold swapped symbols of any input file. */
|
||||
struct internal_syment *internal_syms;
|
||||
/* Buffer large enough to hold sections of symbols of any input file. */
|
||||
asection **sec_ptrs;
|
||||
/* Buffer large enough to hold output indices of symbols of any
|
||||
input file. */
|
||||
long *sym_indices;
|
||||
/* Buffer large enough to hold output symbols for any input file. */
|
||||
bfd_byte *outsyms;
|
||||
/* Buffer large enough to hold external line numbers for any input
|
||||
section. */
|
||||
bfd_byte *linenos;
|
||||
/* Buffer large enough to hold any input section. */
|
||||
bfd_byte *contents;
|
||||
/* Buffer large enough to hold external relocs of any input section. */
|
||||
bfd_byte *external_relocs;
|
||||
/* Buffer large enough to hold swapped relocs of any input section. */
|
||||
struct internal_reloc *internal_relocs;
|
||||
};
|
||||
|
||||
/* Most COFF variants have no way to record the alignment of a
|
||||
section. This struct is used to set a specific alignment based on
|
||||
the name of the section. */
|
||||
|
||||
struct coff_section_alignment_entry
|
||||
{
|
||||
/* The section name. */
|
||||
const char *name;
|
||||
|
||||
/* This is either (unsigned int) -1, indicating that the section
|
||||
name must match exactly, or it is the number of letters which
|
||||
must match at the start of the name. */
|
||||
unsigned int comparison_length;
|
||||
|
||||
/* These macros may be used to fill in the first two fields in a
|
||||
structure initialization. */
|
||||
#define COFF_SECTION_NAME_EXACT_MATCH(name) (name), ((unsigned int) -1)
|
||||
#define COFF_SECTION_NAME_PARTIAL_MATCH(name) (name), (sizeof (name) - 1)
|
||||
|
||||
/* Only use this entry if the default section alignment for this
|
||||
target is at least that much (as a power of two). If this field
|
||||
is COFF_ALIGNMENT_FIELD_EMPTY, it should be ignored. */
|
||||
unsigned int default_alignment_min;
|
||||
|
||||
/* Only use this entry if the default section alignment for this
|
||||
target is no greater than this (as a power of two). If this
|
||||
field is COFF_ALIGNMENT_FIELD_EMPTY, it should be ignored. */
|
||||
unsigned int default_alignment_max;
|
||||
|
||||
#define COFF_ALIGNMENT_FIELD_EMPTY ((unsigned int) -1)
|
||||
|
||||
/* The desired alignment for this section (as a power of two). */
|
||||
unsigned int alignment_power;
|
||||
};
|
||||
|
||||
extern struct bfd_hash_entry *_bfd_coff_link_hash_newfunc
|
||||
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
|
||||
extern bfd_boolean _bfd_coff_link_hash_table_init
|
||||
(struct coff_link_hash_table *, bfd *,
|
||||
struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
|
||||
struct bfd_hash_table *,
|
||||
const char *),
|
||||
unsigned int);
|
||||
extern struct bfd_link_hash_table *_bfd_coff_link_hash_table_create
|
||||
(bfd *);
|
||||
extern const char *_bfd_coff_internal_syment_name
|
||||
(bfd *, const struct internal_syment *, char *);
|
||||
extern bfd_boolean _bfd_coff_section_already_linked
|
||||
(bfd *, asection *, struct bfd_link_info *);
|
||||
extern bfd_boolean _bfd_coff_link_add_symbols
|
||||
(bfd *, struct bfd_link_info *);
|
||||
extern bfd_boolean _bfd_coff_final_link
|
||||
(bfd *, struct bfd_link_info *);
|
||||
extern struct internal_reloc *_bfd_coff_read_internal_relocs
|
||||
(bfd *, asection *, bfd_boolean, bfd_byte *, bfd_boolean,
|
||||
struct internal_reloc *);
|
||||
extern bfd_boolean _bfd_coff_generic_relocate_section
|
||||
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
|
||||
struct internal_reloc *, struct internal_syment *, asection **);
|
||||
extern struct bfd_hash_entry *_bfd_coff_debug_merge_hash_newfunc
|
||||
(struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
|
||||
extern bfd_boolean _bfd_coff_write_global_sym
|
||||
(struct bfd_hash_entry *, void *);
|
||||
extern bfd_boolean _bfd_coff_write_task_globals
|
||||
(struct coff_link_hash_entry *, void *);
|
||||
extern bfd_boolean _bfd_coff_link_input_bfd
|
||||
(struct coff_final_link_info *, bfd *);
|
||||
extern bfd_boolean _bfd_coff_reloc_link_order
|
||||
(bfd *, struct coff_final_link_info *, asection *,
|
||||
struct bfd_link_order *);
|
||||
|
||||
|
||||
#define coff_get_section_contents_in_window \
|
||||
_bfd_generic_get_section_contents_in_window
|
||||
|
||||
/* Functions in xcofflink.c. */
|
||||
|
||||
extern long _bfd_xcoff_get_dynamic_symtab_upper_bound
|
||||
(bfd *);
|
||||
extern long _bfd_xcoff_canonicalize_dynamic_symtab
|
||||
(bfd *, asymbol **);
|
||||
extern long _bfd_xcoff_get_dynamic_reloc_upper_bound
|
||||
(bfd *);
|
||||
extern long _bfd_xcoff_canonicalize_dynamic_reloc
|
||||
(bfd *, arelent **, asymbol **);
|
||||
extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create
|
||||
(bfd *);
|
||||
extern void _bfd_xcoff_bfd_link_hash_table_free
|
||||
(struct bfd_link_hash_table *);
|
||||
extern bfd_boolean _bfd_xcoff_bfd_link_add_symbols
|
||||
(bfd *, struct bfd_link_info *);
|
||||
extern bfd_boolean _bfd_xcoff_bfd_final_link
|
||||
(bfd *, struct bfd_link_info *);
|
||||
extern bfd_boolean _bfd_xcoff_define_common_symbol
|
||||
(bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *);
|
||||
extern bfd_boolean _bfd_ppc_xcoff_relocate_section
|
||||
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
|
||||
struct internal_reloc *, struct internal_syment *, asection **);
|
||||
|
||||
/* Functions in coff-ppc.c. FIXME: These are called by pe.em in the
|
||||
linker, and so should start with bfd and be declared in bfd.h. */
|
||||
|
||||
extern bfd_boolean ppc_allocate_toc_section
|
||||
(struct bfd_link_info *);
|
||||
extern bfd_boolean ppc_process_before_allocation
|
||||
(bfd *, struct bfd_link_info *);
|
||||
/* Extracted from coffcode.h. */
|
||||
typedef struct coff_ptr_struct
|
||||
{
|
||||
/* Remembers the offset from the first symbol in the file for
|
||||
this symbol. Generated by coff_renumber_symbols. */
|
||||
unsigned int offset;
|
||||
|
||||
/* Should the value of this symbol be renumbered. Used for
|
||||
XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. */
|
||||
unsigned int fix_value : 1;
|
||||
|
||||
/* Should the tag field of this symbol be renumbered.
|
||||
Created by coff_pointerize_aux. */
|
||||
unsigned int fix_tag : 1;
|
||||
|
||||
/* Should the endidx field of this symbol be renumbered.
|
||||
Created by coff_pointerize_aux. */
|
||||
unsigned int fix_end : 1;
|
||||
|
||||
/* Should the x_csect.x_scnlen field be renumbered.
|
||||
Created by coff_pointerize_aux. */
|
||||
unsigned int fix_scnlen : 1;
|
||||
|
||||
/* Fix up an XCOFF C_BINCL/C_EINCL symbol. The value is the
|
||||
index into the line number entries. Set by coff_slurp_symbol_table. */
|
||||
unsigned int fix_line : 1;
|
||||
|
||||
/* The container for the symbol structure as read and translated
|
||||
from the file. */
|
||||
union
|
||||
{
|
||||
union internal_auxent auxent;
|
||||
struct internal_syment syment;
|
||||
} u;
|
||||
} combined_entry_type;
|
||||
|
||||
|
||||
/* Each canonical asymbol really looks like this: */
|
||||
|
||||
typedef struct coff_symbol_struct
|
||||
{
|
||||
/* The actual symbol which the rest of BFD works with */
|
||||
asymbol symbol;
|
||||
|
||||
/* A pointer to the hidden information for this symbol */
|
||||
combined_entry_type *native;
|
||||
|
||||
/* A pointer to the linenumber information for this symbol */
|
||||
struct lineno_cache_entry *lineno;
|
||||
|
||||
/* Have the line numbers been relocated yet ? */
|
||||
bfd_boolean done_lineno;
|
||||
} coff_symbol_type;
|
||||
/* COFF symbol classifications. */
|
||||
|
||||
enum coff_symbol_classification
|
||||
{
|
||||
/* Global symbol. */
|
||||
COFF_SYMBOL_GLOBAL,
|
||||
/* Common symbol. */
|
||||
COFF_SYMBOL_COMMON,
|
||||
/* Undefined symbol. */
|
||||
COFF_SYMBOL_UNDEFINED,
|
||||
/* Local symbol. */
|
||||
COFF_SYMBOL_LOCAL,
|
||||
/* PE section symbol. */
|
||||
COFF_SYMBOL_PE_SECTION
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*_bfd_coff_swap_aux_in)
|
||||
(bfd *, void *, int, int, int, int, void *);
|
||||
|
||||
void (*_bfd_coff_swap_sym_in)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
void (*_bfd_coff_swap_lineno_in)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
unsigned int (*_bfd_coff_swap_aux_out)
|
||||
(bfd *, void *, int, int, int, int, void *);
|
||||
|
||||
unsigned int (*_bfd_coff_swap_sym_out)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
unsigned int (*_bfd_coff_swap_lineno_out)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
unsigned int (*_bfd_coff_swap_reloc_out)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
unsigned int (*_bfd_coff_swap_filehdr_out)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
unsigned int (*_bfd_coff_swap_aouthdr_out)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
unsigned int (*_bfd_coff_swap_scnhdr_out)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
unsigned int _bfd_filhsz;
|
||||
unsigned int _bfd_aoutsz;
|
||||
unsigned int _bfd_scnhsz;
|
||||
unsigned int _bfd_symesz;
|
||||
unsigned int _bfd_auxesz;
|
||||
unsigned int _bfd_relsz;
|
||||
unsigned int _bfd_linesz;
|
||||
unsigned int _bfd_filnmlen;
|
||||
bfd_boolean _bfd_coff_long_filenames;
|
||||
|
||||
bfd_boolean _bfd_coff_long_section_names;
|
||||
bfd_boolean (*_bfd_coff_set_long_section_names)
|
||||
(bfd *, int);
|
||||
|
||||
unsigned int _bfd_coff_default_section_alignment_power;
|
||||
bfd_boolean _bfd_coff_force_symnames_in_strings;
|
||||
unsigned int _bfd_coff_debug_string_prefix_length;
|
||||
|
||||
void (*_bfd_coff_swap_filehdr_in)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
void (*_bfd_coff_swap_aouthdr_in)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
void (*_bfd_coff_swap_scnhdr_in)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
void (*_bfd_coff_swap_reloc_in)
|
||||
(bfd *abfd, void *, void *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_bad_format_hook)
|
||||
(bfd *, void *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_set_arch_mach_hook)
|
||||
(bfd *, void *);
|
||||
|
||||
void * (*_bfd_coff_mkobject_hook)
|
||||
(bfd *, void *, void *);
|
||||
|
||||
bfd_boolean (*_bfd_styp_to_sec_flags_hook)
|
||||
(bfd *, void *, const char *, asection *, flagword *);
|
||||
|
||||
void (*_bfd_set_alignment_hook)
|
||||
(bfd *, asection *, void *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_slurp_symbol_table)
|
||||
(bfd *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_symname_in_debug)
|
||||
(bfd *, struct internal_syment *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_pointerize_aux_hook)
|
||||
(bfd *, combined_entry_type *, combined_entry_type *,
|
||||
unsigned int, combined_entry_type *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_print_aux)
|
||||
(bfd *, FILE *, combined_entry_type *, combined_entry_type *,
|
||||
combined_entry_type *, unsigned int);
|
||||
|
||||
void (*_bfd_coff_reloc16_extra_cases)
|
||||
(bfd *, struct bfd_link_info *, struct bfd_link_order *, arelent *,
|
||||
bfd_byte *, unsigned int *, unsigned int *);
|
||||
|
||||
int (*_bfd_coff_reloc16_estimate)
|
||||
(bfd *, asection *, arelent *, unsigned int,
|
||||
struct bfd_link_info *);
|
||||
|
||||
enum coff_symbol_classification (*_bfd_coff_classify_symbol)
|
||||
(bfd *, struct internal_syment *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_compute_section_file_positions)
|
||||
(bfd *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_start_final_link)
|
||||
(bfd *, struct bfd_link_info *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_relocate_section)
|
||||
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
|
||||
struct internal_reloc *, struct internal_syment *, asection **);
|
||||
|
||||
reloc_howto_type *(*_bfd_coff_rtype_to_howto)
|
||||
(bfd *, asection *, struct internal_reloc *,
|
||||
struct coff_link_hash_entry *, struct internal_syment *,
|
||||
bfd_vma *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_adjust_symndx)
|
||||
(bfd *, struct bfd_link_info *, bfd *, asection *,
|
||||
struct internal_reloc *, bfd_boolean *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_link_add_one_symbol)
|
||||
(struct bfd_link_info *, bfd *, const char *, flagword,
|
||||
asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean,
|
||||
struct bfd_link_hash_entry **);
|
||||
|
||||
bfd_boolean (*_bfd_coff_link_output_has_begun)
|
||||
(bfd *, struct coff_final_link_info *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_final_link_postscript)
|
||||
(bfd *, struct coff_final_link_info *);
|
||||
|
||||
bfd_boolean (*_bfd_coff_print_pdata)
|
||||
(bfd *, void *);
|
||||
|
||||
} bfd_coff_backend_data;
|
||||
|
||||
#define coff_backend_info(abfd) \
|
||||
((bfd_coff_backend_data *) (abfd)->xvec->backend_data)
|
||||
|
||||
#define bfd_coff_swap_aux_in(a,e,t,c,ind,num,i) \
|
||||
((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,i))
|
||||
|
||||
#define bfd_coff_swap_sym_in(a,e,i) \
|
||||
((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i))
|
||||
|
||||
#define bfd_coff_swap_lineno_in(a,e,i) \
|
||||
((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i))
|
||||
|
||||
#define bfd_coff_swap_reloc_out(abfd, i, o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_swap_lineno_out(abfd, i, o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_swap_aux_out(a,i,t,c,ind,num,o) \
|
||||
((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,o))
|
||||
|
||||
#define bfd_coff_swap_sym_out(abfd, i,o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_swap_scnhdr_out(abfd, i,o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_swap_filehdr_out(abfd, i,o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_swap_aouthdr_out(abfd, i,o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz)
|
||||
#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz)
|
||||
#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz)
|
||||
#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz)
|
||||
#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz)
|
||||
#define bfd_coff_relsz(abfd) (coff_backend_info (abfd)->_bfd_relsz)
|
||||
#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz)
|
||||
#define bfd_coff_filnmlen(abfd) (coff_backend_info (abfd)->_bfd_filnmlen)
|
||||
#define bfd_coff_long_filenames(abfd) \
|
||||
(coff_backend_info (abfd)->_bfd_coff_long_filenames)
|
||||
#define bfd_coff_long_section_names(abfd) \
|
||||
(coff_backend_info (abfd)->_bfd_coff_long_section_names)
|
||||
#define bfd_coff_set_long_section_names(abfd, enable) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_set_long_section_names) (abfd, enable))
|
||||
#define bfd_coff_default_section_alignment_power(abfd) \
|
||||
(coff_backend_info (abfd)->_bfd_coff_default_section_alignment_power)
|
||||
#define bfd_coff_swap_filehdr_in(abfd, i,o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_swap_aouthdr_in(abfd, i,o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_swap_scnhdr_in(abfd, i,o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_swap_reloc_in(abfd, i, o) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_swap_reloc_in) (abfd, i, o))
|
||||
|
||||
#define bfd_coff_bad_format_hook(abfd, filehdr) \
|
||||
((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr))
|
||||
|
||||
#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr))
|
||||
#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_mkobject_hook)\
|
||||
(abfd, filehdr, aouthdr))
|
||||
|
||||
#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr, name, section, flags_ptr)\
|
||||
((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook)\
|
||||
(abfd, scnhdr, name, section, flags_ptr))
|
||||
|
||||
#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\
|
||||
((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr))
|
||||
|
||||
#define bfd_coff_slurp_symbol_table(abfd)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd))
|
||||
|
||||
#define bfd_coff_symname_in_debug(abfd, sym)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym))
|
||||
|
||||
#define bfd_coff_force_symnames_in_strings(abfd)\
|
||||
(coff_backend_info (abfd)->_bfd_coff_force_symnames_in_strings)
|
||||
|
||||
#define bfd_coff_debug_string_prefix_length(abfd)\
|
||||
(coff_backend_info (abfd)->_bfd_coff_debug_string_prefix_length)
|
||||
|
||||
#define bfd_coff_print_aux(abfd, file, base, symbol, aux, indaux)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_print_aux)\
|
||||
(abfd, file, base, symbol, aux, indaux))
|
||||
|
||||
#define bfd_coff_reloc16_extra_cases(abfd, link_info, link_order,\
|
||||
reloc, data, src_ptr, dst_ptr)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\
|
||||
(abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr))
|
||||
|
||||
#define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\
|
||||
(abfd, section, reloc, shrink, link_info))
|
||||
|
||||
#define bfd_coff_classify_symbol(abfd, sym)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_classify_symbol)\
|
||||
(abfd, sym))
|
||||
|
||||
#define bfd_coff_compute_section_file_positions(abfd)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_compute_section_file_positions)\
|
||||
(abfd))
|
||||
|
||||
#define bfd_coff_start_final_link(obfd, info)\
|
||||
((coff_backend_info (obfd)->_bfd_coff_start_final_link)\
|
||||
(obfd, info))
|
||||
#define bfd_coff_relocate_section(obfd,info,ibfd,o,con,rel,isyms,secs)\
|
||||
((coff_backend_info (ibfd)->_bfd_coff_relocate_section)\
|
||||
(obfd, info, ibfd, o, con, rel, isyms, secs))
|
||||
#define bfd_coff_rtype_to_howto(abfd, sec, rel, h, sym, addendp)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_rtype_to_howto)\
|
||||
(abfd, sec, rel, h, sym, addendp))
|
||||
#define bfd_coff_adjust_symndx(obfd, info, ibfd, sec, rel, adjustedp)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_adjust_symndx)\
|
||||
(obfd, info, ibfd, sec, rel, adjustedp))
|
||||
#define bfd_coff_link_add_one_symbol(info, abfd, name, flags, section,\
|
||||
value, string, cp, coll, hashp)\
|
||||
((coff_backend_info (abfd)->_bfd_coff_link_add_one_symbol)\
|
||||
(info, abfd, name, flags, section, value, string, cp, coll, hashp))
|
||||
|
||||
#define bfd_coff_link_output_has_begun(a,p) \
|
||||
((coff_backend_info (a)->_bfd_coff_link_output_has_begun) (a, p))
|
||||
#define bfd_coff_final_link_postscript(a,p) \
|
||||
((coff_backend_info (a)->_bfd_coff_final_link_postscript) (a, p))
|
||||
|
||||
#define bfd_coff_have_print_pdata(a) \
|
||||
(coff_backend_info (a)->_bfd_coff_print_pdata)
|
||||
#define bfd_coff_print_pdata(a,p) \
|
||||
((coff_backend_info (a)->_bfd_coff_print_pdata) (a, p))
|
||||
|
||||
/* Macro: Returns true if the bfd is a PE executable as opposed to a
|
||||
PE object file. */
|
||||
#define bfd_pei_p(abfd) \
|
||||
(CONST_STRNEQ ((abfd)->xvec->name, "pei-"))
|
245
src/sbattach.c
Normal file
245
src/sbattach.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <ccan/talloc/talloc.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "image.h"
|
||||
#include "fileio.h"
|
||||
|
||||
static const char *toolname = "sbattach";
|
||||
|
||||
static struct option options[] = {
|
||||
{ "attach", required_argument, NULL, 'a' },
|
||||
{ "detach", required_argument, NULL, 'd' },
|
||||
{ "remove", no_argument, NULL, 'r' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: %s --attach <sigfile> <efi-boot-image>\n"
|
||||
" or: %s --detach <sigfile> [--remove] <efi-boot-image>\n"
|
||||
" or: %s --remove <efi-boot-image>\n"
|
||||
"Attach or detach a signature file to/from a boot image\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
"\t--attach <sigfile> set <sigfile> as the boot image's\n"
|
||||
"\t signature table\n"
|
||||
"\t--detach <sigfile> copy the boot image's signature table\n"
|
||||
"\t to <sigfile>\n"
|
||||
"\t--remove remove the boot image's signature\n"
|
||||
"\t table from the original file\n",
|
||||
toolname, toolname, toolname);
|
||||
}
|
||||
|
||||
static void version(void)
|
||||
{
|
||||
printf("%s %s\n", toolname, VERSION);
|
||||
}
|
||||
|
||||
static int detach_sig(struct image *image, const char *sig_filename)
|
||||
{
|
||||
return image_write_detached(image, sig_filename);
|
||||
}
|
||||
|
||||
static int attach_sig(struct image *image, const char *image_filename,
|
||||
const char *sig_filename)
|
||||
{
|
||||
const uint8_t *tmp_buf;
|
||||
uint8_t *sigbuf;
|
||||
size_t size;
|
||||
PKCS7 *p7;
|
||||
int rc;
|
||||
|
||||
rc = fileio_read_file(image, sig_filename, &sigbuf, &size);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
image_add_signature(image, sigbuf, size);
|
||||
|
||||
rc = -1;
|
||||
tmp_buf = sigbuf;
|
||||
p7 = d2i_PKCS7(NULL, &tmp_buf, size);
|
||||
if (!p7) {
|
||||
fprintf(stderr, "Unable to parse signature data in file: %s\n",
|
||||
sig_filename);
|
||||
ERR_print_errors_fp(stderr);
|
||||
goto out;
|
||||
}
|
||||
rc = PKCS7_verify(p7, NULL, NULL, NULL, NULL,
|
||||
PKCS7_BINARY | PKCS7_NOVERIFY | PKCS7_NOSIGS);
|
||||
if (!rc) {
|
||||
fprintf(stderr, "PKCS7 verification failed for file %s\n",
|
||||
sig_filename);
|
||||
ERR_print_errors_fp(stderr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = image_write(image, image_filename);
|
||||
if (rc)
|
||||
fprintf(stderr, "Error writing %s: %s\n", image_filename,
|
||||
strerror(errno));
|
||||
|
||||
out:
|
||||
talloc_free(sigbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int remove_sig(struct image *image, const char *image_filename)
|
||||
{
|
||||
int rc;
|
||||
|
||||
image_remove_signature(image);
|
||||
|
||||
rc = image_write(image, image_filename);
|
||||
if (rc)
|
||||
fprintf(stderr, "Error writing %s: %s\n", image_filename,
|
||||
strerror(errno));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
enum action {
|
||||
ACTION_NONE,
|
||||
ACTION_ATTACH,
|
||||
ACTION_DETACH,
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *image_filename, *sig_filename;
|
||||
struct image *image;
|
||||
enum action action;
|
||||
bool remove;
|
||||
int c, rc;
|
||||
|
||||
action = ACTION_NONE;
|
||||
sig_filename = NULL;
|
||||
remove = false;
|
||||
|
||||
for (;;) {
|
||||
int idx;
|
||||
c = getopt_long(argc, argv, "a:d:rhV", options, &idx);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'a':
|
||||
case 'd':
|
||||
if (action != ACTION_NONE) {
|
||||
fprintf(stderr, "Multiple actions specified\n");
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
action = (c == 'a') ? ACTION_ATTACH : ACTION_DETACH;
|
||||
sig_filename = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
remove = true;
|
||||
break;
|
||||
case 'V':
|
||||
version();
|
||||
return EXIT_SUCCESS;
|
||||
case 'h':
|
||||
usage();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != optind + 1) {
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
image_filename = argv[optind];
|
||||
|
||||
/* sanity check action combinations */
|
||||
if (action == ACTION_ATTACH && remove) {
|
||||
fprintf(stderr, "Can't use --remove with --attach\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (action == ACTION_NONE && !remove) {
|
||||
fprintf(stderr, "No action (attach/detach/remove) specified\n");
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ERR_load_crypto_strings();
|
||||
OpenSSL_add_all_digests();
|
||||
|
||||
image = image_load(image_filename);
|
||||
if (!image) {
|
||||
fprintf(stderr, "Can't load image file %s\n", image_filename);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
if (action == ACTION_ATTACH)
|
||||
rc = attach_sig(image, image_filename, sig_filename);
|
||||
|
||||
else if (action == ACTION_DETACH)
|
||||
rc = detach_sig(image, sig_filename);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (remove)
|
||||
rc = remove_sig(image, image_filename);
|
||||
|
||||
out:
|
||||
talloc_free(image);
|
||||
return (rc == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
277
src/sbsiglist.c
Normal file
277
src/sbsiglist.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/talloc/talloc.h>
|
||||
|
||||
#include "efivars.h"
|
||||
#include "fileio.h"
|
||||
|
||||
static const char *toolname = "sbsiglist";
|
||||
|
||||
static struct option options[] = {
|
||||
{ "output", required_argument, NULL, 'o' },
|
||||
{ "type", required_argument, NULL, 't' },
|
||||
{ "owner", required_argument, NULL, 'w' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
#define EFI_CERT_X509_GUID \
|
||||
{ 0xa5c059a1, 0x94e4, 0x4aa7, \
|
||||
{ 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 } }
|
||||
|
||||
#define EFI_CERT_SHA256_GUID \
|
||||
{ 0xc1c41626, 0x504c, 0x4092, \
|
||||
{ 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } }
|
||||
|
||||
struct cert_type {
|
||||
const char *name;
|
||||
const EFI_GUID guid;
|
||||
unsigned int sigsize;
|
||||
};
|
||||
|
||||
struct cert_type cert_types[] = {
|
||||
{ "x509", EFI_CERT_X509_GUID, 0 },
|
||||
{ "sha256", EFI_CERT_SHA256_GUID, sizeof(EFI_SIGNATURE_DATA) + 16 },
|
||||
};
|
||||
|
||||
struct siglist_context {
|
||||
int verbose;
|
||||
|
||||
const char *infilename;
|
||||
const char *outfilename;
|
||||
const struct cert_type *type;
|
||||
EFI_GUID owner;
|
||||
|
||||
uint8_t *data;
|
||||
size_t data_len;
|
||||
|
||||
EFI_SIGNATURE_LIST *siglist;
|
||||
};
|
||||
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
printf("Usage: %s [options] --owner <guid> --type <type> <sig-file>\n"
|
||||
"Create an EFI_SIGNATURE_LIST from a signature file\n"
|
||||
"Options:\n"
|
||||
"\t--owner <guid> Signature owner GUID\n"
|
||||
"\t--type <type> Signature type. One of:\n",
|
||||
toolname);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cert_types); i++)
|
||||
printf("\t %s\n", cert_types[i].name);
|
||||
|
||||
printf("\t--output <file> write signed data to <file>\n"
|
||||
"\t (default <sig-file>.siglist)\n");
|
||||
}
|
||||
|
||||
static void version(void)
|
||||
{
|
||||
printf("%s %s\n", toolname, VERSION);
|
||||
}
|
||||
|
||||
static int siglist_create(struct siglist_context *ctx)
|
||||
{
|
||||
EFI_SIGNATURE_LIST *siglist;
|
||||
EFI_SIGNATURE_DATA *sigdata;
|
||||
uint32_t size;
|
||||
|
||||
if (ctx->type->sigsize && ctx->data_len + sizeof(*sigdata)
|
||||
!= ctx->type->sigsize) {
|
||||
fprintf(stderr, "Error: signature lists of type '%s' expect "
|
||||
"%d bytes of data, "
|
||||
"%zd bytes provided.\n",
|
||||
ctx->type->name,
|
||||
ctx->type->sigsize,
|
||||
ctx->data_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = sizeof(*siglist) + sizeof(*sigdata) + ctx->data_len;
|
||||
|
||||
siglist = talloc_size(ctx, size);
|
||||
sigdata = (void *)(siglist + 1);
|
||||
|
||||
siglist->SignatureType = ctx->type->guid;
|
||||
siglist->SignatureListSize = size;
|
||||
siglist->SignatureHeaderSize = 0;
|
||||
siglist->SignatureSize = ctx->data_len;
|
||||
|
||||
sigdata->SignatureOwner = ctx->owner;
|
||||
|
||||
memcpy(sigdata->SignatureData, ctx->data, ctx->data_len);
|
||||
|
||||
ctx->siglist = siglist;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_guid(const char *str, EFI_GUID *guid)
|
||||
{
|
||||
uuid_t uuid;
|
||||
|
||||
if (uuid_parse(str, uuid))
|
||||
return -1;
|
||||
|
||||
/* convert to an EFI_GUID */
|
||||
guid->Data1 = uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3];
|
||||
guid->Data2 = uuid[4] << 8 | uuid[5];
|
||||
guid->Data3 = uuid[6] << 8 | uuid[7];
|
||||
memcpy(guid->Data4, &uuid[8], sizeof(guid->Data4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cert_type *parse_type(const char *str)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cert_types); i++)
|
||||
if (!strcasecmp(cert_types[i].name, str))
|
||||
return &cert_types[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void set_default_outfilename(struct siglist_context *ctx)
|
||||
{
|
||||
const char *extension = "siglist";
|
||||
|
||||
ctx->outfilename = talloc_asprintf(ctx, "%s.%s",
|
||||
ctx->infilename, extension);
|
||||
}
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *type_str, *owner_guid_str;
|
||||
struct siglist_context *ctx;
|
||||
int c;
|
||||
|
||||
ctx = talloc_zero(NULL, struct siglist_context);
|
||||
|
||||
owner_guid_str = NULL;
|
||||
type_str = NULL;
|
||||
|
||||
for (;;) {
|
||||
int idx;
|
||||
c = getopt_long(argc, argv, "o:t:w:ivVh", options, &idx);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'o':
|
||||
ctx->outfilename = optarg;
|
||||
break;
|
||||
case 't':
|
||||
type_str = optarg;
|
||||
break;
|
||||
case 'w':
|
||||
owner_guid_str = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
ctx->verbose = 1;
|
||||
break;
|
||||
case 'V':
|
||||
version();
|
||||
return EXIT_SUCCESS;
|
||||
case 'h':
|
||||
usage();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != optind + 1) {
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ctx->infilename = argv[optind];
|
||||
|
||||
ctx->type = parse_type(type_str);
|
||||
if (!ctx->type) {
|
||||
fprintf(stderr, "Invalid type '%s'\n", type_str);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (parse_guid(owner_guid_str, &ctx->owner)) {
|
||||
fprintf(stderr, "Invalid owner GUID '%s'\n", owner_guid_str);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!ctx->outfilename)
|
||||
set_default_outfilename(ctx);
|
||||
|
||||
if (fileio_read_file(ctx, ctx->infilename,
|
||||
&ctx->data, &ctx->data_len)) {
|
||||
fprintf(stderr, "Can't read input file %s\n", ctx->infilename);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (siglist_create(ctx))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (fileio_write_file(ctx->outfilename,
|
||||
(void *)ctx->siglist,
|
||||
ctx->siglist->SignatureListSize)) {
|
||||
fprintf(stderr, "Can't write output file %s\n",
|
||||
ctx->outfilename);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
231
src/sbsign.c
Normal file
231
src/sbsign.c
Normal file
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/asn1t.h>
|
||||
|
||||
#include <ccan/talloc/talloc.h>
|
||||
|
||||
#include "idc.h"
|
||||
#include "image.h"
|
||||
#include "fileio.h"
|
||||
|
||||
static const char *toolname = "sbsign";
|
||||
|
||||
struct sign_context {
|
||||
struct image *image;
|
||||
const char *infilename;
|
||||
const char *outfilename;
|
||||
int verbose;
|
||||
int detached;
|
||||
};
|
||||
|
||||
static struct option options[] = {
|
||||
{ "output", required_argument, NULL, 'o' },
|
||||
{ "cert", required_argument, NULL, 'c' },
|
||||
{ "key", required_argument, NULL, 'k' },
|
||||
{ "detached", no_argument, NULL, 'd' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: %s [options] --key <keyfile> --cert <certfile> "
|
||||
"<efi-boot-image>\n"
|
||||
"Sign an EFI boot image for use with secure boot.\n\n"
|
||||
"Options:\n"
|
||||
"\t--key <keyfile> signing key (PEM-encoded RSA "
|
||||
"private key)\n"
|
||||
"\t--cert <certfile> certificate (x509 certificate)\n"
|
||||
"\t--detached write a detached signature, instead of\n"
|
||||
"\t a signed binary\n"
|
||||
"\t--output <file> write signed data to <file>\n"
|
||||
"\t (default <efi-boot-image>.signed,\n"
|
||||
"\t or <efi-boot-image>.pk7 for detached\n"
|
||||
"\t signatures)\n",
|
||||
toolname);
|
||||
}
|
||||
|
||||
static void version(void)
|
||||
{
|
||||
printf("%s %s\n", toolname, VERSION);
|
||||
}
|
||||
|
||||
static void set_default_outfilename(struct sign_context *ctx)
|
||||
{
|
||||
const char *extension;
|
||||
|
||||
extension = ctx->detached ? "pk7" : "signed";
|
||||
|
||||
ctx->outfilename = talloc_asprintf(ctx, "%s.%s",
|
||||
ctx->infilename, extension);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *keyfilename, *certfilename;
|
||||
struct sign_context *ctx;
|
||||
uint8_t *buf, *tmp;
|
||||
int rc, c, sigsize;
|
||||
|
||||
ctx = talloc_zero(NULL, struct sign_context);
|
||||
|
||||
keyfilename = NULL;
|
||||
certfilename = NULL;
|
||||
|
||||
for (;;) {
|
||||
int idx;
|
||||
c = getopt_long(argc, argv, "o:c:k:dvVh", options, &idx);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'o':
|
||||
ctx->outfilename = talloc_strdup(ctx, optarg);
|
||||
break;
|
||||
case 'c':
|
||||
certfilename = optarg;
|
||||
break;
|
||||
case 'k':
|
||||
keyfilename = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
ctx->detached = 1;
|
||||
break;
|
||||
case 'v':
|
||||
ctx->verbose = 1;
|
||||
break;
|
||||
case 'V':
|
||||
version();
|
||||
return EXIT_SUCCESS;
|
||||
case 'h':
|
||||
usage();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != optind + 1) {
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ctx->infilename = argv[optind];
|
||||
if (!ctx->outfilename)
|
||||
set_default_outfilename(ctx);
|
||||
|
||||
if (!certfilename) {
|
||||
fprintf(stderr,
|
||||
"error: No certificate specified (with --cert)\n");
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!keyfilename) {
|
||||
fprintf(stderr,
|
||||
"error: No key specified (with --key)\n");
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ctx->image = image_load(ctx->infilename);
|
||||
if (!ctx->image)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
talloc_steal(ctx, ctx->image);
|
||||
|
||||
ERR_load_crypto_strings();
|
||||
OpenSSL_add_all_digests();
|
||||
OpenSSL_add_all_ciphers();
|
||||
|
||||
EVP_PKEY *pkey = fileio_read_pkey(keyfilename);
|
||||
if (!pkey)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
X509 *cert = fileio_read_cert(certfilename);
|
||||
if (!cert)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
const EVP_MD *md = EVP_get_digestbyname("SHA256");
|
||||
|
||||
/* set up the PKCS7 object */
|
||||
PKCS7 *p7 = PKCS7_new();
|
||||
PKCS7_set_type(p7, NID_pkcs7_signed);
|
||||
|
||||
PKCS7_SIGNER_INFO *si = PKCS7_sign_add_signer(p7, cert,
|
||||
pkey, md, PKCS7_BINARY);
|
||||
if (!si) {
|
||||
fprintf(stderr, "error in key/certificate chain\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
PKCS7_content_new(p7, NID_pkcs7_data);
|
||||
|
||||
rc = IDC_set(p7, si, ctx->image);
|
||||
if (rc)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
sigsize = i2d_PKCS7(p7, NULL);
|
||||
tmp = buf = talloc_array(ctx->image, uint8_t, sigsize);
|
||||
i2d_PKCS7(p7, &tmp);
|
||||
ERR_print_errors_fp(stdout);
|
||||
|
||||
image_add_signature(ctx->image, buf, sigsize);
|
||||
|
||||
if (ctx->detached)
|
||||
image_write_detached(ctx->image, ctx->outfilename);
|
||||
else
|
||||
image_write(ctx->image, ctx->outfilename);
|
||||
|
||||
talloc_free(ctx);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
533
src/sbvarsign.c
Normal file
533
src/sbvarsign.c
Normal file
|
@ -0,0 +1,533 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
#include <ccan/talloc/talloc.h>
|
||||
|
||||
#include "efivars.h"
|
||||
#include "fileio.h"
|
||||
|
||||
static const char *toolname = "sbvarsign";
|
||||
|
||||
|
||||
struct varsign_context {
|
||||
const char *infilename;
|
||||
const char *outfilename;
|
||||
|
||||
uint8_t *data;
|
||||
size_t data_len;
|
||||
|
||||
CHAR16 *var_name;
|
||||
int var_name_bytes;
|
||||
EFI_GUID var_guid;
|
||||
uint32_t var_attrs;
|
||||
|
||||
EVP_PKEY *key;
|
||||
X509 *cert;
|
||||
|
||||
EFI_VARIABLE_AUTHENTICATION_2 *auth_descriptor;
|
||||
int auth_descriptor_len;
|
||||
EFI_TIME timestamp;
|
||||
|
||||
int verbose;
|
||||
};
|
||||
|
||||
struct attr {
|
||||
const char *name;
|
||||
int value;
|
||||
};
|
||||
|
||||
static struct attr attrs[] = {
|
||||
{ "NON_VOLATILE", 0x0001 },
|
||||
{ "BOOTSERVICE_ACCESS", 0x0002 },
|
||||
{ "RUNTIME_ACCESS", 0x0004 },
|
||||
{ "TIME_BASED_AUTHENTICATED_WRITE_ACCESS", 0x0020 },
|
||||
{ "APPEND_WRITE", 0x0040 },
|
||||
};
|
||||
|
||||
#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0020
|
||||
|
||||
static uint32_t attr_invalid = 0xffffffffu;
|
||||
static const char *attr_prefix = "EFI_VARIABLE_";
|
||||
|
||||
static const EFI_GUID default_guid = EFI_GLOBAL_VARIABLE;
|
||||
static const EFI_GUID cert_pkcs7_guid = EFI_CERT_TYPE_PKCS7_GUID;
|
||||
|
||||
static void set_default_outfilename(struct varsign_context *ctx)
|
||||
{
|
||||
const char *extension = "signed";
|
||||
|
||||
ctx->outfilename = talloc_asprintf(ctx, "%s.%s",
|
||||
ctx->infilename, extension);
|
||||
}
|
||||
|
||||
static uint32_t parse_single_attr(const char *attr_str)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* skip standard prefix, if present */
|
||||
if (!strncmp(attr_str, attr_prefix, strlen(attr_prefix)))
|
||||
attr_str += strlen(attr_prefix);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(attrs); i++) {
|
||||
if (!strcmp(attr_str, attrs[i].name))
|
||||
return attrs[i].value;
|
||||
}
|
||||
|
||||
return attr_invalid;
|
||||
}
|
||||
|
||||
static uint32_t parse_attrs(const char *attrs_str)
|
||||
{
|
||||
uint32_t attr, attrs_val;
|
||||
const char *attr_str;
|
||||
char *str;
|
||||
|
||||
/* we always need E_V_T_B_A_W_A */
|
||||
attrs_val = EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
|
||||
|
||||
if (!attrs_str || !attrs_str[0])
|
||||
return attrs_val;
|
||||
|
||||
str = strdup(attrs_str);
|
||||
|
||||
for (attr_str = strtok(str, ","); attr_str;
|
||||
attr_str = strtok(NULL, ",")) {
|
||||
|
||||
attr = parse_single_attr(attr_str);
|
||||
if (attr == attr_invalid) {
|
||||
fprintf(stderr, "Invalid attribute string %s\n",
|
||||
attr_str);
|
||||
return attr_invalid;
|
||||
}
|
||||
|
||||
attrs_val |= attr;
|
||||
}
|
||||
|
||||
return attrs_val;
|
||||
}
|
||||
|
||||
static int set_varname(struct varsign_context *ctx, const char *str)
|
||||
{
|
||||
CHAR16 *wstr;
|
||||
int i, len;
|
||||
|
||||
len = strlen(str);
|
||||
|
||||
wstr = talloc_array(ctx, CHAR16, len + 1);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
wstr[i] = str[i];
|
||||
|
||||
wstr[i] = '\0';
|
||||
|
||||
ctx->var_name = wstr;
|
||||
ctx->var_name_bytes = i * sizeof(CHAR16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_guid(const char *str, EFI_GUID *guid)
|
||||
{
|
||||
uuid_t uuid;
|
||||
|
||||
if (uuid_parse(str, uuid))
|
||||
return -1;
|
||||
|
||||
/* convert to an EFI_GUID */
|
||||
guid->Data1 = uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3];
|
||||
guid->Data2 = uuid[4] << 8 | uuid[5];
|
||||
guid->Data3 = uuid[6] << 8 | uuid[7];
|
||||
memcpy(guid->Data4, &uuid[8], sizeof(guid->Data4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_timestamp(EFI_TIME *timestamp)
|
||||
{
|
||||
struct tm *tm;
|
||||
time_t t;
|
||||
|
||||
time(&t);
|
||||
|
||||
tm = gmtime(&t);
|
||||
if (!tm) {
|
||||
perror("gmtime");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* copy to our EFI-specific time structure. Other fields (Nanosecond,
|
||||
* TimeZone, Daylight and Pad) are defined to be zero */
|
||||
memset(timestamp, 0, sizeof(timestamp));
|
||||
timestamp->Year = tm->tm_year;
|
||||
timestamp->Month = tm->tm_mon;
|
||||
timestamp->Day = tm->tm_mday;
|
||||
timestamp->Hour = tm->tm_hour;
|
||||
timestamp->Minute = tm->tm_min;
|
||||
timestamp->Second = tm->tm_sec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_auth_descriptor(struct varsign_context *ctx)
|
||||
{
|
||||
EFI_VARIABLE_AUTHENTICATION_2 *auth;
|
||||
int rc, len, flags;
|
||||
EFI_TIME timestamp;
|
||||
const EVP_MD *md;
|
||||
BIO *data_bio;
|
||||
uint8_t *tmp;
|
||||
PKCS7 *p7;
|
||||
|
||||
if (set_timestamp(×tamp))
|
||||
return -1;
|
||||
|
||||
/* create a BIO for our variable data, containing:
|
||||
* * Variablename (not including trailing nul)
|
||||
* * VendorGUID
|
||||
* * Attributes
|
||||
* * TimeStamp
|
||||
* * Data
|
||||
*/
|
||||
data_bio = BIO_new(BIO_s_mem());
|
||||
BIO_write(data_bio, ctx->var_name, ctx->var_name_bytes);
|
||||
BIO_write(data_bio, &ctx->var_guid, sizeof(ctx->var_guid));
|
||||
BIO_write(data_bio, &ctx->var_attrs, sizeof(ctx->var_attrs));
|
||||
BIO_write(data_bio, ×tamp, sizeof(timestamp));
|
||||
BIO_write(data_bio, &ctx->data, ctx->data_len);
|
||||
|
||||
md = EVP_get_digestbyname("SHA256");
|
||||
|
||||
p7 = PKCS7_new();
|
||||
flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOSMIMECAP;;
|
||||
PKCS7_set_type(p7, NID_pkcs7_signed);
|
||||
|
||||
PKCS7_content_new(p7, NID_pkcs7_data);
|
||||
|
||||
PKCS7_sign_add_signer(p7, ctx->cert, ctx->key, md, flags);
|
||||
|
||||
PKCS7_set_detached(p7, 1);
|
||||
|
||||
rc = PKCS7_final(p7, data_bio, flags);
|
||||
if (!rc) {
|
||||
fprintf(stderr, "Error signing variable data\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
BIO_free_all(data_bio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = i2d_PKCS7(p7, NULL);
|
||||
|
||||
|
||||
/* set up our auth descriptor */
|
||||
auth = talloc_size(ctx, sizeof(*auth) + len);
|
||||
|
||||
auth->TimeStamp = timestamp;
|
||||
auth->AuthInfo.Hdr.dwLength = len + sizeof(EFI_GUID);
|
||||
auth->AuthInfo.Hdr.wRevision = 0x0200;
|
||||
auth->AuthInfo.Hdr.wCertificateType = 0x0EF1;
|
||||
auth->AuthInfo.CertType = cert_pkcs7_guid;
|
||||
tmp = auth->AuthInfo.CertData;
|
||||
i2d_PKCS7(p7, &tmp);
|
||||
|
||||
ctx->auth_descriptor = auth;
|
||||
ctx->auth_descriptor_len = sizeof(*auth) + len;
|
||||
|
||||
BIO_free_all(data_bio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_signed(struct varsign_context *ctx, int include_attrs)
|
||||
{
|
||||
int fd, rc;
|
||||
|
||||
fd = open(ctx->outfilename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* For some uses (eg, writing to the efivars filesystem), we may
|
||||
* want to prefix the signed variable with four bytes of attribute
|
||||
* data
|
||||
*/
|
||||
if (include_attrs) {
|
||||
rc = write_all(fd, &ctx->var_attrs, sizeof(ctx->var_attrs));
|
||||
if (!rc) {
|
||||
perror("write_all");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the authentication descriptor */
|
||||
rc = write_all(fd, ctx->auth_descriptor, ctx->auth_descriptor_len);
|
||||
if (!rc) {
|
||||
perror("write_all");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* ... and the variable data itself */
|
||||
rc = write_all(fd, ctx->data, ctx->data_len);
|
||||
if (!rc) {
|
||||
perror("write_all");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ctx->verbose) {
|
||||
size_t i = 0;
|
||||
|
||||
printf("Wrote signed data:\n");
|
||||
if (include_attrs) {
|
||||
i = sizeof(ctx->var_attrs);
|
||||
printf(" [%04zx:%04zx] attrs\n", 0l, i);
|
||||
}
|
||||
|
||||
printf(" [%04zx:%04x] authentication descriptor\n",
|
||||
i, ctx->auth_descriptor_len);
|
||||
|
||||
printf(" [%04zx:%04zx] EFI_VAR_AUTH_2 header\n",
|
||||
i,
|
||||
sizeof(EFI_VARIABLE_AUTHENTICATION_2));
|
||||
|
||||
printf(" [%04zx:%04zx] WIN_CERT_UEFI_GUID header\n",
|
||||
i + offsetof(EFI_VARIABLE_AUTHENTICATION_2,
|
||||
AuthInfo),
|
||||
sizeof(WIN_CERTIFICATE_UEFI_GUID));
|
||||
|
||||
printf(" [%04zx:%04zx] WIN_CERT header\n",
|
||||
i + offsetof(EFI_VARIABLE_AUTHENTICATION_2,
|
||||
AuthInfo.Hdr),
|
||||
sizeof(WIN_CERTIFICATE));
|
||||
|
||||
printf(" [%04zx:%04zx] pkcs7 data\n",
|
||||
i + offsetof(EFI_VARIABLE_AUTHENTICATION_2,
|
||||
AuthInfo.CertData),
|
||||
ctx->auth_descriptor_len -
|
||||
sizeof(EFI_VARIABLE_AUTHENTICATION_2));
|
||||
|
||||
i += ctx->auth_descriptor_len;
|
||||
|
||||
printf(" [%04zx:%04zx] variable data\n",
|
||||
i, i + ctx->data_len);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
fprintf(stderr, "Can't write signed data to file '%s'\n",
|
||||
ctx->outfilename);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
{ "output", required_argument, NULL, 'o' },
|
||||
{ "guid", required_argument, NULL, 'g' },
|
||||
{ "attrs", required_argument, NULL, 'a' },
|
||||
{ "key", required_argument, NULL, 'k' },
|
||||
{ "cert", required_argument, NULL, 'c' },
|
||||
{ "include-attrs", no_argument, NULL, 'i' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
printf("Usage: %s [options] --key <keyfile> --cert <certfile> "
|
||||
"<var-name> <var-data-file>\n"
|
||||
"Sign a blob of data for use in SetVariable().\n\n"
|
||||
"Options:\n"
|
||||
"\t--key <keyfile> signing key (PEM-encoded RSA "
|
||||
"private key)\n"
|
||||
"\t--cert <certfile> certificate (x509 certificate)\n"
|
||||
"\t--include-attrs include attrs at beginning of output file\n"
|
||||
"\t--guid <GUID> EFI GUID for the variable. If omitted,\n"
|
||||
"\t EFI_GLOBAL_VARIABLE will be used\n"
|
||||
"\t--attr <attrs> variable attributes. One or more of:\n",
|
||||
toolname);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(attrs); i++)
|
||||
printf("\t %s\n", attrs[i].name);
|
||||
|
||||
printf("\t Separate multiple attrs with a comma\n"
|
||||
"\t--output <file> write signed data to <file>\n"
|
||||
"\t (default <var-data-file>.signed)\n");
|
||||
}
|
||||
|
||||
static void version(void)
|
||||
{
|
||||
printf("%s %s\n", toolname, VERSION);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *keyfilename, *certfilename;
|
||||
const char *guid_str, *attr_str;
|
||||
struct varsign_context *ctx;
|
||||
bool include_attrs;
|
||||
int c;
|
||||
|
||||
ctx = talloc_zero(NULL, struct varsign_context);
|
||||
|
||||
keyfilename = NULL;
|
||||
certfilename = NULL;
|
||||
guid_str = NULL;
|
||||
attr_str= NULL;
|
||||
include_attrs = false;
|
||||
|
||||
for (;;) {
|
||||
int idx;
|
||||
c = getopt_long(argc, argv, "o:g:a:k:c:ivVh", options, &idx);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'o':
|
||||
ctx->outfilename = optarg;
|
||||
break;
|
||||
case 'g':
|
||||
guid_str = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
attr_str = optarg;
|
||||
break;
|
||||
case 'k':
|
||||
keyfilename = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
certfilename = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
include_attrs = true;
|
||||
break;
|
||||
case 'v':
|
||||
ctx->verbose = 1;
|
||||
break;
|
||||
case 'V':
|
||||
version();
|
||||
return EXIT_SUCCESS;
|
||||
case 'h':
|
||||
usage();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != optind + 2) {
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!keyfilename) {
|
||||
fprintf(stderr, "No signing key specified\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!certfilename) {
|
||||
fprintf(stderr, "No signing certificate specified\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* initialise openssl */
|
||||
OpenSSL_add_all_digests();
|
||||
OpenSSL_add_all_ciphers();
|
||||
ERR_load_crypto_strings();
|
||||
|
||||
/* set up the variable signing context */
|
||||
set_varname(ctx, argv[optind]);
|
||||
ctx->infilename = argv[optind+1];
|
||||
|
||||
if (!ctx->outfilename)
|
||||
set_default_outfilename(ctx);
|
||||
|
||||
ctx->var_attrs = parse_attrs(attr_str);
|
||||
if (ctx->var_attrs == attr_invalid)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (guid_str) {
|
||||
if (parse_guid(guid_str, &ctx->var_guid)) {
|
||||
fprintf(stderr, "Invalid GUID '%s'\n", guid_str);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} else {
|
||||
ctx->var_guid = default_guid;
|
||||
}
|
||||
|
||||
if (fileio_read_file(ctx, ctx->infilename, &ctx->data, &ctx->data_len))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
ctx->key = fileio_read_pkey(keyfilename);
|
||||
if (!ctx->key)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
ctx->cert = fileio_read_cert(certfilename);
|
||||
if (!ctx->cert)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* do the signing */
|
||||
if (add_auth_descriptor(ctx))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* write the resulting image */
|
||||
if (write_signed(ctx, include_attrs))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
252
src/sbverify.c
Normal file
252
src/sbverify.c
Normal file
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the OpenSSL
|
||||
* library under certain conditions as described in each individual source file,
|
||||
* and distribute linked combinations including the two.
|
||||
*
|
||||
* You must obey the GNU General Public License in all respects for all
|
||||
* of the code used other than OpenSSL. If you modify file(s) with this
|
||||
* exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do
|
||||
* so, delete this exception statement from your version. If you delete
|
||||
* this exception statement from all source files in the program, then
|
||||
* also delete it here.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <ccan/talloc/talloc.h>
|
||||
#include <ccan/read_write_all/read_write_all.h>
|
||||
|
||||
#include "image.h"
|
||||
#include "idc.h"
|
||||
#include "fileio.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
static const char *toolname = "sbverify";
|
||||
|
||||
enum verify_status {
|
||||
VERIFY_FAIL = 0,
|
||||
VERIFY_OK = 1,
|
||||
};
|
||||
|
||||
static struct option options[] = {
|
||||
{ "cert", required_argument, NULL, 'c' },
|
||||
{ "no-verify", no_argument, NULL, 'n' },
|
||||
{ "detached", required_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: %s [options] --cert <certfile> <efi-boot-image>\n"
|
||||
"Verify a UEFI secure boot image.\n\n"
|
||||
"Options:\n"
|
||||
"\t--cert <certfile> certificate (x509 certificate)\n"
|
||||
"\t--no-verify don't perform certificate verification\n"
|
||||
"\t--detached <file> read signature from <file>, instead of\n"
|
||||
"\t looking for an embedded signature\n",
|
||||
toolname);
|
||||
}
|
||||
|
||||
static void version(void)
|
||||
{
|
||||
printf("%s %s\n", toolname, VERSION);
|
||||
}
|
||||
|
||||
int load_cert(X509_STORE *certs, const char *filename)
|
||||
{
|
||||
X509 *cert;
|
||||
|
||||
cert = fileio_read_cert(filename);
|
||||
if (!cert)
|
||||
return -1;
|
||||
|
||||
X509_STORE_add_cert(certs, cert);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_image_signature_data(struct image *image,
|
||||
uint8_t **buf, size_t *len)
|
||||
{
|
||||
struct cert_table_header *header;
|
||||
|
||||
if (!image->data_dir_sigtable->addr
|
||||
|| !image->data_dir_sigtable->size) {
|
||||
fprintf(stderr, "No signature table present\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
header = (void *)image->buf + image->data_dir_sigtable->addr;
|
||||
*buf = (void *)(header + 1);
|
||||
*len = header->size - sizeof(*header);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_detached_signature_data(struct image *image,
|
||||
const char *filename, uint8_t **buf, size_t *len)
|
||||
{
|
||||
return fileio_read_file(image, filename, buf, len);
|
||||
}
|
||||
|
||||
static int x509_verify_cb(int status, X509_STORE_CTX *ctx)
|
||||
{
|
||||
int err = X509_STORE_CTX_get_error(ctx);
|
||||
|
||||
/* also accept code-signing keys */
|
||||
if (err == X509_V_ERR_INVALID_PURPOSE
|
||||
&& ctx->cert->ex_xkusage == XKU_CODE_SIGN)
|
||||
status = 1;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *detached_sig_filename, *image_filename;
|
||||
enum verify_status status;
|
||||
int rc, c, flags, verify;
|
||||
const uint8_t *tmp_buf;
|
||||
struct image *image;
|
||||
X509_STORE *certs;
|
||||
uint8_t *sig_buf;
|
||||
size_t sig_size;
|
||||
struct idc *idc;
|
||||
BIO *idcbio;
|
||||
PKCS7 *p7;
|
||||
|
||||
status = VERIFY_FAIL;
|
||||
certs = X509_STORE_new();
|
||||
verify = 1;
|
||||
detached_sig_filename = NULL;
|
||||
|
||||
OpenSSL_add_all_digests();
|
||||
ERR_load_crypto_strings();
|
||||
|
||||
for (;;) {
|
||||
int idx;
|
||||
c = getopt_long(argc, argv, "c:d:nVh", options, &idx);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'c':
|
||||
rc = load_cert(certs, optarg);
|
||||
if (rc)
|
||||
return EXIT_FAILURE;
|
||||
break;
|
||||
case 'd':
|
||||
detached_sig_filename = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
verify = 0;
|
||||
break;
|
||||
case 'V':
|
||||
version();
|
||||
return EXIT_SUCCESS;
|
||||
case 'h':
|
||||
usage();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (argc != optind + 1) {
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
image_filename = argv[optind];
|
||||
|
||||
image = image_load(image_filename);
|
||||
if (!image) {
|
||||
fprintf(stderr, "Can't open image %s\n", image_filename);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (detached_sig_filename)
|
||||
rc = load_detached_signature_data(image, detached_sig_filename,
|
||||
&sig_buf, &sig_size);
|
||||
else
|
||||
rc = load_image_signature_data(image, &sig_buf, &sig_size);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "Unable to read signature data from %s\n",
|
||||
detached_sig_filename ? : image_filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp_buf = sig_buf;
|
||||
p7 = d2i_PKCS7(NULL, &tmp_buf, sig_size);
|
||||
if (!p7) {
|
||||
fprintf(stderr, "Unable to parse signature data\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
idcbio = BIO_new(BIO_s_mem());
|
||||
idc = IDC_get(p7, idcbio);
|
||||
if (!idc)
|
||||
goto out;
|
||||
|
||||
rc = IDC_check_hash(idc, image);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
flags = PKCS7_BINARY;
|
||||
if (!verify)
|
||||
flags |= PKCS7_NOVERIFY;
|
||||
|
||||
X509_STORE_set_verify_cb_func(certs, x509_verify_cb);
|
||||
rc = PKCS7_verify(p7, NULL, certs, idcbio, NULL, flags);
|
||||
if (!rc) {
|
||||
printf("PKCS7 verification failed\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = VERIFY_OK;
|
||||
|
||||
out:
|
||||
talloc_free(image);
|
||||
if (status == VERIFY_OK)
|
||||
printf("Signature verification OK\n");
|
||||
else
|
||||
printf("Signature verification failed\n");
|
||||
|
||||
return status == VERIFY_OK ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
10
src/verify.c
Normal file
10
src/verify.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "image.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue