2
0
mirror of https://github.com/xcat2/xNBA.git synced 2026-06-17 00:50:49 +00:00
Conflicts:
	src/config/general.h
	src/net/arp.c
This commit is contained in:
Jarrod Johnson
2012-05-09 15:00:15 -04:00
321 changed files with 31310 additions and 65355 deletions
+2
View File
@@ -7,6 +7,7 @@ CLEANUP :=
CFLAGS :=
ASFLAGS :=
LDFLAGS :=
HOST_CFLAGS :=
MAKEDEPS := Makefile
###############################################################################
@@ -32,6 +33,7 @@ RANLIB := $(CROSS_COMPILE)ranlib
OBJCOPY := $(CROSS_COMPILE)objcopy
NM := $(CROSS_COMPILE)nm
OBJDUMP := $(CROSS_COMPILE)objdump
OPENSSL := openssl
PARSEROM := ./util/parserom.pl
FIXROM := ./util/fixrom.pl
SYMCHECK := ./util/symcheck.pl
+146 -45
View File
@@ -381,6 +381,7 @@ CFLAGS += -g
ifeq ($(CCTYPE),gcc)
CFLAGS += -ffreestanding
CFLAGS += -Wall -W -Wformat-nonliteral
HOST_CFLAGS += -Wall -W -Wformat-nonliteral
endif
ifeq ($(CCTYPE),icc)
CFLAGS += -fno-builtin
@@ -411,12 +412,14 @@ endif
CFLAGS += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
ASFLAGS += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
LDFLAGS += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS)
HOST_CFLAGS += -O2 -g
# Inhibit -Werror if NO_WERROR is specified on make command line
#
ifneq ($(NO_WERROR),1)
CFLAGS += -Werror
ASFLAGS += --fatal-warnings
HOST_CFLAGS += -Werror
endif
# Function trace recorder state in the last build. This is needed
@@ -514,6 +517,136 @@ RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@
DEBUG_TARGETS += dbg%.o c s
# List of embedded images included in the last build of embedded.o.
# This is needed in order to correctly rebuild embedded.o whenever the
# list of objects changes.
#
EMBED := $(EMBEDDED_IMAGE) # Maintain backwards compatibility
EMBEDDED_LIST := $(BIN)/.embedded.list
ifeq ($(wildcard $(EMBEDDED_LIST)),)
EMBED_OLD := <invalid>
else
EMBED_OLD := $(shell cat $(EMBEDDED_LIST))
endif
ifneq ($(EMBED_OLD),$(EMBED))
$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST))
endif
$(EMBEDDED_LIST) :
VERYCLEANUP += $(EMBEDDED_LIST)
EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED))
EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
\"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
embedded_DEPS += $(EMBEDDED_FILES) $(EMBEDDED_LIST)
CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
# List of trusted root certificates
#
TRUSTED_LIST := $(BIN)/.trusted.list
ifeq ($(wildcard $(TRUSTED_LIST)),)
TRUST_OLD := <invalid>
else
TRUST_OLD := $(shell cat $(TRUSTED_LIST))
endif
ifneq ($(TRUST_OLD),$(TRUST))
$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST))
endif
$(TRUSTED_LIST) :
VERYCLEANUP += $(TRUSTED_LIST)
# Trusted root certificate fingerprints
#
TRUSTED_CERTS := $(subst $(COMMA), ,$(TRUST))
TRUSTED_FPS := $(foreach CERT,$(TRUSTED_CERTS),\
0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\
$(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \
-fingerprint))))$(COMMA))
rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST)
CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
# (Single-element) list of client certificates
#
CERT_LIST := $(BIN)/.certificate.list
ifeq ($(wildcard $(CERT_LIST)),)
CERT_OLD := <invalid>
else
CERT_OLD := $(shell cat $(CERT_LIST))
endif
ifneq ($(CERT_OLD),$(CERT))
$(shell $(ECHO) "$(CERT)" > $(CERT_LIST))
endif
$(CERT_LIST) :
VERYCLEANUP += $(CERT_LIST)
# Embedded client certificate
#
CERT_INC := $(BIN)/.certificate.der
ifdef CERT
$(CERT_INC) : $(CERT) $(CERT_LIST)
$(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
clientcert_DEPS += $(CERT_INC)
endif
CLEANUP += $(CERT_INC)
clientcert_DEPS += $(CERT_LIST)
CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"")
# (Single-element) list of client private keys
#
KEY_LIST := $(BIN)/.private_key.list
ifeq ($(wildcard $(KEY_LIST)),)
KEY_OLD := <invalid>
else
KEY_OLD := $(shell cat $(KEY_LIST))
endif
ifneq ($(KEY_OLD),$(KEY))
$(shell $(ECHO) "$(KEY)" > $(KEY_LIST))
endif
$(KEY_LIST) :
VERYCLEANUP += $(KEY_LIST)
# Embedded client private key
#
KEY_INC := $(BIN)/.private_key.der
ifdef KEY
$(KEY_INC) : $(KEY) $(KEY_LIST)
$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
clientcert_DEPS += $(KEY_INC)
endif
CLEANUP += $(KEY_INC)
clientcert_DEPS += $(KEY_LIST)
CFLAGS_clientcert += $(if $(KEY),-DPRIVATE_KEY="\"$(KEY_INC)\"")
# These files use .incbin inline assembly to include a binary file.
# Unfortunately ccache does not detect this dependency and caches
# builds even when the binary file has changed.
#
$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
$(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC)
# We automatically generate rules for any file mentioned in AUTO_SRCS
# using the following set of templates. It would be cleaner to use
# $(eval ...), but this function exists only in GNU make >= 3.80.
@@ -529,7 +662,7 @@ define deps_template
@$(MKDIR) -p $(BIN)/deps/$(dir $(1))
@$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
-Wno-error -M $(1) -MG -MP | \
sed 's/\.o\s*:/_DEPS =/' > $(BIN)/deps/$(1).d
sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d
endef
# rules_template : generate rules for a given source file
@@ -603,40 +736,6 @@ drivers :
roms :
@$(ECHO) $(ROMS)
# List of embedded images included in the last build of embedded.o.
# This is needed in order to correctly rebuild embedded.o whenever the
# list of objects changes.
#
EMBED := $(EMBEDDED_IMAGE) # Maintain backwards compatibility
EMBEDDED_LIST := $(BIN)/.embedded.list
ifeq ($(wildcard $(EMBEDDED_LIST)),)
EMBED_OLD := <invalid>
else
EMBED_OLD := $(shell cat $(EMBEDDED_LIST))
endif
ifneq ($(EMBED_OLD),$(EMBED))
$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST))
endif
$(EMBEDDED_LIST) :
VERYCLEANUP += $(EMBEDDED_LIST)
EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED))
EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
\"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
$(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST)
# This file uses .incbin inline assembly to include a binary file.
# Unfortunately ccache does not detect this dependency and caches builds even
# when the binary file has changed.
#
$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
# Generate error usage information
#
$(BIN)/%.einfo : $(BIN)/%.o
@@ -961,13 +1060,13 @@ endif # defined(BIN)
#
$(NRV2B) : util/nrv2b.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG \
-DBITSIZE=32 -DENDIAN=0 -o $@ $<
$(Q)$(HOST_CC) $(HOST_CFLAGS) -DENCODE -DDECODE -DMAIN -DVERBOSE \
-DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
CLEANUP += $(NRV2B)
$(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) -O2 -o $@ $<
$(Q)$(HOST_CC) $(HOST_CFLAGS) -o $@ $<
CLEANUP += $(ZBIN)
###############################################################################
@@ -975,23 +1074,25 @@ CLEANUP += $(ZBIN)
# The EFI image converter
#
ELF2EFI_CFLAGS := -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \
-I$(ZLIB_DIR)/include -idirafter include \
-L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
-I$(ZLIB_DIR)/include -idirafter include
ELF2EFI_LDFLAGS := -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
-lbfd -ldl -liberty -lz -Wl,--no-warn-search-mismatch
$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 -O2 -o $@
$(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 $< \
$(ELF2EFI_LDFLAGS) -o $@
CLEANUP += $(ELF2EFI32)
$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 -O2 -o $@
$(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 $< \
$(ELF2EFI_LDFLAGS) -o $@
CLEANUP += $(ELF2EFI64)
$(EFIROM) : util/efirom.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
CLEANUP += $(EFIROM)
###############################################################################
@@ -1000,7 +1101,7 @@ CLEANUP += $(EFIROM)
#
$(ICCFIX) : util/iccfix.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
CLEANUP += $(ICCFIX)
###############################################################################
@@ -1009,7 +1110,7 @@ CLEANUP += $(ICCFIX)
#
$(EINFO) : util/einfo.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
CLEANUP += $(EINFO)
###############################################################################
+1 -7
View File
@@ -85,15 +85,9 @@ SRCDIRS += arch/i386/interface/pcbios
SRCDIRS += arch/i386/interface/pxe
SRCDIRS += arch/i386/interface/pxeparent
SRCDIRS += arch/i386/interface/syslinux
SRCDIRS += arch/i386/interface/vmware
SRCDIRS += arch/i386/hci/commands
# The various xxx_loader.c files are #included into core/loader.c and
# should not be compiled directly.
#
NON_AUTO_SRCS += arch/i386/core/aout_loader.c
NON_AUTO_SRCS += arch/i386/core/freebsd_loader.c
NON_AUTO_SRCS += arch/i386/core/wince_loader.c
# Include common x86 Makefile
#
MAKEDEPS += arch/x86/Makefile
-144
View File
@@ -1,144 +0,0 @@
/* a.out */
struct exec {
unsigned long a_midmag; /* flags<<26 | mid<<16 | magic */
unsigned long a_text; /* text segment size */
unsigned long a_data; /* initialized data size */
unsigned long a_bss; /* uninitialized data size */
unsigned long a_syms; /* symbol table size */
unsigned long a_entry; /* entry point */
unsigned long a_trsize; /* text relocation size */
unsigned long a_drsize; /* data relocation size */
};
struct aout_state {
struct exec head;
unsigned long curaddr;
int segment; /* current segment number, -1 for none */
unsigned long loc; /* start offset of current block */
unsigned long skip; /* padding to be skipped to current segment */
unsigned long toread; /* remaining data to be read in the segment */
};
static struct aout_state astate;
static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
{
unsigned long start, mid, end, istart, iend;
if (len < sizeof(astate.head)) {
return 0;
}
memcpy(&astate.head, data, sizeof(astate.head));
if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
return 0;
}
printf("(a.out");
aout_freebsd_probe();
printf(")... ");
/* Check the aout image */
start = astate.head.a_entry;
mid = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
end = ((mid + 4095) & ~4095) + astate.head.a_bss;
istart = 4096;
iend = istart + (mid - start);
if (!prep_segment(start, mid, end, istart, iend))
return dead_download;
astate.segment = -1;
astate.loc = 0;
astate.skip = 0;
astate.toread = 0;
return aout_download;
}
static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
{
unsigned int offset; /* working offset in the current data block */
offset = 0;
#ifdef AOUT_LYNX_KDI
astate.segment++;
if (astate.segment == 0) {
astate.curaddr = 0x100000;
astate.head.a_entry = astate.curaddr + 0x20;
}
memcpy(phys_to_virt(astate.curaddr), data, len);
astate.curaddr += len;
return 0;
#endif
do {
if (astate.segment != -1) {
if (astate.skip) {
if (astate.skip >= len - offset) {
astate.skip -= len - offset;
break;
}
offset += astate.skip;
astate.skip = 0;
}
if (astate.toread) {
if (astate.toread >= len - offset) {
memcpy(phys_to_virt(astate.curaddr), data+offset,
len - offset);
astate.curaddr += len - offset;
astate.toread -= len - offset;
break;
}
memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
offset += astate.toread;
astate.toread = 0;
}
}
/* Data left, but current segment finished - look for the next
* segment. This is quite simple for a.out files. */
astate.segment++;
switch (astate.segment) {
case 0:
/* read text */
astate.curaddr = astate.head.a_entry;
astate.skip = 4096;
astate.toread = astate.head.a_text;
break;
case 1:
/* read data */
/* skip and curaddr may be wrong, but I couldn't find
* examples where this failed. There is no reasonable
* documentation for a.out available. */
astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
astate.curaddr = (astate.curaddr + 4095) & ~4095;
astate.toread = astate.head.a_data;
break;
case 2:
/* initialize bss and start kernel */
astate.curaddr = (astate.curaddr + 4095) & ~4095;
astate.skip = 0;
astate.toread = 0;
memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
goto aout_startkernel;
default:
break;
}
} while (offset < len);
astate.loc += len;
if (eof) {
unsigned long entry;
aout_startkernel:
entry = astate.head.a_entry;
done(1);
aout_freebsd_boot();
#ifdef AOUT_LYNX_KDI
xstart32(entry);
#endif
printf("unexpected a.out variant\n");
longjmp(restart_etherboot, -2);
}
return 0;
}
-377
View File
@@ -1,377 +0,0 @@
/* bootinfo */
#define BOOTINFO_VERSION 1
#define NODEV (-1) /* non-existent device */
#define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */
#define PAGE_SIZE (1<<PAGE_SHIFT) /* bytes/page */
#define PAGE_MASK (PAGE_SIZE-1)
#define N_BIOS_GEOM 8
struct bootinfo {
unsigned int bi_version;
const unsigned char *bi_kernelname;
struct nfs_diskless *bi_nfs_diskless;
/* End of fields that are always present. */
#define bi_endcommon bi_n_bios_used
unsigned int bi_n_bios_used;
unsigned long bi_bios_geom[N_BIOS_GEOM];
unsigned int bi_size;
unsigned char bi_memsizes_valid;
unsigned char bi_pad[3];
unsigned long bi_basemem;
unsigned long bi_extmem;
unsigned long bi_symtab;
unsigned long bi_esymtab;
/* Note that these are in the FreeBSD headers but were not here... */
unsigned long bi_kernend; /* end of kernel space */
unsigned long bi_envp; /* environment */
unsigned long bi_modulep; /* preloaded modules */
};
static struct bootinfo bsdinfo;
#ifdef ELF_IMAGE
static Elf32_Shdr *shdr; /* To support the FreeBSD kludge! */
static Address symtab_load;
static Address symstr_load;
static int symtabindex;
static int symstrindex;
#endif
static enum {
Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD,
} image_type = Unknown;
static unsigned int off;
#ifdef ELF_IMAGE
static void elf_freebsd_probe(void)
{
image_type = Elf;
if ( (estate.e.elf32.e_entry & 0xf0000000) &&
(estate.e.elf32.e_type == ET_EXEC))
{
image_type = Elf_FreeBSD;
printf("/FreeBSD");
off = -(estate.e.elf32.e_entry & 0xff000000);
estate.e.elf32.e_entry += off;
}
/* Make sure we have a null to start with... */
shdr = 0;
/* Clear the symbol index values... */
symtabindex = -1;
symstrindex = -1;
/* ...and the load addresses of the symbols */
symtab_load = 0;
symstr_load = 0;
}
static void elf_freebsd_fixup_segment(void)
{
if (image_type == Elf_FreeBSD) {
estate.p.phdr32[estate.segment].p_paddr += off;
}
}
static void elf_freebsd_find_segment_end(void)
{
/* Count the bytes read even for the last block
* as we will need to know where the last block
* ends in order to load the symbols correctly.
* (plus it could be useful elsewhere...)
* Note that we need to count the actual size,
* not just the end of the disk image size.
*/
estate.curaddr +=
(estate.p.phdr32[estate.segment].p_memsz -
estate.p.phdr32[estate.segment].p_filesz);
}
static int elf_freebsd_debug_loader(unsigned int offset)
{
/* No more segments to be loaded - time to start the
* nasty state machine to support the loading of
* FreeBSD debug symbols due to the fact that FreeBSD
* uses/exports the kernel's debug symbols in order
* to make much of the system work! Amazing (arg!)
*
* We depend on the fact that for the FreeBSD kernel,
* there is only one section of debug symbols and that
* the section is after all of the loaded sections in
* the file. This assumes a lot but is somewhat required
* to make this code not be too annoying. (Where do you
* load symbols when the code has not loaded yet?)
* Since this function is actually just a callback from
* the network data transfer code, we need to be able to
* work with the data as it comes in. There is no chance
* for doing a seek other than forwards.
*
* The process we use is to first load the section
* headers. Once they are loaded (shdr != 0) we then
* look for where the symbol table and symbol table
* strings are and setup some state that we found
* them and fall into processing the first one (which
* is the symbol table) and after that has been loaded,
* we try the symbol strings. Note that the order is
* actually required as the memory image depends on
* the symbol strings being loaded starting at the
* end of the symbol table. The kernel assumes this
* layout of the image.
*
* At any point, if we get to the end of the load file
* or the section requested is earlier in the file than
* the current file pointer, we just end up falling
* out of this and booting the kernel without this
* information.
*/
/* Make sure that the next address is long aligned... */
/* Assumes size of long is a power of 2... */
estate.curaddr = (estate.curaddr + sizeof(long) - 1) & ~(sizeof(long) - 1);
/* If we have not yet gotten the shdr loaded, try that */
if (shdr == 0)
{
estate.toread = estate.e.elf32.e_shnum * estate.e.elf32.e_shentsize;
estate.skip = estate.e.elf32.e_shoff - (estate.loc + offset);
if (estate.toread)
{
#if ELF_DEBUG
printf("shdr *, size %lX, curaddr %lX\n",
estate.toread, estate.curaddr);
#endif
/* Start reading at the curaddr and make that the shdr */
shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr);
/* Start to read... */
return 1;
}
}
else
{
/* We have the shdr loaded, check if we have found
* the indexs where the symbols are supposed to be */
if ((symtabindex == -1) && (symstrindex == -1))
{
int i;
/* Make sure that the address is page aligned... */
/* Symbols need to start in their own page(s)... */
estate.curaddr = (estate.curaddr + 4095) & ~4095;
/* Need to make new indexes... */
for (i=0; i < estate.e.elf32.e_shnum; i++)
{
if (shdr[i].sh_type == SHT_SYMTAB)
{
int j;
for (j=0; j < estate.e.elf32.e_phnum; j++)
{
/* Check only for loaded sections */
if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80))
{
/* Only the extra symbols */
if ((shdr[i].sh_offset >= estate.p.phdr32[j].p_offset) &&
((shdr[i].sh_offset + shdr[i].sh_size) <=
(estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz)))
{
shdr[i].sh_offset=0;
shdr[i].sh_size=0;
break;
}
}
}
if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0))
{
symtabindex = i;
symstrindex = shdr[i].sh_link;
}
}
}
}
/* Check if we have a symbol table index and have not loaded it */
if ((symtab_load == 0) && (symtabindex >= 0))
{
/* No symbol table yet? Load it first... */
/* This happens to work out in a strange way.
* If we are past the point in the file already,
* we will skip a *large* number of bytes which
* ends up bringing us to the end of the file and
* an old (default) boot. Less code and lets
* the state machine work in a cleaner way but this
* is a nasty side-effect trick... */
estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset);
/* And we need to read this many bytes... */
estate.toread = shdr[symtabindex].sh_size;
if (estate.toread)
{
#if ELF_DEBUG
printf("db sym, size %lX, curaddr %lX\n",
estate.toread, estate.curaddr);
#endif
/* Save where we are loading this... */
symtab_load = estate.curaddr;
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
estate.curaddr += sizeof(long);
/* Start to read... */
return 1;
}
}
else if ((symstr_load == 0) && (symstrindex >= 0))
{
/* We have already loaded the symbol table, so
* now on to the symbol strings... */
/* Same nasty trick as above... */
estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset);
/* And we need to read this many bytes... */
estate.toread = shdr[symstrindex].sh_size;
if (estate.toread)
{
#if ELF_DEBUG
printf("db str, size %lX, curaddr %lX\n",
estate.toread, estate.curaddr);
#endif
/* Save where we are loading this... */
symstr_load = estate.curaddr;
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
estate.curaddr += sizeof(long);
/* Start to read... */
return 1;
}
}
}
/* all done */
return 0;
}
static void elf_freebsd_boot(unsigned long entry)
{
if (image_type != Elf_FreeBSD)
return;
memset(&bsdinfo, 0, sizeof(bsdinfo));
bsdinfo.bi_basemem = meminfo.basememsize;
bsdinfo.bi_extmem = meminfo.memsize;
bsdinfo.bi_memsizes_valid = 1;
bsdinfo.bi_version = BOOTINFO_VERSION;
bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
bsdinfo.bi_nfs_diskless = NULL;
bsdinfo.bi_size = sizeof(bsdinfo);
#define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */
if(freebsd_kernel_env[0] != '\0'){
freebsd_howto |= RB_BOOTINFO;
bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env;
}
/* Check if we have symbols loaded, and if so,
* made the meta_data needed to pass those to
* the kernel. */
if ((symtab_load !=0) && (symstr_load != 0))
{
unsigned long *t;
bsdinfo.bi_symtab = symtab_load;
/* End of symbols (long aligned...) */
/* Assumes size of long is a power of 2... */
bsdinfo.bi_esymtab = (symstr_load +
sizeof(long) +
*((long *)phys_to_virt(symstr_load)) +
sizeof(long) - 1) & ~(sizeof(long) - 1);
/* Where we will build the meta data... */
t = phys_to_virt(bsdinfo.bi_esymtab);
#if ELF_DEBUG
printf("Metadata at %lX\n",t);
#endif
/* Set up the pointer to the memory... */
bsdinfo.bi_modulep = virt_to_phys(t);
/* The metadata structure is an array of 32-bit
* words where we store some information about the
* system. This is critical, as FreeBSD now looks
* only for the metadata for the extended symbol
* information rather than in the bootinfo.
*/
/* First, do the kernel name and the kernel type */
/* Note that this assumed x86 byte order... */
/* 'kernel\0\0' */
*t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65;
/* 'elf kernel\0\0' */
*t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65;
/* Now the symbol start/end - note that they are
* here in local/physical address - the Kernel
* boot process will relocate the addresses. */
*t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab;
*t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab;
*t++=MODINFO_END; *t++=0; /* end of metadata */
/* Since we have symbols we need to make
* sure that the kernel knows its own end
* of memory... It is not _end but after
* the symbols and the metadata... */
bsdinfo.bi_kernend = virt_to_phys(t);
/* Signal locore.s that we have a valid bootinfo
* structure that was completely filled in. */
freebsd_howto |= 0x80000000;
}
xstart32(entry, freebsd_howto, NODEV, 0, 0, 0,
virt_to_phys(&bsdinfo), 0, 0, 0);
longjmp(restart_etherboot, -2);
}
#endif
#ifdef AOUT_IMAGE
static void aout_freebsd_probe(void)
{
image_type = Aout;
if (((astate.head.a_midmag >> 16) & 0xffff) == 0) {
/* Some other a.out variants have a different
* value, and use other alignments (e.g. 1K),
* not the 4K used by FreeBSD. */
image_type = Aout_FreeBSD;
printf("/FreeBSD");
off = -(astate.head.a_entry & 0xff000000);
astate.head.a_entry += off;
}
}
static void aout_freebsd_boot(void)
{
if (image_type == Aout_FreeBSD) {
memset(&bsdinfo, 0, sizeof(bsdinfo));
bsdinfo.bi_basemem = meminfo.basememsize;
bsdinfo.bi_extmem = meminfo.memsize;
bsdinfo.bi_memsizes_valid = 1;
bsdinfo.bi_version = BOOTINFO_VERSION;
bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
bsdinfo.bi_nfs_diskless = NULL;
bsdinfo.bi_size = sizeof(bsdinfo);
xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0,
virt_to_phys(&bsdinfo), 0, 0, 0);
longjmp(restart_etherboot, -2);
}
}
#endif
+11 -3
View File
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/init.h>
@@ -189,19 +190,25 @@ static int initrd_init ( void ) {
initrd_phys, ( initrd_phys + initrd_len ) );
/* Allocate image */
image = alloc_image();
image = alloc_image ( NULL );
if ( ! image ) {
DBGC ( colour, "RUNTIME could not allocate image for "
"initrd\n" );
rc = -ENOMEM;
goto err_alloc_image;
}
image_set_name ( image, "<INITRD>" );
if ( ( rc = image_set_name ( image, "<INITRD>" ) ) != 0 ) {
DBGC ( colour, "RUNTIME could not set image name: %s\n",
strerror ( rc ) );
goto err_set_name;
}
/* Allocate and copy initrd content */
image->data = umalloc ( initrd_len );
if ( ! image->data ) {
DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
DBGC ( colour, "RUNTIME could not allocate %d bytes for "
"initrd\n", initrd_len );
rc = -ENOMEM;
goto err_umalloc;
}
image->len = initrd_len;
@@ -225,6 +232,7 @@ static int initrd_init ( void ) {
err_register_image:
err_umalloc:
err_set_name:
image_put ( image );
err_alloc_image:
return rc;
+9
View File
@@ -11,6 +11,14 @@
#include <ipxe/console.h>
#include <ipxe/init.h>
#include "vga.h"
#include <config/console.h>
/* Set default console usage if applicable */
#if ! ( defined ( CONSOLE_DIRECT_VGA ) && \
CONSOLE_EXPLICIT ( CONSOLE_DIRECT_VGA ) )
#undef CONSOLE_DIRECT_VGA
#define CONSOLE_DIRECT_VGA ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
#endif
struct console_driver vga_console __console_driver;
@@ -97,6 +105,7 @@ static void vga_putc(int byte)
struct console_driver vga_console __console_driver = {
.putchar = vga_putc,
.disabled = 1,
.usage = CONSOLE_DIRECT_VGA,
};
struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = {
-273
View File
@@ -1,273 +0,0 @@
#define LOAD_DEBUG 0
static int get_x_header(unsigned char *data, unsigned long now);
static void jump_2ep();
static unsigned char ce_signature[] = {'B', '0', '0', '0', 'F', 'F', '\n',};
static char ** ep;
#define BOOT_ARG_PTR_LOCATION 0x001FFFFC
typedef struct _BOOT_ARGS{
unsigned char ucVideoMode;
unsigned char ucComPort;
unsigned char ucBaudDivisor;
unsigned char ucPCIConfigType;
unsigned long dwSig;
#define BOOTARG_SIG 0x544F4F42
unsigned long dwLen;
unsigned char ucLoaderFlags;
unsigned char ucEshellFlags;
unsigned char ucEdbgAdapterType;
unsigned char ucEdbgIRQ;
unsigned long dwEdbgBaseAddr;
unsigned long dwEdbgDebugZone;
unsigned long dwDHCPLeaseTime;
unsigned long dwEdbgFlags;
unsigned long dwEBootFlag;
unsigned long dwEBootAddr;
unsigned long dwLaunchAddr;
unsigned long pvFlatFrameBuffer;
unsigned short vesaMode;
unsigned short cxDisplayScreen;
unsigned short cyDisplayScreen;
unsigned short cxPhysicalScreen;
unsigned short cyPhysicalScreen;
unsigned short cbScanLineLength;
unsigned short bppScreen;
unsigned char RedMaskSize;
unsigned char REdMaskPosition;
unsigned char GreenMaskSize;
unsigned char GreenMaskPosition;
unsigned char BlueMaskSize;
unsigned char BlueMaskPosition;
} BOOT_ARGS;
BOOT_ARGS BootArgs;
static struct segment_info{
unsigned long addr; // Section Address
unsigned long size; // Section Size
unsigned long checksum; // Section CheckSum
} X;
#define PSIZE (1500) //Max Packet Size
#define DSIZE (PSIZE+12)
static unsigned long dbuffer_available =0;
static unsigned long not_loadin =0;
static unsigned long d_now =0;
unsigned long entry;
static unsigned long ce_curaddr;
static sector_t ce_loader(unsigned char *data, unsigned int len, int eof);
static os_download_t wince_probe(unsigned char *data, unsigned int len)
{
if (strncmp(ce_signature, data, sizeof(ce_signature)) != 0) {
return 0;
}
printf("(WINCE)");
return ce_loader;
}
static sector_t ce_loader(unsigned char *data, unsigned int len, int eof)
{
static unsigned char dbuffer[DSIZE];
int this_write = 0;
static int firsttime = 1;
/*
* new packet in, we have to
* [1] copy data to dbuffer,
*
* update...
* [2] dbuffer_available
*/
memcpy( (dbuffer+dbuffer_available), data, len); //[1]
dbuffer_available += len; // [2]
len = 0;
d_now = 0;
#if 0
printf("dbuffer_available =%ld \n", dbuffer_available);
#endif
if (firsttime)
{
d_now = sizeof(ce_signature);
printf("String Physical Address = %lx \n",
*(unsigned long *)(dbuffer+d_now));
d_now += sizeof(unsigned long);
printf("Image Size = %ld [%lx]\n",
*(unsigned long *)(dbuffer+d_now),
*(unsigned long *)(dbuffer+d_now));
d_now += sizeof(unsigned long);
dbuffer_available -= d_now;
d_now = (unsigned long)get_x_header(dbuffer, d_now);
firsttime = 0;
}
if (not_loadin == 0)
{
d_now = get_x_header(dbuffer, d_now);
}
while ( not_loadin > 0 )
{
/* dbuffer do not have enough data to loading, copy all */
#if LOAD_DEBUG
printf("[0] not_loadin = [%ld], dbuffer_available = [%ld] \n",
not_loadin, dbuffer_available);
printf("[0] d_now = [%ld] \n", d_now);
#endif
if( dbuffer_available <= not_loadin)
{
this_write = dbuffer_available ;
memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write );
ce_curaddr += this_write;
not_loadin -= this_write;
/* reset index and available in the dbuffer */
dbuffer_available = 0;
d_now = 0;
#if LOAD_DEBUG
printf("[1] not_loadin = [%ld], dbuffer_available = [%ld] \n",
not_loadin, dbuffer_available);
printf("[1] d_now = [%ld], this_write = [%d] \n",
d_now, this_write);
#endif
// get the next packet...
return (0);
}
/* dbuffer have more data then loading ... , copy partital.... */
else
{
this_write = not_loadin;
memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write);
ce_curaddr += this_write;
not_loadin = 0;
/* reset index and available in the dbuffer */
dbuffer_available -= this_write;
d_now += this_write;
#if LOAD_DEBUG
printf("[2] not_loadin = [%ld], dbuffer_available = [%ld] \n",
not_loadin, dbuffer_available);
printf("[2] d_now = [%ld], this_write = [%d] \n\n",
d_now, this_write);
#endif
/* dbuffer not empty, proceed processing... */
// don't have enough data to get_x_header..
if ( dbuffer_available < (sizeof(unsigned long) * 3) )
{
// printf("we don't have enough data remaining to call get_x. \n");
memcpy( (dbuffer+0), (dbuffer+d_now), dbuffer_available);
return (0);
}
else
{
#if LOAD_DEBUG
printf("with remaining data to call get_x \n");
printf("dbuffer available = %ld , d_now = %ld\n",
dbuffer_available, d_now);
#endif
d_now = get_x_header(dbuffer, d_now);
}
}
}
return (0);
}
static int get_x_header(unsigned char *dbuffer, unsigned long now)
{
X.addr = *(unsigned long *)(dbuffer + now);
X.size = *(unsigned long *)(dbuffer + now + sizeof(unsigned long));
X.checksum = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)*2);
if (X.addr == 0)
{
entry = X.size;
done(1);
printf("Entry Point Address = [%lx] \n", entry);
jump_2ep();
}
if (!prep_segment(X.addr, X.addr + X.size, X.addr + X.size, 0, 0)) {
longjmp(restart_etherboot, -2);
}
ce_curaddr = X.addr;
now += sizeof(unsigned long)*3;
/* re-calculate dbuffer available... */
dbuffer_available -= sizeof(unsigned long)*3;
/* reset index of this section */
not_loadin = X.size;
#if 1
printf("\n");
printf("\t Section Address = [%lx] \n", X.addr);
printf("\t Size = %d [%lx]\n", X.size, X.size);
printf("\t Checksum = %ld [%lx]\n", X.checksum, X.checksum);
#endif
#if LOAD_DEBUG
printf("____________________________________________\n");
printf("\t dbuffer_now = %ld \n", now);
printf("\t dbuffer available = %ld \n", dbuffer_available);
printf("\t not_loadin = %ld \n", not_loadin);
#endif
return now;
}
static void jump_2ep()
{
BootArgs.ucVideoMode = 1;
BootArgs.ucComPort = 1;
BootArgs.ucBaudDivisor = 1;
BootArgs.ucPCIConfigType = 1; // do not fill with 0
BootArgs.dwSig = BOOTARG_SIG;
BootArgs.dwLen = sizeof(BootArgs);
if(BootArgs.ucVideoMode == 0)
{
BootArgs.cxDisplayScreen = 640;
BootArgs.cyDisplayScreen = 480;
BootArgs.cxPhysicalScreen = 640;
BootArgs.cyPhysicalScreen = 480;
BootArgs.bppScreen = 16;
BootArgs.cbScanLineLength = 1024;
BootArgs.pvFlatFrameBuffer = 0x800a0000; // ollie say 0x98000000
}
else if(BootArgs.ucVideoMode != 0xFF)
{
BootArgs.cxDisplayScreen = 0;
BootArgs.cyDisplayScreen = 0;
BootArgs.cxPhysicalScreen = 0;
BootArgs.cyPhysicalScreen = 0;
BootArgs.bppScreen = 0;
BootArgs.cbScanLineLength = 0;
BootArgs.pvFlatFrameBuffer = 0;
}
ep = phys_to_virt(BOOT_ARG_PTR_LOCATION);
*ep= virt_to_phys(&BootArgs);
xstart32(entry);
}
+47 -2
View File
@@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
#include <unistd.h>
#include <byteswap.h>
#include <pxe.h>
#include <realmode.h>
#include <pic8259.h>
@@ -166,6 +167,10 @@ static int undinet_isr_triggered ( void ) {
static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
#define undinet_tbd __use_data16 ( undinet_tbd )
/** UNDI transmit destination address */
static uint8_t __data16_array ( undinet_destaddr, [ETH_ALEN] );
#define undinet_destaddr __use_data16 ( undinet_destaddr )
/**
* Transmit packet
*
@@ -175,8 +180,14 @@ static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
*/
static int undinet_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
struct undi_nic *undinic = netdev->priv;
struct s_PXENV_UNDI_TRANSMIT undi_transmit;
size_t len = iob_len ( iobuf );
const void *ll_dest;
const void *ll_source;
uint16_t net_proto;
unsigned int flags;
uint8_t protocol;
size_t len;
int rc;
/* Technically, we ought to make sure that the previous
@@ -189,15 +200,49 @@ static int undinet_transmit ( struct net_device *netdev,
* transmit the next packet.
*/
/* Some PXE stacks are unable to cope with P_UNKNOWN, and will
* always try to prepend a link-layer header. Work around
* these stacks by stripping the existing link-layer header
* and allowing the PXE stack to (re)construct the link-layer
* header itself.
*/
if ( ( rc = eth_pull ( netdev, iobuf, &ll_dest, &ll_source,
&net_proto, &flags ) ) != 0 ) {
DBGC ( undinic, "UNDINIC %p could not strip Ethernet header: "
"%s\n", undinic, strerror ( rc ) );
return rc;
}
memcpy ( undinet_destaddr, ll_dest, sizeof ( undinet_destaddr ) );
switch ( net_proto ) {
case htons ( ETH_P_IP ) :
protocol = P_IP;
break;
case htons ( ETH_P_ARP ) :
protocol = P_ARP;
break;
case htons ( ETH_P_RARP ) :
protocol = P_RARP;
break;
default:
/* Unknown protocol; restore the original link-layer header */
iob_push ( iobuf, sizeof ( struct ethhdr ) );
protocol = P_UNKNOWN;
break;
}
/* Copy packet to UNDI I/O buffer */
len = iob_len ( iobuf );
if ( len > sizeof ( basemem_packet ) )
len = sizeof ( basemem_packet );
memcpy ( &basemem_packet, iobuf->data, len );
/* Create PXENV_UNDI_TRANSMIT data structure */
memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
undi_transmit.Protocol = protocol;
undi_transmit.XmitFlag = ( ( flags & LL_BROADCAST ) ?
XMT_BROADCAST : XMT_DESTADDR );
undi_transmit.DestAddr.segment = rm_ds;
undi_transmit.DestAddr.offset = __from_data16 ( &undinet_tbd );
undi_transmit.DestAddr.offset = __from_data16 ( &undinet_destaddr );
undi_transmit.TBD.segment = rm_ds;
undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
@@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/console.h>
#include <ipxe/ansiesc.h>
#include <ipxe/keymap.h>
#include <config/console.h>
#define ATTR_BOLD 0x08
@@ -48,6 +49,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ATTR_DEFAULT ATTR_FCOL_WHITE
/* Set default console usage if applicable */
#if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) )
#undef CONSOLE_PCBIOS
#define CONSOLE_PCBIOS ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
#endif
/** Current character attribute */
static unsigned int bios_attr = ATTR_DEFAULT;
@@ -163,6 +170,14 @@ static void bios_putchar ( int character ) {
/* Skip non-printable characters */
"cmpb $0x20, %%al\n\t"
"jb 1f\n\t"
/* Read attribute */
"movb %%al, %%cl\n\t"
"movb $0x08, %%ah\n\t"
"int $0x10\n\t"
"xchgb %%al, %%cl\n\t"
/* Skip if attribute matches */
"cmpb %%ah, %%bl\n\t"
"je 1f\n\t"
/* Set attribute */
"movw $0x0001, %%cx\n\t"
"movb $0x09, %%ah\n\t"
@@ -201,6 +216,8 @@ static const char ansi_sequences[] = {
BIOS_KEY ( "\x4d", "[C" ) /* Right arrow */
BIOS_KEY ( "\x47", "[H" ) /* Home */
BIOS_KEY ( "\x4f", "[F" ) /* End */
BIOS_KEY ( "\x49", "[5~" ) /* Page up */
BIOS_KEY ( "\x51", "[6~" ) /* Page down */
BIOS_KEY ( "\x3f", "[15~" ) /* F5 */
BIOS_KEY ( "\x40", "[17~" ) /* F6 */
BIOS_KEY ( "\x41", "[18~" ) /* F7 */
@@ -311,4 +328,5 @@ struct console_driver bios_console __console_driver = {
.putchar = bios_putchar,
.getchar = bios_getchar,
.iskey = bios_iskey,
.usage = CONSOLE_PCBIOS,
};
+2 -1
View File
@@ -42,10 +42,11 @@ FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
*/
static int elfboot_exec ( struct image *image ) {
physaddr_t entry;
physaddr_t max;
int rc;
/* Load the image using core ELF support */
if ( ( rc = elf_load ( image, &entry ) ) != 0 ) {
if ( ( rc = elf_load ( image, &entry, &max ) ) != 0 ) {
DBGC ( image, "ELF %p could not load: %s\n",
image, strerror ( rc ) );
return rc;
+78 -65
View File
@@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/elf.h>
#include <ipxe/init.h>
#include <ipxe/features.h>
#include <ipxe/uri.h>
FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 );
@@ -139,53 +140,60 @@ static void multiboot_build_memmap ( struct image *image,
/**
* Add command line in base memory
*
* @v imgname Image name
* @v cmdline Command line
* @v image Image
* @ret physaddr Physical address of command line
*/
physaddr_t multiboot_add_cmdline ( const char *imgname, const char *cmdline ) {
char *mb_cmdline;
static physaddr_t multiboot_add_cmdline ( struct image *image ) {
char *mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
size_t remaining = ( sizeof ( mb_cmdlines ) - mb_cmdline_offset );
char *buf = mb_cmdline;
size_t len;
if ( ! cmdline )
cmdline = "";
/* Copy image URI to base memory buffer as start of command line */
len = ( unparse_uri ( buf, remaining, image->uri,
URI_ALL ) + 1 /* NUL */ );
if ( len > remaining )
len = remaining;
mb_cmdline_offset += len;
buf += len;
remaining -= len;
/* Copy command line to base memory buffer */
mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
mb_cmdline_offset +=
( snprintf ( mb_cmdline,
( sizeof ( mb_cmdlines ) - mb_cmdline_offset ),
"%s %s", imgname, cmdline ) + 1 );
/* Truncate to terminating NUL in buffer if necessary */
if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) )
mb_cmdline_offset = ( sizeof ( mb_cmdlines ) - 1 );
/* Copy command line to base memory buffer, if present */
if ( image->cmdline ) {
mb_cmdline_offset--; /* Strip NUL */
buf--;
remaining++;
len = ( snprintf ( buf, remaining, " %s",
image->cmdline ) + 1 /* NUL */ );
if ( len > remaining )
len = remaining;
mb_cmdline_offset += len;
}
return virt_to_phys ( mb_cmdline );
}
/**
* Build multiboot module list
* Add multiboot modules
*
* @v image Multiboot image
* @v modules Module list to fill, or NULL
* @ret count Number of modules
* @v start Start address for modules
* @v mbinfo Multiboot information structure
* @v modules Multiboot module list
* @ret rc Return status code
*/
static unsigned int
multiboot_build_module_list ( struct image *image,
struct multiboot_module *modules,
unsigned int limit ) {
static int multiboot_add_modules ( struct image *image, physaddr_t start,
struct multiboot_info *mbinfo,
struct multiboot_module *modules,
unsigned int limit ) {
struct image *module_image;
struct multiboot_module *module;
unsigned int count = 0;
unsigned int insert;
physaddr_t start;
physaddr_t end;
unsigned int i;
int rc;
/* Add each image as a multiboot module */
for_each_image ( module_image ) {
if ( count >= limit ) {
if ( mbinfo->mods_count >= limit ) {
DBGC ( image, "MULTIBOOT %p limit of %d modules "
"reached\n", image, limit );
break;
@@ -195,38 +203,36 @@ multiboot_build_module_list ( struct image *image,
if ( module_image == image )
continue;
/* At least some OSes expect the multiboot modules to
* be in ascending order, so we have to support it.
*/
start = user_to_phys ( module_image->data, 0 );
end = user_to_phys ( module_image->data, module_image->len );
for ( insert = 0 ; insert < count ; insert++ ) {
if ( start < modules[insert].mod_start )
break;
/* Page-align the module */
start = ( ( start + 0xfff ) & ~0xfff );
/* Prepare segment */
if ( ( rc = prep_segment ( phys_to_user ( start ),
module_image->len,
module_image->len ) ) != 0 ) {
DBGC ( image, "MULTIBOOT %p could not prepare module "
"%s: %s\n", image, module_image->name,
strerror ( rc ) );
return rc;
}
module = &modules[insert];
memmove ( ( module + 1 ), module,
( ( count - insert ) * sizeof ( *module ) ) );
/* Copy module */
memcpy_user ( phys_to_user ( start ), 0,
module_image->data, 0, module_image->len );
/* Add module to list */
module = &modules[mbinfo->mods_count++];
module->mod_start = start;
module->mod_end = end;
module->string = multiboot_add_cmdline ( module_image->name,
module_image->cmdline );
module->mod_end = ( start + module_image->len );
module->string = multiboot_add_cmdline ( module_image );
module->reserved = 0;
/* We promise to page-align modules */
assert ( ( module->mod_start & 0xfff ) == 0 );
count++;
DBGC ( image, "MULTIBOOT %p module %s is [%x,%x)\n",
image, module_image->name, module->mod_start,
module->mod_end );
start += module_image->len;
}
/* Dump module configuration */
for ( i = 0 ; i < count ; i++ ) {
DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n",
image, i, modules[i].mod_start,
modules[i].mod_end );
}
return count;
return 0;
}
/**
@@ -305,11 +311,12 @@ static int multiboot_find_header ( struct image *image,
* @v image Multiboot file
* @v hdr Multiboot header descriptor
* @ret entry Entry point
* @ret max Maximum used address
* @ret rc Return status code
*/
static int multiboot_load_raw ( struct image *image,
struct multiboot_header_info *hdr,
physaddr_t *entry ) {
physaddr_t *entry, physaddr_t *max ) {
size_t offset;
size_t filesz;
size_t memsz;
@@ -340,8 +347,9 @@ static int multiboot_load_raw ( struct image *image,
/* Copy image to segment */
memcpy_user ( buffer, 0, image->data, offset, filesz );
/* Record execution entry point */
/* Record execution entry point and maximum used address */
*entry = hdr->mb.entry_addr;
*max = ( hdr->mb.load_addr + memsz );
return 0;
}
@@ -351,13 +359,15 @@ static int multiboot_load_raw ( struct image *image,
*
* @v image Multiboot file
* @ret entry Entry point
* @ret max Maximum used address
* @ret rc Return status code
*/
static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
static int multiboot_load_elf ( struct image *image, physaddr_t *entry,
physaddr_t *max ) {
int rc;
/* Load ELF image*/
if ( ( rc = elf_load ( image, entry ) ) != 0 ) {
if ( ( rc = elf_load ( image, entry, max ) ) != 0 ) {
DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
image, strerror ( rc ) );
return rc;
@@ -375,6 +385,7 @@ static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
static int multiboot_exec ( struct image *image ) {
struct multiboot_header_info hdr;
physaddr_t entry;
physaddr_t max;
int rc;
/* Locate multiboot header, if present */
@@ -396,8 +407,8 @@ static int multiboot_exec ( struct image *image ) {
* the ELF header if present, and Solaris relies on this
* behaviour.
*/
if ( ( ( rc = multiboot_load_elf ( image, &entry ) ) != 0 ) &&
( ( rc = multiboot_load_raw ( image, &hdr, &entry ) ) != 0 ) )
if ( ( ( rc = multiboot_load_elf ( image, &entry, &max ) ) != 0 ) &&
( ( rc = multiboot_load_raw ( image, &hdr, &entry, &max ) ) != 0 ))
return rc;
/* Populate multiboot information structure */
@@ -405,12 +416,14 @@ static int multiboot_exec ( struct image *image ) {
mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
mb_cmdline_offset = 0;
mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
mbinfo.cmdline = multiboot_add_cmdline ( image );
mbinfo.mods_addr = virt_to_phys ( mbmodules );
mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
if ( ( rc = multiboot_add_modules ( image, max, &mbinfo, mbmodules,
( sizeof ( mbmodules ) /
sizeof ( mbmodules[0] ) ) ) ) !=0)
return rc;
/* Multiboot images may not return and have no callback
* interface, so shut everything down prior to booting the OS.
+1
View File
@@ -4,6 +4,7 @@
FILE_LICENCE ( GPL2_OR_LATER );
#define BDA_SEG 0x0040
#define BDA_EQUIPMENT_WORD 0x0010
#define BDA_FBMS 0x0013
#define BDA_NUM_DRIVES 0x0075
+59 -32
View File
@@ -1,43 +1,70 @@
#ifndef ETHERBOOT_BITS_BYTESWAP_H
#define ETHERBOOT_BITS_BYTESWAP_H
#ifndef _BITS_BYTESWAP_H
#define _BITS_BYTESWAP_H
/** @file
*
* Byte-order swapping functions
*
*/
#include <stdint.h>
FILE_LICENCE ( GPL2_OR_LATER );
static inline __attribute__ ((always_inline, const)) uint16_t
__bswap_variable_16(uint16_t x)
{
__asm__("xchgb %b0,%h0\n\t"
: "=q" (x)
: "0" (x));
static inline __attribute__ (( always_inline, const )) uint16_t
__bswap_variable_16 ( uint16_t x ) {
__asm__ ( "xchgb %b0,%h0" : "=q" ( x ) : "0" ( x ) );
return x;
}
static inline __attribute__ ((always_inline, const)) uint32_t
__bswap_variable_32(uint32_t x)
{
__asm__("xchgb %b0,%h0\n\t"
"rorl $16,%0\n\t"
"xchgb %b0,%h0"
: "=q" (x)
: "0" (x));
static inline __attribute__ (( always_inline )) void
__bswap_16s ( uint16_t *x ) {
__asm__ ( "rorw $8, %0" : "+m" ( *x ) );
}
static inline __attribute__ (( always_inline, const )) uint32_t
__bswap_variable_32 ( uint32_t x ) {
__asm__ ( "bswapl %0" : "=r" ( x ) : "0" ( x ) );
return x;
}
static inline __attribute__ ((always_inline, const)) uint64_t
__bswap_variable_64(uint64_t x)
{
union {
uint64_t qword;
uint32_t dword[2];
} u;
u.qword = x;
u.dword[0] = __bswap_variable_32(u.dword[0]);
u.dword[1] = __bswap_variable_32(u.dword[1]);
__asm__("xchgl %0,%1"
: "=r" ( u.dword[0] ), "=r" ( u.dword[1] )
: "0" ( u.dword[0] ), "1" ( u.dword[1] ) );
return u.qword;
static inline __attribute__ (( always_inline )) void
__bswap_32s ( uint32_t *x ) {
__asm__ ( "bswapl %0" : "=r" ( *x ) : "0" ( *x ) );
}
#endif /* ETHERBOOT_BITS_BYTESWAP_H */
static inline __attribute__ (( always_inline, const )) uint64_t
__bswap_variable_64 ( uint64_t x ) {
uint32_t in_high = ( x >> 32 );
uint32_t in_low = ( x & 0xffffffffUL );
uint32_t out_high;
uint32_t out_low;
__asm__ ( "bswapl %0\n\t"
"bswapl %1\n\t"
"xchgl %0,%1\n\t"
: "=r" ( out_high ), "=r" ( out_low )
: "0" ( in_high ), "1" ( in_low ) );
return ( ( ( ( uint64_t ) out_high ) << 32 ) |
( ( uint64_t ) out_low ) );
}
static inline __attribute__ (( always_inline )) void
__bswap_64s ( uint64_t *x ) {
struct {
uint32_t low;
uint32_t high;
} __attribute__ (( may_alias )) *dwords = ( ( void * ) x );
uint32_t discard;
__asm__ ( "movl %0,%2\n\t"
"bswapl %2\n\t"
"xchgl %2,%1\n\t"
"bswapl %2\n\t"
"movl %2,%0\n\t"
: "+m" ( dwords->low ), "+m" ( dwords->high ),
"=r" ( discard ) );
}
#endif /* _BITS_BYTESWAP_H */
+14
View File
@@ -0,0 +1,14 @@
#ifndef _BITS_ENTROPY_H
#define _BITS_ENTROPY_H
/** @file
*
* i386-specific entropy API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/rtc_entropy.h>
#endif /* _BITS_ENTROPY_H */
+3
View File
@@ -16,6 +16,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 )
#define ERRFILE_pxeparent ( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 )
#define ERRFILE_runtime ( ERRFILE_ARCH | ERRFILE_CORE | 0x00070000 )
#define ERRFILE_vmware ( ERRFILE_ARCH | ERRFILE_CORE | 0x00080000 )
#define ERRFILE_guestrpc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00090000 )
#define ERRFILE_guestinfo ( ERRFILE_ARCH | ERRFILE_CORE | 0x000a0000 )
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
+14
View File
@@ -0,0 +1,14 @@
#ifndef _BITS_TIME_H
#define _BITS_TIME_H
/** @file
*
* i386-specific time API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/rtc_time.h>
#endif /* _BITS_TIME_H */
+52
View File
@@ -71,6 +71,19 @@ FILE_LICENCE ( GPL2_OR_LATER );
/** Block size for non-extended INT 13 calls */
#define INT13_BLKSIZE 512
/** @defgroup int13fddtype INT 13 floppy disk drive types
* @{
*/
/** 360K */
#define INT13_FDD_TYPE_360K 0x01
/** 1.2M */
#define INT13_FDD_TYPE_1M2 0x02
/** 720K */
#define INT13_FDD_TYPE_720K 0x03
/** 1.44M */
#define INT13_FDD_TYPE_1M44 0x04
/** An INT 13 disk address packet */
struct int13_disk_address {
/** Size of the packet, in bytes */
@@ -394,4 +407,43 @@ enum eltorito_media_type {
ELTORITO_NO_EMULATION = 0,
};
/** A floppy disk geometry */
struct int13_fdd_geometry {
/** Number of tracks */
uint8_t tracks;
/** Number of heads and sectors per track */
uint8_t heads_spt;
};
/** Define a floppy disk geometry */
#define INT13_FDD_GEOMETRY( cylinders, heads, sectors ) \
{ \
.tracks = (cylinders), \
.heads_spt = ( ( (heads) << 6 ) | (sectors) ), \
}
/** Get floppy disk number of cylinders */
#define INT13_FDD_CYLINDERS( geometry ) ( (geometry)->tracks )
/** Get floppy disk number of heads */
#define INT13_FDD_HEADS( geometry ) ( (geometry)->heads_spt >> 6 )
/** Get floppy disk number of sectors per track */
#define INT13_FDD_SECTORS( geometry ) ( (geometry)->heads_spt & 0x3f )
/** A floppy drive parameter table */
struct int13_fdd_parameters {
uint8_t step_rate__head_unload;
uint8_t head_load__ndma;
uint8_t motor_off_delay;
uint8_t bytes_per_sector;
uint8_t sectors_per_track;
uint8_t gap_length;
uint8_t data_length;
uint8_t format_gap_length;
uint8_t format_filler;
uint8_t head_settle_time;
uint8_t motor_start_time;
} __attribute__ (( packed ));
#endif /* INT13_H */
+68
View File
@@ -0,0 +1,68 @@
#ifndef _IPXE_GUESTRPC_H
#define _IPXE_GUESTRPC_H
/** @file
*
* VMware GuestRPC mechanism
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <ipxe/vmware.h>
/** GuestRPC magic number */
#define GUESTRPC_MAGIC 0x49435052 /* "RPCI" */
/** Open RPC channel */
#define GUESTRPC_OPEN 0x00
/** Open RPC channel success status */
#define GUESTRPC_OPEN_SUCCESS 0x00010000
/** Send RPC command length */
#define GUESTRPC_COMMAND_LEN 0x01
/** Send RPC command length success status */
#define GUESTRPC_COMMAND_LEN_SUCCESS 0x00810000
/** Send RPC command data */
#define GUESTRPC_COMMAND_DATA 0x02
/** Send RPC command data success status */
#define GUESTRPC_COMMAND_DATA_SUCCESS 0x00010000
/** Receive RPC reply length */
#define GUESTRPC_REPLY_LEN 0x03
/** Receive RPC reply length success status */
#define GUESTRPC_REPLY_LEN_SUCCESS 0x00830000
/** Receive RPC reply data */
#define GUESTRPC_REPLY_DATA 0x04
/** Receive RPC reply data success status */
#define GUESTRPC_REPLY_DATA_SUCCESS 0x00010000
/** Finish receiving RPC reply */
#define GUESTRPC_REPLY_FINISH 0x05
/** Finish receiving RPC reply success status */
#define GUESTRPC_REPLY_FINISH_SUCCESS 0x00010000
/** Close RPC channel */
#define GUESTRPC_CLOSE 0x06
/** Close RPC channel success status */
#define GUESTRPC_CLOSE_SUCCESS 0x00010000
/** RPC command success status */
#define GUESTRPC_SUCCESS 0x2031 /* "1 " */
extern int guestrpc_open ( void );
extern void guestrpc_close ( int channel );
extern int guestrpc_command ( int channel, const char *command, char *reply,
size_t reply_len );
#endif /* _IPXE_GUESTRPC_H */
+62
View File
@@ -0,0 +1,62 @@
#ifndef _IPXE_RTC_ENTROPY_H
#define _IPXE_RTC_ENTROPY_H
/** @file
*
* RTC-based entropy source
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#ifdef ENTROPY_RTC
#define ENTROPY_PREFIX_rtc
#else
#define ENTROPY_PREFIX_rtc __rtc_
#endif
/**
* min-entropy per sample
*
* @ret min_entropy min-entropy of each sample
*/
static inline __always_inline double
ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
/* The min-entropy has been measured on several platforms
* using the entropy_sample test code. Modelling the samples
* as independent, and using a confidence level of 99.99%, the
* measurements were as follows:
*
* qemu-kvm : 7.38 bits
* VMware : 7.46 bits
* Physical hardware : 2.67 bits
*
* We choose the lowest of these (2.67 bits) and apply a 50%
* safety margin to allow for some potential non-independence
* of samples.
*/
return 1.3;
}
extern uint8_t rtc_sample ( void );
/**
* Get noise sample
*
* @ret noise Noise sample
* @ret rc Return status code
*/
static inline __always_inline int
ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) {
/* Get sample */
*noise = rtc_sample();
/* Always successful */
return 0;
}
#endif /* _IPXE_RTC_ENTROPY_H */
+18
View File
@@ -0,0 +1,18 @@
#ifndef _IPXE_RTC_TIME_H
#define _IPXE_RTC_TIME_H
/** @file
*
* RTC-based time source
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#ifdef TIME_RTC
#define TIME_PREFIX_rtc
#else
#define TIME_PREFIX_rtc __rtc_
#endif
#endif /* _IPXE_RTC_TIME_H */
+81
View File
@@ -0,0 +1,81 @@
#ifndef _IPXE_VMWARE_H
#define _IPXE_VMWARE_H
/** @file
*
* VMware backdoor mechanism
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
/** VMware backdoor I/O port */
#define VMW_PORT 0x5658
/** VMware backdoor magic value */
#define VMW_MAGIC 0x564d5868 /* "VMXh" */
/** VMware backdoor magic instruction */
#define VMW_BACKDOOR "inl %%dx, %%eax"
/** Get VMware version */
#define VMW_CMD_GET_VERSION 0x0a
/** Issue GuestRPC command */
#define VMW_CMD_GUESTRPC 0x1e
/**
* Get VMware version
*
* @ret version VMware version(?)
* @ret magic VMware magic number, if present
* @ret product_type VMware product type
*/
static inline __attribute__ (( always_inline )) void
vmware_cmd_get_version ( uint32_t *version, uint32_t *magic,
uint32_t *product_type ) {
uint32_t discard_d;
/* Perform backdoor call */
__asm__ __volatile__ ( VMW_BACKDOOR
: "=a" ( *version ), "=b" ( *magic ),
"=c" ( *product_type ), "=d" ( discard_d )
: "0" ( VMW_MAGIC ), "1" ( 0 ),
"2" ( VMW_CMD_GET_VERSION ),
"3" ( VMW_PORT ) );
}
/**
* Issue GuestRPC command
*
* @v channel Channel number
* @v subcommand GuestRPC subcommand
* @v parameter Subcommand-specific parameter
* @ret edxhi Subcommand-specific result
* @ret ebx Subcommand-specific result
* @ret status Command status
*/
static inline __attribute__ (( always_inline )) uint32_t
vmware_cmd_guestrpc ( int channel, uint16_t subcommand, uint32_t parameter,
uint16_t *edxhi, uint32_t *ebx ) {
uint32_t discard_a;
uint32_t status;
uint32_t edx;
/* Perform backdoor call */
__asm__ __volatile__ ( VMW_BACKDOOR
: "=a" ( discard_a ), "=b" ( *ebx ),
"=c" ( status ), "=d" ( edx )
: "0" ( VMW_MAGIC ), "1" ( parameter ),
"2" ( VMW_CMD_GUESTRPC | ( subcommand << 16 )),
"3" ( VMW_PORT | ( channel << 16 ) ) );
*edxhi = ( edx >> 16 );
return status;
}
extern int vmware_present ( void );
#endif /* _IPXE_VMWARE_H */
+2
View File
@@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#ifndef PIC8259_H
#define PIC8259_H
#include <ipxe/io.h>
/* For segoff_t */
#include "realmode.h"
+83
View File
@@ -0,0 +1,83 @@
#ifndef _RTC_H
#define _RTC_H
/** @file
*
* CMOS Real-Time Clock (RTC)
*
* The CMOS/RTC registers are documented (with varying degrees of
* accuracy and consistency) at
*
* http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt
* http://wiki.osdev.org/RTC
* http://wiki.osdev.org/CMOS
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <pic8259.h>
/** RTC IRQ */
#define RTC_IRQ 8
/** RTC interrupt vector */
#define RTC_INT IRQ_INT ( RTC_IRQ )
/** CMOS/RTC address (and NMI) register */
#define CMOS_ADDRESS 0x70
/** NMI disable bit */
#define CMOS_DISABLE_NMI 0x80
/** CMOS/RTC data register */
#define CMOS_DATA 0x71
/** RTC seconds */
#define RTC_SEC 0x00
/** RTC minutes */
#define RTC_MIN 0x02
/** RTC hours */
#define RTC_HOUR 0x04
/** RTC weekday */
#define RTC_WDAY 0x06
/** RTC day of month */
#define RTC_MDAY 0x07
/** RTC month */
#define RTC_MON 0x08
/** RTC year */
#define RTC_YEAR 0x09
/** RTC status register A */
#define RTC_STATUS_A 0x0a
/** RTC update in progress bit */
#define RTC_STATUS_A_UPDATE_IN_PROGRESS 0x80
/** RTC status register B */
#define RTC_STATUS_B 0x0b
/** RTC 24 hour format bit */
#define RTC_STATUS_B_24_HOUR 0x02
/** RTC binary mode bit */
#define RTC_STATUS_B_BINARY 0x04
/** RTC Periodic Interrupt Enabled bit */
#define RTC_STATUS_B_PIE 0x40
/** RTC status register C */
#define RTC_STATUS_C 0x0c
/** RTC status register D */
#define RTC_STATUS_D 0x0d
/** CMOS default address */
#define CMOS_DEFAULT_ADDRESS RTC_STATUS_D
#endif /* _RTC_H */
+244 -57
View File
@@ -75,9 +75,9 @@ struct int13_drive {
/** Underlying block device interface */
struct interface block;
/** BIOS in-use drive number (0x80-0xff) */
/** BIOS in-use drive number (0x00-0xff) */
unsigned int drive;
/** BIOS natural drive number (0x80-0xff)
/** BIOS natural drive number (0x00-0xff)
*
* This is the drive number that would have been assigned by
* 'naturally' appending the drive to the end of the BIOS
@@ -142,17 +142,44 @@ static struct segoff __text16 ( int13_vector );
/** Assembly wrapper */
extern void int13_wrapper ( void );
/** Dummy floppy disk parameter table */
static struct int13_fdd_parameters __data16 ( int13_fdd_params ) = {
/* 512 bytes per sector */
.bytes_per_sector = 0x02,
/* Highest sectors per track that we ever return */
.sectors_per_track = 48,
};
#define int13_fdd_params __use_data16 ( int13_fdd_params )
/** List of registered emulated drives */
static LIST_HEAD ( int13s );
/**
* Number of BIOS drives
* Equipment word
*
* Note that this is the number of drives in the system as a whole
* (i.e. a mirror of the counter at 40:75), rather than a count of the
* number of emulated drives.
* This is a cached copy of the BIOS Data Area equipment word at
* 40:10.
*/
static uint8_t num_drives;
static uint16_t equipment_word;
/**
* Number of BIOS floppy disk drives
*
* This is derived from the equipment word. It is held in .text16 to
* allow for easy access by the INT 13,08 wrapper.
*/
static uint8_t __text16 ( num_fdds );
#define num_fdds __use_text16 ( num_fdds )
/**
* Number of BIOS hard disk drives
*
* This is a cached copy of the BIOS Data Area number of hard disk
* drives at 40:75. It is held in .text16 to allow for easy access by
* the INT 13,08 wrapper.
*/
static uint8_t __text16 ( num_drives );
#define num_drives __use_text16 ( num_drives )
/**
* Calculate INT 13 drive sector size
@@ -160,7 +187,7 @@ static uint8_t num_drives;
* @v int13 Emulated drive
* @ret blksize Sector size
*/
static inline unsigned int int13_blksize ( struct int13_drive *int13 ) {
static inline size_t int13_blksize ( struct int13_drive *int13 ) {
return ( int13->capacity.blksize << int13->blksize_shift );
}
@@ -185,6 +212,16 @@ static inline uint32_t int13_capacity32 ( struct int13_drive *int13 ) {
return ( ( capacity <= 0xffffffffUL ) ? capacity : 0xffffffff );
}
/**
* Test if INT 13 drive is a floppy disk drive
*
* @v int13 Emulated drive
* @ret is_fdd Emulated drive is a floppy disk
*/
static inline int int13_is_fdd ( struct int13_drive *int13 ) {
return ( ! ( int13->drive & 0x80 ) );
}
/** An INT 13 command */
struct int13_command {
/** Status */
@@ -499,33 +536,33 @@ static int int13_parse_iso9660 ( struct int13_drive *int13, void *scratch ) {
}
/**
* Guess INT 13 drive geometry
* Guess INT 13 hard disk drive geometry
*
* @v int13 Emulated drive
* @v scratch Scratch area for single-sector reads
* @ret heads Guessed number of heads
* @ret sectors Guessed number of sectors per track
* @ret rc Return status code
*
* Guesses the drive geometry by inspecting the partition table.
*/
static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
static int int13_guess_geometry_hdd ( struct int13_drive *int13, void *scratch,
unsigned int *heads,
unsigned int *sectors ) {
struct master_boot_record *mbr = scratch;
struct partition_table_entry *partition;
unsigned int guessed_heads = 255;
unsigned int guessed_sectors_per_track = 63;
unsigned int blocks;
unsigned int blocks_per_cyl;
unsigned int i;
int rc;
/* Don't even try when the blksize is invalid for C/H/S access */
if ( int13_blksize ( int13 ) != INT13_BLKSIZE )
return 0;
/* Default guess is xx/255/63 */
*heads = 255;
*sectors = 63;
/* Read partition table */
if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( mbr ),
block_read ) ) != 0 ) {
DBGC ( int13, "INT13 drive %02x could not read partition "
"table to guess geometry: %s\n",
DBGC ( int13, "INT13 drive %02x could not read "
"partition table to guess geometry: %s\n",
int13->drive, strerror ( rc ) );
return rc;
}
@@ -534,25 +571,126 @@ static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
DBGC ( int13, "INT13 drive %02x has signature %08x\n",
int13->drive, mbr->signature );
/* Scan through partition table and modify guesses for heads
* and sectors_per_track if we find any used partitions.
/* Scan through partition table and modify guesses for
* heads and sectors_per_track if we find any used
* partitions.
*/
for ( i = 0 ; i < 4 ; i++ ) {
partition = &mbr->partitions[i];
if ( ! partition->type )
continue;
guessed_heads = ( PART_HEAD ( partition->chs_end ) + 1 );
guessed_sectors_per_track = PART_SECTOR ( partition->chs_end );
*heads = ( PART_HEAD ( partition->chs_end ) + 1 );
*sectors = PART_SECTOR ( partition->chs_end );
DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based "
"on partition %d\n", int13->drive, guessed_heads,
guessed_sectors_per_track, ( i + 1 ) );
"on partition %d\n",
int13->drive, *heads, *sectors, ( i + 1 ) );
}
return 0;
}
/** Recognised floppy disk geometries */
static const struct int13_fdd_geometry int13_fdd_geometries[] = {
INT13_FDD_GEOMETRY ( 40, 1, 8 ),
INT13_FDD_GEOMETRY ( 40, 1, 9 ),
INT13_FDD_GEOMETRY ( 40, 2, 8 ),
INT13_FDD_GEOMETRY ( 40, 1, 9 ),
INT13_FDD_GEOMETRY ( 80, 2, 8 ),
INT13_FDD_GEOMETRY ( 80, 2, 9 ),
INT13_FDD_GEOMETRY ( 80, 2, 15 ),
INT13_FDD_GEOMETRY ( 80, 2, 18 ),
INT13_FDD_GEOMETRY ( 80, 2, 20 ),
INT13_FDD_GEOMETRY ( 80, 2, 21 ),
INT13_FDD_GEOMETRY ( 82, 2, 21 ),
INT13_FDD_GEOMETRY ( 83, 2, 21 ),
INT13_FDD_GEOMETRY ( 80, 2, 22 ),
INT13_FDD_GEOMETRY ( 80, 2, 23 ),
INT13_FDD_GEOMETRY ( 80, 2, 24 ),
INT13_FDD_GEOMETRY ( 80, 2, 36 ),
INT13_FDD_GEOMETRY ( 80, 2, 39 ),
INT13_FDD_GEOMETRY ( 80, 2, 40 ),
INT13_FDD_GEOMETRY ( 80, 2, 44 ),
INT13_FDD_GEOMETRY ( 80, 2, 48 ),
};
/**
* Guess INT 13 floppy disk drive geometry
*
* @v int13 Emulated drive
* @ret heads Guessed number of heads
* @ret sectors Guessed number of sectors per track
* @ret rc Return status code
*
* Guesses the drive geometry by inspecting the disk size.
*/
static int int13_guess_geometry_fdd ( struct int13_drive *int13,
unsigned int *heads,
unsigned int *sectors ) {
unsigned int blocks = int13_blksize ( int13 );
const struct int13_fdd_geometry *geometry;
unsigned int cylinders;
unsigned int i;
/* Look for a match against a known geometry */
for ( i = 0 ; i < ( sizeof ( int13_fdd_geometries ) /
sizeof ( int13_fdd_geometries[0] ) ) ; i++ ) {
geometry = &int13_fdd_geometries[i];
cylinders = INT13_FDD_CYLINDERS ( geometry );
*heads = INT13_FDD_HEADS ( geometry );
*sectors = INT13_FDD_SECTORS ( geometry );
if ( ( cylinders * (*heads) * (*sectors) ) == blocks ) {
DBGC ( int13, "INT13 drive %02x guessing C/H/S "
"%d/%d/%d based on size %dK\n", int13->drive,
cylinders, *heads, *sectors, ( blocks / 2 ) );
return 0;
}
}
/* Otherwise, assume a partial disk image in the most common
* format (1440K, 80/2/18).
*/
*heads = 2;
*sectors = 18;
DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size "
"%dK\n", int13->drive, *heads, *sectors, ( blocks / 2 ) );
return 0;
}
/**
* Guess INT 13 drive geometry
*
* @v int13 Emulated drive
* @v scratch Scratch area for single-sector reads
* @ret rc Return status code
*/
static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
unsigned int guessed_heads;
unsigned int guessed_sectors;
unsigned int blocks;
unsigned int blocks_per_cyl;
int rc;
/* Don't even try when the blksize is invalid for C/H/S access */
if ( int13_blksize ( int13 ) != INT13_BLKSIZE )
return 0;
/* Guess geometry according to drive type */
if ( int13_is_fdd ( int13 ) ) {
if ( ( rc = int13_guess_geometry_fdd ( int13, &guessed_heads,
&guessed_sectors )) != 0)
return rc;
} else {
if ( ( rc = int13_guess_geometry_hdd ( int13, scratch,
&guessed_heads,
&guessed_sectors )) != 0)
return rc;
}
/* Apply guesses if no geometry already specified */
if ( ! int13->heads )
int13->heads = guessed_heads;
if ( ! int13->sectors_per_track )
int13->sectors_per_track = guessed_sectors_per_track;
int13->sectors_per_track = guessed_sectors;
if ( ! int13->cylinders ) {
/* Avoid attempting a 64-bit divide on a 32-bit system */
blocks = int13_capacity32 ( int13 );
@@ -569,19 +707,40 @@ static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
/**
* Update BIOS drive count
*/
static void int13_set_num_drives ( void ) {
static void int13_sync_num_drives ( void ) {
struct int13_drive *int13;
uint8_t *counter;
uint8_t max_drive;
uint8_t required;
/* Get current drive count */
/* Get current drive counts */
get_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
num_fdds = ( ( equipment_word & 0x0001 ) ?
( ( ( equipment_word >> 6 ) & 0x3 ) + 1 ) : 0 );
/* Ensure count is large enough to cover all of our emulated drives */
list_for_each_entry ( int13, &int13s, list ) {
if ( num_drives <= ( int13->drive & 0x7f ) )
num_drives = ( ( int13->drive & 0x7f ) + 1 );
counter = ( int13_is_fdd ( int13 ) ? &num_fdds : &num_drives );
max_drive = int13->drive;
if ( max_drive < int13->natural_drive )
max_drive = int13->natural_drive;
required = ( ( max_drive & 0x7f ) + 1 );
if ( *counter < required ) {
*counter = required;
DBGC ( int13, "INT13 drive %02x added to drive count: "
"%d HDDs, %d FDDs\n",
int13->drive, num_drives, num_fdds );
}
}
/* Update current drive count */
equipment_word &= ~( ( 0x3 << 6 ) | 0x0001 );
if ( num_fdds ) {
equipment_word |= ( 0x0001 |
( ( ( num_fdds - 1 ) & 0x3 ) << 6 ) );
}
put_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
}
@@ -589,13 +748,14 @@ static void int13_set_num_drives ( void ) {
* Check number of drives
*/
static void int13_check_num_drives ( void ) {
uint16_t check_equipment_word;
uint8_t check_num_drives;
get_real ( check_equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES );
if ( check_num_drives != num_drives ) {
int13_set_num_drives();
DBG ( "INT13 fixing up number of drives from %d to %d\n",
check_num_drives, num_drives );
if ( ( check_equipment_word != equipment_word ) ||
( check_num_drives != num_drives ) ) {
int13_sync_num_drives();
}
}
@@ -669,14 +829,19 @@ static int int13_rw_sectors ( struct int13_drive *int13,
int13->drive, int13_blksize ( int13 ) );
return -INT13_STATUS_INVALID;
}
/* Calculate parameters */
cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
assert ( cylinder < int13->cylinders );
head = ix86->regs.dh;
assert ( head < int13->heads );
sector = ( ix86->regs.cl & 0x3f );
assert ( ( sector >= 1 ) && ( sector <= int13->sectors_per_track ) );
if ( ( cylinder >= int13->cylinders ) ||
( head >= int13->heads ) ||
( sector < 1 ) || ( sector > int13->sectors_per_track ) ) {
DBGC ( int13, "C/H/S %d/%d/%d out of range for geometry "
"%d/%d/%d\n", cylinder, head, sector, int13->cylinders,
int13->heads, int13->sectors_per_track );
return -INT13_STATUS_INVALID;
}
lba = ( ( ( ( cylinder * int13->heads ) + head )
* int13->sectors_per_track ) + sector - 1 );
count = ix86->regs.al;
@@ -761,10 +926,19 @@ static int int13_get_parameters ( struct int13_drive *int13,
return -INT13_STATUS_INVALID;
}
/* Common parameters */
ix86->regs.ch = ( max_cylinder & 0xff );
ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector );
ix86->regs.dh = max_head;
get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES );
ix86->regs.dl = ( int13_is_fdd ( int13 ) ? num_fdds : num_drives );
/* Floppy-specific parameters */
if ( int13_is_fdd ( int13 ) ) {
ix86->regs.bl = INT13_FDD_TYPE_1M44;
ix86->segs.es = rm_ds;
ix86->regs.di = __from_data16 ( &int13_fdd_params );
}
return 0;
}
@@ -781,10 +955,15 @@ static int int13_get_disk_type ( struct int13_drive *int13,
uint32_t blocks;
DBGC2 ( int13, "Get disk type\n" );
blocks = int13_capacity32 ( int13 );
ix86->regs.cx = ( blocks >> 16 );
ix86->regs.dx = ( blocks & 0xffff );
return INT13_DISK_TYPE_HDD;
if ( int13_is_fdd ( int13 ) ) {
return INT13_DISK_TYPE_FDD;
} else {
blocks = int13_capacity32 ( int13 );
ix86->regs.cx = ( blocks >> 16 );
ix86->regs.dx = ( blocks & 0xffff );
return INT13_DISK_TYPE_HDD;
}
}
/**
@@ -833,6 +1012,13 @@ static int int13_extended_rw ( struct int13_drive *int13,
userptr_t buffer;
int rc;
/* Extended reads are not allowed on floppy drives.
* ELTORITO.SYS seems to assume that we are really a CD-ROM if
* we support extended reads for a floppy drive.
*/
if ( int13_is_fdd ( int13 ) )
return -INT13_STATUS_INVALID;
/* Get buffer size */
get_real ( bufsize, ix86->segs.ds,
( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) );
@@ -1300,26 +1486,28 @@ static void int13_hook_vector ( void ) {
"popw 6(%%bp)\n\t"
/* Fix up %dl:
*
* INT 13,15 : do nothing
* INT 13,15 : do nothing if hard disk
* INT 13,08 : load with number of drives
* all others: restore original value
*/
"cmpb $0x15, -1(%%bp)\n\t"
"je 2f\n\t"
"jne 2f\n\t"
"testb $0x80, -4(%%bp)\n\t"
"jnz 3f\n\t"
"\n2:\n\t"
"movb -4(%%bp), %%dl\n\t"
"cmpb $0x08, -1(%%bp)\n\t"
"jne 2f\n\t"
"pushw %%ds\n\t"
"pushw %1\n\t"
"popw %%ds\n\t"
"movb %c2, %%dl\n\t"
"popw %%ds\n\t"
"jne 3f\n\t"
"testb $0x80, %%dl\n\t"
"movb %%cs:num_drives, %%dl\n\t"
"jnz 3f\n\t"
"movb %%cs:num_fdds, %%dl\n\t"
/* Return */
"\n2:\n\t"
"\n3:\n\t"
"movw %%bp, %%sp\n\t"
"popw %%bp\n\t"
"iret\n\t" )
: : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) );
: : "i" ( int13 ) );
hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper,
&int13_vector );
@@ -1404,14 +1592,13 @@ static void int13_free ( struct refcnt *refcnt ) {
*/
static int int13_hook ( struct uri *uri, unsigned int drive ) {
struct int13_drive *int13;
uint8_t num_drives;
unsigned int natural_drive;
void *scratch;
int rc;
/* Calculate natural drive number */
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
natural_drive = ( num_drives | 0x80 );
int13_sync_num_drives();
natural_drive = ( ( drive & 0x80 ) ? ( num_drives | 0x80 ) : num_fdds );
/* Check that drive number is not in use */
list_for_each_entry ( int13, &int13s, list ) {
@@ -1468,7 +1655,7 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
list_add ( &int13->list, &int13s );
/* Update BIOS drive count */
int13_set_num_drives();
int13_sync_num_drives();
free ( scratch );
return 0;
@@ -52,6 +52,9 @@ static userptr_t top = UNULL;
/** Bottom of heap (current lowest allocated block) */
static userptr_t bottom = UNULL;
/** Remaining space on heap */
static size_t heap_size;
/**
* Initialise external heap
*
@@ -59,12 +62,12 @@ static userptr_t bottom = UNULL;
*/
static int init_eheap ( void ) {
struct memory_map memmap;
unsigned long heap_size = 0;
unsigned int i;
DBG ( "Allocating external heap\n" );
get_memmap ( &memmap );
heap_size = 0;
for ( i = 0 ; i < memmap.count ; i++ ) {
struct memory_region *region = &memmap.regions[i];
unsigned long r_start, r_end;
@@ -99,8 +102,8 @@ static int init_eheap ( void ) {
return -ENOMEM;
}
DBG ( "External heap grows downwards from %lx\n",
user_to_phys ( top, 0 ) );
DBG ( "External heap grows downwards from %lx (size %zx)\n",
user_to_phys ( top, 0 ), heap_size );
return 0;
}
@@ -110,6 +113,7 @@ static int init_eheap ( void ) {
*/
static void ecollect_free ( void ) {
struct external_memory extmem;
size_t len;
/* Walk the free list and collect empty blocks */
while ( bottom != top ) {
@@ -119,8 +123,9 @@ static void ecollect_free ( void ) {
break;
DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
user_to_phys ( bottom, extmem.size ) );
bottom = userptr_add ( bottom,
( extmem.size + sizeof ( extmem ) ) );
len = ( extmem.size + sizeof ( extmem ) );
bottom = userptr_add ( bottom, len );
heap_size += len;
}
}
@@ -153,7 +158,12 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
sizeof ( extmem ) );
} else {
/* Create a zero-length block */
if ( heap_size < sizeof ( extmem ) ) {
DBG ( "EXTMEM out of space\n" );
return UNULL;
}
ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
heap_size -= sizeof ( extmem );
DBG ( "EXTMEM allocating [%lx,%lx)\n",
user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
extmem.size = 0;
@@ -163,6 +173,10 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
/* Expand/shrink block if possible */
if ( ptr == bottom ) {
/* Update block */
if ( new_size > ( heap_size - extmem.size ) ) {
DBG ( "EXTMEM out of space\n" );
return UNULL;
}
new = userptr_add ( ptr, - ( new_size - extmem.size ) );
align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
new_size += align;
@@ -174,8 +188,9 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
user_to_phys ( new, new_size ));
memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
extmem.size : new_size ) );
extmem.size = new_size;
bottom = new;
heap_size -= ( new_size - extmem.size );
extmem.size = new_size;
} else {
/* Cannot expand; can only pretend to shrink */
if ( new_size > extmem.size ) {
@@ -193,7 +208,8 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
/* Collect any free blocks and update hidden memory region */
ecollect_free();
hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ),
hide_umalloc ( user_to_phys ( bottom, ( ( bottom == top ) ?
0 : -sizeof ( extmem ) ) ),
user_to_phys ( top, 0 ) );
return ( new_size ? new : UNOWHERE );
@@ -0,0 +1,198 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* RTC-based entropy source
*
*/
#include <stdint.h>
#include <string.h>
#include <biosint.h>
#include <pic8259.h>
#include <rtc.h>
#include <ipxe/entropy.h>
/** RTC "interrupt triggered" flag */
static uint8_t __text16 ( rtc_flag );
#define rtc_flag __use_text16 ( rtc_flag )
/** RTC interrupt handler */
extern void rtc_isr ( void );
/** Previous RTC interrupt handler */
static struct segoff rtc_old_handler;
/**
* Hook RTC interrupt handler
*
*/
static void rtc_hook_isr ( void ) {
/* RTC interrupt handler */
__asm__ __volatile__ (
TEXT16_CODE ( "\nrtc_isr:\n\t"
/* Preserve registers */
"pushw %%ax\n\t"
/* Set "interrupt triggered" flag */
"cs movb $0x01, %c0\n\t"
/* Read RTC status register C to
* acknowledge interrupt
*/
"movb %3, %%al\n\t"
"outb %%al, %1\n\t"
"inb %2\n\t"
/* Send EOI */
"movb $0x20, %%al\n\t"
"outb %%al, $0xa0\n\t"
"outb %%al, $0x20\n\t"
/* Restore registers and return */
"popw %%ax\n\t"
"iret\n\t" )
:
: "p" ( __from_text16 ( &rtc_flag ) ),
"i" ( CMOS_ADDRESS ), "i" ( CMOS_DATA ),
"i" ( RTC_STATUS_C ) );
hook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
&rtc_old_handler );
}
/**
* Unhook RTC interrupt handler
*
*/
static void rtc_unhook_isr ( void ) {
int rc;
rc = unhook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
&rtc_old_handler );
assert ( rc == 0 ); /* Should always be able to unhook */
}
/**
* Enable RTC interrupts
*
*/
static void rtc_enable_int ( void ) {
uint8_t status_b;
/* Set Periodic Interrupt Enable bit in status register B */
outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
status_b = inb ( CMOS_DATA );
outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
outb ( ( status_b | RTC_STATUS_B_PIE ), CMOS_DATA );
/* Re-enable NMI and reset to default address */
outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
}
/**
* Disable RTC interrupts
*
*/
static void rtc_disable_int ( void ) {
uint8_t status_b;
/* Clear Periodic Interrupt Enable bit in status register B */
outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
status_b = inb ( CMOS_DATA );
outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
outb ( ( status_b & ~RTC_STATUS_B_PIE ), CMOS_DATA );
/* Re-enable NMI and reset to default address */
outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
}
/**
* Enable entropy gathering
*
* @ret rc Return status code
*/
static int rtc_entropy_enable ( void ) {
rtc_hook_isr();
enable_irq ( RTC_IRQ );
rtc_enable_int();
return 0;
}
/**
* Disable entropy gathering
*
*/
static void rtc_entropy_disable ( void ) {
rtc_disable_int();
disable_irq ( RTC_IRQ );
rtc_unhook_isr();
}
/**
* Measure a single RTC tick
*
* @ret delta Length of RTC tick (in TSC units)
*/
uint8_t rtc_sample ( void ) {
uint32_t before;
uint32_t after;
uint32_t temp;
__asm__ __volatile__ (
REAL_CODE ( /* Enable interrupts */
"sti\n\t"
/* Wait for RTC interrupt */
"cs movb %b2, %c4\n\t"
"\n1:\n\t"
"cs xchgb %b2, %c4\n\t" /* Serialize */
"testb %b2, %b2\n\t"
"jz 1b\n\t"
/* Read "before" TSC */
"rdtsc\n\t"
/* Store "before" TSC on stack */
"pushl %0\n\t"
/* Wait for another RTC interrupt */
"xorb %b2, %b2\n\t"
"cs movb %b2, %c4\n\t"
"\n1:\n\t"
"cs xchgb %b2, %c4\n\t" /* Serialize */
"testb %b2, %b2\n\t"
"jz 1b\n\t"
/* Read "after" TSC */
"rdtsc\n\t"
/* Retrieve "before" TSC on stack */
"popl %1\n\t"
/* Disable interrupts */
"cli\n\t"
)
: "=a" ( after ), "=d" ( before ), "=q" ( temp )
: "2" ( 0 ), "p" ( __from_text16 ( &rtc_flag ) ) );
return ( after - before );
}
PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
PROVIDE_ENTROPY_INLINE ( rtc, get_noise );
+137
View File
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* RTC-based time source
*
*/
#include <stdint.h>
#include <time.h>
#include <rtc.h>
#include <ipxe/time.h>
/**
* Read RTC register
*
* @v address Register address
* @ret data Data
*/
static unsigned int rtc_readb ( int address ) {
outb ( address, CMOS_ADDRESS );
return inb ( CMOS_DATA );
}
/**
* Check if RTC update is in progress
*
* @ret is_busy RTC update is in progress
*/
static int rtc_is_busy ( void ) {
return ( rtc_readb ( RTC_STATUS_A ) & RTC_STATUS_A_UPDATE_IN_PROGRESS );
}
/**
* Read RTC BCD register
*
* @v address Register address
* @ret value Value
*/
static unsigned int rtc_readb_bcd ( int address ) {
unsigned int bcd;
bcd = rtc_readb ( address );
return ( bcd - ( 6 * ( bcd >> 4 ) ) );
}
/**
* Read RTC time
*
* @ret time Time, in seconds
*/
static time_t rtc_read_time ( void ) {
unsigned int status_b;
int is_binary;
int is_24hour;
unsigned int ( * read_component ) ( int address );
struct tm tm;
int is_pm;
unsigned int hour;
time_t time;
/* Wait for any in-progress update to complete */
while ( rtc_is_busy() ) {}
/* Determine RTC mode */
status_b = rtc_readb ( RTC_STATUS_B );
is_binary = ( status_b & RTC_STATUS_B_BINARY );
is_24hour = ( status_b & RTC_STATUS_B_24_HOUR );
read_component = ( is_binary ? rtc_readb : rtc_readb_bcd );
/* Read time values */
tm.tm_sec = read_component ( RTC_SEC );
tm.tm_min = read_component ( RTC_MIN );
hour = read_component ( RTC_HOUR );
if ( ! is_24hour ) {
is_pm = ( hour >= 80 );
hour = ( ( ( ( hour & 0x7f ) % 80 ) % 12 ) +
( is_pm ? 12 : 0 ) );
}
tm.tm_hour = hour;
tm.tm_mday = read_component ( RTC_MDAY );
tm.tm_mon = ( read_component ( RTC_MON ) - 1 );
tm.tm_year = ( read_component ( RTC_YEAR ) +
100 /* Assume we are in the 21st century, since
* this code was written in 2012 */ );
DBGC ( RTC_STATUS_A, "RTCTIME is %04d-%02d-%02d %02d:%02d:%02d "
"(%s,%d-hour)\n", ( tm.tm_year + 1900 ), ( tm.tm_mon + 1 ),
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
( is_binary ? "binary" : "BCD" ), ( is_24hour ? 24 : 12 ) );
/* Convert to seconds since the Epoch */
time = mktime ( &tm );
return time;
}
/**
* Get current time in seconds
*
* @ret time Time, in seconds
*/
static time_t rtc_now ( void ) {
time_t time = 0;
time_t last_time;
/* Read time until we get two matching values in a row, in
* case we end up reading a corrupted value in the middle of
* an update.
*/
do {
last_time = time;
time = rtc_read_time();
} while ( time != last_time );
return time;
}
PROVIDE_TIME ( rtc, time_now, rtc_now );
@@ -166,6 +166,8 @@ void comboot_force_text_mode ( void ) {
* Fetch kernel and optional initrd
*/
static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
struct image *kernel;
struct image *initrd;
char *initrd_file;
int rc;
@@ -184,8 +186,7 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
DBG ( "COMBOOT: fetching initrd '%s'\n", initrd_file );
/* Fetch initrd */
if ( ( rc = imgdownload_string ( initrd_file, NULL, NULL,
NULL ) ) != 0 ) {
if ( ( rc = imgdownload_string ( initrd_file, &initrd ) ) != 0){
DBG ( "COMBOOT: could not fetch initrd: %s\n",
strerror ( rc ) );
return rc;
@@ -198,14 +199,20 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
DBG ( "COMBOOT: fetching kernel '%s'\n", kernel_file );
/* Allocate and fetch kernel */
if ( ( rc = imgdownload_string ( kernel_file, NULL, cmdline,
image_replace ) ) != 0 ) {
/* Fetch kernel */
if ( ( rc = imgdownload_string ( kernel_file, &kernel ) ) != 0 ) {
DBG ( "COMBOOT: could not fetch kernel: %s\n",
strerror ( rc ) );
return rc;
}
/* Replace comboot image with kernel */
if ( ( rc = image_replace ( kernel ) ) != 0 ) {
DBG ( "COMBOOT: could not replace with kernel: %s\n",
strerror ( rc ) );
return rc;
}
return 0;
}
+281
View File
@@ -0,0 +1,281 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* VMware GuestInfo settings
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ipxe/init.h>
#include <ipxe/settings.h>
#include <ipxe/netdevice.h>
#include <ipxe/guestrpc.h>
/** GuestInfo GuestRPC channel */
static int guestinfo_channel;
/**
* Fetch value of typed GuestInfo setting
*
* @v settings Settings block
* @v setting Setting to fetch
* @v type Setting type to attempt (or NULL for default)
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret found Setting found in GuestInfo
* @ret len Length of setting data, or negative error
*/
static int guestinfo_fetch_type ( struct settings *settings,
struct setting *setting,
struct setting_type *type,
void *data, size_t len, int *found ) {
const char *parent_name = settings->parent->name;
char command[ 24 /* "info-get guestinfo.ipxe." */ +
strlen ( parent_name ) + 1 /* "." */ +
strlen ( setting->name ) + 1 /* "." */ +
( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ];
struct setting *named_setting;
char *info;
int info_len;
int check_len;
int ret;
/* Construct info-get command */
snprintf ( command, sizeof ( command ),
"info-get guestinfo.ipxe.%s%s%s%s%s",
parent_name, ( parent_name[0] ? "." : "" ), setting->name,
( type ? "." : "" ), ( type ? type->name : "" ) );
/* Check for existence and obtain length of GuestInfo value */
info_len = guestrpc_command ( guestinfo_channel, command, NULL, 0 );
if ( info_len < 0 ) {
ret = info_len;
goto err_get_info_len;
}
/* Mark as found */
*found = 1;
/* Determine default type if necessary */
if ( ! type ) {
named_setting = find_setting ( setting->name );
type = ( named_setting ?
named_setting->type : &setting_type_string );
}
assert ( type != NULL );
/* Allocate temporary block to hold GuestInfo value */
info = zalloc ( info_len + 1 /* NUL */ );
if ( ! info ) {
DBGC ( settings, "GuestInfo %p could not allocate %zd bytes\n",
settings, info_len );
ret = -ENOMEM;
goto err_alloc;
}
info[info_len] = '\0';
/* Fetch GuestInfo value */
check_len = guestrpc_command ( guestinfo_channel, command,
info, info_len );
if ( check_len < 0 ) {
ret = check_len;
goto err_get_info;
}
if ( check_len != info_len ) {
DBGC ( settings, "GuestInfo %p length mismatch (expected %d, "
"got %d)\n", settings, info_len, check_len );
ret = -EIO;
goto err_get_info;
}
DBGC2 ( settings, "GuestInfo %p found %s = \"%s\"\n",
settings, &command[9] /* Skip "info-get " */, info );
/* Parse GuestInfo value according to type */
ret = type->parse ( info, data, len );
if ( ret < 0 ) {
DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: "
"%s\n", settings, info, type->name, strerror ( ret ) );
goto err_parse;
}
err_parse:
err_get_info:
free ( info );
err_alloc:
err_get_info_len:
return ret;
}
/**
* Fetch value of GuestInfo setting
*
* @v settings Settings block
* @v setting Setting to fetch
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int guestinfo_fetch ( struct settings *settings,
struct setting *setting,
void *data, size_t len ) {
struct setting_type *type;
int found = 0;
int ret;
/* Try default type first */
ret = guestinfo_fetch_type ( settings, setting, NULL,
data, len, &found );
if ( found )
return ret;
/* Otherwise, try all possible types */
for_each_table_entry ( type, SETTING_TYPES ) {
ret = guestinfo_fetch_type ( settings, setting, type,
data, len, &found );
if ( found )
return ret;
}
/* Not found */
return -ENOENT;
}
/** GuestInfo settings operations */
static struct settings_operations guestinfo_settings_operations = {
.fetch = guestinfo_fetch,
};
/** GuestInfo settings */
static struct settings guestinfo_settings = {
.refcnt = NULL,
.siblings = LIST_HEAD_INIT ( guestinfo_settings.siblings ),
.children = LIST_HEAD_INIT ( guestinfo_settings.children ),
.op = &guestinfo_settings_operations,
};
/** Initialise GuestInfo settings */
static void guestinfo_init ( void ) {
int rc;
/* Open GuestRPC channel */
guestinfo_channel = guestrpc_open();
if ( guestinfo_channel < 0 ) {
rc = guestinfo_channel;
DBG ( "GuestInfo could not open channel: %s\n",
strerror ( rc ) );
return;
}
/* Register root GuestInfo settings */
if ( ( rc = register_settings ( &guestinfo_settings, NULL,
"vmware" ) ) != 0 ) {
DBG ( "GuestInfo could not register settings: %s\n",
strerror ( rc ) );
return;
}
}
/** GuestInfo settings initialiser */
struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = {
.initialise = guestinfo_init,
};
/**
* Create per-netdevice GuestInfo settings
*
* @v netdev Network device
* @ret rc Return status code
*/
static int guestinfo_net_probe ( struct net_device *netdev ) {
struct settings *settings;
int rc;
/* Do nothing unless we have a GuestInfo channel available */
if ( guestinfo_channel < 0 )
return 0;
/* Allocate and initialise settings block */
settings = zalloc ( sizeof ( *settings ) );
if ( ! settings ) {
rc = -ENOMEM;
goto err_alloc;
}
settings_init ( settings, &guestinfo_settings_operations, NULL, 0 );
/* Register settings */
if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
"vmware" ) ) != 0 ) {
DBGC ( settings, "GuestInfo %p could not register for %s: %s\n",
settings, netdev->name, strerror ( rc ) );
goto err_register;
}
DBGC ( settings, "GuestInfo %p registered for %s\n",
settings, netdev->name );
return 0;
err_register:
free ( settings );
err_alloc:
return rc;
}
/**
* Handle network device or link state change
*
* @v netdev Network device
*/
static void guestinfo_net_notify ( struct net_device *netdev __unused ) {
/* Nothing to do */
}
/**
* Remove per-netdevice GuestInfo settings
*
* @v netdev Network device
*/
static void guestinfo_net_remove ( struct net_device *netdev ) {
struct settings *parent = netdev_settings ( netdev );
struct settings *settings;
list_for_each_entry ( settings, &parent->children, siblings ) {
if ( settings->op == &guestinfo_settings_operations ) {
DBGC ( settings, "GuestInfo %p unregistered for %s\n",
settings, netdev->name );
unregister_settings ( settings );
free ( settings );
return;
}
}
}
/** GuestInfo per-netdevice driver */
struct net_driver guestinfo_net_driver __net_driver = {
.name = "GuestInfo",
.probe = guestinfo_net_probe,
.notify = guestinfo_net_notify,
.remove = guestinfo_net_remove,
};
+327
View File
@@ -0,0 +1,327 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* VMware GuestRPC mechanism
*
*/
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/vmware.h>
#include <ipxe/guestrpc.h>
/* Disambiguate the various error causes */
#define EPROTO_OPEN __einfo_error ( EINFO_EPROTO_OPEN )
#define EINFO_EPROTO_OPEN \
__einfo_uniqify ( EINFO_EPROTO, 0x00, "GuestRPC open failed" )
#define EPROTO_COMMAND_LEN __einfo_error ( EINFO_EPROTO_COMMAND_LEN )
#define EINFO_EPROTO_COMMAND_LEN \
__einfo_uniqify ( EINFO_EPROTO, 0x01, "GuestRPC command length failed" )
#define EPROTO_COMMAND_DATA __einfo_error ( EINFO_EPROTO_COMMAND_DATA )
#define EINFO_EPROTO_COMMAND_DATA \
__einfo_uniqify ( EINFO_EPROTO, 0x02, "GuestRPC command data failed" )
#define EPROTO_REPLY_LEN __einfo_error ( EINFO_EPROTO_REPLY_LEN )
#define EINFO_EPROTO_REPLY_LEN \
__einfo_uniqify ( EINFO_EPROTO, 0x03, "GuestRPC reply length failed" )
#define EPROTO_REPLY_DATA __einfo_error ( EINFO_EPROTO_REPLY_DATA )
#define EINFO_EPROTO_REPLY_DATA \
__einfo_uniqify ( EINFO_EPROTO, 0x04, "GuestRPC reply data failed" )
#define EPROTO_REPLY_FINISH __einfo_error ( EINFO_EPROTO_REPLY_FINISH )
#define EINFO_EPROTO_REPLY_FINISH \
__einfo_uniqify ( EINFO_EPROTO, 0x05, "GuestRPC reply finish failed" )
#define EPROTO_CLOSE __einfo_error ( EINFO_EPROTO_CLOSE )
#define EINFO_EPROTO_CLOSE \
__einfo_uniqify ( EINFO_EPROTO, 0x06, "GuestRPC close failed" )
/**
* Open GuestRPC channel
*
* @ret channel Channel number, or negative error
*/
int guestrpc_open ( void ) {
uint16_t channel;
uint32_t discard_b;
uint32_t status;
/* Issue GuestRPC command */
status = vmware_cmd_guestrpc ( 0, GUESTRPC_OPEN, GUESTRPC_MAGIC,
&channel, &discard_b );
if ( status != GUESTRPC_OPEN_SUCCESS ) {
DBGC ( GUESTRPC_MAGIC, "GuestRPC open failed: status %08x\n",
status );
return -EPROTO_OPEN;
}
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d opened\n", channel );
return channel;
}
/**
* Send GuestRPC command length
*
* @v channel Channel number
* @v len Command length
* @ret rc Return status code
*/
static int guestrpc_command_len ( int channel, size_t len ) {
uint16_t discard_d;
uint32_t discard_b;
uint32_t status;
/* Issue GuestRPC command */
status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_LEN, len,
&discard_d, &discard_b );
if ( status != GUESTRPC_COMMAND_LEN_SUCCESS ) {
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
"length %zd failed: status %08x\n",
channel, len, status );
return -EPROTO_COMMAND_LEN;
}
return 0;
}
/**
* Send GuestRPC command data
*
* @v channel Channel number
* @v data Command data
* @ret rc Return status code
*/
static int guestrpc_command_data ( int channel, uint32_t data ) {
uint16_t discard_d;
uint32_t discard_b;
uint32_t status;
/* Issue GuestRPC command */
status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_DATA, data,
&discard_d, &discard_b );
if ( status != GUESTRPC_COMMAND_DATA_SUCCESS ) {
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
"data %08x failed: status %08x\n",
channel, data, status );
return -EPROTO_COMMAND_DATA;
}
return 0;
}
/**
* Receive GuestRPC reply length
*
* @v channel Channel number
* @ret reply_id Reply ID
* @ret len Reply length, or negative error
*/
static int guestrpc_reply_len ( int channel, uint16_t *reply_id ) {
uint32_t len;
uint32_t status;
/* Issue GuestRPC command */
status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_LEN, 0,
reply_id, &len );
if ( status != GUESTRPC_REPLY_LEN_SUCCESS ) {
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
"length failed: status %08x\n", channel, status );
return -EPROTO_REPLY_LEN;
}
return len;
}
/**
* Receive GuestRPC reply data
*
* @v channel Channel number
* @v reply_id Reply ID
* @ret data Reply data
* @ret rc Return status code
*/
static int guestrpc_reply_data ( int channel, uint16_t reply_id,
uint32_t *data ) {
uint16_t discard_d;
uint32_t status;
/* Issue GuestRPC command */
status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_DATA, reply_id,
&discard_d, data );
if ( status != GUESTRPC_REPLY_DATA_SUCCESS ) {
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
"%d data failed: status %08x\n",
channel, reply_id, status );
return -EPROTO_REPLY_DATA;
}
return 0;
}
/**
* Finish receiving GuestRPC reply
*
* @v channel Channel number
* @v reply_id Reply ID
* @ret rc Return status code
*/
static int guestrpc_reply_finish ( int channel, uint16_t reply_id ) {
uint16_t discard_d;
uint32_t discard_b;
uint32_t status;
/* Issue GuestRPC command */
status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_FINISH, reply_id,
&discard_d, &discard_b );
if ( status != GUESTRPC_REPLY_FINISH_SUCCESS ) {
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d finish reply %d "
"failed: status %08x\n", channel, reply_id, status );
return -EPROTO_REPLY_FINISH;
}
return 0;
}
/**
* Close GuestRPC channel
*
* @v channel Channel number
*/
void guestrpc_close ( int channel ) {
uint16_t discard_d;
uint32_t discard_b;
uint32_t status;
/* Issue GuestRPC command */
status = vmware_cmd_guestrpc ( channel, GUESTRPC_CLOSE, 0,
&discard_d, &discard_b );
if ( status != GUESTRPC_CLOSE_SUCCESS ) {
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d close failed: "
"status %08x\n", channel, status );
return;
}
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d closed\n", channel );
}
/**
* Issue GuestRPC command
*
* @v channel Channel number
* @v command Command
* @v reply Reply buffer
* @v reply_len Length of reply buffer
* @ret len Length of reply, or negative error
*
* The actual length of the reply will be returned even if the buffer
* was too small.
*/
int guestrpc_command ( int channel, const char *command, char *reply,
size_t reply_len ) {
const uint8_t *command_bytes = ( ( const void * ) command );
uint8_t *reply_bytes = ( ( void * ) reply );
size_t command_len = strlen ( command );
int orig_reply_len = reply_len;
uint16_t status;
uint8_t *status_bytes = ( ( void * ) &status );
size_t status_len = sizeof ( status );
uint32_t data;
uint16_t reply_id;
int len;
int remaining;
unsigned int i;
int rc;
DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d issuing command:\n",
channel );
DBGC2_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
/* Sanity check */
assert ( ( reply != NULL ) || ( reply_len == 0 ) );
/* Send command length */
if ( ( rc = guestrpc_command_len ( channel, command_len ) ) < 0 )
return rc;
/* Send command data */
while ( command_len ) {
data = 0;
for ( i = sizeof ( data ) ; i ; i-- ) {
if ( command_len ) {
data = ( ( data & ~0xff ) |
*(command_bytes++) );
command_len--;
}
data = ( ( data << 24 ) | ( data >> 8 ) );
}
if ( ( rc = guestrpc_command_data ( channel, data ) ) < 0 )
return rc;
}
/* Receive reply length */
if ( ( len = guestrpc_reply_len ( channel, &reply_id ) ) < 0 ) {
rc = len;
return rc;
}
/* Receive reply */
for ( remaining = len ; remaining > 0 ; remaining -= sizeof ( data ) ) {
if ( ( rc = guestrpc_reply_data ( channel, reply_id,
&data ) ) < 0 ) {
return rc;
}
for ( i = sizeof ( data ) ; i ; i-- ) {
if ( status_len ) {
*(status_bytes++) = ( data & 0xff );
status_len--;
len--;
} else if ( reply_len ) {
*(reply_bytes++) = ( data & 0xff );
reply_len--;
}
data = ( ( data << 24 ) | ( data >> 8 ) );
}
}
/* Finish receiving RPC reply */
if ( ( rc = guestrpc_reply_finish ( channel, reply_id ) ) < 0 )
return rc;
DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d received reply (id %d, "
"length %d):\n", channel, reply_id, len );
DBGC2_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
DBGC2_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
( ( len < orig_reply_len ) ? len : orig_reply_len ) );
/* Check reply status */
if ( status != GUESTRPC_SUCCESS ) {
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d command failed "
"(status %04x, reply id %d, reply length %d):\n",
channel, status, reply_id, len );
DBGC_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
DBGC_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
DBGC_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
( ( len < orig_reply_len ) ? len : orig_reply_len ));
return -EIO;
}
return len;
}
+133
View File
@@ -0,0 +1,133 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* VMware logfile console
*
*/
#include <string.h>
#include <ipxe/console.h>
#include <ipxe/lineconsole.h>
#include <ipxe/init.h>
#include <ipxe/guestrpc.h>
#include <config/console.h>
/** VMware logfile console buffer size */
#define VMCONSOLE_BUFSIZE 128
/* Set default console usage if applicable */
#if ! ( defined ( CONSOLE_VMWARE ) && CONSOLE_EXPLICIT ( CONSOLE_VMWARE ) )
#undef CONSOLE_VMWARE
#define CONSOLE_VMWARE ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI )
#endif
/** VMware logfile console GuestRPC channel */
static int vmconsole_channel;
/** VMware logfile console line buffer */
static struct {
char prefix[4];
char message[VMCONSOLE_BUFSIZE];
} vmconsole_buffer = {
.prefix = "log ",
};
/** VMware logfile console ANSI escape sequence handlers */
static struct ansiesc_handler vmconsole_handlers[] = {
{ 0, NULL }
};
/** VMware logfile line console */
static struct line_console vmconsole_line = {
.buffer = vmconsole_buffer.message,
.len = sizeof ( vmconsole_buffer.message ),
.ctx = {
.handlers = vmconsole_handlers,
},
};
/** VMware logfile console recursion marker */
static int vmconsole_entered;
/**
* Print a character to VMware logfile console
*
* @v character Character to be printed
*/
static void vmconsole_putchar ( int character ) {
int rc;
/* Ignore if we are already mid-logging */
if ( vmconsole_entered )
return;
/* Fill line buffer */
if ( line_putchar ( &vmconsole_line, character ) == 0 )
return;
/* Guard against re-entry */
vmconsole_entered = 1;
/* Send log message */
if ( ( rc = guestrpc_command ( vmconsole_channel,
vmconsole_buffer.prefix, NULL, 0 ) ) <0){
DBG ( "VMware console could not send log message: %s\n",
strerror ( rc ) );
}
/* Clear re-entry flag */
vmconsole_entered = 0;
}
/** VMware logfile console driver */
struct console_driver vmconsole __console_driver = {
.putchar = vmconsole_putchar,
.disabled = 1,
.usage = CONSOLE_VMWARE,
};
/**
* Initialise VMware logfile console
*
*/
static void vmconsole_init ( void ) {
int rc;
/* Attempt to open console */
vmconsole_channel = guestrpc_open();
if ( vmconsole_channel < 0 ) {
rc = vmconsole_channel;
DBG ( "VMware console could not be initialised: %s\n",
strerror ( rc ) );
return;
}
/* Mark console as available */
vmconsole.disabled = 0;
}
/**
* VMware logfile console initialisation function
*/
struct init_fn vmconsole_init_fn __init_fn ( INIT_CONSOLE ) = {
.initialise = vmconsole_init,
};
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* VMware backdoor mechanism
*
* Based on the unofficial documentation at
*
* http://sites.google.com/site/chitchatvmback/backdoor
*
*/
#include <stdint.h>
#include <errno.h>
#include <ipxe/vmware.h>
/**
* Detect VMware presence
*
* @ret rc Return status code
*/
int vmware_present ( void ) {
uint32_t version;
uint32_t magic;
uint32_t product_type;
/* Perform backdoor call */
vmware_cmd_get_version ( &version, &magic, &product_type );
/* Check for VMware presence */
if ( magic != VMW_MAGIC ) {
DBGC ( VMW_MAGIC, "VMware not present\n" );
return -ENOENT;
}
DBGC ( VMW_MAGIC, "VMware product type %04x version %08x detected\n",
product_type, version );
return 0;
}
+90
View File
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <string.h>
#include <ipxe/bigint.h>
/** @file
*
* Big integer support
*/
/**
* Multiply big integers
*
* @v multiplicand0 Element 0 of big integer to be multiplied
* @v multiplier0 Element 0 of big integer to be multiplied
* @v result0 Element 0 of big integer to hold result
* @v size Number of elements
*/
void bigint_multiply_raw ( const uint32_t *multiplicand0,
const uint32_t *multiplier0,
uint32_t *result0, unsigned int size ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
( ( const void * ) multiplicand0 );
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
( ( const void * ) multiplier0 );
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
( ( void * ) result0 );
unsigned int i;
unsigned int j;
uint32_t multiplicand_element;
uint32_t multiplier_element;
uint32_t *result_elements;
uint32_t discard_a;
uint32_t discard_d;
long index;
/* Zero result */
memset ( result, 0, sizeof ( *result ) );
/* Multiply integers one element at a time */
for ( i = 0 ; i < size ; i++ ) {
multiplicand_element = multiplicand->element[i];
for ( j = 0 ; j < size ; j++ ) {
multiplier_element = multiplier->element[j];
result_elements = &result->element[ i + j ];
/* Perform a single multiply, and add the
* resulting double-element into the result,
* carrying as necessary. The carry can
* never overflow beyond the end of the
* result, since:
*
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
__asm__ __volatile__ ( "mull %4\n\t"
"addl %%eax, (%5,%2,4)\n\t"
"adcl %%edx, 4(%5,%2,4)\n\t"
"\n1:\n\t"
"adcl $0, 8(%5,%2,4)\n\t"
"inc %2\n\t"
/* Does not affect CF */
"jc 1b\n\t"
: "=&a" ( discard_a ),
"=&d" ( discard_d ),
"=&r" ( index )
: "0" ( multiplicand_element ),
"g" ( multiplier_element ),
"r" ( result_elements ),
"2" ( 0 ) );
}
}
}
+318
View File
@@ -0,0 +1,318 @@
#ifndef _BITS_BIGINT_H
#define _BITS_BIGINT_H
/** @file
*
* Big integer support
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <string.h>
/** Element of a big integer */
typedef uint32_t bigint_element_t;
/**
* Initialise big integer
*
* @v value0 Element 0 of big integer to initialise
* @v size Number of elements
* @v data Raw data
* @v len Length of raw data
*/
static inline __attribute__ (( always_inline )) void
bigint_init_raw ( uint32_t *value0, unsigned int size,
const void *data, size_t len ) {
long pad_len = ( sizeof ( bigint_t ( size ) ) - len );
void *discard_D;
long discard_c;
/* Copy raw data in reverse order, padding with zeros */
__asm__ __volatile__ ( "\n1:\n\t"
"movb -1(%2,%1), %%al\n\t"
"stosb\n\t"
"loop 1b\n\t"
"xorl %%eax, %%eax\n\t"
"mov %3, %1\n\t"
"rep stosb\n\t"
: "=&D" ( discard_D ), "=&c" ( discard_c )
: "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
"1" ( len )
: "eax" );
}
/**
* Add big integers
*
* @v addend0 Element 0 of big integer to add
* @v value0 Element 0 of big integer to be added to
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
unsigned int size ) {
long index;
void *discard_S;
long discard_c;
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
"\n1:\n\t"
"lodsl\n\t"
"adcl %%eax, (%3,%0,4)\n\t"
"inc %0\n\t" /* Does not affect CF */
"loop 1b\n\t"
: "=&r" ( index ), "=&S" ( discard_S ),
"=&c" ( discard_c )
: "r" ( value0 ), "1" ( addend0 ), "2" ( size )
: "eax" );
}
/**
* Subtract big integers
*
* @v subtrahend0 Element 0 of big integer to subtract
* @v value0 Element 0 of big integer to be subtracted from
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
unsigned int size ) {
long index;
void *discard_S;
long discard_c;
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
"\n1:\n\t"
"lodsl\n\t"
"sbbl %%eax, (%3,%0,4)\n\t"
"inc %0\n\t" /* Does not affect CF */
"loop 1b\n\t"
: "=&r" ( index ), "=&S" ( discard_S ),
"=&c" ( discard_c )
: "r" ( value0 ), "1" ( subtrahend0 ),
"2" ( size )
: "eax" );
}
/**
* Rotate big integer left
*
* @v value0 Element 0 of big integer
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
long index;
long discard_c;
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
"\n1:\n\t"
"rcll $1, (%2,%0,4)\n\t"
"inc %0\n\t" /* Does not affect CF */
"loop 1b\n\t"
: "=&r" ( index ), "=&c" ( discard_c )
: "r" ( value0 ), "1" ( size ) );
}
/**
* Rotate big integer right
*
* @v value0 Element 0 of big integer
* @v size Number of elements
*/
static inline __attribute__ (( always_inline )) void
bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
long discard_c;
__asm__ __volatile__ ( "clc\n\t"
"\n1:\n\t"
"rcrl $1, -4(%1,%0,4)\n\t"
"loop 1b\n\t"
: "=&c" ( discard_c )
: "r" ( value0 ), "0" ( size ) );
}
/**
* Test if big integer is equal to zero
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @ret is_zero Big integer is equal to zero
*/
static inline __attribute__ (( always_inline, pure )) int
bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) {
void *discard_D;
long discard_c;
int result;
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Set ZF */
"repe scasl\n\t"
"sete %b0\n\t"
: "=&a" ( result ), "=&D" ( discard_D ),
"=&c" ( discard_c )
: "1" ( value0 ), "2" ( size ) );
return result;
}
/**
* Compare big integers
*
* @v value0 Element 0 of big integer
* @v reference0 Element 0 of reference big integer
* @v size Number of elements
* @ret geq Big integer is greater than or equal to the reference
*/
static inline __attribute__ (( always_inline, pure )) int
bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0,
unsigned int size ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( const void * ) value0 );
const bigint_t ( size ) __attribute__ (( may_alias )) *reference =
( ( const void * ) reference0 );
void *discard_S;
void *discard_D;
long discard_c;
int result;
__asm__ __volatile__ ( "std\n\t"
"\n1:\n\t"
"lodsl\n\t"
"scasl\n\t"
"loope 1b\n\t"
"setae %b0\n\t"
"cld\n\t"
: "=q" ( result ), "=&S" ( discard_S ),
"=&D" ( discard_D ), "=&c" ( discard_c )
: "0" ( 0 ), "1" ( &value->element[ size - 1 ] ),
"2" ( &reference->element[ size - 1 ] ),
"3" ( size )
: "eax" );
return result;
}
/**
* Test if bit is set in big integer
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @v bit Bit to test
* @ret is_set Bit is set
*/
static inline __attribute__ (( always_inline )) int
bigint_bit_is_set_raw ( const uint32_t *value0, unsigned int size,
unsigned int bit ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *value =
( ( const void * ) value0 );
unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
return ( value->element[index] & ( 1 << subindex ) );
}
/**
* Find highest bit set in big integer
*
* @v value0 Element 0 of big integer
* @v size Number of elements
* @ret max_bit Highest bit set + 1 (or 0 if no bits set)
*/
static inline __attribute__ (( always_inline )) int
bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
long discard_c;
int result;
__asm__ __volatile__ ( "\n1:\n\t"
"bsrl -4(%2,%1,4), %0\n\t"
"loopz 1b\n\t"
"rol %1\n\t" /* Does not affect ZF */
"rol %1\n\t"
"leal 1(%k0,%k1,8), %k0\n\t"
"jnz 2f\n\t"
"xor %0, %0\n\t"
"\n2:\n\t"
: "=&r" ( result ), "=&c" ( discard_c )
: "r" ( value0 ), "1" ( size ) );
return result;
}
/**
* Grow big integer
*
* @v source0 Element 0 of source big integer
* @v source_size Number of elements in source big integer
* @v dest0 Element 0 of destination big integer
* @v dest_size Number of elements in destination big integer
*/
static inline __attribute__ (( always_inline )) void
bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
uint32_t *dest0, unsigned int dest_size ) {
long pad_size = ( dest_size - source_size );
void *discard_D;
void *discard_S;
long discard_c;
__asm__ __volatile__ ( "rep movsl\n\t"
"xorl %%eax, %%eax\n\t"
"mov %3, %2\n\t"
"rep stosl\n\t"
: "=&D" ( discard_D ), "=&S" ( discard_S ),
"=&c" ( discard_c )
: "g" ( pad_size ), "0" ( dest0 ),
"1" ( source0 ), "2" ( source_size )
: "eax" );
}
/**
* Shrink big integer
*
* @v source0 Element 0 of source big integer
* @v source_size Number of elements in source big integer
* @v dest0 Element 0 of destination big integer
* @v dest_size Number of elements in destination big integer
*/
static inline __attribute__ (( always_inline )) void
bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
uint32_t *dest0, unsigned int dest_size ) {
void *discard_D;
void *discard_S;
long discard_c;
__asm__ __volatile__ ( "rep movsl\n\t"
: "=&D" ( discard_D ), "=&S" ( discard_S ),
"=&c" ( discard_c )
: "0" ( dest0 ), "1" ( source0 ),
"2" ( dest_size )
: "eax" );
}
/**
* Finalise big integer
*
* @v value0 Element 0 of big integer to finalise
* @v size Number of elements
* @v out Output buffer
* @v len Length of output buffer
*/
static inline __attribute__ (( always_inline )) void
bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
void *out, size_t len ) {
void *discard_D;
long discard_c;
/* Copy raw data in reverse order */
__asm__ __volatile__ ( "\n1:\n\t"
"movb -1(%2,%1), %%al\n\t"
"stosb\n\t"
"loop 1b\n\t"
: "=&D" ( discard_D ), "=&c" ( discard_c )
: "r" ( value0 ), "0" ( out ), "1" ( len )
: "eax" );
}
extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
const uint32_t *multiplier0,
uint32_t *value0, unsigned int size );
#endif /* _BITS_BIGINT_H */
+1 -1
View File
@@ -22,4 +22,4 @@ _linux_start:
movq $__NR_exit, %rax
syscall
.size _start, . - _start
.size _linux_start, . - _linux_start
+25
View File
@@ -1,22 +1,47 @@
#ifndef _BITS_BYTESWAP_H
#define _BITS_BYTESWAP_H
/** @file
*
* Byte-order swapping functions
*
*/
#include <stdint.h>
FILE_LICENCE ( GPL2_OR_LATER );
static inline __attribute__ (( always_inline, const )) uint16_t
__bswap_variable_16 ( uint16_t x ) {
__asm__ ( "xchgb %b0,%h0" : "=Q" ( x ) : "0" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_16s ( uint16_t *x ) {
__asm__ ( "rorw $8, %0" : "+m" ( *x ) );
}
static inline __attribute__ (( always_inline, const )) uint32_t
__bswap_variable_32 ( uint32_t x ) {
__asm__ ( "bswapl %k0" : "=r" ( x ) : "0" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_32s ( uint32_t *x ) {
__asm__ ( "bswapl %k0" : "=r" ( *x ) : "0" ( *x ) );
}
static inline __attribute__ (( always_inline, const )) uint64_t
__bswap_variable_64 ( uint64_t x ) {
__asm__ ( "bswapq %q0" : "=r" ( x ) : "0" ( x ) );
return x;
}
static inline __attribute__ (( always_inline )) void
__bswap_64s ( uint64_t *x ) {
__asm__ ( "bswapq %q0" : "=r" ( *x ) : "0" ( *x ) );
}
#endif /* _BITS_BYTESWAP_H */
+12
View File
@@ -0,0 +1,12 @@
#ifndef _BITS_ENTROPY_H
#define _BITS_ENTROPY_H
/** @file
*
* x86_64-specific entropy API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#endif /* _BITS_ENTROPY_H */
+12
View File
@@ -0,0 +1,12 @@
#ifndef _BITS_TIME_H
#define _BITS_TIME_H
/** @file
*
* x86_64-specific time API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#endif /* _BITS_TIME_H */
+16 -16
View File
@@ -71,21 +71,24 @@ REQUIRE_OBJECT ( serial_console );
#ifdef CONSOLE_DIRECT_VGA
REQUIRE_OBJECT ( video_subr );
#endif
#ifdef CONSOLE_BTEXT
REQUIRE_OBJECT ( btext );
#endif
#ifdef CONSOLE_PC_KBD
REQUIRE_OBJECT ( pc_kbd );
#endif
#ifdef CONSOLE_SYSLOG
REQUIRE_OBJECT ( syslog );
#endif
#ifdef CONSOLE_SYSLOGS
REQUIRE_OBJECT ( syslogs );
#endif
#ifdef CONSOLE_EFI
REQUIRE_OBJECT ( efi_console );
#endif
#ifdef CONSOLE_LINUX
REQUIRE_OBJECT ( linux_console );
#endif
#ifdef CONSOLE_VMWARE
REQUIRE_OBJECT ( vmconsole );
#endif
/*
* Drag in all requested network protocols
@@ -122,9 +125,6 @@ REQUIRE_OBJECT ( https );
#ifdef DOWNLOAD_PROTO_FTP
REQUIRE_OBJECT ( ftp );
#endif
#ifdef DOWNLOAD_PROTO_TFTM
REQUIRE_OBJECT ( tftm );
#endif
#ifdef DOWNLOAD_PROTO_SLAM
REQUIRE_OBJECT ( slam );
#endif
@@ -155,18 +155,9 @@ REQUIRE_OBJECT ( nbi );
#ifdef IMAGE_ELF
REQUIRE_OBJECT ( elfboot );
#endif
#ifdef IMAGE_FREEBSD
REQUIRE_OBJECT ( freebsd );
#endif
#ifdef IMAGE_MULTIBOOT
REQUIRE_OBJECT ( multiboot );
#endif
#ifdef IMAGE_AOUT
REQUIRE_OBJECT ( aout );
#endif
#ifdef IMAGE_WINCE
REQUIRE_OBJECT ( wince );
#endif
#ifdef IMAGE_PXE
REQUIRE_OBJECT ( pxe_image );
#endif
@@ -214,12 +205,18 @@ REQUIRE_OBJECT ( route_cmd );
#ifdef IMAGE_CMD
REQUIRE_OBJECT ( image_cmd );
#endif
#ifdef IMAGE_TRUST_CMD
REQUIRE_OBJECT ( image_trust_cmd );
#endif
#ifdef DHCP_CMD
REQUIRE_OBJECT ( dhcp_cmd );
#endif
#ifdef SANBOOT_CMD
REQUIRE_OBJECT ( sanboot_cmd );
#endif
#ifdef MENU_CMD
REQUIRE_OBJECT ( menu_cmd );
#endif
#ifdef LOGIN_CMD
REQUIRE_OBJECT ( login_cmd );
#endif
@@ -274,13 +271,16 @@ REQUIRE_OBJECT ( tap );
#endif
/*
* Drag in relevant BOFM entry points
* Drag in relevant sideband entry points
*/
#ifdef CONFIG_BOFM
#ifdef BOFM_EFI
REQUIRE_OBJECT ( efi_bofm );
#endif /* BOFM_EFI */
#endif /* CONFIG_BOFM */
#ifdef VMWARE_SETTINGS
REQUIRE_OBJECT ( guestinfo );
#endif /* VMWARE_SETTINGS */
/*
* Drag in selected keyboard map
+4 -1
View File
@@ -17,12 +17,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
//#define CONSOLE_PCBIOS /* Default BIOS console */
//#define CONSOLE_SERIAL /* Serial port */
//#define CONSOLE_DIRECT_VGA /* Direct access to VGA card */
//#define CONSOLE_BTEXT /* Who knows what this does? */
//#define CONSOLE_PC_KBD /* Direct access to PC keyboard */
//#define CONSOLE_SYSLOG /* Syslog console */
//#define CONSOLE_SYSLOGS /* Encrypted syslog console */
//#define CONSOLE_VMWARE /* VMware logfile console */
#define KEYBOARD_MAP us
#define LOG_LEVEL LOG_NONE
#include <config/local/console.h>
#endif /* CONFIG_CONSOLE_H */
+2
View File
@@ -17,6 +17,8 @@
#define SMBIOS_EFI
#define SANBOOT_NULL
#define BOFM_EFI
#define ENTROPY_NULL
#define TIME_NULL
#define IMAGE_EFI /* EFI image support */
#define IMAGE_SCRIPT /* iPXE script image support */
+2
View File
@@ -14,6 +14,8 @@
#define NAP_LINUX
#define SMBIOS_LINUX
#define SANBOOT_NULL
#define ENTROPY_LINUX
#define TIME_LINUX
#define DRIVERS_LINUX
+2 -1
View File
@@ -18,13 +18,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define UMALLOC_MEMTOP
#define SMBIOS_PCBIOS
#define SANBOOT_PCBIOS
#define ENTROPY_RTC
#define TIME_RTC
#define IMAGE_ELF /* ELF image support */
#define IMAGE_MULTIBOOT /* MultiBoot image support */
#define IMAGE_PXE /* PXE image support */
#define IMAGE_SCRIPT /* iPXE script image support */
#define IMAGE_BZIMAGE /* Linux bzImage image support */
#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
#define PXE_STACK /* PXE stack in iPXE - required for PXELINUX */
#define PXE_MENU /* PXE menu booting */
+16
View File
@@ -0,0 +1,16 @@
#ifndef CONFIG_ENTROPY_H
#define CONFIG_ENTROPY_H
/** @file
*
* Entropy API configuration
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <config/defaults.h>
#include <config/local/entropy.h>
#endif /* CONFIG_ENTROPY_H */
+2 -4
View File
@@ -58,7 +58,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
#undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */
#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */
#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */
/*
@@ -95,10 +94,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
#undef IMAGE_NBI /* NBI image support */
//#define IMAGE_ELF /* ELF image support */
#undef IMAGE_FREEBSD /* FreeBSD kernel image support */
#undef IMAGE_MULTIBOOT /* MultiBoot image support */
#undef IMAGE_AOUT /* a.out image support */
#undef IMAGE_WINCE /* WinCE image support */
//#define IMAGE_PXE /* PXE image support */
//#define IMAGE_SCRIPT /* iPXE script image support */
//#define IMAGE_BZIMAGE /* Linux bzImage image support */
@@ -119,6 +115,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define IMAGE_CMD /* Image management commands */
#undef DHCP_CMD /* DHCP management commands */
#define SANBOOT_CMD /* SAN boot commands */
#undef MENU_CMD /* Menu commands */
#undef LOGIN_CMD /* Login command */
#undef TIME_CMD /* Time commands */
#undef DIGEST_CMD /* Image crypto digest commands */
@@ -126,6 +123,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#undef VLAN_CMD /* VLAN commands */
#undef PXE_CMD /* PXE commands */
#undef REBOOT_CMD /* Reboot command */
#define IMAGE_TRUST_CMD /* Image trust management commands */
/*
* ROM-specific options
+1
View File
@@ -10,5 +10,6 @@
FILE_LICENCE ( GPL2_OR_LATER );
//#define CONFIG_BOFM /* IBM's BladeCenter Open Fabric Manager */
//#define VMWARE_SETTINGS /* VMware GuestInfo settings */
#endif /* CONFIG_SIDEBAND_H */
+16
View File
@@ -0,0 +1,16 @@
#ifndef CONFIG_TIME_H
#define CONFIG_TIME_H
/** @file
*
* Time API configuration
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <config/defaults.h>
#include <config/local/time.h>
#endif /* CONFIG_TIME_H */
-5039
View File
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -7,6 +7,9 @@
FILE_LICENCE ( GPL2_OR_LATER );
/** Current console usage */
int console_usage = CONSOLE_USAGE_STDOUT;
/**
* Write a single character to each console device.
*
@@ -26,7 +29,9 @@ void putchar ( int character ) {
putchar ( '\r' );
for_each_table_entry ( console, CONSOLES ) {
if ( ( ! console->disabled ) && console->putchar )
if ( ( ! console->disabled ) &&
( console_usage & console->usage ) &&
console->putchar )
console->putchar ( character );
}
}
+37 -16
View File
@@ -21,17 +21,38 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <ipxe/io.h>
#include <ipxe/console.h>
/**
* Print debug message
*
* @v fmt Format string
* @v ... Arguments
*/
void dbg_printf ( const char *fmt, ... ) {
int saved_usage;
va_list args;
/* Mark console as in use for debugging messages */
saved_usage = console_set_usage ( CONSOLE_USAGE_DEBUG );
/* Print message */
va_start ( args, fmt );
vprintf ( fmt, args );
va_end ( args );
/* Restore console usage */
console_set_usage ( saved_usage );
}
/**
* Pause until a key is pressed
*
*/
void dbg_pause ( void ) {
printf ( "\nPress a key..." );
dbg_printf ( "\nPress a key..." );
getchar();
printf ( "\r \r" );
dbg_printf ( "\r \r" );
}
/**
@@ -39,9 +60,9 @@ void dbg_pause ( void ) {
*
*/
void dbg_more ( void ) {
printf ( "---more---" );
dbg_printf ( "---more---" );
getchar();
printf ( "\r \r" );
dbg_printf ( "\r \r" );
}
/**
@@ -58,27 +79,27 @@ static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data,
unsigned int i;
uint8_t byte;
printf ( "%08lx :", ( dispaddr + offset ) );
dbg_printf ( "%08lx :", ( dispaddr + offset ) );
for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
if ( i >= len ) {
printf ( " " );
dbg_printf ( " " );
continue;
}
printf ( "%c%02x",
( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] );
dbg_printf ( "%c%02x",
( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] );
}
printf ( " : " );
dbg_printf ( " : " );
for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
if ( i >= len ) {
printf ( " " );
dbg_printf ( " " );
continue;
}
byte = bytes[i];
if ( ( byte < 0x20 ) || ( byte >= 0x7f ) )
byte = '.';
printf ( "%c", byte );
dbg_printf ( "%c", byte );
}
printf ( "\n" );
dbg_printf ( "\n" );
}
/**
@@ -158,8 +179,8 @@ static int dbg_autocolour ( unsigned long stream ) {
* @v stream Message stream ID
*/
void dbg_autocolourise ( unsigned long stream ) {
printf ( "\033[%dm",
( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) );
dbg_printf ( "\033[%dm",
( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) );
}
/**
@@ -167,5 +188,5 @@ void dbg_autocolourise ( unsigned long stream ) {
*
*/
void dbg_decolourise ( void ) {
printf ( "\033[0m" );
dbg_printf ( "\033[0m" );
}
+13 -1
View File
@@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <syslog.h>
#include <ipxe/iobuf.h>
#include <ipxe/xfer.h>
#include <ipxe/open.h>
@@ -73,6 +74,15 @@ static void downloader_free ( struct refcnt *refcnt ) {
*/
static void downloader_finished ( struct downloader *downloader, int rc ) {
/* Log download status */
if ( rc == 0 ) {
syslog ( LOG_NOTICE, "Downloaded \"%s\"\n",
downloader->image->name );
} else {
syslog ( LOG_ERR, "Download of \"%s\" failed: %s\n",
downloader->image->name, strerror ( rc ) );
}
/* Shut down interfaces */
intf_shutdown ( &downloader->xfer, rc );
intf_shutdown ( &downloader->job, rc );
@@ -101,7 +111,7 @@ static int downloader_ensure_size ( struct downloader *downloader,
if ( ! new_buffer ) {
DBGC ( downloader, "Downloader %p could not extend buffer to "
"%zd bytes\n", downloader, len );
return -ENOBUFS;
return -ENOSPC;
}
downloader->image->data = new_buffer;
downloader->image->len = len;
@@ -173,6 +183,8 @@ static int downloader_xfer_deliver ( struct downloader *downloader,
done:
free_iob ( iobuf );
if ( rc != 0 )
downloader_finished ( downloader, rc );
return rc;
}
+106 -22
View File
@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <errno.h>
#include <assert.h>
#include <libgen.h>
#include <syslog.h>
#include <ipxe/list.h>
#include <ipxe/umalloc.h>
#include <ipxe/uri.h>
@@ -36,12 +37,28 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
/* Disambiguate the various error causes */
#define EACCES_UNTRUSTED \
__einfo_error ( EINFO_EACCES_UNTRUSTED )
#define EINFO_EACCES_UNTRUSTED \
__einfo_uniqify ( EINFO_EACCES, 0x01, "Untrusted image" )
#define EACCES_PERMANENT \
__einfo_error ( EINFO_EACCES_PERMANENT )
#define EINFO_EACCES_PERMANENT \
__einfo_uniqify ( EINFO_EACCES, 0x02, "Trust requirement is permanent" )
/** List of registered images */
struct list_head images = LIST_HEAD_INIT ( images );
/** Currently-executing image */
struct image *current_image;
/** Current image trust requirement */
static int require_trusted_images = 0;
/** Prevent changes to image trust requirement */
static int require_trusted_images_permanent = 0;
/**
* Free executable image
*
@@ -50,48 +67,70 @@ struct image *current_image;
static void free_image ( struct refcnt *refcnt ) {
struct image *image = container_of ( refcnt, struct image, refcnt );
DBGC ( image, "IMAGE %s freed\n", image->name );
free ( image->name );
free ( image->cmdline );
uri_put ( image->uri );
ufree ( image->data );
image_put ( image->replacement );
free ( image );
DBGC ( image, "IMAGE %s freed\n", image->name );
}
/**
* Allocate executable image
*
* @v uri URI, or NULL
* @ret image Executable image
*/
struct image * alloc_image ( void ) {
struct image * alloc_image ( struct uri *uri ) {
const char *name;
struct image *image;
int rc;
/* Allocate image */
image = zalloc ( sizeof ( *image ) );
if ( image ) {
ref_init ( &image->refcnt, free_image );
if ( ! image )
goto err_alloc;
/* Initialise image */
ref_init ( &image->refcnt, free_image );
if ( uri ) {
image->uri = uri_get ( uri );
if ( uri->path ) {
name = basename ( ( char * ) uri->path );
if ( ( rc = image_set_name ( image, name ) ) != 0 )
goto err_set_name;
}
}
return image;
err_set_name:
image_put ( image );
err_alloc:
return NULL;
}
/**
* Set image URI
* Set image name
*
* @v image Image
* @v URI New image URI
*
* If no name is set, the name will be updated to the base name of the
* URI path (if any).
* @v name New image name
* @ret rc Return status code
*/
void image_set_uri ( struct image *image, struct uri *uri ) {
const char *path = uri->path;
int image_set_name ( struct image *image, const char *name ) {
char *name_copy;
/* Replace URI reference */
uri_put ( image->uri );
image->uri = uri_get ( uri );
/* Duplicate name */
name_copy = strdup ( name );
if ( ! name_copy )
return -ENOMEM;
/* Set name if none already specified */
if ( path && ( ! image->name[0] ) )
image_set_name ( image, basename ( ( char * ) path ) );
/* Replace existing name */
free ( image->name );
image->name = name_copy;
return 0;
}
/**
@@ -121,11 +160,14 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
*/
int register_image ( struct image *image ) {
static unsigned int imgindex = 0;
char name[8]; /* "imgXXXX" */
int rc;
/* Create image name if it doesn't already have one */
if ( ! image->name[0] ) {
snprintf ( image->name, sizeof ( image->name ), "img%d",
imgindex++ );
if ( ! image->name ) {
snprintf ( name, sizeof ( name ), "img%d", imgindex++ );
if ( ( rc = image_set_name ( image, name ) ) != 0 )
return rc;
}
/* Avoid ending up with multiple "selected" images on
@@ -228,6 +270,12 @@ int image_exec ( struct image *image ) {
if ( ( rc = image_select ( image ) ) != 0 )
return rc;
/* Check that image is trusted (if applicable) */
if ( require_trusted_images && ! ( image->flags & IMAGE_TRUSTED ) ) {
DBGC ( image, "IMAGE %s is not trusted\n", image->name );
return -EACCES_UNTRUSTED;
}
/* Switch current working directory to be that of the image itself */
old_cwuri = uri_get ( cwuri );
churi ( image->uri );
@@ -241,6 +289,9 @@ int image_exec ( struct image *image ) {
*/
current_image = image_get ( image );
/* Record boot attempt */
syslog ( LOG_NOTICE, "Executing \"%s\"\n", image->name );
/* Try executing the image */
if ( ( rc = image->type->exec ( image ) ) != 0 ) {
DBGC ( image, "IMAGE %s could not execute: %s\n",
@@ -248,6 +299,15 @@ int image_exec ( struct image *image ) {
/* Do not return yet; we still have clean-up to do */
}
/* Record result of boot attempt */
if ( rc == 0 ) {
syslog ( LOG_NOTICE, "Execution of \"%s\" completed\n",
image->name );
} else {
syslog ( LOG_ERR, "Execution of \"%s\" failed: %s\n",
image->name, strerror ( rc ) );
}
/* Pick up replacement image before we drop the original
* image's temporary reference. The replacement image must
* already be registered, so we don't need to hold a temporary
@@ -269,8 +329,8 @@ int image_exec ( struct image *image ) {
/* Tail-recurse into replacement image, if one exists */
if ( replacement ) {
DBGC ( image, "IMAGE %s replacing self with IMAGE %s\n",
image->name, replacement->name );
DBGC ( image, "IMAGE <freed> replacing self with IMAGE %s\n",
replacement->name );
if ( ( rc = image_exec ( replacement ) ) != 0 )
return rc;
}
@@ -355,3 +415,27 @@ struct image * image_find_selected ( void ) {
}
return NULL;
}
/**
* Change image trust requirement
*
* @v require_trusted Require trusted images
* @v permanent Make trust requirement permanent
* @ret rc Return status code
*/
int image_set_trust ( int require_trusted, int permanent ) {
/* Update trust requirement, if permitted to do so */
if ( ! require_trusted_images_permanent ) {
require_trusted_images = require_trusted;
require_trusted_images_permanent = permanent;
}
/* Fail if we attempted to change the trust requirement but
* were not permitted to do so.
*/
if ( require_trusted_images != require_trusted )
return -EACCES_PERMANENT;
return 0;
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Line-based console
*
*/
#include <stdint.h>
#include <stddef.h>
#include <ipxe/ansiesc.h>
#include <ipxe/lineconsole.h>
/**
* Print a character to a line-based console
*
* @v character Character to be printed
* @ret print Print line
*/
size_t line_putchar ( struct line_console *line, int character ) {
/* Strip ANSI escape sequences */
character = ansiesc_process ( &line->ctx, character );
if ( character < 0 )
return 0;
/* Ignore carriage return */
if ( character == '\r' )
return 0;
/* Treat newline as a terminator */
if ( character == '\n' )
character = 0;
/* Add character to buffer */
line->buffer[line->index++] = character;
/* Do nothing more unless we reach end-of-line (or end-of-buffer) */
if ( ( character != 0 ) &&
( line->index < ( line->len - 1 /* NUL */ ) ) ) {
return 0;
}
/* Reset to start of buffer */
line->index = 0;
return 1;
}
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* System logger
*
*/
#include <stdarg.h>
#include <syslog.h>
#include <ipxe/console.h>
/**
* Write message to system log
*
* @v fmt Format string
* @v args Arguments
*/
void log_vprintf ( const char *fmt, va_list args ) {
int saved_usage;
/* Mark console as in use for log messages */
saved_usage = console_set_usage ( CONSOLE_USAGE_LOG );
/* Print message */
vprintf ( fmt, args );
/* Restore console usage */
console_set_usage ( saved_usage );
}
/**
* Write message to system log
*
* @v fmt Format string
* @v ... Arguments
*/
void log_printf ( const char *fmt, ... ) {
va_list args;
va_start ( args, fmt );
log_vprintf ( fmt, args );
va_end ( args );
}
+92 -11
View File
@@ -105,11 +105,36 @@ static char heap[HEAP_SIZE] __attribute__ (( aligned ( __alignof__(void *) )));
static inline void valgrind_make_blocks_defined ( void ) {
struct memory_block *block;
if ( RUNNING_ON_VALGRIND > 0 ) {
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks,
sizeof ( free_blocks ) );
list_for_each_entry ( block, &free_blocks, list )
VALGRIND_MAKE_MEM_DEFINED ( block, sizeof ( *block ) );
if ( RUNNING_ON_VALGRIND <= 0 )
return;
/* Traverse free block list, marking each block structure as
* defined. Some contortions are necessary to avoid errors
* from list_check().
*/
/* Mark block list itself as defined */
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks, sizeof ( free_blocks ) );
/* Mark areas accessed by list_check() as defined */
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.prev->next,
sizeof ( free_blocks.prev->next ) );
VALGRIND_MAKE_MEM_DEFINED ( free_blocks.next,
sizeof ( *free_blocks.next ) );
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.next->next->prev,
sizeof ( free_blocks.next->next->prev ) );
/* Mark each block in list as defined */
list_for_each_entry ( block, &free_blocks, list ) {
/* Mark block as defined */
VALGRIND_MAKE_MEM_DEFINED ( block, sizeof ( *block ) );
/* Mark areas accessed by list_check() as defined */
VALGRIND_MAKE_MEM_DEFINED ( block->list.next,
sizeof ( *block->list.next ) );
VALGRIND_MAKE_MEM_DEFINED ( &block->list.next->next->prev,
sizeof ( block->list.next->next->prev ) );
}
}
@@ -119,14 +144,45 @@ static inline void valgrind_make_blocks_defined ( void ) {
*/
static inline void valgrind_make_blocks_noaccess ( void ) {
struct memory_block *block;
struct memory_block *tmp;
struct memory_block *prev = NULL;
if ( RUNNING_ON_VALGRIND > 0 ) {
list_for_each_entry_safe ( block, tmp, &free_blocks, list )
VALGRIND_MAKE_MEM_NOACCESS ( block, sizeof ( *block ) );
VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks,
sizeof ( free_blocks ) );
if ( RUNNING_ON_VALGRIND <= 0 )
return;
/* Traverse free block list, marking each block structure as
* inaccessible. Some contortions are necessary to avoid
* errors from list_check().
*/
/* Mark each block in list as inaccessible */
list_for_each_entry ( block, &free_blocks, list ) {
/* Mark previous block (if any) as inaccessible. (Current
* block will be accessed by list_check().)
*/
if ( prev )
VALGRIND_MAKE_MEM_NOACCESS ( prev, sizeof ( *prev ) );
prev = block;
/* At the end of the list, list_check() will end up
* accessing the first list item. Temporarily mark
* this area as defined.
*/
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.next->prev,
sizeof ( free_blocks.next->prev ) );
}
/* Mark last block (if any) as inaccessible */
if ( prev )
VALGRIND_MAKE_MEM_NOACCESS ( prev, sizeof ( *prev ) );
/* Mark as inaccessible the area that was temporarily marked
* as defined to avoid errors from list_check().
*/
VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks.next->prev,
sizeof ( free_blocks.next->prev ) );
/* Mark block list itself as inaccessible */
VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
}
/**
@@ -144,6 +200,18 @@ static unsigned int discard_cache ( void ) {
return discarded;
}
/**
* Discard all cached data
*
*/
static void discard_all_cache ( void ) {
unsigned int discarded;
do {
discarded = discard_cache();
} while ( discarded );
}
/**
* Allocate a memory block
*
@@ -458,6 +526,19 @@ struct init_fn heap_init_fn __init_fn ( INIT_EARLY ) = {
.initialise = init_heap,
};
/**
* Discard all cached data on shutdown
*
*/
static void shutdown_cache ( int booting __unused ) {
discard_all_cache();
}
/** Memory allocator shutdown function */
struct startup_fn heap_startup_fn __startup_fn ( STARTUP_EARLY ) = {
.shutdown = shutdown_cache,
};
#if 0
#include <stdio.h>
/**
+177
View File
@@ -0,0 +1,177 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Menu selection
*
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ipxe/list.h>
#include <ipxe/menu.h>
/** List of all menus */
static LIST_HEAD ( menus );
/**
* Create menu
*
* @v name Menu name, or NULL
* @v title Menu title, or NULL
* @ret menu Menu, or NULL on failure
*/
struct menu * create_menu ( const char *name, const char *title ) {
size_t name_len;
size_t title_len;
size_t len;
struct menu *menu;
char *name_copy;
char *title_copy;
/* Destroy any existing menu of this name */
menu = find_menu ( name );
if ( menu )
destroy_menu ( menu );
/* Use empty title if none given */
if ( ! title )
title = "";
/* Allocate menu */
name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 );
title_len = ( strlen ( title ) + 1 /* NUL */ );
len = ( sizeof ( *menu ) + name_len + title_len );
menu = zalloc ( len );
if ( ! menu )
return NULL;
name_copy = ( ( void * ) ( menu + 1 ) );
title_copy = ( name_copy + name_len );
/* Initialise menu */
if ( name ) {
strcpy ( name_copy, name );
menu->name = name_copy;
}
strcpy ( title_copy, title );
menu->title = title_copy;
INIT_LIST_HEAD ( &menu->items );
/* Add to list of menus */
list_add_tail ( &menu->list, &menus );
DBGC ( menu, "MENU %s created with title \"%s\"\n",
menu->name, menu->title );
return menu;
}
/**
* Add menu item
*
* @v menu Menu
* @v label Label, or NULL
* @v text Text, or NULL
* @v shortcut Shortcut key
* @v is_default Item is the default item
* @ret item Menu item, or NULL on failure
*/
struct menu_item * add_menu_item ( struct menu *menu, const char *label,
const char *text, int shortcut,
int is_default ) {
size_t label_len;
size_t text_len;
size_t len;
struct menu_item *item;
char *label_copy;
char *text_copy;
/* Use empty text if none given */
if ( ! text )
text = "";
/* Allocate item */
label_len = ( label ? ( strlen ( label ) + 1 /* NUL */ ) : 0 );
text_len = ( strlen ( text ) + 1 /* NUL */ );
len = ( sizeof ( *item ) + label_len + text_len );
item = zalloc ( len );
if ( ! item )
return NULL;
label_copy = ( ( void * ) ( item + 1 ) );
text_copy = ( label_copy + label_len );
/* Initialise item */
if ( label ) {
strcpy ( label_copy, label );
item->label = label_copy;
}
strcpy ( text_copy, text );
item->text = text_copy;
item->shortcut = shortcut;
item->is_default = is_default;
/* Add to list of items */
list_add_tail ( &item->list, &menu->items );
return item;
}
/**
* Destroy menu
*
* @v menu Menu
*/
void destroy_menu ( struct menu *menu ) {
struct menu_item *item;
struct menu_item *tmp;
/* Remove from list of menus */
list_del ( &menu->list );
/* Free items */
list_for_each_entry_safe ( item, tmp, &menu->items, list ) {
list_del ( &item->list );
free ( item );
}
/* Free menu */
free ( menu );
}
/**
* Find menu
*
* @v name Menu name, or NULL
* @ret menu Menu, or NULL if not found
*/
struct menu * find_menu ( const char *name ) {
struct menu *menu;
list_for_each_entry ( menu, &menus, list ) {
if ( ( menu->name == name ) ||
( strcmp ( menu->name, name ) == 0 ) ) {
return menu;
}
}
return NULL;
}
+12
View File
@@ -35,8 +35,17 @@ int inet_aton ( const char *cp, struct in_addr *inp ) {
unsigned long strtoul ( const char *p, char **endp, int base ) {
unsigned long ret = 0;
int negative = 0;
unsigned int charval;
while ( isspace ( *p ) )
p++;
if ( *p == '-' ) {
negative = 1;
p++;
}
base = strtoul_base ( &p, base );
while ( 1 ) {
@@ -47,6 +56,9 @@ unsigned long strtoul ( const char *p, char **endp, int base ) {
p++;
}
if ( negative )
ret = -ret;
if ( endp )
*endp = ( char * ) p;
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Nonexistent time source
*
*/
#include <ipxe/time.h>
PROVIDE_TIME_INLINE ( null, time_now );
+31 -11
View File
@@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <errno.h>
#include <getopt.h>
#include <ipxe/netdevice.h>
#include <ipxe/image.h>
#include <ipxe/menu.h>
#include <ipxe/parseopt.h>
/** @file
@@ -115,21 +115,22 @@ int parse_netdev ( const char *text, struct net_device **netdev ) {
}
/**
* Parse image name
* Parse menu name
*
* @v text Text
* @ret image Image
* @ret menu Menu
* @ret rc Return status code
*/
int parse_image ( const char *text, struct image **image ) {
int parse_menu ( const char *text, struct menu **menu ) {
/* Sanity check */
assert ( text != NULL );
/* Find network device */
*image = find_image ( text );
if ( ! *image ) {
printf ( "\"%s\": no such image\n", text );
/* Find menu */
*menu = find_menu ( text );
if ( ! *menu ) {
if ( text ) {
printf ( "\"%s\": no such menu\n", text );
} else {
printf ( "No default menu\n" );
}
return -ENOENT;
}
@@ -151,6 +152,25 @@ int parse_flag ( const char *text __unused, int *flag ) {
return 0;
}
/**
* Parse key
*
* @v text Text
* @ret key Key
* @ret rc Return status code
*/
int parse_key ( const char *text, unsigned int *key ) {
/* Interpret single characters as being a literal key character */
if ( text[0] && ! text[1] ) {
*key = text[0];
return 0;
}
/* Otherwise, interpret as an integer */
return parse_integer ( text, key );
}
/**
* Print command usage message
*
-1
View File
@@ -34,7 +34,6 @@ FILE_LICENCE ( GPL2_ONLY );
#define CODE_STATUS "alpha"
#define CODE_VERSION "0.1.3"
#include <pcmcia-opts.h>
#include <ipxe/console.h>
#include <ipxe/init.h>
int sockets; /* AHTODO: Phase this out! */
+8
View File
@@ -1,6 +1,7 @@
#include <ipxe/init.h>
#include <ipxe/serial.h>
#include <ipxe/console.h>
#include <config/console.h>
/** @file
*
@@ -8,6 +9,12 @@
*
*/
/* Set default console usage if applicable */
#if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) )
#undef CONSOLE_SERIAL
#define CONSOLE_SERIAL ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
#endif
struct console_driver serial_console __console_driver;
static void serial_console_init ( void ) {
@@ -21,6 +28,7 @@ struct console_driver serial_console __console_driver = {
.getchar = serial_getc,
.iskey = serial_ischar,
.disabled = 1,
.usage = CONSOLE_SERIAL,
};
/**
+384 -241
View File
@@ -676,6 +676,46 @@ int fetch_setting_len ( struct settings *settings, struct setting *setting ) {
return fetch_setting ( settings, setting, NULL, 0 );
}
/**
* Fetch copy of setting
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v data Buffer to allocate and fill with setting data
* @ret len Length of setting, or negative error
*
* The caller is responsible for eventually freeing the allocated
* buffer.
*
* To allow the caller to distinguish between a non-existent setting
* and an error in allocating memory for the copy, this function will
* return success (and a NULL buffer pointer) for a non-existent
* setting.
*/
int fetch_setting_copy ( struct settings *settings, struct setting *setting,
void **data ) {
int len;
int check_len = 0;
/* Avoid returning uninitialised data on error */
*data = NULL;
/* Fetch setting length, and return success if non-existent */
len = fetch_setting_len ( settings, setting );
if ( len < 0 )
return 0;
/* Allocate buffer */
*data = malloc ( len );
if ( ! *data )
return -ENOMEM;
/* Fetch setting */
check_len = fetch_setting ( settings, setting, *data, len );
assert ( check_len == len );
return len;
}
/**
* Fetch value of string setting
*
@@ -776,6 +816,41 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
return fetch_ipv4_array_setting ( settings, setting, inp, 1 );
}
/**
* Extract numeric value of setting
*
* @v raw Raw setting data
* @v len Length of raw setting data
* @ret signed_value Value, when interpreted as a signed integer
* @ret unsigned_value Value, when interpreted as an unsigned integer
* @ret len Length of setting, or negative error
*/
static int numeric_setting_value ( const void *raw, size_t len,
signed long *signed_value,
unsigned long *unsigned_value ) {
const uint8_t *unsigned_bytes = raw;
const int8_t *signed_bytes = raw;
int is_negative;
unsigned int i;
uint8_t byte;
/* Range check */
if ( len > sizeof ( long ) )
return -ERANGE;
/* Convert to host-ordered longs */
is_negative = ( len && ( signed_bytes[0] < 0 ) );
*signed_value = ( is_negative ? -1L : 0 );
*unsigned_value = 0;
for ( i = 0 ; i < len ; i++ ) {
byte = unsigned_bytes[i];
*signed_value = ( ( *signed_value << 8 ) | byte );
*unsigned_value = ( ( *unsigned_value << 8 ) | byte );
}
return len;
}
/**
* Fetch value of signed integer setting
*
@@ -786,30 +861,20 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
*/
int fetch_int_setting ( struct settings *settings, struct setting *setting,
long *value ) {
union {
uint8_t u8[ sizeof ( long ) ];
int8_t s8[ sizeof ( long ) ];
} buf;
unsigned long dummy;
long tmp;
int len;
int i;
/* Avoid returning uninitialised data on error */
*value = 0;
/* Fetch raw (network-ordered, variable-length) setting */
len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) );
if ( len < 0 )
return len;
if ( len > ( int ) sizeof ( buf ) )
return -ERANGE;
/* Convert to host-ordered signed long */
*value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
for ( i = 0 ; i < len ; i++ ) {
*value = ( ( *value << 8 ) | buf.u8[i] );
}
return len;
/* Extract numeric value */
return numeric_setting_value ( &tmp, len, value, &dummy );
}
/**
@@ -822,22 +887,20 @@ int fetch_int_setting ( struct settings *settings, struct setting *setting,
*/
int fetch_uint_setting ( struct settings *settings, struct setting *setting,
unsigned long *value ) {
long svalue;
signed long dummy;
long tmp;
int len;
/* Avoid returning uninitialised data on error */
*value = 0;
/* Fetch as a signed long */
len = fetch_int_setting ( settings, setting, &svalue );
/* Fetch raw (network-ordered, variable-length) setting */
len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) );
if ( len < 0 )
return len;
/* Mask off sign-extended bits */
assert ( len <= ( int ) sizeof ( long ) );
*value = ( svalue & ( -1UL >> ( 8 * ( sizeof ( long ) - len ) ) ) );
return len;
/* Extract numeric value */
return numeric_setting_value ( &tmp, len, &dummy, value );
}
/**
@@ -929,27 +992,83 @@ int setting_cmp ( struct setting *a, struct setting *b ) {
*/
/**
* Store value of typed setting
* Fetch and format value of setting
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v type Settings type
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
int fetchf_setting ( struct settings *settings, struct setting *setting,
char *buf, size_t len ) {
int raw_len;
int check_len;
int rc;
/* Fetch raw value */
raw_len = fetch_setting_len ( settings, setting );
if ( raw_len < 0 ) {
rc = raw_len;
return rc;
} else {
uint8_t raw[raw_len];
/* Fetch raw value */
check_len = fetch_setting ( settings, setting, raw,
sizeof ( raw ) );
if ( check_len < 0 )
return check_len;
assert ( check_len == raw_len );
/* Format value */
return setting->type->format ( raw, sizeof ( raw ), buf, len );
}
}
/**
* Store formatted value of setting
*
* @v settings Settings block
* @v setting Setting to store
* @v type Settings type
* @v value Formatted setting data, or NULL
* @ret rc Return status code
*/
int storef_setting ( struct settings *settings, struct setting *setting,
const char *value ) {
int raw_len;
int check_len;
int rc;
/* NULL value implies deletion. Avoid imposing the burden of
* checking for NULL values on each typed setting's storef()
* method.
*/
/* NULL value implies deletion */
if ( ! value )
return delete_setting ( settings, setting );
return setting->type->storef ( settings, setting, value );
/* Parse formatted value */
raw_len = setting->type->parse ( value, NULL, 0 );
if ( raw_len < 0 ) {
rc = raw_len;
return rc;
} else {
uint8_t raw[raw_len];
/* Parse formatted value */
check_len = setting->type->parse ( value, raw, sizeof ( raw ) );
assert ( check_len == raw_len );
/* Store raw value */
return store_setting ( settings, setting, raw, sizeof ( raw ) );
}
}
/******************************************************************************
*
* Named settings
*
******************************************************************************
*/
/**
* Find named setting
*
@@ -1176,302 +1295,334 @@ int fetchf_named_setting ( const char *name,
*/
/**
* Parse and store value of string setting
* Parse string setting value
*
* @v settings Settings block
* @v setting Setting to store
* @v value Formatted setting data
* @ret rc Return status code
* @v value Formatted setting value
* @v buf Buffer to contain raw value
* @v len Length of buffer
* @ret len Length of raw value, or negative error
*/
static int storef_string ( struct settings *settings, struct setting *setting,
const char *value ) {
return store_setting ( settings, setting, value, strlen ( value ) );
static int parse_string_setting ( const char *value, void *buf, size_t len ) {
size_t raw_len = strlen ( value ); /* Exclude terminating NUL */
/* Copy string to buffer */
if ( len > raw_len )
len = raw_len;
memcpy ( buf, value, len );
return raw_len;
}
/**
* Fetch and format value of string setting
* Format string setting value
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v raw Raw setting value
* @v raw_len Length of raw setting value
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int fetchf_string ( struct settings *settings, struct setting *setting,
char *buf, size_t len ) {
return fetch_string_setting ( settings, setting, buf, len );
static int format_string_setting ( const void *raw, size_t raw_len, char *buf,
size_t len ) {
/* Copy string to buffer, and terminate */
memset ( buf, 0, len );
if ( len > raw_len )
len = raw_len;
memcpy ( buf, raw, len );
return raw_len;
}
/** A string setting type */
struct setting_type setting_type_string __setting_type = {
.name = "string",
.storef = storef_string,
.fetchf = fetchf_string,
.parse = parse_string_setting,
.format = format_string_setting,
};
/**
* Parse and store value of URI-encoded string setting
* Parse URI-encoded string setting value
*
* @v settings Settings block
* @v setting Setting to store
* @v value Formatted setting data
* @ret rc Return status code
* @v value Formatted setting value
* @v buf Buffer to contain raw value
* @v len Length of buffer
* @ret len Length of raw value, or negative error
*/
static int storef_uristring ( struct settings *settings,
struct setting *setting,
const char *value ) {
char buf[ strlen ( value ) + 1 ]; /* Decoding never expands string */
size_t len;
static int parse_uristring_setting ( const char *value, void *buf,
size_t len ) {
char tmp[ len + 1 /* NUL */ ];
size_t raw_len;
len = uri_decode ( value, buf, sizeof ( buf ) );
return store_setting ( settings, setting, buf, len );
/* Decode to temporary buffer (including NUL) */
raw_len = uri_decode ( value, tmp, sizeof ( tmp ) );
/* Copy to output buffer (excluding NUL) */
if ( len > raw_len )
len = raw_len;
memcpy ( buf, tmp, len );
return raw_len;
}
/**
* Fetch and format value of URI-encoded string setting
* Format URI-encoded string setting value
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v raw Raw setting value
* @v raw_len Length of raw setting value
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int fetchf_uristring ( struct settings *settings,
struct setting *setting,
char *buf, size_t len ) {
ssize_t raw_len;
static int format_uristring_setting ( const void *raw, size_t raw_len,
char *buf, size_t len ) {
char tmp[ raw_len + 1 /* NUL */ ];
/* We need to always retrieve the full raw string to know the
* length of the encoded string.
*/
raw_len = fetch_setting ( settings, setting, NULL, 0 );
if ( raw_len < 0 )
return raw_len;
/* Copy to temporary buffer and terminate */
memcpy ( tmp, raw, raw_len );
tmp[raw_len] = '\0';
{
char raw_buf[ raw_len + 1 ];
fetch_string_setting ( settings, setting, raw_buf,
sizeof ( raw_buf ) );
return uri_encode ( raw_buf, buf, len, URI_FRAGMENT );
}
/* Encode directly into output buffer */
return uri_encode ( tmp, buf, len, URI_FRAGMENT );
}
/** A URI-encoded string setting type */
struct setting_type setting_type_uristring __setting_type = {
.name = "uristring",
.storef = storef_uristring,
.fetchf = fetchf_uristring,
.parse = parse_uristring_setting,
.format = format_uristring_setting,
};
/**
* Parse and store value of IPv4 address setting
* Parse IPv4 address setting value
*
* @v settings Settings block
* @v setting Setting to store
* @v value Formatted setting data
* @ret rc Return status code
* @v value Formatted setting value
* @v buf Buffer to contain raw value
* @v len Length of buffer
* @ret len Length of raw value, or negative error
*/
static int storef_ipv4 ( struct settings *settings, struct setting *setting,
const char *value ) {
static int parse_ipv4_setting ( const char *value, void *buf, size_t len ) {
struct in_addr ipv4;
/* Parse IPv4 address */
if ( inet_aton ( value, &ipv4 ) == 0 )
return -EINVAL;
return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) );
/* Copy to buffer */
if ( len > sizeof ( ipv4 ) )
len = sizeof ( ipv4 );
memcpy ( buf, &ipv4, len );
return ( sizeof ( ipv4 ) );
}
/**
* Fetch and format value of IPv4 address setting
* Format IPv4 address setting value
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v raw Raw setting value
* @v raw_len Length of raw setting value
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int fetchf_ipv4 ( struct settings *settings, struct setting *setting,
char *buf, size_t len ) {
struct in_addr ipv4;
int raw_len;
static int format_ipv4_setting ( const void *raw, size_t raw_len, char *buf,
size_t len ) {
const struct in_addr *ipv4 = raw;
if ( ( raw_len = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0)
return raw_len;
return snprintf ( buf, len, "%s", inet_ntoa ( ipv4 ) );
if ( raw_len < sizeof ( *ipv4 ) )
return -EINVAL;
return snprintf ( buf, len, "%s", inet_ntoa ( *ipv4 ) );
}
/** An IPv4 address setting type */
struct setting_type setting_type_ipv4 __setting_type = {
.name = "ipv4",
.storef = storef_ipv4,
.fetchf = fetchf_ipv4,
.parse = parse_ipv4_setting,
.format = format_ipv4_setting,
};
/**
* Parse and store value of integer setting
* Parse integer setting value
*
* @v settings Settings block
* @v setting Setting to store
* @v value Formatted setting data
* @v value Formatted setting value
* @v buf Buffer to contain raw value
* @v len Length of buffer
* @v size Integer size, in bytes
* @ret rc Return status code
* @ret len Length of raw value, or negative error
*/
static int storef_int ( struct settings *settings, struct setting *setting,
const char *value, unsigned int size ) {
static int parse_int_setting ( const char *value, void *buf, size_t len,
unsigned int size ) {
union {
uint32_t num;
uint8_t bytes[4];
} u;
char *endp;
/* Parse value */
u.num = htonl ( strtoul ( value, &endp, 0 ) );
if ( *endp )
return -EINVAL;
return store_setting ( settings, setting,
&u.bytes[ sizeof ( u ) - size ], size );
/* Copy to buffer */
if ( len > size )
len = size;
memcpy ( buf, &u.bytes[ sizeof ( u ) - size ], len );
return size;
}
/**
* Parse and store value of 8-bit integer setting
* Parse 8-bit integer setting value
*
* @v settings Settings block
* @v setting Setting to store
* @v value Formatted setting data
* @v value Formatted setting value
* @v buf Buffer to contain raw value
* @v len Length of buffer
* @v size Integer size, in bytes
* @ret rc Return status code
* @ret len Length of raw value, or negative error
*/
static int storef_int8 ( struct settings *settings, struct setting *setting,
const char *value ) {
return storef_int ( settings, setting, value, 1 );
static int parse_int8_setting ( const char *value, void *buf, size_t len ) {
return parse_int_setting ( value, buf, len, sizeof ( uint8_t ) );
}
/**
* Parse and store value of 16-bit integer setting
* Parse 16-bit integer setting value
*
* @v settings Settings block
* @v setting Setting to store
* @v value Formatted setting data
* @v value Formatted setting value
* @v buf Buffer to contain raw value
* @v len Length of buffer
* @v size Integer size, in bytes
* @ret rc Return status code
* @ret len Length of raw value, or negative error
*/
static int storef_int16 ( struct settings *settings, struct setting *setting,
const char *value ) {
return storef_int ( settings, setting, value, 2 );
static int parse_int16_setting ( const char *value, void *buf, size_t len ) {
return parse_int_setting ( value, buf, len, sizeof ( uint16_t ) );
}
/**
* Parse and store value of 32-bit integer setting
* Parse 32-bit integer setting value
*
* @v settings Settings block
* @v setting Setting to store
* @v value Formatted setting data
* @v value Formatted setting value
* @v buf Buffer to contain raw value
* @v len Length of buffer
* @v size Integer size, in bytes
* @ret rc Return status code
* @ret len Length of raw value, or negative error
*/
static int storef_int32 ( struct settings *settings, struct setting *setting,
const char *value ) {
return storef_int ( settings, setting, value, 4 );
static int parse_int32_setting ( const char *value, void *buf, size_t len ) {
return parse_int_setting ( value, buf, len, sizeof ( uint32_t ) );
}
/**
* Fetch and format value of signed integer setting
* Format signed integer setting value
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v raw Raw setting value
* @v raw_len Length of raw setting value
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int fetchf_int ( struct settings *settings, struct setting *setting,
char *buf, size_t len ) {
long value;
int rc;
static int format_int_setting ( const void *raw, size_t raw_len, char *buf,
size_t len ) {
signed long value;
unsigned long dummy;
int check_len;
if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 )
return rc;
/* Extract numeric value */
check_len = numeric_setting_value ( raw, raw_len, &value, &dummy );
if ( check_len < 0 )
return check_len;
assert ( check_len == ( int ) raw_len );
/* Format value */
return snprintf ( buf, len, "%ld", value );
}
/**
* Fetch and format value of unsigned integer setting
* Format unsigned integer setting value
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v raw Raw setting value
* @v raw_len Length of raw setting value
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int fetchf_uint ( struct settings *settings, struct setting *setting,
char *buf, size_t len ) {
static int format_uint_setting ( const void *raw, size_t raw_len, char *buf,
size_t len ) {
signed long dummy;
unsigned long value;
int rc;
int check_len;
if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 )
return rc;
/* Extract numeric value */
check_len = numeric_setting_value ( raw, raw_len, &dummy, &value );
if ( check_len < 0 )
return check_len;
assert ( check_len == ( int ) raw_len );
/* Format value */
return snprintf ( buf, len, "%#lx", value );
}
/** A signed 8-bit integer setting type */
struct setting_type setting_type_int8 __setting_type = {
.name = "int8",
.storef = storef_int8,
.fetchf = fetchf_int,
.parse = parse_int8_setting,
.format = format_int_setting,
};
/** A signed 16-bit integer setting type */
struct setting_type setting_type_int16 __setting_type = {
.name = "int16",
.storef = storef_int16,
.fetchf = fetchf_int,
.parse = parse_int16_setting,
.format = format_int_setting,
};
/** A signed 32-bit integer setting type */
struct setting_type setting_type_int32 __setting_type = {
.name = "int32",
.storef = storef_int32,
.fetchf = fetchf_int,
.parse = parse_int32_setting,
.format = format_int_setting,
};
/** An unsigned 8-bit integer setting type */
struct setting_type setting_type_uint8 __setting_type = {
.name = "uint8",
.storef = storef_int8,
.fetchf = fetchf_uint,
.parse = parse_int8_setting,
.format = format_uint_setting,
};
/** An unsigned 16-bit integer setting type */
struct setting_type setting_type_uint16 __setting_type = {
.name = "uint16",
.storef = storef_int16,
.fetchf = fetchf_uint,
.parse = parse_int16_setting,
.format = format_uint_setting,
};
/** An unsigned 32-bit integer setting type */
struct setting_type setting_type_uint32 __setting_type = {
.name = "uint32",
.storef = storef_int32,
.fetchf = fetchf_uint,
.parse = parse_int32_setting,
.format = format_uint_setting,
};
/**
* Parse and store value of hex string setting
* Parse hex string setting value
*
* @v settings Settings block
* @v setting Setting to store
* @v value Formatted setting data
* @ret rc Return status code
* @v value Formatted setting value
* @v buf Buffer to contain raw value
* @v len Length of buffer
* @ret len Length of raw value, or negative error
*/
static int storef_hex ( struct settings *settings, struct setting *setting,
const char *value ) {
static int parse_hex_setting ( const char *value, void *buf, size_t len ) {
char *ptr = ( char * ) value;
uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
unsigned int len = 0;
uint8_t *bytes = buf;
unsigned int count = 0;
uint8_t byte;
while ( 1 ) {
bytes[len++] = strtoul ( ptr, &ptr, 16 );
byte = strtoul ( ptr, &ptr, 16 );
if ( count++ < len )
*bytes++ = byte;
switch ( *ptr ) {
case '\0' :
return store_setting ( settings, setting, bytes, len );
return count;
case ':' :
case '-' :
ptr++;
@@ -1483,128 +1634,112 @@ static int storef_hex ( struct settings *settings, struct setting *setting,
}
/**
* Fetch and format value of hex string setting
* Format hex string setting value
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v raw Raw setting value
* @v raw_len Length of raw setting value
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @v delimiter Byte delimiter
* @ret len Length of formatted value, or negative error
*/
static int fetchf_hex ( struct settings *settings, struct setting *setting,
char *buf, size_t len, const char *delimiter ) {
int raw_len;
int check_len;
static int format_hex_setting ( const void *raw, size_t raw_len, char *buf,
size_t len, const char *delimiter ) {
const uint8_t *bytes = raw;
int used = 0;
int i;
unsigned int i;
raw_len = fetch_setting_len ( settings, setting );
if ( raw_len < 0 )
return raw_len;
{
uint8_t raw[raw_len];
check_len = fetch_setting ( settings, setting, raw,
sizeof ( raw ) );
if ( check_len < 0 )
return check_len;
assert ( check_len == raw_len );
if ( len )
buf[0] = 0; /* Ensure that a terminating NUL exists */
for ( i = 0 ; i < raw_len ; i++ ) {
used += ssnprintf ( ( buf + used ), ( len - used ),
"%s%02x", ( used ? delimiter : "" ),
raw[i] );
}
return used;
if ( len )
buf[0] = 0; /* Ensure that a terminating NUL exists */
for ( i = 0 ; i < raw_len ; i++ ) {
used += ssnprintf ( ( buf + used ), ( len - used ),
"%s%02x", ( used ? delimiter : "" ),
bytes[i] );
}
return used;
}
/**
* Fetch and format value of hex string setting (using colon delimiter)
* Format hex string setting value (using colon delimiter)
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v raw Raw setting value
* @v raw_len Length of raw setting value
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int fetchf_hex_colon ( struct settings *settings,
struct setting *setting,
char *buf, size_t len ) {
return fetchf_hex ( settings, setting, buf, len, ":" );
static int format_hex_colon_setting ( const void *raw, size_t raw_len,
char *buf, size_t len ) {
return format_hex_setting ( raw, raw_len, buf, len, ":" );
}
/**
* Fetch and format value of hex string setting (using hyphen delimiter)
* Format hex string setting value (using hyphen delimiter)
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v raw Raw setting value
* @v raw_len Length of raw setting value
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int fetchf_hex_hyphen ( struct settings *settings,
struct setting *setting,
char *buf, size_t len ) {
return fetchf_hex ( settings, setting, buf, len, "-" );
static int format_hex_hyphen_setting ( const void *raw, size_t raw_len,
char *buf, size_t len ) {
return format_hex_setting ( raw, raw_len, buf, len, "-" );
}
/** A hex-string setting (colon-delimited) */
struct setting_type setting_type_hex __setting_type = {
.name = "hex",
.storef = storef_hex,
.fetchf = fetchf_hex_colon,
.parse = parse_hex_setting,
.format = format_hex_colon_setting,
};
/** A hex-string setting (hyphen-delimited) */
struct setting_type setting_type_hexhyp __setting_type = {
.name = "hexhyp",
.storef = storef_hex,
.fetchf = fetchf_hex_hyphen,
.parse = parse_hex_setting,
.format = format_hex_hyphen_setting,
};
/**
* Parse and store value of UUID setting
* Parse UUID setting value
*
* @v settings Settings block
* @v setting Setting to store
* @v value Formatted setting data
* @ret rc Return status code
* @v value Formatted setting value
* @v buf Buffer to contain raw value
* @v len Length of buffer
* @ret len Length of raw value, or negative error
*/
static int storef_uuid ( struct settings *settings __unused,
struct setting *setting __unused,
const char *value __unused ) {
static int parse_uuid_setting ( const char *value __unused,
void *buf __unused, size_t len __unused ) {
return -ENOTSUP;
}
/**
* Fetch and format value of UUID setting
* Format UUID setting value
*
* @v settings Settings block, or NULL to search all blocks
* @v setting Setting to fetch
* @v raw Raw setting value
* @v raw_len Length of raw setting value
* @v buf Buffer to contain formatted value
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int fetchf_uuid ( struct settings *settings, struct setting *setting,
char *buf, size_t len ) {
union uuid uuid;
int raw_len;
static int format_uuid_setting ( const void *raw, size_t raw_len, char *buf,
size_t len ) {
const union uuid *uuid = raw;
if ( ( raw_len = fetch_uuid_setting ( settings, setting, &uuid ) ) < 0)
return raw_len;
return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) );
/* Range check */
if ( raw_len != sizeof ( *uuid ) )
return -ERANGE;
/* Format value */
return snprintf ( buf, len, "%s", uuid_ntoa ( uuid ) );
}
/** UUID setting type */
struct setting_type setting_type_uuid __setting_type = {
.name = "uuid",
.storef = storef_uuid,
.fetchf = fetchf_uuid,
.parse = parse_uuid_setting,
.format = format_uuid_setting,
};
/******************************************************************************
@@ -1703,6 +1838,14 @@ struct setting hostname_setting __setting ( SETTING_HOST ) = {
.type = &setting_type_string,
};
/** TFTP server setting */
struct setting next_server_setting __setting ( SETTING_BOOT ) = {
.name = "next-server",
.description = "TFTP server",
.tag = DHCP_EB_SIADDR,
.type = &setting_type_ipv4,
};
/** Filename setting */
struct setting filename_setting __setting ( SETTING_BOOT ) = {
.name = "filename",
+12
View File
@@ -29,8 +29,17 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
unsigned long long strtoull ( const char *p, char **endp, int base ) {
unsigned long long ret = 0;
int negative = 0;
unsigned int charval;
while ( isspace ( *p ) )
p++;
if ( *p == '-' ) {
negative = 1;
p++;
}
base = strtoul_base ( &p, base );
while ( 1 ) {
@@ -41,6 +50,9 @@ unsigned long long strtoull ( const char *p, char **endp, int base ) {
p++;
}
if ( negative )
ret = -ret;
if ( endp )
*endp = ( char * ) p;
+137
View File
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <time.h>
/** @file
*
* Date and time
*
* POSIX:2008 section 4.15 defines "seconds since the Epoch" as an
* abstract measure approximating the number of seconds that have
* elapsed since the Epoch, excluding leap seconds. The formula given
* is
*
* tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
* (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
* ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
*
* This calculation assumes that leap years occur in each year that is
* either divisible by 4 but not divisible by 100, or is divisible by
* 400.
*/
/** Days of week (for debugging) */
static const char *weekdays[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
/**
* Determine whether or not year is a leap year
*
* @v tm_year Years since 1900
* @v is_leap_year Year is a leap year
*/
static int is_leap_year ( int tm_year ) {
int leap_year = 0;
if ( ( tm_year % 4 ) == 0 )
leap_year = 1;
if ( ( tm_year % 100 ) == 0 )
leap_year = 0;
if ( ( tm_year % 400 ) == 100 )
leap_year = 1;
return leap_year;
}
/**
* Calculate number of leap years since 1900
*
* @v tm_year Years since 1900
* @v num_leap_years Number of leap years
*/
static int leap_years_to_end ( int tm_year ) {
int leap_years = 0;
leap_years += ( tm_year / 4 );
leap_years -= ( tm_year / 100 );
leap_years += ( ( tm_year + 300 ) / 400 );
return leap_years;
}
/**
* Calculate day of week
*
* @v tm_year Years since 1900
* @v tm_mon Month of year [0,11]
* @v tm_day Day of month [1,31]
*/
static int day_of_week ( int tm_year, int tm_mon, int tm_mday ) {
static const uint8_t offset[12] =
{ 1, 4, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 };
int pseudo_year = tm_year;
if ( tm_mon < 2 )
pseudo_year--;
return ( ( pseudo_year + leap_years_to_end ( pseudo_year ) +
offset[tm_mon] + tm_mday ) % 7 );
}
/** Days from start of year until start of months (in non-leap years) */
static const uint16_t days_to_month_start[] =
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
/**
* Calculate seconds since the Epoch
*
* @v tm Broken-down time
* @ret time Seconds since the Epoch
*/
time_t mktime ( struct tm *tm ) {
int days_since_epoch;
int seconds_since_day;
time_t seconds;
/* Calculate day of year */
tm->tm_yday = ( ( tm->tm_mday - 1 ) +
days_to_month_start[ tm->tm_mon ] );
if ( ( tm->tm_mon >= 2 ) && is_leap_year ( tm->tm_year ) )
tm->tm_yday++;
/* Calculate day of week */
tm->tm_wday = day_of_week ( tm->tm_year, tm->tm_mon, tm->tm_mday );
/* Calculate seconds since the Epoch */
days_since_epoch = ( tm->tm_yday + ( 365 * tm->tm_year ) - 25567 +
leap_years_to_end ( tm->tm_year - 1 ) );
seconds_since_day =
( ( ( ( tm->tm_hour * 60 ) + tm->tm_min ) * 60 ) + tm->tm_sec );
seconds = ( ( ( ( time_t ) days_since_epoch ) * ( ( time_t ) 86400 ) ) +
seconds_since_day );
DBGC ( &weekdays, "TIME %04d-%02d-%02d %02d:%02d:%02d => %lld (%s, "
"day %d)\n", ( tm->tm_year + 1900 ), ( tm->tm_mon + 1 ),
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, seconds,
weekdays[ tm->tm_wday ], tm->tm_yday );
return seconds;
}
+1 -1
View File
@@ -35,7 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
* @v uuid UUID
* @ret string UUID in canonical form
*/
char * uuid_ntoa ( union uuid *uuid ) {
char * uuid_ntoa ( const union uuid *uuid ) {
static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
sprintf ( buf, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
-1
View File
@@ -21,7 +21,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <ipxe/console.h>
#include <errno.h>
#include <ipxe/vsprintf.h>
+19 -7
View File
@@ -19,6 +19,7 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ipxe/iobuf.h>
@@ -297,17 +298,28 @@ int xfer_deliver_raw ( struct interface *intf, const void *data, size_t len ) {
*/
int xfer_vprintf ( struct interface *intf, const char *format,
va_list args ) {
size_t len;
va_list args_tmp;
char *buf;
int len;
int rc;
/* Create temporary string */
va_copy ( args_tmp, args );
len = vsnprintf ( NULL, 0, format, args );
{
char buf[len + 1];
vsnprintf ( buf, sizeof ( buf ), format, args_tmp );
va_end ( args_tmp );
return xfer_deliver_raw ( intf, buf, len );
len = vasprintf ( &buf, format, args );
if ( len < 0 ) {
rc = len;
goto err_asprintf;
}
va_end ( args_tmp );
/* Transmit string */
if ( ( rc = xfer_deliver_raw ( intf, buf, len ) ) != 0 )
goto err_deliver;
err_deliver:
free ( buf );
err_asprintf:
return rc;
}
/**
+108
View File
@@ -0,0 +1,108 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ipxe/xfer.h>
#include <ipxe/iobuf.h>
#include <ipxe/xferbuf.h>
/** @file
*
* Data transfer buffer
*
*/
/**
* Finish using data transfer buffer
*
* @v xferbuf Data transfer buffer
*/
void xferbuf_done ( struct xfer_buffer *xferbuf ) {
free ( xferbuf->data );
xferbuf->data = NULL;
xferbuf->len = 0;
xferbuf->pos = 0;
}
/**
* Ensure that data transfer buffer is large enough for the specified size
*
* @v xferbuf Data transfer buffer
* @v len Required minimum size
* @ret rc Return status code
*/
static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
void *new_data;
/* If buffer is already large enough, do nothing */
if ( len <= xferbuf->len )
return 0;
/* Extend buffer */
new_data = realloc ( xferbuf->data, len );
if ( ! new_data ) {
DBGC ( xferbuf, "XFERBUF %p could not extend buffer to "
"%zd bytes\n", xferbuf, len );
return -ENOSPC;
}
xferbuf->data = new_data;
xferbuf->len = len;
return 0;
}
/**
* Add received data to data transfer buffer
*
* @v xferbuf Data transfer buffer
* @v iobuf I/O buffer
* @v meta Data transfer metadata
* @ret rc Return status code
*/
int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf,
struct xfer_metadata *meta ) {
size_t len;
size_t max;
int rc;
/* Calculate new buffer position */
if ( meta->flags & XFER_FL_ABS_OFFSET )
xferbuf->pos = 0;
xferbuf->pos += meta->offset;
/* Ensure that we have enough buffer space for this data */
len = iob_len ( iobuf );
max = ( xferbuf->pos + len );
if ( ( rc = xferbuf_ensure_size ( xferbuf, max ) ) != 0 )
goto done;
/* Copy data to buffer */
memcpy ( ( xferbuf->data + xferbuf->pos ), iobuf->data, len );
/* Update current buffer position */
xferbuf->pos += len;
done:
free_iob ( iobuf );
return rc;
}
+1 -1
View File
@@ -48,7 +48,7 @@ int aes_wrap ( const void *kek, const void *src, void *dest, int nblk )
cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 );
/* Set up */
memset ( A, 0xA6, sizeof ( A ) );
memset ( A, 0xA6, 8 );
memmove ( dest + 8, src, nblk * 8 );
/* Wrap */
+221 -6
View File
@@ -20,7 +20,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <ipxe/tables.h>
#include <ipxe/asn1.h>
/** @file
@@ -42,12 +44,32 @@ FILE_LICENCE ( GPL2_OR_LATER );
__einfo_error ( EINFO_EINVAL_ASN1_LEN )
#define EINFO_EINVAL_ASN1_LEN \
__einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
#define EINVAL_ASN1_BOOLEAN \
__einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN )
#define EINFO_EINVAL_ASN1_BOOLEAN \
__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )
#define EINVAL_ASN1_INTEGER \
__einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
#define EINFO_EINVAL_ASN1_INTEGER \
__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
/**
* Invalidate ASN.1 object cursor
*
* @v cursor ASN.1 object cursor
*/
void asn1_invalidate_cursor ( struct asn1_cursor *cursor ) {
static uint8_t asn1_invalid_object[] = { ASN1_END, 0 };
cursor->data = asn1_invalid_object;
cursor->len = 0;
}
/**
* Start parsing ASN.1 object
*
* @v cursor ASN.1 object cursor
* @v type Expected type
* @v type Expected type, or ASN1_ANY
* @ret len Length of object body, or negative error
*
* The object cursor will be updated to point to the start of the
@@ -67,7 +89,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
}
/* Check the tag byte */
if ( *( ( uint8_t * ) cursor->data ) != type ) {
if ( ( type != ASN1_ANY ) && ( type != asn1_type ( cursor ) ) ) {
DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
cursor, type, *( ( uint8_t * ) cursor->data ) );
return -ENXIO;
@@ -110,7 +132,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
* Enter ASN.1 object
*
* @v cursor ASN.1 object cursor
* @v type Expected type
* @v type Expected type, or ASN1_ANY
* @ret rc Return status code
*
* The object cursor will be updated to point to the body of the
@@ -137,7 +159,7 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
* Skip ASN.1 object if present
*
* @v cursor ASN.1 object cursor
* @v type Expected type
* @v type Expected type, or ASN1_ANY
* @ret rc Return status code
*
* The object cursor will be updated to point to the next ASN.1
@@ -168,7 +190,7 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
* Skip ASN.1 object
*
* @v cursor ASN.1 object cursor
* @v type Expected type
* @v type Expected type, or ASN1_ANY
* @ret rc Return status code
*
* The object cursor will be updated to point to the next ASN.1
@@ -178,10 +200,203 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
int rc;
if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) < 0 ) {
if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) {
asn1_invalidate_cursor ( cursor );
return rc;
}
return 0;
}
/**
* Shrink ASN.1 cursor to fit object
*
* @v cursor ASN.1 object cursor
* @v type Expected type, or ASN1_ANY
* @ret rc Return status code
*
* The object cursor will be shrunk to contain only the current ASN.1
* object. If any error occurs, the object cursor will be
* invalidated.
*/
int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) {
struct asn1_cursor temp;
const void *end;
int len;
/* Find end of object */
memcpy ( &temp, cursor, sizeof ( temp ) );
len = asn1_start ( &temp, type );
if ( len < 0 ) {
asn1_invalidate_cursor ( cursor );
return len;
}
end = ( temp.data + len );
/* Shrink original cursor to contain only its first object */
cursor->len = ( end - cursor->data );
return 0;
}
/**
* Enter ASN.1 object of any type
*
* @v cursor ASN.1 object cursor
* @ret rc Return status code
*/
int asn1_enter_any ( struct asn1_cursor *cursor ) {
return asn1_enter ( cursor, ASN1_ANY );
}
/**
* Skip ASN.1 object of any type
*
* @v cursor ASN.1 object cursor
* @ret rc Return status code
*/
int asn1_skip_any ( struct asn1_cursor *cursor ) {
return asn1_skip ( cursor, ASN1_ANY );
}
/**
* Shrink ASN.1 object of any type
*
* @v cursor ASN.1 object cursor
* @ret rc Return status code
*/
int asn1_shrink_any ( struct asn1_cursor *cursor ) {
return asn1_shrink ( cursor, ASN1_ANY );
}
/**
* Parse value of ASN.1 boolean
*
* @v cursor ASN.1 object cursor
* @ret value Value, or negative error
*/
int asn1_boolean ( const struct asn1_cursor *cursor ) {
struct asn1_cursor contents;
const struct asn1_boolean *boolean;
/* Enter boolean */
memcpy ( &contents, cursor, sizeof ( contents ) );
asn1_enter ( &contents, ASN1_BOOLEAN );
if ( contents.len != sizeof ( *boolean ) )
return -EINVAL_ASN1_BOOLEAN;
/* Extract value */
boolean = contents.data;
return boolean->value;
}
/**
* Parse value of ASN.1 integer
*
* @v cursor ASN.1 object cursor
* @v value Value to fill in
* @ret rc Return status code
*/
int asn1_integer ( const struct asn1_cursor *cursor, int *value ) {
struct asn1_cursor contents;
uint8_t high_byte;
int rc;
/* Enter integer */
memcpy ( &contents, cursor, sizeof ( contents ) );
if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 )
return rc;
if ( contents.len < 1 )
return -EINVAL_ASN1_INTEGER;
/* Initialise value according to sign byte */
*value = *( ( int8_t * ) contents.data );
contents.data++;
contents.len--;
/* Process value */
while ( contents.len ) {
high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) );
if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) {
DBGC ( cursor, "ASN1 %p integer overflow\n", cursor );
return -EINVAL_ASN1_INTEGER;
}
*value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) );
contents.data++;
contents.len--;
}
return 0;
}
/**
* Compare two ASN.1 objects
*
* @v cursor1 ASN.1 object cursor
* @v cursor2 ASN.1 object cursor
* @ret difference Difference as returned by memcmp()
*
* Note that invalid and empty cursors will compare as equal with each
* other.
*/
int asn1_compare ( const struct asn1_cursor *cursor1,
const struct asn1_cursor *cursor2 ) {
int difference;
difference = ( cursor2->len - cursor1->len );
return ( difference ? difference :
memcmp ( cursor1->data, cursor2->data, cursor1->len ) );
}
/**
* Identify ASN.1 algorithm by OID
*
* @v cursor ASN.1 object cursor
* @ret algorithm Algorithm, or NULL
*/
static struct asn1_algorithm *
asn1_find_algorithm ( const struct asn1_cursor *cursor ) {
struct asn1_algorithm *algorithm;
for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) {
if ( asn1_compare ( &algorithm->oid, cursor ) == 0 )
return algorithm;
}
return NULL;
}
/**
* Parse ASN.1 OID-identified algorithm
*
* @v cursor ASN.1 object cursor
* @ret algorithm Algorithm, or NULL
*/
struct asn1_algorithm * asn1_algorithm ( const struct asn1_cursor *cursor ) {
struct asn1_cursor contents;
struct asn1_algorithm *algorithm;
int rc;
/* Enter signatureAlgorithm */
memcpy ( &contents, cursor, sizeof ( contents ) );
asn1_enter ( &contents, ASN1_SEQUENCE );
/* Enter algorithm */
if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) {
DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n",
cursor );
DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
return NULL;
}
/* Identify algorithm */
algorithm = asn1_find_algorithm ( &contents );
if ( ! algorithm ) {
DBGC ( cursor, "ASN1 %p unrecognised algorithm:\n", cursor );
DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
return NULL;
}
return algorithm;
}
+85 -106
View File
@@ -1,23 +1,33 @@
/*
* Copyright(C) 2006 Cameron Rich
* Copyright (c) 2007, Cameron Rich
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* All rights reserved.
*
* This library 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 Lesser General Public License for more details.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/**
* AES implementation - this is a small code version. There are much faster
* versions around but they are much larger in size (i.e. they use large
@@ -25,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
#include <string.h>
#include "os_port.h"
#include "crypto.h"
/* all commented out in skeleton mode */
@@ -64,10 +75,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
(f8)^=rot2(f4), \
(f8)^rot1(f9))
/* some macros to do endian independent byte extraction */
#define n2l(c,l) l=ntohl(*c); c++
#define l2n(l,c) *c++=htonl(l)
/*
* AES S-box
*/
@@ -154,11 +161,15 @@ static const unsigned char Rcon[30]=
0xb3,0x7d,0xfa,0xef,0xc5,0x91,
};
/* ----- static functions ----- */
static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
x^8+x^4+x^3+x+1 */
static unsigned char AES_xtime(uint32_t x)
{
return x = (x&0x80) ? (x<<1)^0x1b : x<<1;
return (x&0x80) ? (x<<1)^0x1b : x<<1;
}
/**
@@ -247,7 +258,7 @@ void AES_convert_key(AES_CTX *ctx)
k = ctx->ks;
k += 4;
for (i=ctx->rounds*4; i>4; i--)
for (i= ctx->rounds*4; i > 4; i--)
{
w= *k;
w = inv_mix_col(w,t1,t2,t3,t4);
@@ -255,52 +266,43 @@ void AES_convert_key(AES_CTX *ctx)
}
}
#if 0
/**
* Encrypt a byte sequence (with a block size 16) using the AES cipher.
*/
void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
{
uint32_t tin0, tin1, tin2, tin3;
uint32_t tout0, tout1, tout2, tout3;
uint32_t tin[4];
uint32_t *iv = (uint32_t *)ctx->iv;
uint32_t *msg_32 = (uint32_t *)msg;
uint32_t *out_32 = (uint32_t *)out;
int i;
uint32_t tin[4], tout[4], iv[4];
n2l(iv, tout0);
n2l(iv, tout1);
n2l(iv, tout2);
n2l(iv, tout3);
iv -= 4;
memcpy(iv, ctx->iv, AES_IV_SIZE);
for (i = 0; i < 4; i++)
tout[i] = ntohl(iv[i]);
for (length -= 16; length >= 0; length -= 16)
for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
{
n2l(msg_32, tin0);
n2l(msg_32, tin1);
n2l(msg_32, tin2);
n2l(msg_32, tin3);
tin[0] = tin0^tout0;
tin[1] = tin1^tout1;
tin[2] = tin2^tout2;
tin[3] = tin3^tout3;
uint32_t msg_32[4];
uint32_t out_32[4];
memcpy(msg_32, msg, AES_BLOCKSIZE);
msg += AES_BLOCKSIZE;
for (i = 0; i < 4; i++)
tin[i] = ntohl(msg_32[i])^tout[i];
AES_encrypt(ctx, tin);
tout0 = tin[0];
l2n(tout0, out_32);
tout1 = tin[1];
l2n(tout1, out_32);
tout2 = tin[2];
l2n(tout2, out_32);
tout3 = tin[3];
l2n(tout3, out_32);
for (i = 0; i < 4; i++)
{
tout[i] = tin[i];
out_32[i] = htonl(tout[i]);
}
memcpy(out, out_32, AES_BLOCKSIZE);
out += AES_BLOCKSIZE;
}
l2n(tout0, iv);
l2n(tout1, iv);
l2n(tout2, iv);
l2n(tout3, iv);
for (i = 0; i < 4; i++)
iv[i] = htonl(tout[i]);
memcpy(ctx->iv, iv, AES_IV_SIZE);
}
/**
@@ -308,61 +310,48 @@ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
*/
void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
{
uint32_t tin0, tin1, tin2, tin3;
uint32_t xor0,xor1,xor2,xor3;
uint32_t tout0,tout1,tout2,tout3;
uint32_t data[4];
uint32_t *iv = (uint32_t *)ctx->iv;
uint32_t *msg_32 = (uint32_t *)msg;
uint32_t *out_32 = (uint32_t *)out;
int i;
uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
n2l(iv ,xor0);
n2l(iv, xor1);
n2l(iv, xor2);
n2l(iv, xor3);
iv -= 4;
memcpy(iv, ctx->iv, AES_IV_SIZE);
for (i = 0; i < 4; i++)
xor[i] = ntohl(iv[i]);
for (length-=16; length >= 0; length -= 16)
for (length -= 16; length >= 0; length -= 16)
{
n2l(msg_32, tin0);
n2l(msg_32, tin1);
n2l(msg_32, tin2);
n2l(msg_32, tin3);
uint32_t msg_32[4];
uint32_t out_32[4];
memcpy(msg_32, msg, AES_BLOCKSIZE);
msg += AES_BLOCKSIZE;
data[0] = tin0;
data[1] = tin1;
data[2] = tin2;
data[3] = tin3;
for (i = 0; i < 4; i++)
{
tin[i] = ntohl(msg_32[i]);
data[i] = tin[i];
}
AES_decrypt(ctx, data);
tout0 = data[0]^xor0;
tout1 = data[1]^xor1;
tout2 = data[2]^xor2;
tout3 = data[3]^xor3;
for (i = 0; i < 4; i++)
{
tout[i] = data[i]^xor[i];
xor[i] = tin[i];
out_32[i] = htonl(tout[i]);
}
xor0 = tin0;
xor1 = tin1;
xor2 = tin2;
xor3 = tin3;
l2n(tout0, out_32);
l2n(tout1, out_32);
l2n(tout2, out_32);
l2n(tout3, out_32);
memcpy(out, out_32, AES_BLOCKSIZE);
out += AES_BLOCKSIZE;
}
l2n(xor0, iv);
l2n(xor1, iv);
l2n(xor2, iv);
l2n(xor3, iv);
for (i = 0; i < 4; i++)
iv[i] = htonl(xor[i]);
memcpy(ctx->iv, iv, AES_IV_SIZE);
}
#endif
/**
* Encrypt a single block (16 bytes) of data
*/
void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
{
/* To make this code smaller, generate the sbox entries on the fly.
* This will have a really heavy effect upon performance.
@@ -375,9 +364,7 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
/* Pre-round key addition */
for (row = 0; row < 4; row++)
{
data[row] ^= *(k++);
}
/* Encrypt one block. */
for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
@@ -395,12 +382,10 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
{
tmp1 = a0 ^ a1 ^ a2 ^ a3;
old_a0 = a0;
a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
}
tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
@@ -409,32 +394,28 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
/* KeyAddition - note that it is vital that this loop is separate from
the MixColumn operation, which must be atomic...*/
for (row = 0; row < 4; row++)
{
data[row] = tmp[row] ^ *(k++);
}
}
}
/**
* Decrypt a single block (16 bytes) of data
*/
void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
{
uint32_t tmp[4];
uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
uint32_t a0, a1, a2, a3, row;
int curr_rnd;
int rounds = ctx->rounds;
uint32_t *k = (uint32_t*)ctx->ks + ((rounds+1)*4);
const uint32_t *k = ctx->ks + ((rounds+1)*4);
/* pre-round key addition */
for (row=4; row > 0;row--)
{
data[row-1] ^= *(--k);
}
/* Decrypt one block */
for (curr_rnd=0; curr_rnd < rounds; curr_rnd++)
for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
{
/* Perform ByteSub and ShiftRow operations together */
for (row = 4; row > 0; row--)
@@ -469,9 +450,7 @@ void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
}
for (row = 4; row > 0; row--)
{
data[row-1] = tmp[row-1] ^ *(--k);
}
}
}
File diff suppressed because it is too large Load Diff
+33 -27
View File
@@ -1,44 +1,43 @@
/*
* Copyright(C) 2006 Cameron Rich
* Copyright (c) 2007, Cameron Rich
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* All rights reserved.
*
* This library 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 Lesser General Public License for more details.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#ifndef BIGINT_HEADER
#define BIGINT_HEADER
/* enable features based on a 'super-set' capbaility. */
#if defined(CONFIG_SSL_FULL_MODE)
#define CONFIG_SSL_ENABLE_CLIENT
#define CONFIG_SSL_CERT_VERIFICATION
#elif defined(CONFIG_SSL_ENABLE_CLIENT)
#define CONFIG_SSL_CERT_VERIFICATION
#endif
#include "crypto.h"
#include "os_port.h"
#include "bigint_impl.h"
#ifndef CONFIG_BIGINT_CHECK_ON
#define check(A) /**< disappears in normal production mode */
#endif
BI_CTX *bi_initialize(void);
void bi_terminate(BI_CTX *ctx);
void bi_permanent(bigint *bi);
void bi_depermanent(bigint *bi);
void bi_clear_cache(BI_CTX *ctx);
void bi_free(BI_CTX *ctx, bigint *bi);
bigint *bi_copy(bigint *bi);
bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
@@ -90,4 +89,11 @@ bigint *bi_square(BI_CTX *ctx, bigint *bi);
#define bi_square(A, B) bi_multiply(A, bi_copy(B), B)
#endif
#ifdef CONFIG_BIGINT_CRT
bigint *bi_crt(BI_CTX *ctx, bigint *bi,
bigint *dP, bigint *dQ,
bigint *p, bigint *q,
bigint *qInv);
#endif
#endif
+46 -20
View File
@@ -1,19 +1,31 @@
/*
* Copyright(C) 2006 Cameron Rich
* Copyright (c) 2007, Cameron Rich
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
* All rights reserved.
*
* This library 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 Lesser General Public License for more details.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BIGINT_IMPL_HEADER
@@ -30,20 +42,39 @@
#endif
/* Architecture specific functions for big ints */
#if defined(CONFIG_INTEGER_8BIT)
#define COMP_RADIX 256U /**< Max component + 1 */
#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */
#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */
#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */
#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */
typedef uint8_t comp; /**< A single precision component. */
typedef uint16_t long_comp; /**< A double precision component. */
typedef int16_t slong_comp; /**< A signed double precision component. */
#elif defined(CONFIG_INTEGER_16BIT)
#define COMP_RADIX 65536U /**< Max component + 1 */
#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */
#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */
#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */
#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */
typedef uint16_t comp; /**< A single precision component. */
typedef uint32_t long_comp; /**< A double precision component. */
typedef int32_t slong_comp; /**< A signed double precision component. */
#else /* regular 32 bit */
#ifdef WIN32
#define COMP_RADIX 4294967296i64
#define COMP_BIG_MSB 0x8000000000000000i64
#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64
#else
#define COMP_RADIX 4294967296ULL /**< Max component + 1 */
#define COMP_BIG_MSB 0x8000000000000000ULL /**< (Max dbl comp + 1)/ 2 */
#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
#endif
#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */
#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */
#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */
typedef uint32_t comp; /**< A single precision component. */
typedef uint64_t long_comp; /**< A double precision component. */
typedef int64_t slong_comp; /**< A signed double precision component. */
#endif
/**
* @struct _bigint
@@ -97,9 +128,4 @@ typedef struct /**< A big integer "session" context. */
#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */
#define V1 v->comps[v->size-1] /**< v1 for division */
#define V2 v->comps[v->size-2] /**< v2 for division */
#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */
#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */
#endif
+13
View File
@@ -0,0 +1,13 @@
#ifndef AXTLS_CONFIG_H
#define AXTLS_CONFIG_H
/**
* @file config.h
*
* Trick the axtls code into building within our build environment.
*/
#define CONFIG_SSL_ENABLE_CLIENT 1
#define CONFIG_BIGINT_CLASSICAL 1
#endif
+81 -154
View File
@@ -1,23 +1,33 @@
/*
* Copyright(C) 2006 Cameron Rich
* Copyright (c) 2007, Cameron Rich
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* All rights reserved.
*
* This library 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 Lesser General Public License for more details.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/**
* @file crypto.h
*/
@@ -29,20 +39,40 @@ FILE_LICENCE ( GPL2_OR_LATER );
extern "C" {
#endif
#include "config.h"
#include "bigint_impl.h"
#include "bigint.h"
#ifndef STDCALL
#define STDCALL
#endif
#ifndef EXP_FUNC
#define EXP_FUNC
#endif
/* enable features based on a 'super-set' capbaility. */
#if defined(CONFIG_SSL_FULL_MODE)
#define CONFIG_SSL_ENABLE_CLIENT
#define CONFIG_SSL_CERT_VERIFICATION
#elif defined(CONFIG_SSL_ENABLE_CLIENT)
#define CONFIG_SSL_CERT_VERIFICATION
#endif
/**************************************************************************
* AES declarations
**************************************************************************/
#define AES_MAXROUNDS 14
#define AES_BLOCKSIZE 16
#define AES_IV_SIZE 16
typedef struct aes_key_st
{
uint16_t rounds;
uint16_t key_size;
uint32_t ks[(AES_MAXROUNDS+1)*8];
uint8_t iv[16];
uint8_t iv[AES_IV_SIZE];
} AES_CTX;
typedef enum
@@ -57,8 +87,6 @@ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg,
uint8_t *out, int length);
void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
void AES_convert_key(AES_CTX *ctx);
void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
/**************************************************************************
* RC4 declarations
@@ -66,7 +94,7 @@ void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
typedef struct
{
int x, y, m[256];
uint8_t x, y, m[256];
} RC4_CTX;
void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
@@ -84,22 +112,38 @@ void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
*/
typedef struct
{
uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
uint32_t Length_Low; /* Message length in bits */
uint32_t Length_High; /* Message length in bits */
uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
uint32_t Length_Low; /* Message length in bits */
uint32_t Length_High; /* Message length in bits */
uint16_t Message_Block_Index; /* Index into message block array */
uint8_t Message_Block[64]; /* 512-bit message blocks */
uint8_t Message_Block[64]; /* 512-bit message blocks */
} SHA1_CTX;
void SHA1Init(SHA1_CTX *);
void SHA1Update(SHA1_CTX *, const uint8_t * msg, int len);
void SHA1Final(SHA1_CTX *, uint8_t *digest);
void SHA1_Init(SHA1_CTX *);
void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
void SHA1_Final(uint8_t *digest, SHA1_CTX *);
/**************************************************************************
* MD5 declarations
* MD2 declarations
**************************************************************************/
/* MD5 context. */
#define MD2_SIZE 16
typedef struct
{
unsigned char cksum[16]; /* checksum of the data block */
unsigned char state[48]; /* intermediate digest state */
unsigned char buffer[16]; /* data block being processed */
int left; /* amount of data in buffer */
} MD2_CTX;
EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
/**************************************************************************
* MD5 declarations
**************************************************************************/
#define MD5_SIZE 16
@@ -110,9 +154,9 @@ typedef struct
uint8_t buffer[64]; /* input buffer */
} MD5_CTX;
void MD5Init(MD5_CTX *);
void MD5Update(MD5_CTX *, const uint8_t *msg, int len);
void MD5Final(MD5_CTX *, uint8_t *digest);
EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
/**************************************************************************
* HMAC declarations
@@ -122,19 +166,6 @@ void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
int key_len, uint8_t *digest);
/**************************************************************************
* RNG declarations
**************************************************************************/
void RNG_initialize(const uint8_t *seed_buf, int size);
void RNG_terminate(void);
void get_random(int num_rand_bytes, uint8_t *rand_data);
//void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
#include <string.h>
static inline void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) {
memset ( rand_data, 0x01, num_rand_bytes );
}
/**************************************************************************
* RSA declarations
**************************************************************************/
@@ -152,7 +183,6 @@ typedef struct
bigint *qInv; /* q^-1 mod p */
#endif
int num_octets;
bigint *sig_m; /* signature modulus */
BI_CTX *bi_ctx;
} RSA_CTX;
@@ -175,125 +205,22 @@ void RSA_free(RSA_CTX *ctx);
int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
int is_decryption);
bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
#ifdef CONFIG_SSL_CERT_VERIFICATION
bigint *RSA_raw_sign_verify(RSA_CTX *c, bigint *bi_msg);
#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
bigint *modulus, bigint *pub_exp);
bigint *RSA_public(const RSA_CTX *c, bigint *bi_msg);
bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
uint8_t *out_data, int is_signing);
void RSA_print(const RSA_CTX *ctx);
#endif
/**************************************************************************
* ASN1 declarations
* RNG declarations
**************************************************************************/
#define X509_OK 0
#define X509_NOT_OK -1
#define X509_VFY_ERROR_NO_TRUSTED_CERT -2
#define X509_VFY_ERROR_BAD_SIGNATURE -3
#define X509_VFY_ERROR_NOT_YET_VALID -4
#define X509_VFY_ERROR_EXPIRED -5
#define X509_VFY_ERROR_SELF_SIGNED -6
#define X509_VFY_ERROR_INVALID_CHAIN -7
#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8
#define X509_INVALID_PRIV_KEY -9
/*
* The Distinguished Name
*/
#define X509_NUM_DN_TYPES 3
#define X509_COMMON_NAME 0
#define X509_ORGANIZATION 1
#define X509_ORGANIZATIONAL_TYPE 2
#define ASN1_INTEGER 0x02
#define ASN1_BIT_STRING 0x03
#define ASN1_OCTET_STRING 0x04
#define ASN1_NULL 0x05
#define ASN1_OID 0x06
#define ASN1_PRINTABLE_STR 0x13
#define ASN1_TELETEX_STR 0x14
#define ASN1_IA5_STR 0x16
#define ASN1_UTC_TIME 0x17
#define ASN1_SEQUENCE 0x30
#define ASN1_SET 0x31
#define ASN1_IMPLICIT_TAG 0x80
#define ASN1_EXPLICIT_TAG 0xa0
#define SALT_SIZE 8
struct _x509_ctx
{
char *ca_cert_dn[X509_NUM_DN_TYPES];
char *cert_dn[X509_NUM_DN_TYPES];
#if defined(_WIN32_WCE)
long not_before;
long not_after;
#else
time_t not_before;
time_t not_after;
#endif
uint8_t *signature;
uint16_t sig_len;
uint8_t sig_type;
RSA_CTX *rsa_ctx;
bigint *digest;
struct _x509_ctx *next;
};
typedef struct _x509_ctx X509_CTX;
#ifdef CONFIG_SSL_CERT_VERIFICATION
typedef struct
{
X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
} CA_CERT_CTX;
#endif
int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
void x509_free(X509_CTX *x509_ctx);
#ifdef CONFIG_SSL_CERT_VERIFICATION
int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
const uint8_t *x509_get_signature(const uint8_t *asn1_signature, int *len);
#endif
#ifdef CONFIG_SSL_FULL_MODE
void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
void x509_display_error(int error);
#endif
/**************************************************************************
* MISC declarations
**************************************************************************/
extern const char * const unsupported_str;
typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);
typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key,
int key_len, uint8_t *digest);
typedef struct
{
uint8_t *pre_data; /* include the ssl record bytes */
uint8_t *data; /* the regular ssl data */
int max_len;
int index;
} BUF_MEM;
BUF_MEM buf_new(void);
void buf_grow(BUF_MEM *bm, int len);
void buf_free(BUF_MEM *bm);
int get_file(const char *filename, uint8_t **buf);
#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)
void print_blob(const char *format, const uint8_t *data, int size, ...);
#else
#define print_blob(...)
#endif
EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size);
EXP_FUNC void STDCALL RNG_terminate(void);
EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
#ifdef __cplusplus
}
+32 -39
View File
@@ -1,61 +1,54 @@
#ifndef AXTLS_OS_PORT_H
#define AXTLS_OS_PORT_H
/**
* @file os_port.h
*
* Trick the axtls code into building within our build environment.
*/
#ifndef HEADER_OS_PORT_H
#define HEADER_OS_PORT_H
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <byteswap.h>
#define STDCALL
#define EXP_FUNC
#define TTY_FLUSH()
/** All imported axTLS files are licensed using the three-clause BSD licence */
FILE_LICENCE ( BSD3 );
/** We can't actually abort, since we are effectively a kernel... */
#define abort() assert ( 0 )
/** crypto_misc.c has a bad #ifdef */
static inline void close ( int fd __unused ) {
/* Do nothing */
/** rsa.c uses alloca() */
#define alloca( size ) __builtin_alloca ( size )
#include <ipxe/random_nz.h>
static inline void get_random_NZ ( int num_rand_bytes, uint8_t *rand_data ) {
/* AXTLS does not check for failures when generating random
* data. Rely on the fact that get_random_nz() does not
* request prediction resistance (and so cannot introduce new
* failures) and therefore any potential failure must already
* have been encountered by e.g. tls_generate_random(), which
* does check for failures.
*/
get_random_nz ( rand_data, num_rand_bytes );
}
typedef void FILE;
/* Expose AES_encrypt() and AES_decrypt() in aes.o */
#define aes 1
#if OBJECT
static inline FILE * fopen ( const char *filename __unused,
const char *mode __unused ) {
return NULL;
struct aes_key_st;
static void AES_encrypt ( const struct aes_key_st *ctx, uint32_t *data );
static void AES_decrypt ( const struct aes_key_st *ctx, uint32_t *data );
void axtls_aes_encrypt ( void *ctx, uint32_t *data ) {
AES_encrypt ( ctx, data );
}
static inline int fseek ( FILE *stream __unused, long offset __unused,
int whence __unused ) {
return -1;
void axtls_aes_decrypt ( void *ctx, uint32_t *data ) {
AES_decrypt ( ctx, data );
}
static inline long ftell ( FILE *stream __unused ) {
return -1;
}
static inline size_t fread ( void *ptr __unused, size_t size __unused,
size_t nmemb __unused, FILE *stream __unused ) {
return -1;
}
static inline int fclose ( FILE *stream __unused ) {
return -1;
}
#define CONFIG_SSL_CERT_VERIFICATION 1
#define CONFIG_SSL_MAX_CERTS 1
#define CONFIG_X509_MAX_CA_CERTS 1
#define CONFIG_SSL_EXPIRY_TIME 24
#define CONFIG_SSL_ENABLE_CLIENT 1
#define CONFIG_BIGINT_CLASSICAL 1
#endif
#undef aes
#endif
-332
View File
@@ -1,332 +0,0 @@
/*
* Copyright(C) 2006 Cameron Rich
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* Implements the RSA public encryption algorithm. Uses the bigint library to
* perform its calculations.
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include "crypto.h"
#ifdef CONFIG_BIGINT_CRT
static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi);
#endif
void RSA_priv_key_new(RSA_CTX **ctx,
const uint8_t *modulus, int mod_len,
const uint8_t *pub_exp, int pub_len,
const uint8_t *priv_exp, int priv_len
#if CONFIG_BIGINT_CRT
, const uint8_t *p, int p_len,
const uint8_t *q, int q_len,
const uint8_t *dP, int dP_len,
const uint8_t *dQ, int dQ_len,
const uint8_t *qInv, int qInv_len
#endif
)
{
RSA_CTX *rsa_ctx;
BI_CTX *bi_ctx;
RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
rsa_ctx = *ctx;
bi_ctx = rsa_ctx->bi_ctx;
rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
bi_permanent(rsa_ctx->d);
#ifdef CONFIG_BIGINT_CRT
rsa_ctx->p = bi_import(bi_ctx, p, p_len);
rsa_ctx->q = bi_import(bi_ctx, q, q_len);
rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
bi_permanent(rsa_ctx->dP);
bi_permanent(rsa_ctx->dQ);
bi_permanent(rsa_ctx->qInv);
bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
#endif
}
void RSA_pub_key_new(RSA_CTX **ctx,
const uint8_t *modulus, int mod_len,
const uint8_t *pub_exp, int pub_len)
{
RSA_CTX *rsa_ctx;
BI_CTX *bi_ctx = bi_initialize();
*ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
rsa_ctx = *ctx;
rsa_ctx->bi_ctx = bi_ctx;
rsa_ctx->num_octets = (mod_len & 0xFFF0);
rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
bi_permanent(rsa_ctx->e);
}
/**
* Free up any RSA context resources.
*/
void RSA_free(RSA_CTX *rsa_ctx)
{
BI_CTX *bi_ctx;
if (rsa_ctx == NULL) /* deal with ptrs that are null */
return;
bi_ctx = rsa_ctx->bi_ctx;
bi_depermanent(rsa_ctx->e);
bi_free(bi_ctx, rsa_ctx->e);
bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
if (rsa_ctx->d)
{
bi_depermanent(rsa_ctx->d);
bi_free(bi_ctx, rsa_ctx->d);
#ifdef CONFIG_BIGINT_CRT
bi_depermanent(rsa_ctx->dP);
bi_depermanent(rsa_ctx->dQ);
bi_depermanent(rsa_ctx->qInv);
bi_free(bi_ctx, rsa_ctx->dP);
bi_free(bi_ctx, rsa_ctx->dQ);
bi_free(bi_ctx, rsa_ctx->qInv);
bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
#endif
}
bi_terminate(bi_ctx);
free(rsa_ctx);
}
/**
* @brief Use PKCS1.5 for decryption/verification.
* @param ctx [in] The context
* @param in_data [in] The data to encrypt (must be < modulus size-11)
* @param out_data [out] The encrypted data.
* @param is_decryption [in] Decryption or verify operation.
* @return The number of bytes that were originally encrypted. -1 on error.
* @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
*/
int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data,
uint8_t *out_data, int is_decryption)
{
int byte_size = ctx->num_octets;
uint8_t *block;
int i, size;
bigint *decrypted_bi, *dat_bi;
memset(out_data, 0, byte_size); /* initialise */
/* decrypt */
dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
#ifdef CONFIG_SSL_CERT_VERIFICATION
decrypted_bi = is_decryption ? /* decrypt or verify? */
RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
#else /* always a decryption */
decrypted_bi = RSA_private(ctx, dat_bi);
#endif
/* convert to a normal block */
block = (uint8_t *)malloc(byte_size);
bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
i = 10; /* start at the first possible non-padded byte */
#ifdef CONFIG_SSL_CERT_VERIFICATION
if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
{
while (block[i++] == 0xff && i < byte_size);
if (block[i-2] != 0xff)
i = byte_size; /*ensure size is 0 */
}
else /* PKCS1.5 encryption padding is random */
#endif
{
while (block[i++] && i < byte_size);
}
size = byte_size - i;
/* get only the bit we want */
if (size > 0)
memcpy(out_data, &block[i], size);
free(block);
return size ? size : -1;
}
/**
* Performs m = c^d mod n
*/
bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
{
#ifdef CONFIG_BIGINT_CRT
return bi_crt(c, bi_msg);
#else
BI_CTX *ctx = c->bi_ctx;
ctx->mod_offset = BIGINT_M_OFFSET;
return bi_mod_power(ctx, bi_msg, c->d);
#endif
}
#ifdef CONFIG_BIGINT_CRT
/**
* Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
* This should really be in bigint.c (and was at one stage), but needs
* access to the RSA_CTX context...
*/
static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi)
{
BI_CTX *ctx = rsa->bi_ctx;
bigint *m1, *m2, *h;
/* Montgomery has a condition the 0 < x, y < m and these products violate
* that condition. So disable Montgomery when using CRT */
#if defined(CONFIG_BIGINT_MONTGOMERY)
ctx->use_classical = 1;
#endif
ctx->mod_offset = BIGINT_P_OFFSET;
m1 = bi_mod_power(ctx, bi_copy(bi), rsa->dP);
ctx->mod_offset = BIGINT_Q_OFFSET;
m2 = bi_mod_power(ctx, bi, rsa->dQ);
h = bi_subtract(ctx, bi_add(ctx, m1, rsa->p), bi_copy(m2), NULL);
h = bi_multiply(ctx, h, rsa->qInv);
ctx->mod_offset = BIGINT_P_OFFSET;
h = bi_residue(ctx, h);
#if defined(CONFIG_BIGINT_MONTGOMERY)
ctx->use_classical = 0; /* reset for any further operation */
#endif
return bi_add(ctx, m2, bi_multiply(ctx, rsa->q, h));
}
#endif
#ifdef CONFIG_SSL_FULL_MODE
/**
* Used for diagnostics.
*/
void RSA_print(const RSA_CTX *rsa_ctx)
{
if (rsa_ctx == NULL)
return;
printf("----------------- RSA DEBUG ----------------\n");
printf("Size:\t%d\n", rsa_ctx->num_octets);
bi_print("Modulus", rsa_ctx->m);
bi_print("Public Key", rsa_ctx->e);
bi_print("Private Key", rsa_ctx->d);
}
#endif
#ifdef CONFIG_SSL_CERT_VERIFICATION
/**
* Performs c = m^e mod n
*/
bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
{
c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
return bi_mod_power(c->bi_ctx, bi_msg, c->e);
}
/**
* Use PKCS1.5 for encryption/signing.
* see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
*/
int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
uint8_t *out_data, int is_signing)
{
int byte_size = ctx->num_octets;
int num_pads_needed = byte_size-in_len-3;
bigint *dat_bi, *encrypt_bi;
/* note: in_len+11 must be > byte_size */
out_data[0] = 0; /* ensure encryption block is < modulus */
if (is_signing)
{
out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */
memset(&out_data[2], 0xff, num_pads_needed);
}
else /* randomize the encryption padding with non-zero bytes */
{
out_data[1] = 2;
get_random_NZ(num_pads_needed, &out_data[2]);
}
out_data[2+num_pads_needed] = 0;
memcpy(&out_data[3+num_pads_needed], in_data, in_len);
/* now encrypt it */
dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) :
RSA_public(ctx, dat_bi);
bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
return byte_size;
}
#if 0
/**
* Take a signature and decrypt it.
*/
bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
bigint *modulus, bigint *pub_exp)
{
uint8_t *block;
int i, size;
bigint *decrypted_bi, *dat_bi;
bigint *bir = NULL;
block = (uint8_t *)malloc(sig_len);
/* decrypt */
dat_bi = bi_import(ctx, sig, sig_len);
ctx->mod_offset = BIGINT_M_OFFSET;
/* convert to a normal block */
decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
bi_export(ctx, decrypted_bi, block, sig_len);
ctx->mod_offset = BIGINT_M_OFFSET;
i = 10; /* start at the first possible non-padded byte */
while (block[i++] && i < sig_len);
size = sig_len - i;
/* get only the bit we want */
if (size > 0)
{
int len;
const uint8_t *sig_ptr = x509_get_signature(&block[i], &len);
if (sig_ptr)
{
bir = bi_import(ctx, sig_ptr, len);
}
}
free(block);
return bir;
}
#endif
#endif /* CONFIG_SSL_CERT_VERIFICATION */
-240
View File
@@ -1,240 +0,0 @@
/*
* Copyright(C) 2006 Cameron Rich
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
* This code was originally taken from RFC3174
*/
#include <string.h>
#include "crypto.h"
/*
* Define the SHA1 circular left shift macro
*/
#define SHA1CircularShift(bits,word) \
(((word) << (bits)) | ((word) >> (32-(bits))))
/* ----- static functions ----- */
static void SHA1PadMessage(SHA1_CTX *ctx);
static void SHA1ProcessMessageBlock(SHA1_CTX *ctx);
/**
* Initialize the SHA1 context
*/
void SHA1Init(SHA1_CTX *ctx)
{
ctx->Length_Low = 0;
ctx->Length_High = 0;
ctx->Message_Block_Index = 0;
ctx->Intermediate_Hash[0] = 0x67452301;
ctx->Intermediate_Hash[1] = 0xEFCDAB89;
ctx->Intermediate_Hash[2] = 0x98BADCFE;
ctx->Intermediate_Hash[3] = 0x10325476;
ctx->Intermediate_Hash[4] = 0xC3D2E1F0;
}
/**
* Accepts an array of octets as the next portion of the message.
*/
void SHA1Update(SHA1_CTX *ctx, const uint8_t *msg, int len)
{
while (len--)
{
ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);
ctx->Length_Low += 8;
if (ctx->Length_Low == 0)
{
ctx->Length_High++;
}
if (ctx->Message_Block_Index == 64)
{
SHA1ProcessMessageBlock(ctx);
}
msg++;
}
}
/**
* Return the 160-bit message digest into the user's array
*/
void SHA1Final(SHA1_CTX *ctx, uint8_t *digest)
{
int i;
SHA1PadMessage(ctx);
memset(ctx->Message_Block, 0, 64);
ctx->Length_Low = 0; /* and clear length */
ctx->Length_High = 0;
for (i = 0; i < SHA1_SIZE; i++)
{
digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
}
}
/**
* Process the next 512 bits of the message stored in the array.
*/
static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
{
const uint32_t K[] = { /* Constants defined in SHA-1 */
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; /* Loop counter */
uint32_t temp; /* Temporary word value */
uint32_t W[80]; /* Word sequence */
uint32_t A, B, C, D, E; /* Word buffers */
/*
* Initialize the first 16 words in the array W
*/
for (t = 0; t < 16; t++)
{
W[t] = ctx->Message_Block[t * 4] << 24;
W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
W[t] |= ctx->Message_Block[t * 4 + 3];
}
for (t = 16; t < 80; t++)
{
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = ctx->Intermediate_Hash[0];
B = ctx->Intermediate_Hash[1];
C = ctx->Intermediate_Hash[2];
D = ctx->Intermediate_Hash[3];
E = ctx->Intermediate_Hash[4];
for (t = 0; t < 20; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | ((~B) & D)) + E + W[t] + K[0];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for (t = 20; t < 40; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for (t = 40; t < 60; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for (t = 60; t < 80; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
ctx->Intermediate_Hash[0] += A;
ctx->Intermediate_Hash[1] += B;
ctx->Intermediate_Hash[2] += C;
ctx->Intermediate_Hash[3] += D;
ctx->Intermediate_Hash[4] += E;
ctx->Message_Block_Index = 0;
}
/*
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64
* bits represent the length of the original message. All bits in
* between should be 0. This function will pad the message
* according to those rules by filling the Message_Block array
* accordingly. It will also call the ProcessMessageBlock function
* provided appropriately. When it returns, it can be assumed that
* the message digest has been computed.
*
* @param ctx [in, out] The SHA1 context
*/
static void SHA1PadMessage(SHA1_CTX *ctx)
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if (ctx->Message_Block_Index > 55)
{
ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
while(ctx->Message_Block_Index < 64)
{
ctx->Message_Block[ctx->Message_Block_Index++] = 0;
}
SHA1ProcessMessageBlock(ctx);
while (ctx->Message_Block_Index < 56)
{
ctx->Message_Block[ctx->Message_Block_Index++] = 0;
}
}
else
{
ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
while(ctx->Message_Block_Index < 56)
{
ctx->Message_Block[ctx->Message_Block_Index++] = 0;
}
}
/*
* Store the message length as the last 8 octets
*/
ctx->Message_Block[56] = ctx->Length_High >> 24;
ctx->Message_Block[57] = ctx->Length_High >> 16;
ctx->Message_Block[58] = ctx->Length_High >> 8;
ctx->Message_Block[59] = ctx->Length_High;
ctx->Message_Block[60] = ctx->Length_Low >> 24;
ctx->Message_Block[61] = ctx->Length_Low >> 16;
ctx->Message_Block[62] = ctx->Length_Low >> 8;
ctx->Message_Block[63] = ctx->Length_Low;
SHA1ProcessMessageBlock(ctx);
}
+3 -2
View File
@@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
#include <ipxe/crypto.h>
#include <ipxe/cbc.h>
@@ -119,7 +120,7 @@ static void aes_encrypt ( void *ctx, const void *src, void *dst,
assert ( len == AES_BLOCKSIZE );
if ( aes_ctx->decrypting )
assert ( 0 );
aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_encrypt );
aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_encrypt );
}
/**
@@ -139,7 +140,7 @@ static void aes_decrypt ( void *ctx, const void *src, void *dst,
AES_convert_key ( &aes_ctx->axtls_ctx );
aes_ctx->decrypting = 1;
}
aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_decrypt );
aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_decrypt );
}
/** Basic AES algorithm */
-25
View File
@@ -1,25 +0,0 @@
#include "crypto/axtls/crypto.h"
#include <ipxe/crypto.h>
#include <ipxe/sha1.h>
static void sha1_init ( void *ctx ) {
SHA1Init ( ctx );
}
static void sha1_update ( void *ctx, const void *data, size_t len ) {
SHA1Update ( ctx, data, len );
}
static void sha1_final ( void *ctx, void *out ) {
SHA1Final ( ctx, out );
}
struct digest_algorithm sha1_algorithm = {
.name = "sha1",
.ctxsize = SHA1_CTX_SIZE,
.blocksize = 64,
.digestsize = SHA1_DIGEST_SIZE,
.init = sha1_init,
.update = sha1_update,
.final = sha1_final,
};
+134
View File
@@ -0,0 +1,134 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <ipxe/bigint.h>
/** @file
*
* Big integer support
*/
/**
* Perform modular multiplication of big integers
*
* @v multiplicand0 Element 0 of big integer to be multiplied
* @v multiplier0 Element 0 of big integer to be multiplied
* @v modulus0 Element 0 of big integer modulus
* @v result0 Element 0 of big integer to hold result
* @v size Number of elements in base, modulus, and result
* @v tmp Temporary working space
*/
void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
const bigint_element_t *multiplier0,
const bigint_element_t *modulus0,
bigint_element_t *result0,
unsigned int size, void *tmp ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
( ( const void * ) multiplicand0 );
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
( ( const void * ) multiplier0 );
const bigint_t ( size ) __attribute__ (( may_alias )) *modulus =
( ( const void * ) modulus0 );
bigint_t ( size ) __attribute__ (( may_alias )) *result =
( ( void * ) result0 );
struct {
bigint_t ( size * 2 ) result;
bigint_t ( size * 2 ) modulus;
} *temp = tmp;
int rotation;
int i;
/* Sanity check */
assert ( sizeof ( *temp ) == bigint_mod_multiply_tmp_len ( modulus ) );
/* Perform multiplication */
bigint_multiply ( multiplicand, multiplier, &temp->result );
/* Rescale modulus to match result */
bigint_grow ( modulus, &temp->modulus );
rotation = ( bigint_max_set_bit ( &temp->result ) -
bigint_max_set_bit ( &temp->modulus ) );
for ( i = 0 ; i < rotation ; i++ )
bigint_rol ( &temp->modulus );
/* Subtract multiples of modulus */
for ( i = 0 ; i <= rotation ; i++ ) {
if ( bigint_is_geq ( &temp->result, &temp->modulus ) )
bigint_subtract ( &temp->modulus, &temp->result );
bigint_ror ( &temp->modulus );
}
/* Resize result */
bigint_shrink ( &temp->result, result );
/* Sanity check */
assert ( bigint_is_geq ( modulus, result ) );
}
/**
* Perform modular exponentiation of big integers
*
* @v base0 Element 0 of big integer base
* @v modulus0 Element 0 of big integer modulus
* @v exponent0 Element 0 of big integer exponent
* @v result0 Element 0 of big integer to hold result
* @v size Number of elements in base, modulus, and result
* @v exponent_size Number of elements in exponent
* @v tmp Temporary working space
*/
void bigint_mod_exp_raw ( const bigint_element_t *base0,
const bigint_element_t *modulus0,
const bigint_element_t *exponent0,
bigint_element_t *result0,
unsigned int size, unsigned int exponent_size,
void *tmp ) {
const bigint_t ( size ) __attribute__ (( may_alias )) *base =
( ( const void * ) base0 );
const bigint_t ( size ) __attribute__ (( may_alias )) *modulus =
( ( const void * ) modulus0 );
const bigint_t ( exponent_size ) __attribute__ (( may_alias ))
*exponent = ( ( const void * ) exponent0 );
bigint_t ( size ) __attribute__ (( may_alias )) *result =
( ( void * ) result0 );
size_t mod_multiply_len = bigint_mod_multiply_tmp_len ( modulus );
struct {
bigint_t ( size ) base;
bigint_t ( exponent_size ) exponent;
uint8_t mod_multiply[mod_multiply_len];
} *temp = tmp;
static const uint8_t start[1] = { 0x01 };
memcpy ( &temp->base, base, sizeof ( temp->base ) );
memcpy ( &temp->exponent, exponent, sizeof ( temp->exponent ) );
bigint_init ( result, start, sizeof ( start ) );
while ( ! bigint_is_zero ( &temp->exponent ) ) {
if ( bigint_bit_is_set ( &temp->exponent, 0 ) ) {
bigint_mod_multiply ( result, &temp->base, modulus,
result, temp->mod_multiply );
}
bigint_ror ( &temp->exponent );
bigint_mod_multiply ( &temp->base, &temp->base, modulus,
&temp->base, temp->mod_multiply );
}
}
+182
View File
@@ -0,0 +1,182 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ipxe/dhcp.h>
#include <ipxe/settings.h>
#include <ipxe/clientcert.h>
/** @file
*
* Client certificate store
*
* Life would in theory be easier if we could use a single file to
* hold both the certificate and corresponding private key.
* Unfortunately, the only common format which supports this is
* PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my
* codebase. See, for reference and amusement:
*
* http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html
*
*/
/* Sanity checks */
#if defined(CERTIFICATE) && ! defined(PRIVATE_KEY)
#warning "Attempting to embed certificate with no corresponding private key"
#endif
#if defined(PRIVATE_KEY) && ! defined(CERTIFICATE)
#warning "Attempting to embed private key with no corresponding certificate"
#endif
/* Allow client certificates to be overridden if not explicitly specified */
#ifdef CERTIFICATE
#define ALLOW_CERT_OVERRIDE 0
#else
#define ALLOW_CERT_OVERRIDE 1
#endif
/* Raw client certificate data */
extern char client_certificate_data[];
extern char client_certificate_len[];
__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
"\nclient_certificate_data:\n\t"
#ifdef CERTIFICATE
".incbin \"" CERTIFICATE "\"\n\t"
#endif /* CERTIFICATE */
".size client_certificate_data, ( . - client_certificate_data )\n\t"
".equ client_certificate_len, ( . - client_certificate_data )\n\t"
".previous\n\t" );
/* Raw client private key data */
extern char client_private_key_data[];
extern char client_private_key_len[];
__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
"\nclient_private_key_data:\n\t"
#ifdef PRIVATE_KEY
".incbin \"" PRIVATE_KEY "\"\n\t"
#endif /* PRIVATE_KEY */
".size client_private_key_data, ( . - client_private_key_data )\n\t"
".equ client_private_key_len, ( . - client_private_key_data )\n\t"
".previous\n\t" );
/** Client certificate */
struct client_certificate client_certificate = {
.data = client_certificate_data,
.len = ( ( size_t ) client_certificate_len ),
};
/** Client private key */
struct client_private_key client_private_key = {
.data = client_private_key_data,
.len = ( ( size_t ) client_private_key_len ),
};
/** Client certificate setting */
static struct setting cert_setting __setting ( SETTING_CRYPTO ) = {
.name = "cert",
.description = "Client certificate",
.tag = DHCP_EB_CERT,
.type = &setting_type_hex,
};
/** Client private key setting */
static struct setting key_setting __setting ( SETTING_CRYPTO ) = {
.name = "key",
.description = "Client private key",
.tag = DHCP_EB_KEY,
.type = &setting_type_hex,
};
/**
* Apply client certificate store configuration settings
*
* @ret rc Return status code
*/
static int clientcert_apply_settings ( void ) {
static void *cert = NULL;
static void *key = NULL;
int len;
int rc;
/* Allow client certificate to be overridden only if
* not explicitly specified at build time.
*/
if ( ALLOW_CERT_OVERRIDE ) {
/* Restore default client certificate */
client_certificate.data = client_certificate_data;
client_certificate.len = ( ( size_t ) client_certificate_len );
/* Fetch new client certificate, if any */
free ( cert );
len = fetch_setting_copy ( NULL, &cert_setting, &cert );
if ( len < 0 ) {
rc = len;
DBGC ( &client_certificate, "CLIENTCERT cannot fetch "
"client certificate: %s\n", strerror ( rc ) );
return rc;
}
if ( cert ) {
client_certificate.data = cert;
client_certificate.len = len;
}
/* Restore default client private key */
client_private_key.data = client_private_key_data;
client_private_key.len = ( ( size_t ) client_private_key_len );
/* Fetch new client private key, if any */
free ( key );
len = fetch_setting_copy ( NULL, &key_setting, &key );
if ( len < 0 ) {
rc = len;
DBGC ( &client_certificate, "CLIENTCERT cannot fetch "
"client private key: %s\n", strerror ( rc ) );
return rc;
}
if ( key ) {
client_private_key.data = key;
client_private_key.len = len;
}
}
/* Debug */
if ( have_client_certificate() ) {
DBGC ( &client_certificate, "CLIENTCERT using %s "
"certificate:\n", ( cert ? "external" : "built-in" ) );
DBGC_HDA ( &client_certificate, 0, client_certificate.data,
client_certificate.len );
DBGC ( &client_certificate, "CLIENTCERT using %s private "
"key:\n", ( key ? "external" : "built-in" ) );
DBGC_HDA ( &client_certificate, 0, client_private_key.data,
client_private_key.len );
} else {
DBGC ( &client_certificate, "CLIENTCERT has no certificate\n" );
}
return 0;
}
/** Client certificate store settings applicator */
struct settings_applicator clientcert_applicator __settings_applicator = {
.apply = clientcert_apply_settings,
};
+727
View File
@@ -0,0 +1,727 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Cryptographic Message Syntax (PKCS #7)
*
* The format of CMS messages is defined in RFC 5652.
*
*/
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <ipxe/asn1.h>
#include <ipxe/x509.h>
#include <ipxe/malloc.h>
#include <ipxe/uaccess.h>
#include <ipxe/cms.h>
/* Disambiguate the various error causes */
#define EACCES_NON_SIGNING \
__einfo_error ( EINFO_EACCES_NON_SIGNING )
#define EINFO_EACCES_NON_SIGNING \
__einfo_uniqify ( EINFO_EACCES, 0x01, "Not a signing certificate" )
#define EACCES_NON_CODE_SIGNING \
__einfo_error ( EINFO_EACCES_NON_CODE_SIGNING )
#define EINFO_EACCES_NON_CODE_SIGNING \
__einfo_uniqify ( EINFO_EACCES, 0x02, "Not a code-signing certificate" )
#define EACCES_WRONG_NAME \
__einfo_error ( EINFO_EACCES_WRONG_NAME )
#define EINFO_EACCES_WRONG_NAME \
__einfo_uniqify ( EINFO_EACCES, 0x04, "Incorrect certificate name" )
#define EACCES_NO_SIGNATURES \
__einfo_error ( EINFO_EACCES_NO_SIGNATURES )
#define EINFO_EACCES_NO_SIGNATURES \
__einfo_uniqify ( EINFO_EACCES, 0x05, "No signatures present" )
#define EINVAL_DIGEST \
__einfo_error ( EINFO_EINVAL_DIGEST )
#define EINFO_EINVAL_DIGEST \
__einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a digest algorithm" )
#define EINVAL_PUBKEY \
__einfo_error ( EINFO_EINVAL_PUBKEY )
#define EINFO_EINVAL_PUBKEY \
__einfo_uniqify ( EINFO_EINVAL, 0x02, "Not a public-key algorithm" )
#define ENOTSUP_SIGNEDDATA \
__einfo_error ( EINFO_ENOTSUP_SIGNEDDATA )
#define EINFO_ENOTSUP_SIGNEDDATA \
__einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Not a digital signature" )
#define ENOTSUP_DIGEST \
__einfo_error ( EINFO_ENOTSUP_DIGEST )
#define EINFO_ENOTSUP_DIGEST \
__einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported digest algorithm" )
#define ENOTSUP_PUBKEY \
__einfo_error ( EINFO_ENOTSUP_PUBKEY )
#define EINFO_ENOTSUP_PUBKEY \
__einfo_uniqify ( EINFO_ENOTSUP, 0x03, \
"Unsupported public-key algorithm" )
/** "pkcs7-signedData" object identifier */
static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA };
/** "pkcs7-signedData" object identifier cursor */
static struct asn1_cursor oid_signeddata_cursor =
ASN1_OID_CURSOR ( oid_signeddata );
/**
* Parse CMS signature content type
*
* @v sig CMS signature
* @v raw ASN.1 cursor
* @ret rc Return status code
*/
static int cms_parse_content_type ( struct cms_signature *sig,
const struct asn1_cursor *raw ) {
struct asn1_cursor cursor;
/* Enter contentType */
memcpy ( &cursor, raw, sizeof ( cursor ) );
asn1_enter ( &cursor, ASN1_OID );
/* Check OID is pkcs7-signedData */
if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) {
DBGC ( sig, "CMS %p does not contain signedData:\n", sig );
DBGC_HDA ( sig, 0, raw->data, raw->len );
return -ENOTSUP_SIGNEDDATA;
}
DBGC ( sig, "CMS %p contains signedData\n", sig );
return 0;
}
/**
* Parse CMS signature certificate list
*
* @v sig CMS signature
* @v raw ASN.1 cursor
* @ret rc Return status code
*/
static int cms_parse_certificates ( struct cms_signature *sig,
const struct asn1_cursor *raw ) {
struct asn1_cursor cursor;
struct x509_certificate *cert;
int rc;
/* Enter certificates */
memcpy ( &cursor, raw, sizeof ( cursor ) );
asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
/* Add each certificate */
while ( cursor.len ) {
/* Add certificate to chain */
if ( ( rc = x509_append_raw ( sig->certificates, cursor.data,
cursor.len ) ) != 0 ) {
DBGC ( sig, "CMS %p could not append certificate: %s\n",
sig, strerror ( rc) );
DBGC_HDA ( sig, 0, cursor.data, cursor.len );
return rc;
}
cert = x509_last ( sig->certificates );
DBGC ( sig, "CMS %p found certificate %s\n",
sig, cert->subject.name );
/* Move to next certificate */
asn1_skip_any ( &cursor );
}
return 0;
}
/**
* Identify CMS signature certificate by issuer and serial number
*
* @v sig CMS signature
* @v issuer Issuer
* @v serial Serial number
* @ret cert X.509 certificate, or NULL if not found
*/
static struct x509_certificate *
cms_find_issuer_serial ( struct cms_signature *sig,
const struct asn1_cursor *issuer,
const struct asn1_cursor *serial ) {
struct x509_link *link;
struct x509_certificate *cert;
/* Scan through certificate list */
list_for_each_entry ( link, &sig->certificates->links, list ) {
/* Check issuer and serial number */
cert = link->cert;
if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) &&
( asn1_compare ( serial, &cert->serial.raw ) == 0 ) )
return cert;
}
return NULL;
}
/**
* Parse CMS signature signer identifier
*
* @v sig CMS signature
* @v info Signer information to fill in
* @v raw ASN.1 cursor
* @ret rc Return status code
*/
static int cms_parse_signer_identifier ( struct cms_signature *sig,
struct cms_signer_info *info,
const struct asn1_cursor *raw ) {
struct asn1_cursor cursor;
struct asn1_cursor serial;
struct asn1_cursor issuer;
struct x509_certificate *cert;
int rc;
/* Enter issuerAndSerialNumber */
memcpy ( &cursor, raw, sizeof ( cursor ) );
asn1_enter ( &cursor, ASN1_SEQUENCE );
/* Identify issuer */
memcpy ( &issuer, &cursor, sizeof ( issuer ) );
if ( ( rc = asn1_shrink ( &issuer, ASN1_SEQUENCE ) ) != 0 ) {
DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n",
sig, info, strerror ( rc ) );
DBGC_HDA ( sig, 0, raw->data, raw->len );
return rc;
}
DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info );
DBGC_HDA ( sig, 0, issuer.data, issuer.len );
asn1_skip_any ( &cursor );
/* Identify serialNumber */
memcpy ( &serial, &cursor, sizeof ( serial ) );
if ( ( rc = asn1_shrink ( &serial, ASN1_INTEGER ) ) != 0 ) {
DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n",
sig, info, strerror ( rc ) );
DBGC_HDA ( sig, 0, raw->data, raw->len );
return rc;
}
DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info );
DBGC_HDA ( sig, 0, serial.data, serial.len );
/* Identify certificate */
cert = cms_find_issuer_serial ( sig, &issuer, &serial );
if ( ! cert ) {
DBGC ( sig, "CMS %p/%p could not identify signer's "
"certificate\n", sig, info );
return -ENOENT;
}
/* Append certificate to chain */
if ( ( rc = x509_append ( info->chain, cert ) ) != 0 ) {
DBGC ( sig, "CMS %p/%p could not append certificate: %s\n",
sig, info, strerror ( rc ) );
return rc;
}
/* Append remaining certificates to chain */
if ( ( rc = x509_auto_append ( info->chain,
sig->certificates ) ) != 0 ) {
DBGC ( sig, "CMS %p/%p could not append certificates: %s\n",
sig, info, strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Parse CMS signature digest algorithm
*
* @v sig CMS signature
* @v info Signer information to fill in
* @v raw ASN.1 cursor
* @ret rc Return status code
*/
static int cms_parse_digest_algorithm ( struct cms_signature *sig,
struct cms_signer_info *info,
const struct asn1_cursor *raw ) {
struct asn1_algorithm *algorithm;
/* Identify algorithm */
algorithm = asn1_algorithm ( raw );
if ( ! algorithm ) {
DBGC ( sig, "CMS %p/%p could not identify digest algorithm:\n",
sig, info );
DBGC_HDA ( sig, 0, raw->data, raw->len );
return -ENOTSUP_DIGEST;
}
/* Check algorithm is a digest algorithm */
if ( ! algorithm->digest ) {
DBGC ( sig, "CMS %p/%p algorithm %s is not a digest "
"algorithm\n", sig, info, algorithm->name );
return -EINVAL_DIGEST;
}
/* Record digest algorithm */
info->digest = algorithm->digest;
DBGC ( sig, "CMS %p/%p digest algorithm is %s\n",
sig, info, algorithm->name );
return 0;
}
/**
* Parse CMS signature algorithm
*
* @v sig CMS signature
* @v info Signer information to fill in
* @v raw ASN.1 cursor
* @ret rc Return status code
*/
static int cms_parse_signature_algorithm ( struct cms_signature *sig,
struct cms_signer_info *info,
const struct asn1_cursor *raw ) {
struct asn1_algorithm *algorithm;
/* Identify algorithm */
algorithm = asn1_algorithm ( raw );
if ( ! algorithm ) {
DBGC ( sig, "CMS %p/%p could not identify public-key "
"algorithm:\n", sig, info );
DBGC_HDA ( sig, 0, raw->data, raw->len );
return -ENOTSUP_PUBKEY;
}
/* Check algorithm is a signature algorithm */
if ( ! algorithm->pubkey ) {
DBGC ( sig, "CMS %p/%p algorithm %s is not a public-key "
"algorithm\n", sig, info, algorithm->name );
return -EINVAL_PUBKEY;
}
/* Record signature algorithm */
info->pubkey = algorithm->pubkey;
DBGC ( sig, "CMS %p/%p public-key algorithm is %s\n",
sig, info, algorithm->name );
return 0;
}
/**
* Parse CMS signature value
*
* @v sig CMS signature
* @v info Signer information to fill in
* @v raw ASN.1 cursor
* @ret rc Return status code
*/
static int cms_parse_signature_value ( struct cms_signature *sig,
struct cms_signer_info *info,
const struct asn1_cursor *raw ) {
struct asn1_cursor cursor;
int rc;
/* Enter signature */
memcpy ( &cursor, raw, sizeof ( cursor ) );
if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
DBGC ( sig, "CMS %p/%p could not locate signature:\n",
sig, info );
DBGC_HDA ( sig, 0, raw->data, raw->len );
return rc;
}
/* Record signature */
info->signature_len = cursor.len;
info->signature = malloc ( info->signature_len );
if ( ! info->signature )
return -ENOMEM;
memcpy ( info->signature, cursor.data, info->signature_len );
DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info );
DBGC_HDA ( sig, 0, info->signature, info->signature_len );
return 0;
}
/**
* Parse CMS signature signer information
*
* @v sig CMS signature
* @v info Signer information to fill in
* @v raw ASN.1 cursor
* @ret rc Return status code
*/
static int cms_parse_signer_info ( struct cms_signature *sig,
struct cms_signer_info *info,
const struct asn1_cursor *raw ) {
struct asn1_cursor cursor;
int rc;
/* Enter signerInfo */
memcpy ( &cursor, raw, sizeof ( cursor ) );
asn1_enter ( &cursor, ASN1_SEQUENCE );
/* Skip version */
asn1_skip ( &cursor, ASN1_INTEGER );
/* Parse sid */
if ( ( rc = cms_parse_signer_identifier ( sig, info, &cursor ) ) != 0 )
return rc;
asn1_skip_any ( &cursor );
/* Parse digestAlgorithm */
if ( ( rc = cms_parse_digest_algorithm ( sig, info, &cursor ) ) != 0 )
return rc;
asn1_skip_any ( &cursor );
/* Skip signedAttrs, if present */
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
/* Parse signatureAlgorithm */
if ( ( rc = cms_parse_signature_algorithm ( sig, info, &cursor ) ) != 0)
return rc;
asn1_skip_any ( &cursor );
/* Parse signature */
if ( ( rc = cms_parse_signature_value ( sig, info, &cursor ) ) != 0 )
return rc;
return 0;
}
/**
* Parse CMS signature from ASN.1 data
*
* @v sig CMS signature
* @v raw ASN.1 cursor
* @ret rc Return status code
*/
static int cms_parse ( struct cms_signature *sig,
const struct asn1_cursor *raw ) {
struct asn1_cursor cursor;
struct cms_signer_info *info;
int rc;
/* Enter contentInfo */
memcpy ( &cursor, raw, sizeof ( cursor ) );
asn1_enter ( &cursor, ASN1_SEQUENCE );
/* Parse contentType */
if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
return rc;
asn1_skip_any ( &cursor );
/* Enter content */
asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
/* Enter signedData */
asn1_enter ( &cursor, ASN1_SEQUENCE );
/* Skip version */
asn1_skip ( &cursor, ASN1_INTEGER );
/* Skip digestAlgorithms */
asn1_skip ( &cursor, ASN1_SET );
/* Skip encapContentInfo */
asn1_skip ( &cursor, ASN1_SEQUENCE );
/* Parse certificates */
if ( ( rc = cms_parse_certificates ( sig, &cursor ) ) != 0 )
return rc;
asn1_skip_any ( &cursor );
/* Skip crls, if present */
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) );
/* Enter signerInfos */
asn1_enter ( &cursor, ASN1_SET );
/* Add each signerInfo. Errors are handled by ensuring that
* cms_put() will always be able to free any allocated memory.
*/
while ( cursor.len ) {
/* Allocate signer information block */
info = zalloc ( sizeof ( *info ) );
if ( ! info )
return -ENOMEM;
list_add ( &info->list, &sig->info );
/* Allocate certificate chain */
info->chain = x509_alloc_chain();
if ( ! info->chain )
return -ENOMEM;
/* Parse signerInfo */
if ( ( rc = cms_parse_signer_info ( sig, info,
&cursor ) ) != 0 )
return rc;
asn1_skip_any ( &cursor );
}
return 0;
}
/**
* Free CMS signature
*
* @v refcnt Reference count
*/
static void cms_free ( struct refcnt *refcnt ) {
struct cms_signature *sig =
container_of ( refcnt, struct cms_signature, refcnt );
struct cms_signer_info *info;
struct cms_signer_info *tmp;
list_for_each_entry_safe ( info, tmp, &sig->info, list ) {
list_del ( &info->list );
x509_chain_put ( info->chain );
free ( info->signature );
free ( info );
}
x509_chain_put ( sig->certificates );
free ( sig );
}
/**
* Create CMS signature
*
* @v data Raw signature data
* @v len Length of raw data
* @ret sig CMS signature
* @ret rc Return status code
*
* On success, the caller holds a reference to the CMS signature, and
* is responsible for ultimately calling cms_put().
*/
int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) {
struct asn1_cursor cursor;
int rc;
/* Allocate and initialise signature */
*sig = zalloc ( sizeof ( **sig ) );
if ( ! *sig ) {
rc = -ENOMEM;
goto err_alloc;
}
ref_init ( &(*sig)->refcnt, cms_free );
INIT_LIST_HEAD ( &(*sig)->info );
/* Allocate certificate list */
(*sig)->certificates = x509_alloc_chain();
if ( ! (*sig)->certificates ) {
rc = -ENOMEM;
goto err_alloc_chain;
}
/* Initialise cursor */
cursor.data = data;
cursor.len = len;
asn1_shrink_any ( &cursor );
/* Parse signature */
if ( ( rc = cms_parse ( *sig, &cursor ) ) != 0 )
goto err_parse;
return 0;
err_parse:
err_alloc_chain:
cms_put ( *sig );
err_alloc:
return rc;
}
/**
* Calculate digest of CMS-signed data
*
* @v sig CMS signature
* @v info Signer information
* @v data Signed data
* @v len Length of signed data
* @v out Digest output
*/
static void cms_digest ( struct cms_signature *sig,
struct cms_signer_info *info,
userptr_t data, size_t len, void *out ) {
struct digest_algorithm *digest = info->digest;
uint8_t ctx[ digest->ctxsize ];
uint8_t block[ digest->blocksize ];
size_t offset = 0;
size_t frag_len;
/* Initialise digest */
digest_init ( digest, ctx );
/* Process data one block at a time */
while ( len ) {
frag_len = len;
if ( frag_len > sizeof ( block ) )
frag_len = sizeof ( block );
copy_from_user ( block, data, offset, frag_len );
digest_update ( digest, ctx, block, frag_len );
offset += frag_len;
len -= frag_len;
}
/* Finalise digest */
digest_final ( digest, ctx, out );
DBGC ( sig, "CMS %p/%p digest value:\n", sig, info );
DBGC_HDA ( sig, 0, out, digest->digestsize );
}
/**
* Verify digest of CMS-signed data
*
* @v sig CMS signature
* @v info Signer information
* @v cert Corresponding certificate
* @v data Signed data
* @v len Length of signed data
* @ret rc Return status code
*/
static int cms_verify_digest ( struct cms_signature *sig,
struct cms_signer_info *info,
struct x509_certificate *cert,
userptr_t data, size_t len ) {
struct digest_algorithm *digest = info->digest;
struct pubkey_algorithm *pubkey = info->pubkey;
struct x509_public_key *public_key = &cert->subject.public_key;
uint8_t digest_out[ digest->digestsize ];
uint8_t ctx[ pubkey->ctxsize ];
int rc;
/* Generate digest */
cms_digest ( sig, info, data, len, digest_out );
/* Initialise public-key algorithm */
if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data,
public_key->raw.len ) ) != 0 ) {
DBGC ( sig, "CMS %p/%p could not initialise public key: %s\n",
sig, info, strerror ( rc ) );
goto err_init;
}
/* Verify digest */
if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out,
info->signature,
info->signature_len ) ) != 0 ) {
DBGC ( sig, "CMS %p/%p signature verification failed: %s\n",
sig, info, strerror ( rc ) );
goto err_verify;
}
err_verify:
pubkey_final ( pubkey, ctx );
err_init:
return rc;
}
/**
* Verify CMS signature signer information
*
* @v sig CMS signature
* @v info Signer information
* @v data Signed data
* @v len Length of signed data
* @v time Time at which to validate certificates
* @v root Root certificate store, or NULL to use default
* @ret rc Return status code
*/
static int cms_verify_signer_info ( struct cms_signature *sig,
struct cms_signer_info *info,
userptr_t data, size_t len,
time_t time, struct x509_root *root ) {
struct x509_certificate *cert;
int rc;
/* Validate certificate chain */
if ( ( rc = x509_validate_chain ( info->chain, time, root ) ) != 0 ) {
DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
sig, info, strerror ( rc ) );
return rc;
}
/* Extract code-signing certificate */
cert = x509_first ( info->chain );
assert ( cert != NULL );
/* Check that certificate can create digital signatures */
if ( ! ( cert->extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) {
DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n",
sig, info );
return -EACCES_NON_SIGNING;
}
/* Check that certificate can sign code */
if ( ! ( cert->extensions.ext_usage.bits & X509_CODE_SIGNING ) ) {
DBGC ( sig, "CMS %p/%p certificate is not code-signing\n",
sig, info );
return -EACCES_NON_CODE_SIGNING;
}
/* Verify digest */
if ( ( rc = cms_verify_digest ( sig, info, cert, data, len ) ) != 0 )
return rc;
return 0;
}
/**
* Verify CMS signature
*
* @v sig CMS signature
* @v data Signed data
* @v len Length of signed data
* @v name Required common name, or NULL to check all signatures
* @v time Time at which to validate certificates
* @v root Root certificate store, or NULL to use default
* @ret rc Return status code
*/
int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
const char *name, time_t time, struct x509_root *root ) {
struct cms_signer_info *info;
struct x509_certificate *cert;
int count = 0;
int rc;
/* Verify using all signerInfos */
list_for_each_entry ( info, &sig->info, list ) {
cert = x509_first ( info->chain );
if ( name && ( ( cert->subject.name == NULL ) ||
( strcmp ( cert->subject.name, name ) != 0 ) ) )
continue;
if ( ( rc = cms_verify_signer_info ( sig, info, data, len,
time, root ) ) != 0 )
return rc;
count++;
}
/* Check that we have verified at least one signature */
if ( count == 0 ) {
if ( name ) {
DBGC ( sig, "CMS %p had no signatures matching name "
"%s\n", sig, name );
return -EACCES_WRONG_NAME;
} else {
DBGC ( sig, "CMS %p had no signatures\n", sig );
return -EACCES_NO_SIGNATURES;
}
}
return 0;
}
-55
View File
@@ -1,55 +0,0 @@
/*
* Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Cryptographically strong random number generator
*
* Currently the cryptographic part is not implemented, and this just
* uses random().
*/
#include <ipxe/crypto.h>
#include <stdlib.h>
/**
* Get cryptographically strong random bytes
*
* @v buf Buffer in which to store random bytes
* @v len Number of random bytes to generate
*
* @b WARNING: This function is currently underimplemented, and does
* not give numbers any stronger than random()!
*/
void get_random_bytes ( void *buf, size_t len )
{
u8 *bufp = buf;
/*
* Somewhat arbitrarily, choose the 0x00FF0000-masked byte
* returned by random() as having good entropy. PRNGs often
* don't provide good entropy in lower bits, and the top byte
* might show a pattern because of sign issues.
*/
while ( len-- ) {
*bufp++ = ( random() >> 16 ) & 0xFF;
}
}
+49
View File
@@ -81,7 +81,56 @@ struct cipher_algorithm cipher_null = {
.decrypt = cipher_null_decrypt,
};
static int pubkey_null_init ( void *ctx __unused, const void *key __unused,
size_t key_len __unused ) {
return 0;
}
static size_t pubkey_null_max_len ( void *ctx __unused ) {
return 0;
}
static int pubkey_null_encrypt ( void *ctx __unused,
const void *plaintext __unused,
size_t plaintext_len __unused,
void *ciphertext __unused ) {
return 0;
}
static int pubkey_null_decrypt ( void *ctx __unused,
const void *ciphertext __unused,
size_t ciphertext_len __unused,
void *plaintext __unused ) {
return 0;
}
static int pubkey_null_sign ( void *ctx __unused,
struct digest_algorithm *digest __unused,
const void *value __unused,
void *signature __unused ) {
return 0;
}
static int pubkey_null_verify ( void *ctx __unused,
struct digest_algorithm *digest __unused,
const void *value __unused,
const void *signature __unused ,
size_t signature_len __unused ) {
return 0;
}
static void pubkey_null_final ( void *ctx __unused ) {
/* Do nothing */
}
struct pubkey_algorithm pubkey_null = {
.name = "null",
.ctxsize = 0,
.init = pubkey_null_init,
.max_len = pubkey_null_max_len,
.encrypt = pubkey_null_encrypt,
.decrypt = pubkey_null_decrypt,
.sign = pubkey_null_sign,
.verify = pubkey_null_verify,
.final = pubkey_null_final,
};
+18 -8
View File
@@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/entropy.h>
@@ -62,7 +63,7 @@ int drbg_instantiate ( struct drbg_state *state, const void *personal,
unsigned int entropy_bits = ( ( 3 * DRBG_SECURITY_STRENGTH + 1 ) / 2 );
size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES;
size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES;
uint8_t data[ entropy_bufsize ( entropy_bits, min_len, max_len ) ];
uint8_t data[max_len];
int len;
int rc;
@@ -127,8 +128,8 @@ int drbg_instantiate ( struct drbg_state *state, const void *personal,
state, strerror ( rc ) );
return rc;
}
assert ( len >= min_len );
assert ( len <= sizeof ( data ) );
assert ( len >= ( int ) min_len );
assert ( len <= ( int ) sizeof ( data ) );
/* 9. initial_working_state = Instantiate_algorithm (
* entropy_input, nonce, personalization_string ).
@@ -150,6 +151,7 @@ int drbg_instantiate ( struct drbg_state *state, const void *personal,
* in-situ.)
*/
state->reseed_required = 0;
state->valid = 1;
/* 12. Return SUCCESS and state_handle. */
return 0;
@@ -173,7 +175,7 @@ int drbg_reseed ( struct drbg_state *state, const void *additional,
unsigned int entropy_bits = DRBG_SECURITY_STRENGTH;
size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES;
size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES;
uint8_t data[ entropy_bufsize ( entropy_bits, min_len, max_len ) ];
uint8_t data[max_len];
int len;
int rc;
@@ -186,9 +188,13 @@ int drbg_reseed ( struct drbg_state *state, const void *additional,
* If state_handle indicates an invalid or empty internal
* state, return an ERROR_FLAG.
*
* (Nothing to do since the memory holding the internal state
* was passed in by the caller.)
* (Almost nothing to do since the memory holding the internal
* state was passed in by the caller.)
*/
if ( ! state->valid ) {
DBGC ( state, "DRBG %p not valid\n", state );
return -EINVAL;
}
/* 2. If prediction_resistance_request is set, and
* prediction_resistance_flag is not set, then return an
@@ -272,9 +278,13 @@ int drbg_generate ( struct drbg_state *state, const void *additional,
* for the instantiation. If state_handle indicates an
* invalid or empty internal state, then return an ERROR_FLAG.
*
* (Nothing to do since the memory holding the internal state
* was passed in by the caller.)
* (Almost nothing to do since the memory holding the internal
* state was passed in by the caller.)
*/
if ( ! state->valid ) {
DBGC ( state, "DRBG %p not valid\n", state );
return -EINVAL;
}
/* 2. If requested_number_of_bits >
* max_number_of_bits_per_request, then return an
+443 -13
View File
@@ -22,27 +22,457 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
* Entropy source
*
* This algorithm is designed to comply with ANS X9.82 Part 4 (April
* 2011 Draft) Section 13.3. This standard is unfortunately not
* freely available.
*/
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <ipxe/crypto.h>
#include <ipxe/hash_df.h>
#include <ipxe/entropy.h>
/* Disambiguate the various error causes */
#define EPIPE_REPETITION_COUNT_TEST \
__einfo_error ( EINFO_EPIPE_REPETITION_COUNT_TEST )
#define EINFO_EPIPE_REPETITION_COUNT_TEST \
__einfo_uniqify ( EINFO_EPIPE, 0x01, "Repetition count test failed" )
#define EPIPE_ADAPTIVE_PROPORTION_TEST \
__einfo_error ( EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST )
#define EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST \
__einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" )
/**
* Obtain entropy input
* Calculate cutoff value for the repetition count test
*
* @v entropy_bits Minimum amount of entropy, in bits
* @v data Data buffer
* @v min_len Minimum length of entropy input, in bytes
* @v max_len Maximum length of entropy input, in bytes
* @ret len Length of entropy input, in bytes
* @ret cutoff Cutoff value
*
* This is the cutoff value for the Repetition Count Test defined in
* ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2.
*/
int get_entropy_input ( unsigned int entropy_bits, void *data, size_t min_len,
size_t max_len ) {
static inline __attribute__ (( always_inline )) unsigned int
repetition_count_cutoff ( void ) {
double max_repetitions;
unsigned int cutoff;
/* Placeholder to allow remainder of RBG code to be tested */
( void ) entropy_bits;
( void ) min_len;
memset ( data, 0x01, max_len );
/* The cutoff formula for the repetition test is:
*
* C = ( 1 + ( -log2(W) / H_min ) )
*
* where W is set at 2^(-30) (in ANS X9.82 Part 2 (October
* 2011 Draft) Section 8.5.2.1.3.1).
*/
max_repetitions = ( 1 + ( 30 / min_entropy_per_sample() ) );
return max_len;
/* Round up to a whole number of repetitions. We don't have
* the ceil() function available, so do the rounding by hand.
*/
cutoff = max_repetitions;
if ( cutoff < max_repetitions )
cutoff++;
linker_assert ( ( cutoff >= max_repetitions ), rounding_error );
/* Floating-point operations are not allowed in iPXE since we
* never set up a suitable environment. Abort the build
* unless the calculated number of repetitions is a
* compile-time constant.
*/
linker_assert ( __builtin_constant_p ( cutoff ),
repetition_count_cutoff_not_constant );
return cutoff;
}
/**
* Perform repetition count test
*
* @v sample Noise sample
* @ret rc Return status code
*
* This is the Repetition Count Test defined in ANS X9.82 Part 2
* (October 2011 Draft) Section 8.5.2.1.2.
*/
static int repetition_count_test ( noise_sample_t sample ) {
static noise_sample_t most_recent_sample;
static unsigned int repetition_count = 0;
/* A = the most recently seen sample value
* B = the number of times that value A has been seen in a row
* C = the cutoff value above which the repetition test should fail
*/
/* 1. For each new sample processed:
*
* (Note that the test for "repetition_count > 0" ensures that
* the initial value of most_recent_sample is treated as being
* undefined.)
*/
if ( ( sample == most_recent_sample ) && ( repetition_count > 0 ) ) {
/* a) If the new sample = A, then B is incremented by one. */
repetition_count++;
/* i. If B >= C, then an error condition is raised
* due to a failure of the test
*/
if ( repetition_count >= repetition_count_cutoff() )
return -EPIPE_REPETITION_COUNT_TEST;
} else {
/* b) Else:
* i. A = new sample
*/
most_recent_sample = sample;
/* ii. B = 1 */
repetition_count = 1;
}
return 0;
}
/**
* Window size for the adaptive proportion test
*
* ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows
* five possible window sizes: 16, 64, 256, 4096 and 65536.
*
* We expect to generate relatively few (<256) entropy samples during
* a typical iPXE run; the use of a large window size would mean that
* the test would never complete a single cycle. We use a window size
* of 64, which is the smallest window size that permits values of
* H_min down to one bit per sample.
*/
#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64
/**
* Combine adaptive proportion test window size and min-entropy
*
* @v n N (window size)
* @v h H (min-entropy)
* @ret n_h (N,H) combined value
*/
#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) )
/**
* Define a row of the adaptive proportion cutoff table
*
* @v h H (min-entropy)
* @v c16 Cutoff for N=16
* @v c64 Cutoff for N=64
* @v c256 Cutoff for N=256
* @v c4096 Cutoff for N=4096
* @v c65536 Cutoff for N=65536
*/
#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536) \
case APC_N_H ( 16, h ) : return c16; \
case APC_N_H ( 64, h ) : return c64; \
case APC_N_H ( 256, h ) : return c256; \
case APC_N_H ( 4096, h ) : return c4096; \
case APC_N_H ( 65536, h ) : return c65536;
/** Value used to represent "N/A" in adaptive proportion cutoff table */
#define APC_NA 0
/**
* Look up value in adaptive proportion test cutoff table
*
* @v n N (window size)
* @v h H (min-entropy)
* @ret cutoff Cutoff
*
* This is the table of cutoff values defined in ANS X9.82 Part 2
* (October 2011 Draft) Section 8.5.2.1.3.1.2.
*/
static inline __attribute__ (( always_inline )) unsigned int
adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) {
switch ( APC_N_H ( n, h ) ) {
APC_TABLE_ROW ( 1, APC_NA, 51, 168, 2240, 33537 );
APC_TABLE_ROW ( 2, APC_NA, 35, 100, 1193, 17053 );
APC_TABLE_ROW ( 3, 10, 24, 61, 643, 8705 );
APC_TABLE_ROW ( 4, 8, 16, 38, 354, 4473 );
APC_TABLE_ROW ( 5, 6, 12, 25, 200, 2321 );
APC_TABLE_ROW ( 6, 5, 9, 17, 117, 1220 );
APC_TABLE_ROW ( 7, 4, 7, 15, 71, 653 );
APC_TABLE_ROW ( 8, 4, 5, 9, 45, 358 );
APC_TABLE_ROW ( 9, 3, 4, 7, 30, 202 );
APC_TABLE_ROW ( 10, 3, 4, 5, 21, 118 );
APC_TABLE_ROW ( 11, 2, 3, 4, 15, 71 );
APC_TABLE_ROW ( 12, 2, 3, 4, 11, 45 );
APC_TABLE_ROW ( 13, 2, 2, 3, 9, 30 );
APC_TABLE_ROW ( 14, 2, 2, 3, 7, 21 );
APC_TABLE_ROW ( 15, 1, 2, 2, 6, 15 );
APC_TABLE_ROW ( 16, 1, 2, 2, 5, 11 );
APC_TABLE_ROW ( 17, 1, 1, 2, 4, 9 );
APC_TABLE_ROW ( 18, 1, 1, 2, 4, 7 );
APC_TABLE_ROW ( 19, 1, 1, 1, 3, 6 );
APC_TABLE_ROW ( 20, 1, 1, 1, 3, 5 );
default:
return APC_NA;
}
}
/**
* Calculate cutoff value for the adaptive proportion test
*
* @ret cutoff Cutoff value
*
* This is the cutoff value for the Adaptive Proportion Test defined
* in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2.
*/
static inline __attribute__ (( always_inline )) unsigned int
adaptive_proportion_cutoff ( void ) {
unsigned int h;
unsigned int n;
unsigned int cutoff;
/* Look up cutoff value in cutoff table */
n = ADAPTIVE_PROPORTION_WINDOW_SIZE;
h = min_entropy_per_sample();
cutoff = adaptive_proportion_cutoff_lookup ( n, h );
/* Fail unless cutoff value is a build-time constant */
linker_assert ( __builtin_constant_p ( cutoff ),
adaptive_proportion_cutoff_not_constant );
/* Fail if cutoff value is N/A */
linker_assert ( ( cutoff != APC_NA ),
adaptive_proportion_cutoff_not_applicable );
return cutoff;
}
/**
* Perform adaptive proportion test
*
* @v sample Noise sample
* @ret rc Return status code
*
* This is the Adaptive Proportion Test for the Most Common Value
* defined in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.
*/
static int adaptive_proportion_test ( noise_sample_t sample ) {
static noise_sample_t current_counted_sample;
static unsigned int sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
static unsigned int repetition_count;
/* A = the sample value currently being counted
* B = the number of samples examined in this run of the test so far
* N = the total number of samples that must be observed in
* one run of the test, also known as the "window size" of
* the test
* B = the current number of times that S (sic) has been seen
* in the W (sic) samples examined so far
* C = the cutoff value above which the repetition test should fail
* W = the probability of a false positive: 2^-30
*/
/* 1. The entropy source draws the current sample from the
* noise source.
*
* (Nothing to do; we already have the current sample.)
*/
/* 2. If S = N, then a new run of the test begins: */
if ( sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) {
/* a. A = the current sample */
current_counted_sample = sample;
/* b. S = 0 */
sample_count = 0;
/* c. B = 0 */
repetition_count = 0;
} else {
/* Else: (the test is already running)
* a. S = S + 1
*/
sample_count++;
/* b. If A = the current sample, then: */
if ( sample == current_counted_sample ) {
/* i. B = B + 1 */
repetition_count++;
/* ii. If S (sic) > C then raise an error
* condition, because the test has
* detected a failure
*/
if ( repetition_count > adaptive_proportion_cutoff() )
return -EPIPE_ADAPTIVE_PROPORTION_TEST;
}
}
return 0;
}
/**
* Get entropy sample
*
* @ret entropy Entropy sample
* @ret rc Return status code
*
* This is the GetEntropy function defined in ANS X9.82 Part 2
* (October 2011 Draft) Section 6.5.1.
*/
static int get_entropy ( entropy_sample_t *entropy ) {
static int rc = 0;
noise_sample_t noise;
/* Any failure is permanent */
if ( rc != 0 )
return rc;
/* Get noise sample */
if ( ( rc = get_noise ( &noise ) ) != 0 )
return rc;
/* Perform Repetition Count Test and Adaptive Proportion Test
* as mandated by ANS X9.82 Part 2 (October 2011 Draft)
* Section 8.5.2.1.1.
*/
if ( ( rc = repetition_count_test ( noise ) ) != 0 )
return rc;
if ( ( rc = adaptive_proportion_test ( noise ) ) != 0 )
return rc;
/* We do not use any optional conditioning component */
*entropy = noise;
return 0;
}
/**
* Calculate number of samples required for startup tests
*
* @ret num_samples Number of samples required
*
* ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires
* that at least one full cycle of the continuous tests must be
* performed at start-up.
*/
static inline __attribute__ (( always_inline )) unsigned int
startup_test_count ( void ) {
unsigned int num_samples;
/* At least max(N,C) samples shall be generated by the noise
* source for start-up testing.
*/
num_samples = repetition_count_cutoff();
if ( num_samples < adaptive_proportion_cutoff() )
num_samples = adaptive_proportion_cutoff();
linker_assert ( __builtin_constant_p ( num_samples ),
startup_test_count_not_constant );
return num_samples;
}
/**
* Create next nonce value
*
* @ret nonce Nonce
*
* This is the MakeNextNonce function defined in ANS X9.82 Part 4
* (April 2011 Draft) Section 13.3.4.2.
*/
static uint32_t make_next_nonce ( void ) {
static uint32_t nonce;
/* The simplest implementation of a nonce uses a large counter */
nonce++;
return nonce;
}
/**
* Obtain entropy input temporary buffer
*
* @v num_samples Number of entropy samples
* @v tmp Temporary buffer
* @v tmp_len Length of temporary buffer
* @ret rc Return status code
*
* This is (part of) the implementation of the Get_entropy_input
* function (using an entropy source as the source of entropy input
* and condensing each entropy source output after each GetEntropy
* call) as defined in ANS X9.82 Part 4 (April 2011 Draft) Section
* 13.3.4.2.
*
* To minimise code size, the number of samples required is calculated
* at compilation time.
*/
int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
size_t tmp_len ) {
static unsigned int startup_tested = 0;
struct {
uint32_t nonce;
entropy_sample_t sample;
} __attribute__ (( packed )) data;;
uint8_t df_buf[tmp_len];
unsigned int i;
int rc;
/* Enable entropy gathering */
if ( ( rc = entropy_enable() ) != 0 )
return rc;
/* Perform mandatory startup tests, if not yet performed */
for ( ; startup_tested < startup_test_count() ; startup_tested++ ) {
if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
goto err_get_entropy;
}
/* 3. entropy_total = 0
*
* (Nothing to do; the number of entropy samples required has
* already been precalculated.)
*/
/* 4. tmp = a fixed n-bit value, such as 0^n */
memset ( tmp, 0, tmp_len );
/* 5. While ( entropy_total < min_entropy ) */
while ( num_samples-- ) {
/* 5.1. ( status, entropy_bitstring, assessed_entropy )
* = GetEntropy()
* 5.2. If status indicates an error, return ( status, Null )
*/
if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
goto err_get_entropy;
/* 5.3. nonce = MakeNextNonce() */
data.nonce = make_next_nonce();
/* 5.4. tmp = tmp XOR
* df ( ( nonce || entropy_bitstring ), n )
*/
hash_df ( &entropy_hash_df_algorithm, &data, sizeof ( data ),
df_buf, sizeof ( df_buf ) );
for ( i = 0 ; i < tmp_len ; i++ )
tmp[i] ^= df_buf[i];
/* 5.5. entropy_total = entropy_total + assessed_entropy
*
* (Nothing to do; the number of entropy samples
* required has already been precalculated.)
*/
}
/* Disable entropy gathering */
entropy_disable();
return 0;
err_get_entropy:
entropy_disable();
return rc;
}
+137
View File
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Hash-based derivation function (Hash_df)
*
* This algorithm is designed to comply with ANS X9.82 Part 3-2007
* Section 10.5.2. This standard is not freely available, but most of
* the text appears to be shared with NIST SP 800-90, which can be
* downloaded from
*
* http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
*
* Where possible, references are given to both documents. In the
* case of any disagreement, ANS X9.82 takes priority over NIST SP
* 800-90. (In particular, note that some algorithms that are
* Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
*/
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <byteswap.h>
#include <ipxe/crypto.h>
#include <ipxe/hash_df.h>
/**
* Distribute entropy throughout a buffer
*
* @v hash Underlying hash algorithm
* @v input Input data
* @v input_len Length of input data, in bytes
* @v output Output buffer
* @v output_len Length of output buffer, in bytes
*
* This is the Hash_df function defined in ANS X9.82 Part 3-2007
* Section 10.5.2 (NIST SP 800-90 Section 10.4.1).
*
* The number of bits requested is implicit in the length of the
* output buffer. Requests must be for an integral number of bytes.
*
* The output buffer is filled incrementally with each iteration of
* the central loop, rather than constructing an overall "temp" and
* then taking the leftmost(no_of_bits_to_return) bits.
*
* There is no way for the Hash_df function to fail. The returned
* status SUCCESS is implicit.
*/
void hash_df ( struct digest_algorithm *hash, const void *input,
size_t input_len, void *output, size_t output_len ) {
uint8_t context[hash->ctxsize];
uint8_t digest[hash->digestsize];
size_t frag_len;
struct {
uint8_t pad[3];
uint8_t counter;
uint32_t no_of_bits_to_return;
} __attribute__ (( packed )) prefix;
void *temp;
size_t remaining;
DBGC ( &hash_df, "HASH_DF input:\n" );
DBGC_HDA ( &hash_df, 0, input, input_len );
/* Sanity checks */
assert ( input != NULL );
assert ( output != NULL );
/* 1. temp = the Null string
* 2. len = ceil ( no_of_bits_to_return / outlen )
*
* (Nothing to do. We fill the output buffer incrementally,
* rather than constructing the complete "temp" in-memory.
* "len" is implicit in the number of iterations required to
* fill the output buffer, and so is not calculated
* explicitly.)
*/
/* 3. counter = an 8-bit binary value representing the integer "1" */
prefix.counter = 1;
/* 4. For i = 1 to len do */
for ( temp = output, remaining = output_len ; remaining > 0 ; ) {
/* Comment: in step 5.1 (sic), no_of_bits_to_return is
* used as a 32-bit string.
*
* 4.1 temp = temp || Hash ( counter || no_of_bits_to_return
* || input_string )
*/
prefix.no_of_bits_to_return = htonl ( output_len * 8 );
digest_init ( hash, context );
digest_update ( hash, context, &prefix.counter,
( sizeof ( prefix ) -
offsetof ( typeof ( prefix ), counter ) ) );
digest_update ( hash, context, input, input_len );
digest_final ( hash, context, digest );
/* 4.2 counter = counter + 1 */
prefix.counter++;
/* 5. requested_bits = Leftmost ( no_of_bits_to_return )
* of temp
*
* (We fill the output buffer incrementally.)
*/
frag_len = sizeof ( digest );
if ( frag_len > remaining )
frag_len = remaining;
memcpy ( temp, digest, frag_len );
temp += frag_len;
remaining -= frag_len;
}
/* 6. Return SUCCESS and requested_bits */
DBGC ( &hash_df, "HASH_DF output:\n" );
DBGC_HDA ( &hash_df, 0, output, output_len );
return;
}
+73 -57
View File
@@ -36,7 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/crypto.h>
#include <ipxe/hmac.h>
#include <ipxe/hmac_drbg.h>
@@ -44,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
/**
* Update the HMAC_DRBG key
*
* @v hash Underlying hash algorithm
* @v state HMAC_DRBG internal state
* @v data Provided data
* @v len Length of provided data
@@ -55,40 +58,40 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
* as used by hmac_drbg_update()
*/
static void hmac_drbg_update_key ( struct hmac_drbg_state *state,
static void hmac_drbg_update_key ( struct digest_algorithm *hash,
struct hmac_drbg_state *state,
const void *data, size_t len,
const uint8_t single ) {
uint8_t context[HMAC_DRBG_CTX_SIZE];
size_t key_len = sizeof ( state->key );
uint8_t context[ hash->ctxsize ];
size_t out_len = hash->digestsize;
DBGC ( state, "HMAC_DRBG %p provided data :\n", state );
DBGC ( state, "HMAC_DRBG_%s %p provided data :\n", hash->name, state );
DBGC_HDA ( state, 0, data, len );
/* Sanity checks */
assert ( hash != NULL );
assert ( state != NULL );
assert ( ( data != NULL ) || ( len == 0 ) );
assert ( ( single == 0x00 ) || ( single == 0x01 ) );
/* K = HMAC ( K, V || single || provided_data ) */
hmac_init ( &hmac_drbg_algorithm, context, state->key, &key_len );
assert ( key_len == sizeof ( state->key ) );
hmac_update ( &hmac_drbg_algorithm, context,
state->value, sizeof ( state->value ) );
hmac_update ( &hmac_drbg_algorithm, context,
&single, sizeof ( single ) );
hmac_update ( &hmac_drbg_algorithm, context, data, len );
hmac_final ( &hmac_drbg_algorithm, context, state->key, &key_len,
state->key );
assert ( key_len == sizeof ( state->key ) );
hmac_init ( hash, context, state->key, &out_len );
assert ( out_len == hash->digestsize );
hmac_update ( hash, context, state->value, out_len );
hmac_update ( hash, context, &single, sizeof ( single ) );
hmac_update ( hash, context, data, len );
hmac_final ( hash, context, state->key, &out_len, state->key );
assert ( out_len == hash->digestsize );
DBGC ( state, "HMAC_DRBG %p K = HMAC ( K, V || %#02x || "
"provided_data ) :\n", state, single );
DBGC_HDA ( state, 0, state->key, sizeof ( state->key ) );
DBGC ( state, "HMAC_DRBG_%s %p K = HMAC ( K, V || %#02x || "
"provided_data ) :\n", hash->name, state, single );
DBGC_HDA ( state, 0, state->key, out_len );
}
/**
* Update the HMAC_DRBG value
*
* @v hash Underlying hash algorithm
* @v state HMAC_DRBG internal state
* @v data Provided data
* @v len Length of provided data
@@ -100,29 +103,31 @@ static void hmac_drbg_update_key ( struct hmac_drbg_state *state,
*
* as used by hmac_drbg_update() and hmac_drbg_generate()
*/
static void hmac_drbg_update_value ( struct hmac_drbg_state *state ) {
uint8_t context[HMAC_DRBG_CTX_SIZE];
size_t key_len = sizeof ( state->key );
static void hmac_drbg_update_value ( struct digest_algorithm *hash,
struct hmac_drbg_state *state ) {
uint8_t context[ hash->ctxsize ];
size_t out_len = hash->digestsize;
/* Sanity checks */
assert ( hash != NULL );
assert ( state != NULL );
/* V = HMAC ( K, V ) */
hmac_init ( &hmac_drbg_algorithm, context, state->key, &key_len );
assert ( key_len == sizeof ( state->key ) );
hmac_update ( &hmac_drbg_algorithm, context,
state->value, sizeof ( state->value ) );
hmac_final ( &hmac_drbg_algorithm, context, state->key, &key_len,
state->value );
assert ( key_len == sizeof ( state->key ) );
hmac_init ( hash, context, state->key, &out_len );
assert ( out_len == hash->digestsize );
hmac_update ( hash, context, state->value, out_len );
hmac_final ( hash, context, state->key, &out_len, state->value );
assert ( out_len == hash->digestsize );
DBGC ( state, "HMAC_DRBG %p V = HMAC ( K, V ) :\n", state );
DBGC_HDA ( state, 0, state->value, sizeof ( state->value ) );
DBGC ( state, "HMAC_DRBG_%s %p V = HMAC ( K, V ) :\n",
hash->name, state );
DBGC_HDA ( state, 0, state->value, out_len );
}
/**
* Update HMAC_DRBG internal state
*
* @v hash Underlying hash algorithm
* @v state HMAC_DRBG internal state
* @v data Provided data
* @v len Length of provided data
@@ -133,30 +138,32 @@ static void hmac_drbg_update_value ( struct hmac_drbg_state *state ) {
* The key and value are updated in-place within the HMAC_DRBG
* internal state.
*/
static void hmac_drbg_update ( struct hmac_drbg_state *state,
static void hmac_drbg_update ( struct digest_algorithm *hash,
struct hmac_drbg_state *state,
const void *data, size_t len ) {
DBGC ( state, "HMAC_DRBG %p update\n", state );
DBGC ( state, "HMAC_DRBG_%s %p update\n", hash->name, state );
/* Sanity checks */
assert ( hash != NULL );
assert ( state != NULL );
assert ( ( data != NULL ) || ( len == 0 ) );
/* 1. K = HMAC ( K, V || 0x00 || provided_data ) */
hmac_drbg_update_key ( state, data, len, 0x00 );
hmac_drbg_update_key ( hash, state, data, len, 0x00 );
/* 2. V = HMAC ( K, V ) */
hmac_drbg_update_value ( state );
hmac_drbg_update_value ( hash, state );
/* 3. If ( provided_data = Null ), then return K and V */
if ( ! len )
return;
/* 4. K = HMAC ( K, V || 0x01 || provided_data ) */
hmac_drbg_update_key ( state, data, len, 0x01 );
hmac_drbg_update_key ( hash, state, data, len, 0x01 );
/* 5. V = HMAC ( K, V ) */
hmac_drbg_update_value ( state );
hmac_drbg_update_value ( hash, state );
/* 6. Return K and V */
}
@@ -164,6 +171,7 @@ static void hmac_drbg_update ( struct hmac_drbg_state *state,
/**
* Instantiate HMAC_DRBG
*
* @v hash Underlying hash algorithm
* @v state HMAC_DRBG internal state to be initialised
* @v entropy Entropy input
* @v entropy_len Length of entropy input
@@ -182,17 +190,18 @@ static void hmac_drbg_update ( struct hmac_drbg_state *state,
* The key, value and reseed counter are updated in-place within the
* HMAC_DRBG internal state.
*/
void hmac_drbg_instantiate ( struct hmac_drbg_state *state,
void hmac_drbg_instantiate ( struct digest_algorithm *hash,
struct hmac_drbg_state *state,
const void *entropy, size_t entropy_len,
const void *personal, size_t personal_len ){
size_t out_len = hash->digestsize;
DBGC ( state, "HMAC_DRBG %p instantiate\n", state );
DBGC ( state, "HMAC_DRBG_%s %p instantiate\n", hash->name, state );
/* Sanity checks */
assert ( hash != NULL );
assert ( state != NULL );
assert ( entropy != NULL );
assert ( ( 8 * entropy_len ) >=
( 3 * HMAC_DRBG_SECURITY_STRENGTH / 2 ) );
assert ( ( personal != NULL ) || ( personal_len == 0 ) );
/* 1. seed_material = entropy_input || nonce ||
@@ -200,23 +209,24 @@ void hmac_drbg_instantiate ( struct hmac_drbg_state *state,
*/
/* 2. Key = 0x00 00..00 */
memset ( state->key, 0x00, sizeof ( state->key ) );
memset ( state->key, 0x00, out_len );
/* 3. V = 0x01 01...01 */
memset ( state->value, 0x01, sizeof ( state->value ) );
memset ( state->value, 0x01, out_len );
/* 4. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V )
* 5. reseed_counter = 1
* 6. Return V, Key and reseed_counter as the
* initial_working_state
*/
hmac_drbg_reseed ( state, entropy, entropy_len,
hmac_drbg_reseed ( hash, state, entropy, entropy_len,
personal, personal_len );
}
/**
* Reseed HMAC_DRBG
*
* @v hash Underlying hash algorithm
* @v state HMAC_DRBG internal state
* @v entropy Entropy input
* @v entropy_len Length of entropy input
@@ -229,27 +239,29 @@ void hmac_drbg_instantiate ( struct hmac_drbg_state *state,
* The key, value and reseed counter are updated in-place within the
* HMAC_DRBG internal state.
*/
void hmac_drbg_reseed ( struct hmac_drbg_state *state,
void hmac_drbg_reseed ( struct digest_algorithm *hash,
struct hmac_drbg_state *state,
const void *entropy, size_t entropy_len,
const void *additional, size_t additional_len ) {
uint8_t seed_material[ entropy_len + additional_len ];
DBGC ( state, "HMAC_DRBG %p (re)seed\n", state );
DBGC ( state, "HMAC_DRBG_%s %p (re)seed\n", hash->name, state );
/* Sanity checks */
assert ( hash != NULL );
assert ( state != NULL );
assert ( entropy != NULL );
assert ( ( 8 * entropy_len ) >= HMAC_DRBG_SECURITY_STRENGTH );
assert ( ( additional != NULL ) || ( additional_len == 0 ) );
/* 1. seed_material = entropy_input || additional_input */
memcpy ( seed_material, entropy, entropy_len );
memcpy ( ( seed_material + entropy_len ), additional, additional_len );
DBGC ( state, "HMAC_DRBG %p seed material :\n", state );
DBGC ( state, "HMAC_DRBG_%s %p seed material :\n", hash->name, state );
DBGC_HDA ( state, 0, seed_material, sizeof ( seed_material ) );
/* 2. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) */
hmac_drbg_update ( state, seed_material, sizeof ( seed_material ) );
hmac_drbg_update ( hash, state, seed_material,
sizeof ( seed_material ) );
/* 3. reseed_counter = 1 */
state->reseed_counter = 1;
@@ -260,6 +272,7 @@ void hmac_drbg_reseed ( struct hmac_drbg_state *state,
/**
* Generate pseudorandom bits using HMAC_DRBG
*
* @v hash Underlying hash algorithm
* @v state HMAC_DRBG internal state
* @v additional Additional input
* @v additional_len Length of additional input
@@ -277,16 +290,19 @@ void hmac_drbg_reseed ( struct hmac_drbg_state *state,
*
* Note that the only permitted error is "reseed required".
*/
int hmac_drbg_generate ( struct hmac_drbg_state *state,
int hmac_drbg_generate ( struct digest_algorithm *hash,
struct hmac_drbg_state *state,
const void *additional, size_t additional_len,
void *data, size_t len ) {
size_t out_len = hash->digestsize;
void *orig_data = data;
size_t orig_len = len;
size_t frag_len;
DBGC ( state, "HMAC_DRBG %p generate\n", state );
DBGC ( state, "HMAC_DRBG_%s %p generate\n", hash->name, state );
/* Sanity checks */
assert ( hash != NULL );
assert ( state != NULL );
assert ( data != NULL );
assert ( ( additional != NULL ) || ( additional_len == 0 ) );
@@ -295,8 +311,8 @@ int hmac_drbg_generate ( struct hmac_drbg_state *state,
* indication that a reseed is required
*/
if ( state->reseed_counter > HMAC_DRBG_RESEED_INTERVAL ) {
DBGC ( state, "HMAC_DRBG %p reseed interval exceeded\n",
state );
DBGC ( state, "HMAC_DRBG_%s %p reseed interval exceeded\n",
hash->name, state );
return -ESTALE;
}
@@ -304,7 +320,7 @@ int hmac_drbg_generate ( struct hmac_drbg_state *state,
* ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V )
*/
if ( additional_len )
hmac_drbg_update ( state, additional, additional_len );
hmac_drbg_update ( hash, state, additional, additional_len );
/* 3. temp = Null
* 4. While ( len ( temp ) < requested_number_of_bits ) do:
@@ -312,27 +328,27 @@ int hmac_drbg_generate ( struct hmac_drbg_state *state,
while ( len ) {
/* 4.1 V = HMAC ( Key, V ) */
hmac_drbg_update_value ( state );
hmac_drbg_update_value ( hash, state );
/* 4.2. temp = temp || V
* 5. returned_bits = Leftmost requested_number_of_bits
* of temp
*/
frag_len = len;
if ( frag_len > sizeof ( state->value ) )
frag_len = sizeof ( state->value );
if ( frag_len > out_len )
frag_len = out_len;
memcpy ( data, state->value, frag_len );
data += frag_len;
len -= frag_len;
}
/* 6. ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */
hmac_drbg_update ( state, additional, additional_len );
hmac_drbg_update ( hash, state, additional, additional_len );
/* 7. reseed_counter = reseed_counter + 1 */
state->reseed_counter++;
DBGC ( state, "HMAC_DRBG %p generated :\n", state );
DBGC ( state, "HMAC_DRBG_%s %p generated :\n", hash->name, state );
DBGC_HDA ( state, 0, orig_data, orig_len );
/* 8. Return SUCCESS, returned_bits, and the new values of
+257 -194
View File
@@ -1,234 +1,297 @@
/*
* Cryptographic API.
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* MD5 Message Digest Algorithm (RFC1321).
* 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 2 of the
* License, or any later version.
*
* Derived from cryptoapi implementation, originally based on the
* public domain implementation written by Colin Plumb in 1993.
*
* Reduced object size by around 50% compared to the original Linux
* version for use in Etherboot by Michael Brown.
*
* Copyright (c) Cryptoapi developers.
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
* Copyright (c) 2006 Michael Brown <mbrown@fensystems.co.uk>
*
* 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* MD5 algorithm
*
*/
#include <stdint.h>
#include <string.h>
#include <byteswap.h>
#include <assert.h>
#include <ipxe/rotate.h>
#include <ipxe/crypto.h>
#include <ipxe/asn1.h>
#include <ipxe/md5.h>
/** MD5 variables */
struct md5_variables {
/* This layout matches that of struct md5_digest_data,
* allowing for efficient endianness-conversion,
*/
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
uint32_t w[16];
} __attribute__ (( packed ));
/** MD5 constants */
static const uint32_t k[64] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
};
/** MD5 shift amounts */
static const uint8_t r[64] = {
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
};
/**
* f(b,c,d) for steps 0 to 15
*
* @v v MD5 variables
* @ret f f(b,c,d)
*/
static uint32_t md5_f_0_15 ( struct md5_variables *v ) {
return ( v->d ^ ( v->b & ( v->c ^ v->d ) ) );
}
/**
* f(b,c,d) for steps 16 to 31
*
* @v v MD5 variables
* @ret f f(b,c,d)
*/
static uint32_t md5_f_16_31 ( struct md5_variables *v ) {
return ( v->c ^ ( v->d & ( v->b ^ v->c ) ) );
}
/**
* f(b,c,d) for steps 32 to 47
*
* @v v MD5 variables
* @ret f f(b,c,d)
*/
static uint32_t md5_f_32_47 ( struct md5_variables *v ) {
return ( v->b ^ v->c ^ v->d );
}
/**
* f(b,c,d) for steps 48 to 63
*
* @v v MD5 variables
* @ret f f(b,c,d)
*/
static uint32_t md5_f_48_63 ( struct md5_variables *v ) {
return ( v->c ^ ( v->b | (~v->d) ) );
}
/** An MD5 step function */
struct md5_step {
u32 ( * f ) ( u32 b, u32 c, u32 d );
u8 coefficient;
u8 constant;
/**
* Calculate f(b,c,d)
*
* @v v MD5 variables
* @ret f f(b,c,d)
*/
uint32_t ( * f ) ( struct md5_variables *v );
/** Coefficient of i in g=ni+m */
uint8_t coefficient;
/** Constant term in g=ni+m */
uint8_t constant;
};
static u32 f1(u32 b, u32 c, u32 d)
{
return ( d ^ ( b & ( c ^ d ) ) );
}
static u32 f2(u32 b, u32 c, u32 d)
{
return ( c ^ ( d & ( b ^ c ) ) );
}
static u32 f3(u32 b, u32 c, u32 d)
{
return ( b ^ c ^ d );
}
static u32 f4(u32 b, u32 c, u32 d)
{
return ( c ^ ( b | ~d ) );
}
/** MD5 steps */
static struct md5_step md5_steps[4] = {
{
.f = f1,
.coefficient = 1,
.constant = 0,
},
{
.f = f2,
.coefficient = 5,
.constant = 1,
},
{
.f = f3,
.coefficient = 3,
.constant = 5,
},
{
.f = f4,
.coefficient = 7,
.constant = 0,
}
/** 0 to 15 */
{ .f = md5_f_0_15, .coefficient = 1, .constant = 0 },
/** 16 to 31 */
{ .f = md5_f_16_31, .coefficient = 5, .constant = 1 },
/** 32 to 47 */
{ .f = md5_f_32_47, .coefficient = 3, .constant = 5 },
/** 48 to 63 */
{ .f = md5_f_48_63, .coefficient = 7, .constant = 0 },
};
static const u8 r[64] = {
7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
};
/**
* Initialise MD5 algorithm
*
* @v ctx MD5 context
*/
static void md5_init ( void *ctx ) {
struct md5_context *context = ctx;
static const u32 k[64] = {
0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL,
0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL,
0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL,
0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL,
0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL,
0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL,
0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL,
0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL,
0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL,
};
context->ddd.dd.digest.h[0] = cpu_to_le32 ( 0x67452301 );
context->ddd.dd.digest.h[1] = cpu_to_le32 ( 0xefcdab89 );
context->ddd.dd.digest.h[2] = cpu_to_le32 ( 0x98badcfe );
context->ddd.dd.digest.h[3] = cpu_to_le32 ( 0x10325476 );
context->len = 0;
}
static void md5_transform(u32 *hash, const u32 *in)
{
u32 a, b, c, d, f, g, temp;
int i;
/**
* Calculate MD5 digest of accumulated data
*
* @v context MD5 context
*/
static void md5_digest ( struct md5_context *context ) {
union {
union md5_digest_data_dwords ddd;
struct md5_variables v;
} u;
uint32_t *a = &u.v.a;
uint32_t *b = &u.v.b;
uint32_t *c = &u.v.c;
uint32_t *d = &u.v.d;
uint32_t *w = u.v.w;
uint32_t f;
uint32_t g;
uint32_t temp;
struct md5_step *step;
unsigned int i;
a = hash[0];
b = hash[1];
c = hash[2];
d = hash[3];
/* Sanity checks */
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
linker_assert ( &u.ddd.dd.digest.h[0] == a, md5_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[1] == b, md5_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[2] == c, md5_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[3] == d, md5_bad_layout );
linker_assert ( &u.ddd.dd.data.dword[0] == w, md5_bad_layout );
DBGC ( context, "MD5 digesting:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
sizeof ( context->ddd.dd.digest ) );
DBGC_HDA ( context, context->len, &context->ddd.dd.data,
sizeof ( context->ddd.dd.data ) );
/* Convert h[0..3] to host-endian, and initialise a, b, c, d,
* and w[0..15]
*/
for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
le32_to_cpus ( &context->ddd.dword[i] );
u.ddd.dword[i] = context->ddd.dword[i];
}
/* Main loop */
for ( i = 0 ; i < 64 ; i++ ) {
step = &md5_steps[i >> 4];
f = step->f ( b, c, d );
g = ( ( i * step->coefficient + step->constant ) & 0xf );
temp = d;
d = c;
c = b;
a += ( f + k[i] + in[g] );
a = ( ( a << r[i] ) | ( a >> ( 32-r[i] ) ) );
b += a;
a = temp;
step = &md5_steps[ i / 16 ];
f = step->f ( &u.v );
g = ( ( ( step->coefficient * i ) + step->constant ) % 16 );
temp = *d;
*d = *c;
*c = *b;
*b = ( *b + rol32 ( ( *a + f + k[i] + w[g] ), r[i] ) );
*a = temp;
DBGC2 ( context, "%2d : %08x %08x %08x %08x\n",
i, *a, *b, *c, *d );
}
hash[0] += a;
hash[1] += b;
hash[2] += c;
hash[3] += d;
/* Add chunk to hash and convert back to big-endian */
for ( i = 0 ; i < 4 ; i++ ) {
context->ddd.dd.digest.h[i] =
cpu_to_le32 ( context->ddd.dd.digest.h[i] +
u.ddd.dd.digest.h[i] );
}
DBGC ( context, "MD5 digested:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
sizeof ( context->ddd.dd.digest ) );
}
/* XXX: this stuff can be optimized */
static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
{
while (words--) {
le32_to_cpus(buf);
buf++;
/**
* Accumulate data with MD5 algorithm
*
* @v ctx MD5 context
* @v data Data
* @v len Length of data
*/
static void md5_update ( void *ctx, const void *data, size_t len ) {
struct md5_context *context = ctx;
const uint8_t *byte = data;
size_t offset;
/* Accumulate data a byte at a time, performing the digest
* whenever we fill the data buffer
*/
while ( len-- ) {
offset = ( context->len % sizeof ( context->ddd.dd.data ) );
context->ddd.dd.data.byte[offset] = *(byte++);
context->len++;
if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
md5_digest ( context );
}
}
static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
{
while (words--) {
cpu_to_le32s(buf);
buf++;
}
}
static inline void md5_transform_helper(struct md5_ctx *ctx)
{
le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
md5_transform(ctx->hash, ctx->block);
}
static void md5_init(void *context)
{
struct md5_ctx *mctx = context;
mctx->hash[0] = 0x67452301;
mctx->hash[1] = 0xefcdab89;
mctx->hash[2] = 0x98badcfe;
mctx->hash[3] = 0x10325476;
mctx->byte_count = 0;
}
static void md5_update(void *context, const void *data, size_t len)
{
struct md5_ctx *mctx = context;
const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
mctx->byte_count += len;
if (avail > len) {
memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
data, len);
return;
}
memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
data, avail);
md5_transform_helper(mctx);
data += avail;
len -= avail;
while (len >= sizeof(mctx->block)) {
memcpy(mctx->block, data, sizeof(mctx->block));
md5_transform_helper(mctx);
data += sizeof(mctx->block);
len -= sizeof(mctx->block);
}
memcpy(mctx->block, data, len);
}
static void md5_final(void *context, void *out)
{
struct md5_ctx *mctx = context;
const unsigned int offset = mctx->byte_count & 0x3f;
char *p = (char *)mctx->block + offset;
int padding = 56 - (offset + 1);
*p++ = 0x80;
if (padding < 0) {
memset(p, 0x00, padding + sizeof (u64));
md5_transform_helper(mctx);
p = (char *)mctx->block;
padding = 56;
}
memset(p, 0, padding);
mctx->block[14] = mctx->byte_count << 3;
mctx->block[15] = mctx->byte_count >> 29;
le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
sizeof(u64)) / sizeof(u32));
md5_transform(mctx->hash, mctx->block);
cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
memcpy(out, mctx->hash, sizeof(mctx->hash));
memset(mctx, 0, sizeof(*mctx));
/**
* Generate MD5 digest
*
* @v ctx MD5 context
* @v out Output buffer
*/
static void md5_final ( void *ctx, void *out ) {
struct md5_context *context = ctx;
uint64_t len_bits;
uint8_t pad;
/* Record length before pre-processing */
len_bits = cpu_to_le64 ( ( ( uint64_t ) context->len ) * 8 );
/* Pad with a single "1" bit followed by as many "0" bits as required */
pad = 0x80;
do {
md5_update ( ctx, &pad, sizeof ( pad ) );
pad = 0x00;
} while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
/* Append length (in bits) */
md5_update ( ctx, &len_bits, sizeof ( len_bits ) );
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
/* Copy out final digest */
memcpy ( out, &context->ddd.dd.digest,
sizeof ( context->ddd.dd.digest ) );
}
/** MD5 algorithm */
struct digest_algorithm md5_algorithm = {
.name = "md5",
.ctxsize = MD5_CTX_SIZE,
.blocksize = ( MD5_BLOCK_WORDS * 4 ),
.digestsize = MD5_DIGEST_SIZE,
.ctxsize = sizeof ( struct md5_context ),
.blocksize = sizeof ( union md5_block ),
.digestsize = sizeof ( struct md5_digest ),
.init = md5_init,
.update = md5_update,
.final = md5_final,
};
/** "md5" object identifier */
static uint8_t oid_md5[] = { ASN1_OID_MD5 };
/** "md5" OID-identified algorithm */
struct asn1_algorithm oid_md5_algorithm __asn1_algorithm = {
.name = "md5",
.digest = &md5_algorithm,
.oid = ASN1_OID_CURSOR ( oid_md5 ),
};
+35
View File
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Nonexistent entropy source
*
*
* This source provides no entropy and must NOT be used in a
* security-sensitive environment.
*/
#include <ipxe/entropy.h>
PROVIDE_ENTROPY_INLINE ( null, min_entropy_per_sample );
PROVIDE_ENTROPY_INLINE ( null, entropy_enable );
PROVIDE_ENTROPY_INLINE ( null, entropy_disable );
PROVIDE_ENTROPY_INLINE ( null, get_noise );
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Random non-zero bytes
*
* The RSA algorithm requires the generation of random non-zero bytes,
* i.e. bytes in the range [0x01,0xff].
*
* This algorithm is designed to comply with ANS X9.82 Part 1-2006
* Section 9.2.1. This standard is not freely available, but most of
* the text appears to be shared with NIST SP 800-90, which can be
* downloaded from
*
* http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
*
* Where possible, references are given to both documents. In the
* case of any disagreement, ANS X9.82 takes priority over NIST SP
* 800-90. (In particular, note that some algorithms that are
* Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
*/
#include <stddef.h>
#include <stdint.h>
#include <ipxe/rbg.h>
#include <ipxe/random_nz.h>
/**
* Get random non-zero bytes
*
* @v data Output buffer
* @v len Length of output buffer
* @ret rc Return status code
*
* This algorithm is designed to be isomorphic to the Simple Discard
* Method described in ANS X9.82 Part 1-2006 Section 9.2.1 (NIST SP
* 800-90 Section B.5.1.1).
*/
int get_random_nz ( void *data, size_t len ) {
uint8_t *bytes = data;
int rc;
while ( len ) {
/* Generate random byte */
if ( ( rc = rbg_generate ( NULL, 0, 0, bytes, 1 ) ) != 0 )
return rc;
/* Move to next byte if this byte is acceptable */
if ( *bytes != 0 ) {
bytes++;
len--;
}
}
return 0;
}
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* RBG mechanism
*
* This mechanism is designed to comply with ANS X9.82 Part 4 (April
* 2011 Draft) Section 10. This standard is unfortunately not freely
* available.
*
* The chosen RBG design is that of a DRBG with a live entropy source
* with no conditioning function. Only a single security strength is
* supported. No seedfile is used since there may be no non-volatile
* storage available. The system UUID is used as the personalisation
* string.
*/
#include <stdint.h>
#include <string.h>
#include <ipxe/init.h>
#include <ipxe/settings.h>
#include <ipxe/uuid.h>
#include <ipxe/crypto.h>
#include <ipxe/drbg.h>
#include <ipxe/rbg.h>
/** The RBG */
struct random_bit_generator rbg;
/**
* Start up RBG
*
* @ret rc Return status code
*
* This is the RBG_Startup function defined in ANS X9.82 Part 4 (April
* 2011 Draft) Section 9.1.2.2.
*/
static int rbg_startup ( void ) {
union uuid uuid;
int len;
int rc;
/* Try to obtain system UUID for use as personalisation
* string, in accordance with ANS X9.82 Part 3-2007 Section
* 8.5.2. If no UUID is available, proceed without a
* personalisation string.
*/
if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, &uuid ) ) < 0 ) {
rc = len;
DBGC ( &rbg, "RBG could not fetch personalisation string: "
"%s\n", strerror ( rc ) );
len = 0;
}
/* Instantiate DRBG */
if ( ( rc = drbg_instantiate ( &rbg.state, &uuid, len ) ) != 0 ) {
DBGC ( &rbg, "RBG could not instantiate DRBG: %s\n",
strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Shut down RBG
*
*/
static void rbg_shutdown ( void ) {
/* Uninstantiate DRBG */
drbg_uninstantiate ( &rbg.state );
}
/** RBG startup function */
static void rbg_startup_fn ( void ) {
/* Start up RBG. There is no way to report an error at this
* stage, but a failed startup will result in an invalid DRBG
* that refuses to generate bits.
*/
rbg_startup();
}
/** RBG shutdown function */
static void rbg_shutdown_fn ( int booting __unused ) {
/* Shut down RBG */
rbg_shutdown();
}
/** RBG startup table entry */
struct startup_fn startup_rbg __startup_fn ( STARTUP_NORMAL ) = {
.startup = rbg_startup_fn,
.shutdown = rbg_shutdown_fn,
};
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdlib.h>
#include <ipxe/crypto.h>
#include <ipxe/sha256.h>
#include <ipxe/x509.h>
#include <ipxe/settings.h>
#include <ipxe/dhcp.h>
#include <ipxe/init.h>
#include <ipxe/rootcert.h>
/** @file
*
* Root certificate store
*
*/
/** Length of a root certificate fingerprint */
#define FINGERPRINT_LEN SHA256_DIGEST_SIZE
/* Allow trusted certificates to be overridden if not explicitly specified */
#ifdef TRUSTED
#define ALLOW_TRUST_OVERRIDE 0
#else
#define ALLOW_TRUST_OVERRIDE 1
#endif
/* Use iPXE root CA if no trusted certificates are explicitly specified */
#ifndef TRUSTED
#define TRUSTED \
/* iPXE root CA */ \
0x9f, 0xaf, 0x71, 0x7b, 0x7f, 0x8c, 0xa2, 0xf9, 0x3c, 0x25, \
0x6c, 0x79, 0xf8, 0xac, 0x55, 0x91, 0x89, 0x5d, 0x66, 0xd1, \
0xff, 0x3b, 0xee, 0x63, 0x97, 0xa7, 0x0d, 0x29, 0xc6, 0x5e, \
0xed, 0x1a,
#endif
/** Root certificate fingerprints */
static const uint8_t fingerprints[] = { TRUSTED };
/** Root certificate fingerprint setting */
static struct setting trust_setting __setting ( SETTING_CRYPTO ) = {
.name = "trust",
.description = "Trusted root certificate fingerprints",
.tag = DHCP_EB_TRUST,
.type = &setting_type_hex,
};
/** Root certificates */
struct x509_root root_certificates = {
.digest = &sha256_algorithm,
.count = ( sizeof ( fingerprints ) / FINGERPRINT_LEN ),
.fingerprints = fingerprints,
};
/**
* Initialise root certificate
*
* The list of trusted root certificates can be specified at build
* time using the TRUST= build parameter. If no certificates are
* specified, then the default iPXE root CA certificate is trusted.
*
* If no certificates were explicitly specified, then we allow the
* list of trusted root certificate fingerprints to be overridden
* using the "trust" setting, but only at the point of iPXE
* initialisation. This prevents untrusted sources of settings
* (e.g. DHCP) from subverting the chain of trust, while allowing
* trustworthy sources (e.g. VMware GuestInfo or non-volatile stored
* options) to specify the trusted root certificate without requiring
* a rebuild.
*/
static void rootcert_init ( void ) {
void *external = NULL;
int len;
int rc;
/* Allow trusted root certificates to be overridden only if
* not explicitly specified at build time.
*/
if ( ALLOW_TRUST_OVERRIDE ) {
/* Fetch copy of "trust" setting, if it exists. This
* memory will never be freed.
*/
len = fetch_setting_copy ( NULL, &trust_setting, &external );
if ( len < 0 ) {
rc = len;
DBGC ( &root_certificates, "ROOTCERT cannot fetch "
"trusted root certificate fingerprints: %s\n",
strerror ( rc ) );
/* No way to prevent startup; fail safe by
* trusting no certificates.
*/
root_certificates.count = 0;
return;
}
/* Use certificates from "trust" setting, if present */
if ( external ) {
root_certificates.fingerprints = external;
root_certificates.count = ( len / FINGERPRINT_LEN );
}
}
DBGC ( &root_certificates, "ROOTCERT using %d %s certificate(s):\n",
root_certificates.count, ( external ? "external" : "built-in" ));
DBGC_HDA ( &root_certificates, 0, root_certificates.fingerprints,
( root_certificates.count * FINGERPRINT_LEN ) );
}
/** Root certificate initialiser */
struct init_fn rootcert_init_fn __init_fn ( INIT_LATE ) = {
.initialise = rootcert_init,
};
+648
View File
@@ -0,0 +1,648 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <ipxe/asn1.h>
#include <ipxe/crypto.h>
#include <ipxe/bigint.h>
#include <ipxe/random_nz.h>
#include <ipxe/md5.h>
#include <ipxe/sha1.h>
#include <ipxe/sha256.h>
#include <ipxe/rsa.h>
/** @file
*
* RSA public-key cryptography
*
* RSA is documented in RFC 3447.
*/
/* Disambiguate the various error causes */
#define EACCES_VERIFY \
__einfo_error ( EINFO_EACCES_VERIFY )
#define EINFO_EACCES_VERIFY \
__einfo_uniqify ( EINFO_EACCES, 0x01, "RSA signature incorrect" )
/** "rsaEncryption" object identifier */
static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION };
/** "md5WithRSAEncryption" object identifier */
static uint8_t oid_md5_with_rsa_encryption[] =
{ ASN1_OID_MD5WITHRSAENCRYPTION };
/** "sha1WithRSAEncryption" object identifier */
static uint8_t oid_sha1_with_rsa_encryption[] =
{ ASN1_OID_SHA1WITHRSAENCRYPTION };
/** "sha256WithRSAEncryption" object identifier */
static uint8_t oid_sha256_with_rsa_encryption[] =
{ ASN1_OID_SHA256WITHRSAENCRYPTION };
/** "rsaEncryption" OID-identified algorithm */
struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = {
.name = "rsaEncryption",
.pubkey = &rsa_algorithm,
.digest = NULL,
.oid = ASN1_OID_CURSOR ( oid_rsa_encryption ),
};
/** "md5WithRSAEncryption" OID-identified algorithm */
struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm = {
.name = "md5WithRSAEncryption",
.pubkey = &rsa_algorithm,
.digest = &md5_algorithm,
.oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ),
};
/** "sha1WithRSAEncryption" OID-identified algorithm */
struct asn1_algorithm sha1_with_rsa_encryption_algorithm __asn1_algorithm = {
.name = "sha1WithRSAEncryption",
.pubkey = &rsa_algorithm,
.digest = &sha1_algorithm,
.oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ),
};
/** "sha256WithRSAEncryption" OID-identified algorithm */
struct asn1_algorithm sha256_with_rsa_encryption_algorithm __asn1_algorithm = {
.name = "sha256WithRSAEncryption",
.pubkey = &rsa_algorithm,
.digest = &sha256_algorithm,
.oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ),
};
/** MD5 digestInfo prefix */
static const uint8_t rsa_md5_prefix_data[] =
{ RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) };
/** SHA-1 digestInfo prefix */
static const uint8_t rsa_sha1_prefix_data[] =
{ RSA_DIGESTINFO_PREFIX ( SHA1_DIGEST_SIZE, ASN1_OID_SHA1 ) };
/** SHA-256 digestInfo prefix */
static const uint8_t rsa_sha256_prefix_data[] =
{ RSA_DIGESTINFO_PREFIX ( SHA256_DIGEST_SIZE, ASN1_OID_SHA256 ) };
/** MD5 digestInfo prefix */
struct rsa_digestinfo_prefix rsa_md5_prefix __rsa_digestinfo_prefix = {
.digest = &md5_algorithm,
.data = rsa_md5_prefix_data,
.len = sizeof ( rsa_md5_prefix_data ),
};
/** SHA-1 digestInfo prefix */
struct rsa_digestinfo_prefix rsa_sha1_prefix __rsa_digestinfo_prefix = {
.digest = &sha1_algorithm,
.data = rsa_sha1_prefix_data,
.len = sizeof ( rsa_sha1_prefix_data ),
};
/** SHA-256 digestInfo prefix */
struct rsa_digestinfo_prefix rsa_sha256_prefix __rsa_digestinfo_prefix = {
.digest = &sha256_algorithm,
.data = rsa_sha256_prefix_data,
.len = sizeof ( rsa_sha256_prefix_data ),
};
/**
* Identify RSA prefix
*
* @v digest Digest algorithm
* @ret prefix RSA prefix, or NULL
*/
static struct rsa_digestinfo_prefix *
rsa_find_prefix ( struct digest_algorithm *digest ) {
struct rsa_digestinfo_prefix *prefix;
for_each_table_entry ( prefix, RSA_DIGESTINFO_PREFIXES ) {
if ( prefix->digest == digest )
return prefix;
}
return NULL;
}
/**
* Free RSA dynamic storage
*
* @v context RSA context
*/
static void rsa_free ( struct rsa_context *context ) {
free ( context->dynamic );
context->dynamic = NULL;
}
/**
* Allocate RSA dynamic storage
*
* @v context RSA context
* @v modulus_len Modulus length
* @v exponent_len Exponent length
* @ret rc Return status code
*/
static int rsa_alloc ( struct rsa_context *context, size_t modulus_len,
size_t exponent_len ) {
unsigned int size = bigint_required_size ( modulus_len );
unsigned int exponent_size = bigint_required_size ( exponent_len );
bigint_t ( size ) *modulus;
bigint_t ( exponent_size ) *exponent;
size_t tmp_len = bigint_mod_exp_tmp_len ( modulus, exponent );
struct {
bigint_t ( size ) modulus;
bigint_t ( exponent_size ) exponent;
bigint_t ( size ) input;
bigint_t ( size ) output;
uint8_t tmp[tmp_len];
} __attribute__ (( packed )) *dynamic;
/* Free any existing dynamic storage */
rsa_free ( context );
/* Allocate dynamic storage */
dynamic = malloc ( sizeof ( *dynamic ) );
if ( ! dynamic )
return -ENOMEM;
/* Assign dynamic storage */
context->dynamic = dynamic;
context->modulus0 = &dynamic->modulus.element[0];
context->size = size;
context->max_len = modulus_len;
context->exponent0 = &dynamic->exponent.element[0];
context->exponent_size = exponent_size;
context->input0 = &dynamic->input.element[0];
context->output0 = &dynamic->output.element[0];
context->tmp = &dynamic->tmp;
return 0;
}
/**
* Parse RSA integer
*
* @v context RSA context
* @v integer Integer to fill in
* @v raw ASN.1 cursor
* @ret rc Return status code
*/
static int rsa_parse_integer ( struct rsa_context *context,
struct asn1_cursor *integer,
const struct asn1_cursor *raw ) {
/* Enter integer */
memcpy ( integer, raw, sizeof ( *integer ) );
asn1_enter ( integer, ASN1_INTEGER );
/* Skip initial sign byte if applicable */
if ( ( integer->len > 1 ) &&
( *( ( uint8_t * ) integer->data ) == 0x00 ) ) {
integer->data++;
integer->len--;
}
/* Fail if cursor or integer are invalid */
if ( ! integer->len ) {
DBGC ( context, "RSA %p invalid integer:\n", context );
DBGC_HDA ( context, 0, raw->data, raw->len );
return -EINVAL;
}
return 0;
}
/**
* Initialise RSA cipher
*
* @v ctx RSA context
* @v key Key
* @v key_len Length of key
* @ret rc Return status code
*/
static int rsa_init ( void *ctx, const void *key, size_t key_len ) {
struct rsa_context *context = ctx;
const struct asn1_bit_string *bit_string;
struct asn1_cursor modulus;
struct asn1_cursor exponent;
struct asn1_cursor cursor;
int is_private;
int rc;
/* Initialise context */
memset ( context, 0, sizeof ( *context ) );
/* Initialise cursor */
cursor.data = key;
cursor.len = key_len;
/* Enter subjectPublicKeyInfo/RSAPrivateKey */
asn1_enter ( &cursor, ASN1_SEQUENCE );
/* Determine key format */
if ( asn1_type ( &cursor ) == ASN1_INTEGER ) {
/* Private key */
is_private = 1;
/* Skip version */
asn1_skip_any ( &cursor );
} else {
/* Public key */
is_private = 0;
/* Skip algorithm */
asn1_skip ( &cursor, ASN1_SEQUENCE );
/* Enter subjectPublicKey */
asn1_enter ( &cursor, ASN1_BIT_STRING );
/* Check and skip unused-bits byte of bit string */
bit_string = cursor.data;
if ( ( cursor.len < sizeof ( *bit_string ) ) ||
( bit_string->unused != 0 ) ) {
rc = -EINVAL;
goto err_parse;
}
cursor.data = &bit_string->data;
cursor.len -= offsetof ( typeof ( *bit_string ), data );
/* Enter RSAPublicKey */
asn1_enter ( &cursor, ASN1_SEQUENCE );
}
/* Extract modulus */
if ( ( rc = rsa_parse_integer ( context, &modulus, &cursor ) ) != 0 )
goto err_parse;
asn1_skip_any ( &cursor );
/* Skip public exponent, if applicable */
if ( is_private )
asn1_skip ( &cursor, ASN1_INTEGER );
/* Extract publicExponent/privateExponent */
if ( ( rc = rsa_parse_integer ( context, &exponent, &cursor ) ) != 0 )
goto err_parse;
DBGC ( context, "RSA %p modulus:\n", context );
DBGC_HDA ( context, 0, modulus.data, modulus.len );
DBGC ( context, "RSA %p exponent:\n", context );
DBGC_HDA ( context, 0, exponent.data, exponent.len );
/* Allocate dynamic storage */
if ( ( rc = rsa_alloc ( context, modulus.len, exponent.len ) ) != 0 )
goto err_alloc;
/* Construct big integers */
bigint_init ( ( ( bigint_t ( context->size ) * ) context->modulus0 ),
modulus.data, modulus.len );
bigint_init ( ( ( bigint_t ( context->exponent_size ) * )
context->exponent0 ), exponent.data, exponent.len );
return 0;
rsa_free ( context );
err_alloc:
err_parse:
return rc;
}
/**
* Calculate RSA maximum output length
*
* @v ctx RSA context
* @ret max_len Maximum output length
*/
static size_t rsa_max_len ( void *ctx ) {
struct rsa_context *context = ctx;
return context->max_len;
}
/**
* Perform RSA cipher operation
*
* @v context RSA context
* @v in Input buffer
* @v out Output buffer
*/
static void rsa_cipher ( struct rsa_context *context,
const void *in, void *out ) {
bigint_t ( context->size ) *input = ( ( void * ) context->input0 );
bigint_t ( context->size ) *output = ( ( void * ) context->output0 );
bigint_t ( context->size ) *modulus = ( ( void * ) context->modulus0 );
bigint_t ( context->exponent_size ) *exponent =
( ( void * ) context->exponent0 );
/* Initialise big integer */
bigint_init ( input, in, context->max_len );
/* Perform modular exponentiation */
bigint_mod_exp ( input, modulus, exponent, output, context->tmp );
/* Copy out result */
bigint_done ( output, out, context->max_len );
}
/**
* Encrypt using RSA
*
* @v ctx RSA context
* @v plaintext Plaintext
* @v plaintext_len Length of plaintext
* @v ciphertext Ciphertext
* @ret ciphertext_len Length of ciphertext, or negative error
*/
static int rsa_encrypt ( void *ctx, const void *plaintext,
size_t plaintext_len, void *ciphertext ) {
struct rsa_context *context = ctx;
void *temp;
uint8_t *encoded;
size_t max_len = ( context->max_len - 11 );
size_t random_nz_len = ( max_len - plaintext_len + 8 );
int rc;
/* Sanity check */
if ( plaintext_len > max_len ) {
DBGC ( context, "RSA %p plaintext too long (%zd bytes, max "
"%zd)\n", context, plaintext_len, max_len );
return -ERANGE;
}
DBGC ( context, "RSA %p encrypting:\n", context );
DBGC_HDA ( context, 0, plaintext, plaintext_len );
/* Construct encoded message (using the big integer output
* buffer as temporary storage)
*/
temp = context->output0;
encoded = temp;
encoded[0] = 0x00;
encoded[1] = 0x02;
if ( ( rc = get_random_nz ( &encoded[2], random_nz_len ) ) != 0 ) {
DBGC ( context, "RSA %p could not generate random data: %s\n",
context, strerror ( rc ) );
return rc;
}
encoded[ 2 + random_nz_len ] = 0x00;
memcpy ( &encoded[ context->max_len - plaintext_len ],
plaintext, plaintext_len );
/* Encipher the encoded message */
rsa_cipher ( context, encoded, ciphertext );
DBGC ( context, "RSA %p encrypted:\n", context );
DBGC_HDA ( context, 0, ciphertext, context->max_len );
return context->max_len;
}
/**
* Decrypt using RSA
*
* @v ctx RSA context
* @v ciphertext Ciphertext
* @v ciphertext_len Ciphertext length
* @v plaintext Plaintext
* @ret plaintext_len Plaintext length, or negative error
*/
static int rsa_decrypt ( void *ctx, const void *ciphertext,
size_t ciphertext_len, void *plaintext ) {
struct rsa_context *context = ctx;
void *temp;
uint8_t *encoded;
uint8_t *end;
uint8_t *zero;
uint8_t *start;
size_t plaintext_len;
/* Sanity check */
if ( ciphertext_len != context->max_len ) {
DBGC ( context, "RSA %p ciphertext incorrect length (%zd "
"bytes, should be %zd)\n",
context, ciphertext_len, context->max_len );
return -ERANGE;
}
DBGC ( context, "RSA %p decrypting:\n", context );
DBGC_HDA ( context, 0, ciphertext, ciphertext_len );
/* Decipher the message (using the big integer input buffer as
* temporary storage)
*/
temp = context->input0;
encoded = temp;
rsa_cipher ( context, ciphertext, encoded );
/* Parse the message */
end = ( encoded + context->max_len );
if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) )
goto invalid;
zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) );
if ( ! zero )
goto invalid;
start = ( zero + 1 );
plaintext_len = ( end - start );
/* Copy out message */
memcpy ( plaintext, start, plaintext_len );
DBGC ( context, "RSA %p decrypted:\n", context );
DBGC_HDA ( context, 0, plaintext, plaintext_len );
return plaintext_len;
invalid:
DBGC ( context, "RSA %p invalid decrypted message:\n", context );
DBGC_HDA ( context, 0, encoded, context->max_len );
return -EINVAL;
}
/**
* Encode RSA digest
*
* @v context RSA context
* @v digest Digest algorithm
* @v value Digest value
* @v encoded Encoded digest
* @ret rc Return status code
*/
static int rsa_encode_digest ( struct rsa_context *context,
struct digest_algorithm *digest,
const void *value, void *encoded ) {
struct rsa_digestinfo_prefix *prefix;
size_t digest_len = digest->digestsize;
uint8_t *temp = encoded;
size_t digestinfo_len;
size_t max_len;
size_t pad_len;
/* Identify prefix */
prefix = rsa_find_prefix ( digest );
if ( ! prefix ) {
DBGC ( context, "RSA %p has no prefix for %s\n",
context, digest->name );
return -ENOTSUP;
}
digestinfo_len = ( prefix->len + digest_len );
/* Sanity check */
max_len = ( context->max_len - 11 );
if ( digestinfo_len > max_len ) {
DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, max"
"%zd)\n",
context, digest->name, digestinfo_len, max_len );
return -ERANGE;
}
DBGC ( context, "RSA %p encoding %s digest:\n",
context, digest->name );
DBGC_HDA ( context, 0, value, digest_len );
/* Construct encoded message */
*(temp++) = 0x00;
*(temp++) = 0x01;
pad_len = ( max_len - digestinfo_len + 8 );
memset ( temp, 0xff, pad_len );
temp += pad_len;
*(temp++) = 0x00;
memcpy ( temp, prefix->data, prefix->len );
temp += prefix->len;
memcpy ( temp, value, digest_len );
temp += digest_len;
assert ( temp == ( encoded + context->max_len ) );
DBGC ( context, "RSA %p encoded %s digest:\n", context, digest->name );
DBGC_HDA ( context, 0, encoded, context->max_len );
return 0;
}
/**
* Sign digest value using RSA
*
* @v ctx RSA context
* @v digest Digest algorithm
* @v value Digest value
* @v signature Signature
* @ret signature_len Signature length, or negative error
*/
static int rsa_sign ( void *ctx, struct digest_algorithm *digest,
const void *value, void *signature ) {
struct rsa_context *context = ctx;
void *temp;
int rc;
DBGC ( context, "RSA %p signing %s digest:\n", context, digest->name );
DBGC_HDA ( context, 0, value, digest->digestsize );
/* Encode digest (using the big integer output buffer as
* temporary storage)
*/
temp = context->output0;
if ( ( rc = rsa_encode_digest ( context, digest, value, temp ) ) != 0 )
return rc;
/* Encipher the encoded digest */
rsa_cipher ( context, temp, signature );
DBGC ( context, "RSA %p signed %s digest:\n", context, digest->name );
DBGC_HDA ( context, 0, signature, context->max_len );
return context->max_len;
}
/**
* Verify signed digest value using RSA
*
* @v ctx RSA context
* @v digest Digest algorithm
* @v value Digest value
* @v signature Signature
* @v signature_len Signature length
* @ret rc Return status code
*/
static int rsa_verify ( void *ctx, struct digest_algorithm *digest,
const void *value, const void *signature,
size_t signature_len ) {
struct rsa_context *context = ctx;
void *temp;
void *expected;
void *actual;
int rc;
/* Sanity check */
if ( signature_len != context->max_len ) {
DBGC ( context, "RSA %p signature incorrect length (%zd "
"bytes, should be %zd)\n",
context, signature_len, context->max_len );
return -ERANGE;
}
DBGC ( context, "RSA %p verifying %s digest:\n",
context, digest->name );
DBGC_HDA ( context, 0, value, digest->digestsize );
DBGC_HDA ( context, 0, signature, signature_len );
/* Decipher the signature (using the big integer input buffer
* as temporary storage)
*/
temp = context->input0;
expected = temp;
rsa_cipher ( context, signature, expected );
DBGC ( context, "RSA %p deciphered signature:\n", context );
DBGC_HDA ( context, 0, expected, context->max_len );
/* Encode digest (using the big integer output buffer as
* temporary storage)
*/
temp = context->output0;
actual = temp;
if ( ( rc = rsa_encode_digest ( context, digest, value, actual ) ) !=0 )
return rc;
/* Verify the signature */
if ( memcmp ( actual, expected, context->max_len ) != 0 ) {
DBGC ( context, "RSA %p signature verification failed\n",
context );
return -EACCES_VERIFY;
}
DBGC ( context, "RSA %p signature verified successfully\n", context );
return 0;
}
/**
* Finalise RSA cipher
*
* @v ctx RSA context
*/
static void rsa_final ( void *ctx ) {
struct rsa_context *context = ctx;
rsa_free ( context );
}
/** RSA public-key algorithm */
struct pubkey_algorithm rsa_algorithm = {
.name = "rsa",
.ctxsize = sizeof ( struct rsa_context ),
.init = rsa_init,
.max_len = rsa_max_len,
.encrypt = rsa_encrypt,
.decrypt = rsa_decrypt,
.sign = rsa_sign,
.verify = rsa_verify,
.final = rsa_final,
};
+271
View File
@@ -0,0 +1,271 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* SHA-1 algorithm
*
*/
#include <stdint.h>
#include <string.h>
#include <byteswap.h>
#include <assert.h>
#include <ipxe/rotate.h>
#include <ipxe/crypto.h>
#include <ipxe/asn1.h>
#include <ipxe/sha1.h>
/** SHA-1 variables */
struct sha1_variables {
/* This layout matches that of struct sha1_digest_data,
* allowing for efficient endianness-conversion,
*/
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
uint32_t e;
uint32_t w[80];
} __attribute__ (( packed ));
/**
* f(a,b,c,d) for steps 0 to 19
*
* @v v SHA-1 variables
* @ret f f(a,b,c,d)
*/
static uint32_t sha1_f_0_19 ( struct sha1_variables *v ) {
return ( ( v->b & v->c ) | ( (~v->b) & v->d ) );
}
/**
* f(a,b,c,d) for steps 20 to 39 and 60 to 79
*
* @v v SHA-1 variables
* @ret f f(a,b,c,d)
*/
static uint32_t sha1_f_20_39_60_79 ( struct sha1_variables *v ) {
return ( v->b ^ v->c ^ v->d );
}
/**
* f(a,b,c,d) for steps 40 to 59
*
* @v v SHA-1 variables
* @ret f f(a,b,c,d)
*/
static uint32_t sha1_f_40_59 ( struct sha1_variables *v ) {
return ( ( v->b & v->c ) | ( v->b & v->d ) | ( v->c & v->d ) );
}
/** An SHA-1 step function */
struct sha1_step {
/**
* Calculate f(a,b,c,d)
*
* @v v SHA-1 variables
* @ret f f(a,b,c,d)
*/
uint32_t ( * f ) ( struct sha1_variables *v );
/** Constant k */
uint32_t k;
};
/** SHA-1 steps */
static struct sha1_step sha1_steps[4] = {
/** 0 to 19 */
{ .f = sha1_f_0_19, .k = 0x5a827999 },
/** 20 to 39 */
{ .f = sha1_f_20_39_60_79, .k = 0x6ed9eba1 },
/** 40 to 59 */
{ .f = sha1_f_40_59, .k = 0x8f1bbcdc },
/** 60 to 79 */
{ .f = sha1_f_20_39_60_79, .k = 0xca62c1d6 },
};
/**
* Initialise SHA-1 algorithm
*
* @v ctx SHA-1 context
*/
static void sha1_init ( void *ctx ) {
struct sha1_context *context = ctx;
context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x67452301 );
context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xefcdab89 );
context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x98badcfe );
context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0x10325476 );
context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0xc3d2e1f0 );
context->len = 0;
}
/**
* Calculate SHA-1 digest of accumulated data
*
* @v context SHA-1 context
*/
static void sha1_digest ( struct sha1_context *context ) {
union {
union sha1_digest_data_dwords ddd;
struct sha1_variables v;
} u;
uint32_t *a = &u.v.a;
uint32_t *b = &u.v.b;
uint32_t *c = &u.v.c;
uint32_t *d = &u.v.d;
uint32_t *e = &u.v.e;
uint32_t *w = u.v.w;
uint32_t f;
uint32_t k;
uint32_t temp;
struct sha1_step *step;
unsigned int i;
/* Sanity checks */
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
linker_assert ( &u.ddd.dd.digest.h[0] == a, sha1_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[1] == b, sha1_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[2] == c, sha1_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[3] == d, sha1_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[4] == e, sha1_bad_layout );
linker_assert ( &u.ddd.dd.data.dword[0] == w, sha1_bad_layout );
DBGC ( context, "SHA1 digesting:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
sizeof ( context->ddd.dd.digest ) );
DBGC_HDA ( context, context->len, &context->ddd.dd.data,
sizeof ( context->ddd.dd.data ) );
/* Convert h[0..4] to host-endian, and initialise a, b, c, d,
* e, and w[0..15]
*/
for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
be32_to_cpus ( &context->ddd.dword[i] );
u.ddd.dword[i] = context->ddd.dword[i];
}
/* Initialise w[16..79] */
for ( i = 16 ; i < 80 ; i++ )
w[i] = rol32 ( ( w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16] ), 1 );
/* Main loop */
for ( i = 0 ; i < 80 ; i++ ) {
step = &sha1_steps[ i / 20 ];
f = step->f ( &u.v );
k = step->k;
temp = ( rol32 ( *a, 5 ) + f + *e + k + w[i] );
*e = *d;
*d = *c;
*c = rol32 ( *b, 30 );
*b = *a;
*a = temp;
DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x\n",
i, *a, *b, *c, *d, *e );
}
/* Add chunk to hash and convert back to big-endian */
for ( i = 0 ; i < 5 ; i++ ) {
context->ddd.dd.digest.h[i] =
cpu_to_be32 ( context->ddd.dd.digest.h[i] +
u.ddd.dd.digest.h[i] );
}
DBGC ( context, "SHA1 digested:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
sizeof ( context->ddd.dd.digest ) );
}
/**
* Accumulate data with SHA-1 algorithm
*
* @v ctx SHA-1 context
* @v data Data
* @v len Length of data
*/
static void sha1_update ( void *ctx, const void *data, size_t len ) {
struct sha1_context *context = ctx;
const uint8_t *byte = data;
size_t offset;
/* Accumulate data a byte at a time, performing the digest
* whenever we fill the data buffer
*/
while ( len-- ) {
offset = ( context->len % sizeof ( context->ddd.dd.data ) );
context->ddd.dd.data.byte[offset] = *(byte++);
context->len++;
if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
sha1_digest ( context );
}
}
/**
* Generate SHA-1 digest
*
* @v ctx SHA-1 context
* @v out Output buffer
*/
static void sha1_final ( void *ctx, void *out ) {
struct sha1_context *context = ctx;
uint64_t len_bits;
uint8_t pad;
/* Record length before pre-processing */
len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
/* Pad with a single "1" bit followed by as many "0" bits as required */
pad = 0x80;
do {
sha1_update ( ctx, &pad, sizeof ( pad ) );
pad = 0x00;
} while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
/* Append length (in bits) */
sha1_update ( ctx, &len_bits, sizeof ( len_bits ) );
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
/* Copy out final digest */
memcpy ( out, &context->ddd.dd.digest,
sizeof ( context->ddd.dd.digest ) );
}
/** SHA-1 algorithm */
struct digest_algorithm sha1_algorithm = {
.name = "sha1",
.ctxsize = sizeof ( struct sha1_context ),
.blocksize = sizeof ( union sha1_block ),
.digestsize = sizeof ( struct sha1_digest ),
.init = sha1_init,
.update = sha1_update,
.final = sha1_final,
};
/** "sha1" object identifier */
static uint8_t oid_sha1[] = { ASN1_OID_SHA1 };
/** "sha1" OID-identified algorithm */
struct asn1_algorithm oid_sha1_algorithm __asn1_algorithm = {
.name = "sha1",
.digest = &sha1_algorithm,
.oid = ASN1_OID_CURSOR ( oid_sha1 ),
};
+18 -16
View File
@@ -18,6 +18,7 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
#include <ipxe/crypto.h>
#include <ipxe/sha1.h>
#include <ipxe/hmac.h>
@@ -46,7 +47,7 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
u8 keym[key_len]; /* modifiable copy of key */
u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */
u8 *in_blknr; /* pointer to last byte of in, block number */
u8 out[SHA1_SIZE]; /* HMAC-SHA1 result */
u8 out[SHA1_DIGEST_SIZE]; /* HMAC-SHA1 result */
u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */
const size_t label_len = strlen ( label );
@@ -67,14 +68,14 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) );
hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out );
if ( prf_len <= SHA1_SIZE ) {
if ( prf_len <= sizeof ( out ) ) {
memcpy ( prf, out, prf_len );
break;
}
memcpy ( prf, out, SHA1_SIZE );
prf_len -= SHA1_SIZE;
prf += SHA1_SIZE;
memcpy ( prf, out, sizeof ( out ) );
prf_len -= sizeof ( out );
prf += sizeof ( out );
}
}
@@ -97,30 +98,31 @@ static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
{
u8 pass[pass_len]; /* modifiable passphrase */
u8 in[salt_len + 4]; /* input buffer to first round */
u8 last[SHA1_SIZE]; /* output of round N, input of N+1 */
u8 last[SHA1_DIGEST_SIZE]; /* output of round N, input of N+1 */
u8 sha1_ctx[SHA1_CTX_SIZE];
u8 *next_in = in; /* changed to `last' after first round */
int next_size = sizeof ( in );
int i, j;
int i;
unsigned int j;
blocknr = htonl ( blocknr );
memcpy ( pass, passphrase, pass_len );
memcpy ( in, salt, salt_len );
memcpy ( in + salt_len, &blocknr, 4 );
memset ( block, 0, SHA1_SIZE );
memset ( block, 0, sizeof ( last ) );
for ( i = 0; i < iterations; i++ ) {
hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len );
hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size );
hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last );
for ( j = 0; j < SHA1_SIZE; j++ ) {
for ( j = 0; j < sizeof ( last ); j++ ) {
block[j] ^= last[j];
}
next_in = last;
next_size = SHA1_SIZE;
next_size = sizeof ( last );
}
}
@@ -146,20 +148,20 @@ void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
const void *salt, size_t salt_len,
int iterations, void *key, size_t key_len )
{
u32 blocks = ( key_len + SHA1_SIZE - 1 ) / SHA1_SIZE;
u32 blocks = ( key_len + SHA1_DIGEST_SIZE - 1 ) / SHA1_DIGEST_SIZE;
u32 blk;
u8 buf[SHA1_SIZE];
u8 buf[SHA1_DIGEST_SIZE];
for ( blk = 1; blk <= blocks; blk++ ) {
pbkdf2_sha1_f ( passphrase, pass_len, salt, salt_len,
iterations, blk, buf );
if ( key_len <= SHA1_SIZE ) {
if ( key_len <= sizeof ( buf ) ) {
memcpy ( key, buf, key_len );
break;
}
memcpy ( key, buf, SHA1_SIZE );
key_len -= SHA1_SIZE;
key += SHA1_SIZE;
memcpy ( key, buf, sizeof ( buf ) );
key_len -= sizeof ( buf );
key += sizeof ( buf );
}
}
+255
View File
@@ -0,0 +1,255 @@
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 of the
* License, or 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* SHA-256 algorithm
*
*/
#include <stdint.h>
#include <string.h>
#include <byteswap.h>
#include <assert.h>
#include <ipxe/rotate.h>
#include <ipxe/crypto.h>
#include <ipxe/asn1.h>
#include <ipxe/sha256.h>
/** SHA-256 variables */
struct sha256_variables {
/* This layout matches that of struct sha256_digest_data,
* allowing for efficient endianness-conversion,
*/
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
uint32_t e;
uint32_t f;
uint32_t g;
uint32_t h;
uint32_t w[64];
} __attribute__ (( packed ));
/** SHA-256 constants */
static const uint32_t k[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
/**
* Initialise SHA-256 algorithm
*
* @v ctx SHA-256 context
*/
static void sha256_init ( void *ctx ) {
struct sha256_context *context = ctx;
context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x6a09e667 );
context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xbb67ae85 );
context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x3c6ef372 );
context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0xa54ff53a );
context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0x510e527f );
context->ddd.dd.digest.h[5] = cpu_to_be32 ( 0x9b05688c );
context->ddd.dd.digest.h[6] = cpu_to_be32 ( 0x1f83d9ab );
context->ddd.dd.digest.h[7] = cpu_to_be32 ( 0x5be0cd19 );
context->len = 0;
}
/**
* Calculate SHA-256 digest of accumulated data
*
* @v context SHA-256 context
*/
static void sha256_digest ( struct sha256_context *context ) {
union {
union sha256_digest_data_dwords ddd;
struct sha256_variables v;
} u;
uint32_t *a = &u.v.a;
uint32_t *b = &u.v.b;
uint32_t *c = &u.v.c;
uint32_t *d = &u.v.d;
uint32_t *e = &u.v.e;
uint32_t *f = &u.v.f;
uint32_t *g = &u.v.g;
uint32_t *h = &u.v.h;
uint32_t *w = u.v.w;
uint32_t s0;
uint32_t s1;
uint32_t maj;
uint32_t t1;
uint32_t t2;
uint32_t ch;
unsigned int i;
/* Sanity checks */
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
linker_assert ( &u.ddd.dd.digest.h[0] == a, sha256_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[1] == b, sha256_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[2] == c, sha256_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[3] == d, sha256_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[4] == e, sha256_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[5] == f, sha256_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[6] == g, sha256_bad_layout );
linker_assert ( &u.ddd.dd.digest.h[7] == h, sha256_bad_layout );
linker_assert ( &u.ddd.dd.data.dword[0] == w, sha256_bad_layout );
DBGC ( context, "SHA256 digesting:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
sizeof ( context->ddd.dd.digest ) );
DBGC_HDA ( context, context->len, &context->ddd.dd.data,
sizeof ( context->ddd.dd.data ) );
/* Convert h[0..7] to host-endian, and initialise a, b, c, d,
* e, f, g, h, and w[0..15]
*/
for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
be32_to_cpus ( &context->ddd.dword[i] );
u.ddd.dword[i] = context->ddd.dword[i];
}
/* Initialise w[16..63] */
for ( i = 16 ; i < 64 ; i++ ) {
s0 = ( ror32 ( w[i-15], 7 ) ^ ror32 ( w[i-15], 18 ) ^
( w[i-15] >> 3 ) );
s1 = ( ror32 ( w[i-2], 17 ) ^ ror32 ( w[i-2], 19 ) ^
( w[i-2] >> 10 ) );
w[i] = ( w[i-16] + s0 + w[i-7] + s1 );
}
/* Main loop */
for ( i = 0 ; i < 64 ; i++ ) {
s0 = ( ror32 ( *a, 2 ) ^ ror32 ( *a, 13 ) ^ ror32 ( *a, 22 ) );
maj = ( ( *a & *b ) ^ ( *a & *c ) ^ ( *b & *c ) );
t2 = ( s0 + maj );
s1 = ( ror32 ( *e, 6 ) ^ ror32 ( *e, 11 ) ^ ror32 ( *e, 25 ) );
ch = ( ( *e & *f ) ^ ( (~*e) & *g ) );
t1 = ( *h + s1 + ch + k[i] + w[i] );
*h = *g;
*g = *f;
*f = *e;
*e = ( *d + t1 );
*d = *c;
*c = *b;
*b = *a;
*a = ( t1 + t2 );
DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x %08x %08x "
"%08x\n", i, *a, *b, *c, *d, *e, *f, *g, *h );
}
/* Add chunk to hash and convert back to big-endian */
for ( i = 0 ; i < 8 ; i++ ) {
context->ddd.dd.digest.h[i] =
cpu_to_be32 ( context->ddd.dd.digest.h[i] +
u.ddd.dd.digest.h[i] );
}
DBGC ( context, "SHA256 digested:\n" );
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
sizeof ( context->ddd.dd.digest ) );
}
/**
* Accumulate data with SHA-256 algorithm
*
* @v ctx SHA-256 context
* @v data Data
* @v len Length of data
*/
static void sha256_update ( void *ctx, const void *data, size_t len ) {
struct sha256_context *context = ctx;
const uint8_t *byte = data;
size_t offset;
/* Accumulate data a byte at a time, performing the digest
* whenever we fill the data buffer
*/
while ( len-- ) {
offset = ( context->len % sizeof ( context->ddd.dd.data ) );
context->ddd.dd.data.byte[offset] = *(byte++);
context->len++;
if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
sha256_digest ( context );
}
}
/**
* Generate SHA-256 digest
*
* @v ctx SHA-256 context
* @v out Output buffer
*/
static void sha256_final ( void *ctx, void *out ) {
struct sha256_context *context = ctx;
uint64_t len_bits;
uint8_t pad;
/* Record length before pre-processing */
len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
/* Pad with a single "1" bit followed by as many "0" bits as required */
pad = 0x80;
do {
sha256_update ( ctx, &pad, sizeof ( pad ) );
pad = 0x00;
} while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
/* Append length (in bits) */
sha256_update ( ctx, &len_bits, sizeof ( len_bits ) );
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
/* Copy out final digest */
memcpy ( out, &context->ddd.dd.digest,
sizeof ( context->ddd.dd.digest ) );
}
/** SHA-256 algorithm */
struct digest_algorithm sha256_algorithm = {
.name = "sha256",
.ctxsize = sizeof ( struct sha256_context ),
.blocksize = sizeof ( union sha256_block ),
.digestsize = sizeof ( struct sha256_digest ),
.init = sha256_init,
.update = sha256_update,
.final = sha256_final,
};
/** "sha256" object identifier */
static uint8_t oid_sha256[] = { ASN1_OID_SHA256 };
/** "sha256" OID-identified algorithm */
struct asn1_algorithm oid_sha256_algorithm __asn1_algorithm = {
.name = "sha256",
.digest = &sha256_algorithm,
.oid = ASN1_OID_CURSOR ( oid_sha256 ),
};

Some files were not shown because too many files have changed in this diff Show More