Преглед на файлове

[build] Allow a client certificate to be specified at build time

Allow a client certificate and corresponding private key to be
specified at build time using the syntax

  make CERT=/path/to/certificate KEY=/path/to/key

The build process uses openssl to convert the files into DER format,
and includes them within the client certificate store in
clientcert.c.  The build process will prompt for the private key
password if applicable.

Note that the private key is stored unencrypted, and so the resulting
iPXE binary (and the temporary files created during the build process)
should be treated as being equivalent to an unencrypted private key
file.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown преди 12 години
родител
ревизия
8685280cbd
променени са 3 файла, в които са добавени 197 реда и са изтрити 6 реда
  1. 74
    6
      src/Makefile.housekeeping
  2. 80
    0
      src/crypto/clientcert.c
  3. 43
    0
      src/include/ipxe/clientcert.h

+ 74
- 6
src/Makefile.housekeeping Целия файл

@@ -629,12 +629,6 @@ EMBED_ALL	:= $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
629 629
 
630 630
 $(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST)
631 631
 
632
-# This file uses .incbin inline assembly to include a binary file.
633
-# Unfortunately ccache does not detect this dependency and caches builds even
634
-# when the binary file has changed.
635
-#
636
-$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
637
-
638 632
 CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
639 633
 
640 634
 # List of trusted root certificates
@@ -665,6 +659,80 @@ $(BIN)/rootcert.o : $(TRUSTED_FILES) $(TRUSTED_LIST)
665 659
 
666 660
 CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
667 661
 
662
+# (Single-element) list of client certificates
663
+#
664
+CERT_LIST := $(BIN)/.certificate.list
665
+ifeq ($(wildcard $(CERT_LIST)),)
666
+CERT_OLD := <invalid>
667
+else
668
+CERT_OLD := $(shell cat $(CERT_LIST))
669
+endif
670
+ifneq ($(CERT_OLD),$(CERT))
671
+$(shell $(ECHO) "$(CERT)" > $(CERT_LIST))
672
+endif
673
+
674
+$(CERT_LIST) :
675
+
676
+VERYCLEANUP += $(CERT_LIST)
677
+
678
+# Embedded client certificate
679
+#
680
+CERT_INC := $(BIN)/.certificate.der
681
+
682
+ifdef CERT
683
+$(CERT_INC) : $(CERT) $(CERT_LIST)
684
+	$(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
685
+
686
+$(BIN)/clientcert.o : $(CERT_INC)
687
+endif
688
+
689
+CLEANUP += $(CERT_INC)
690
+
691
+$(BIN)/clientcert.o : $(CERT_LIST)
692
+
693
+CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"")
694
+
695
+# (Single-element) list of client private keys
696
+#
697
+KEY_LIST := $(BIN)/.private_key.list
698
+ifeq ($(wildcard $(KEY_LIST)),)
699
+KEY_OLD := <invalid>
700
+else
701
+KEY_OLD := $(shell cat $(KEY_LIST))
702
+endif
703
+ifneq ($(KEY_OLD),$(KEY))
704
+$(shell $(ECHO) "$(KEY)" > $(KEY_LIST))
705
+endif
706
+
707
+$(KEY_LIST) :
708
+
709
+VERYCLEANUP += $(KEY_LIST)
710
+
711
+# Embedded client private key
712
+#
713
+KEY_INC := $(BIN)/.private_key.der
714
+
715
+ifdef KEY
716
+$(KEY_INC) : $(KEY) $(KEY_LIST)
717
+	$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
718
+
719
+$(BIN)/clientcert.o : $(KEY_INC)
720
+endif
721
+
722
+CLEANUP += $(KEY_INC)
723
+
724
+$(BIN)/clientcert.o : $(KEY_LIST)
725
+
726
+CFLAGS_clientcert += $(if $(KEY),-DPRIVATE_KEY="\"$(KEY_INC)\"")
727
+
728
+# These files use .incbin inline assembly to include a binary file.
729
+# Unfortunately ccache does not detect this dependency and caches
730
+# builds even when the binary file has changed.
731
+#
732
+$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
733
+
734
+$(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC)
735
+
668 736
 # Generate error usage information
