[crypto] Generalise X.509 cache to a full certificate store

Expand the concept of the X.509 cache to provide the functionality of
a certificate store.  Certificates in the store will be automatically
used to complete certificate chains where applicable.

The certificate store may be prepopulated at build time using the
CERT=... build command line option.  For example:

  make bin/ipxe.usb CERT=mycert1.crt,mycert2.crt

Certificates within the certificate store are not implicitly trusted;
the trust list is specified using TRUST=... as before.  For example:

  make bin/ipxe.usb CERT=root.crt TRUST=root.crt

This can be used to embed the full trusted root certificate within the
iPXE binary, which is potentially useful in an HTTPS-only environment
in which there is no HTTP server from which to automatically download
cross-signed certificates or other certificate chain fragments.

This usage of CERT= extends the existing use of CERT= to specify the
client certificate.  The client certificate is now identified
automatically by checking for a match against the private key.  For
example:

  make bin/ipxe.usb CERT=root.crt,client.crt TRUST=root.crt KEY=client.key

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2014-03-28 15:45:10 +00:00
parent 2dd3fffe18
commit bc8ca6b8ce
18 changed files with 640 additions and 398 deletions

View File

@@ -601,7 +601,7 @@ rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST)
CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
# (Single-element) list of client certificates
# List of embedded certificates
#
CERT_LIST := $(BIN)/.certificate.list
ifeq ($(wildcard $(CERT_LIST)),)
@@ -617,24 +617,43 @@ $(CERT_LIST) : $(MAKEDEPS)
VERYCLEANUP += $(CERT_LIST)
# Embedded client certificate
# Embedded certificates concatenated and then split into one file per
# certificate (even if original files contained certificate chains)
#
CERT_INC := $(BIN)/.certificate.der
CERT_FILES := $(subst $(COMMA), ,$(CERT))
CERT_CONCAT := $(BIN)/.certificates.pem
ifdef CERT
$(CERT_INC) : $(CERT) $(CERT_LIST)
ifneq ($(CERT),)
CERT_COUNT := $(shell grep "BEGIN CERTIFICATE" $(CERT_FILES) | wc -l)
$(CERT_CONCAT) : $(CERT_FILES) $(CERT_LIST)
$(Q)cat $(CERT_FILES) > $@
# We must use an (otherwise unnecessary) pattern rule here to encode
# the fact that one "csplit" command generates multiple targets
CERT_PEMS := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
$(BIN)/.certificate.pem.$(i))
$(subst .pem.,.%.,$(CERT_PEMS)) : $(BIN)/.certificates.%
$(Q)$(CSPLIT) -q -n 1 -f $(BIN)/.certificate.pem. $< \
'/BEGIN CERTIFICATE/' '{*}'
CERT_DERS := $(subst .certificate.pem.,.certificate.der.,$(CERT_PEMS))
$(BIN)/.certificate.der.% : $(BIN)/.certificate.pem.%
$(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
clientcert_DEPS += $(CERT_INC)
CERT_ALL := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
CERT ( $(i), \"$(word $(i),$(CERT_DERS))\" ))
endif
CLEANUP += $(CERT_INC)
certstore_DEPS += $(CERT_LIST) $(CERT_FILES) $(CERT_PEMS) $(CERT_DERS)
clientcert_DEPS += $(CERT_LIST)
CFLAGS_certstore += -DCERT_ALL="$(CERT_ALL)"
CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"")
CLEANUP += $(BIN)/.certificate.* $(BIN)/.certificates.*
# (Single-element) list of client private keys
# (Single-element) list of private keys
#
ifdef KEY
PRIVKEY := $(KEY) # Maintain backwards compatibility
@@ -653,7 +672,7 @@ $(PRIVKEY_LIST) : $(MAKEDEPS)
VERYCLEANUP += $(PRIVKEY_LIST)
# Embedded client private key
# Embedded private key
#
PRIVKEY_INC := $(BIN)/.private_key.der
@@ -661,21 +680,22 @@ ifdef PRIVKEY
$(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST)
$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
clientcert_DEPS += $(PRIVKEY_INC)
privkey_DEPS += $(PRIVKEY_INC)
endif
CLEANUP += $(PRIVKEY_INC)
CLEANUP += $(BIN)/.private_key.*
clientcert_DEPS += $(PRIVKEY_LIST)
privkey_DEPS += $(PRIVKEY_LIST)
CFLAGS_clientcert += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"")
CFLAGS_privkey += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_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.% : override CC := env CCACHE_DISABLE=1 $(CC)
$(BIN)/clientcert.% : override CC := env CCACHE_DISABLE=1 $(CC)
$(BIN)/certstore.% : override CC := env CCACHE_DISABLE=1 $(CC)
$(BIN)/privkey.% : override CC := env CCACHE_DISABLE=1 $(CC)
# Version number
#