669 737
 #
670 738
 $(BIN)/%.einfo : $(BIN)/%.o

+ 80
- 0
src/crypto/clientcert.c Целия файл

@@ -0,0 +1,80 @@
1
+/*
2
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <stdint.h>
22
+#include <ipxe/clientcert.h>
23
+
24
+/** @file
25
+ *
26
+ * Client certificate store
27
+ *
28
+ * Life would in theory be easier if we could use a single file to
29
+ * hold both the certificate and corresponding private key.
30
+ * Unfortunately, the only common format which supports this is
31
+ * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my
32
+ * codebase.  See, for reference and amusement:
33
+ *
34
+ *    http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html
35
+ *
36
+ */
37
+
38
+/* Sanity checks */
39
+#if defined(CERTIFICATE) && ! defined(PRIVATE_KEY)
40
+#warning "Attempting to embed certificate with no corresponding private key"
41
+#endif
42
+#if defined(PRIVATE_KEY) && ! defined(CERTIFICATE)
43
+#warning "Attempting to embed private key with no corresponding certificate"
44
+#endif
45
+
46
+/* Raw client certificate data */
47
+extern char client_certificate_data[];
48
+extern char client_certificate_len[];
49
+__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
50
+	  "\nclient_certificate_data:\n\t"
51
+#ifdef CERTIFICATE
52
+	  ".incbin \"" CERTIFICATE "\"\n\t"
53
+#endif /* CERTIFICATE */
54
+	  ".size client_certificate_data, ( . - client_certificate_data )\n\t"
55
+	  ".equ client_certificate_len, ( . - client_certificate_data )\n\t"
56
+	  ".previous\n\t" );
57
+
58
+/** Client certificate */
59
+struct client_certificate client_certificate = {
60
+	.data = client_certificate_data,
61
+	.len = ( ( size_t ) client_certificate_len ),
62
+};
63
+
64
+/* Raw client private key data */
65
+extern char client_private_key_data[];
66
+extern char client_private_key_len[];
67
+__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
68
+	  "\nclient_private_key_data:\n\t"
69
+#ifdef PRIVATE_KEY
70
+	  ".incbin \"" PRIVATE_KEY "\"\n\t"
71
+#endif /* PRIVATE_KEY */
72
+	  ".size client_private_key_data, ( . - client_private_key_data )\n\t"
73
+	  ".equ client_private_key_len, ( . - client_private_key_data )\n\t"
74
+	  ".previous\n\t" );
75
+
76
+/** Client private key */
77
+struct client_private_key client_private_key = {
78
+	.data = client_private_key_data,
79
+	.len = ( ( size_t ) client_private_key_len ),
80
+};

+ 43
- 0
src/include/ipxe/clientcert.h Целия файл

@@ -0,0 +1,43 @@
1
+#ifndef _IPXE_CLIENTCERT_H
2
+#define _IPXE_CLIENTCERT_H
3
+
4
+/** @file
5
+ *
6
+ * Client certificate store
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <stdint.h>
13
+
14
+/** A client certificate */
15
+struct client_certificate {
16
+	/** Data */
17
+	const void *data;
18
+	/** Length */
19
+	size_t len;
20
+};
21
+
22
+/** A client private key */
23
+struct client_private_key {
24
+	/** Data */
25
+	const void *data;
26
+	/** Length */
27
+	size_t len;
28
+};
29
+
30
+extern struct client_certificate client_certificate;
31
+extern struct client_private_key client_private_key;
32
+
33
+/**
34
+ * Check for presence of a client certificate
35
+ *
36
+ * @ret have_cert	We have a client certificate and private key
37
+ */
38
+static inline int have_client_certificate ( void ) {
39
+	return ( ( client_certificate.len > 0 ) &&
40
+		 ( client_private_key.len > 0 ) );
41
+}
42
+
43
+#endif /* _IPXE_CLIENTCERT_H */

Loading…
Отказ
Запис