Browse Source

[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>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
bc8ca6b8ce

+ 1
- 0
src/Makefile View File

@@ -34,6 +34,7 @@ OBJCOPY		:= $(CROSS_COMPILE)objcopy
34 34
 NM		:= $(CROSS_COMPILE)nm
35 35
 OBJDUMP		:= $(CROSS_COMPILE)objdump
36 36
 OPENSSL		:= openssl
37
+CSPLIT		:= csplit
37 38
 PARSEROM	:= ./util/parserom.pl
38 39
 FIXROM		:= ./util/fixrom.pl
39 40
 SYMCHECK	:= ./util/symcheck.pl

+ 36
- 16
src/Makefile.housekeeping View File

@@ -601,7 +601,7 @@ rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST)
601 601
 
602 602
 CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
603 603
 
604
-# (Single-element) list of client certificates
604
+# List of embedded certificates
605 605
 #
606 606
 CERT_LIST := $(BIN)/.certificate.list
607 607
 ifeq ($(wildcard $(CERT_LIST)),)
@@ -617,24 +617,43 @@ $(CERT_LIST) : $(MAKEDEPS)
617 617
 
618 618
 VERYCLEANUP += $(CERT_LIST)
619 619
 
620
-# Embedded client certificate
620
+# Embedded certificates concatenated and then split into one file per
621
+# certificate (even if original files contained certificate chains)
621 622
 #
622
-CERT_INC := $(BIN)/.certificate.der
623
+CERT_FILES := $(subst $(COMMA), ,$(CERT))
624
+CERT_CONCAT := $(BIN)/.certificates.pem
623 625
 
624
-ifdef CERT
625
-$(CERT_INC) : $(CERT) $(CERT_LIST)
626
+ifneq ($(CERT),)
627
+
628
+CERT_COUNT := $(shell grep "BEGIN CERTIFICATE" $(CERT_FILES) | wc -l)
629
+
630
+$(CERT_CONCAT) : $(CERT_FILES) $(CERT_LIST)
631
+	$(Q)cat $(CERT_FILES) > $@
632
+
633
+# We must use an (otherwise unnecessary) pattern rule here to encode
634
+# the fact that one "csplit" command generates multiple targets
635
+CERT_PEMS := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
636
+	       $(BIN)/.certificate.pem.$(i))
637
+$(subst .pem.,.%.,$(CERT_PEMS)) : $(BIN)/.certificates.%
638
+	$(Q)$(CSPLIT) -q -n 1 -f $(BIN)/.certificate.pem. $< \
639
+		'/BEGIN CERTIFICATE/' '{*}'
640
+
641
+CERT_DERS := $(subst .certificate.pem.,.certificate.der.,$(CERT_PEMS))
642
+$(BIN)/.certificate.der.% : $(BIN)/.certificate.pem.%
626 643
 	$(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
627 644
 
628
-clientcert_DEPS += $(CERT_INC)
645
+CERT_ALL := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
646
+	      CERT ( $(i), \"$(word $(i),$(CERT_DERS))\" ))
647
+
629 648
 endif
630 649
 
631
-CLEANUP += $(CERT_INC)
650
+certstore_DEPS += $(CERT_LIST) $(CERT_FILES) $(CERT_PEMS) $(CERT_DERS)
632 651
 
633
-clientcert_DEPS += $(CERT_LIST)
652
+CFLAGS_certstore += -DCERT_ALL="$(CERT_ALL)"
634 653
 
635
-CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"")
654
+CLEANUP += $(BIN)/.certificate.* $(BIN)/.certificates.*
636 655
 
637
-# (Single-element) list of client private keys
656
+# (Single-element) list of private keys
638 657
 #
639 658
 ifdef KEY
640 659
 PRIVKEY	:= $(KEY) # Maintain backwards compatibility
@@ -653,7 +672,7 @@ $(PRIVKEY_LIST) : $(MAKEDEPS)
653 672
 
654 673
 VERYCLEANUP += $(PRIVKEY_LIST)
655 674
 
656
-# Embedded client private key
675
+# Embedded private key
657 676
 #
658 677
 PRIVKEY_INC := $(BIN)/.private_key.der
659 678
 
@@ -661,21 +680,22 @@ ifdef PRIVKEY
661 680
 $(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST)
662 681
 	$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
663 682
 
664
-clientcert_DEPS += $(PRIVKEY_INC)
683
+privkey_DEPS += $(PRIVKEY_INC)
665 684
 endif
666 685
 
667
-CLEANUP += $(PRIVKEY_INC)
686
+CLEANUP += $(BIN)/.private_key.*
668 687
 
669
-clientcert_DEPS += $(PRIVKEY_LIST)
688
+privkey_DEPS += $(PRIVKEY_LIST)
670 689
 
671
-CFLAGS_clientcert += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"")
690
+CFLAGS_privkey += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"")
672 691
 
673 692
 # These files use .incbin inline assembly to include a binary file.
674 693
 # Unfortunately ccache does not detect this dependency and caches
675 694
 # builds even when the binary file has changed.
676 695
 #
677 696
 $(BIN)/embedded.% : override CC := env CCACHE_DISABLE=1 $(CC)
678
-$(BIN)/clientcert.% : override CC := env CCACHE_DISABLE=1 $(CC)
697
+$(BIN)/certstore.% : override CC := env CCACHE_DISABLE=1 $(CC)
698
+$(BIN)/privkey.% : override CC := env CCACHE_DISABLE=1 $(CC)
679 699
 
680 700
 # Version number
681 701
 #

+ 275
- 0
src/crypto/certstore.c View File

@@ -0,0 +1,275 @@
1
+/*
2
+ * Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <string.h>
23
+#include <stdlib.h>
24
+#include <ipxe/init.h>
25
+#include <ipxe/dhcp.h>
26
+#include <ipxe/settings.h>
27
+#include <ipxe/malloc.h>
28
+#include <ipxe/crypto.h>
29
+#include <ipxe/asn1.h>
30
+#include <ipxe/x509.h>
31
+#include <ipxe/certstore.h>
32
+
33
+/** @file
34
+ *
35
+ * Certificate store
36
+ *
37
+ */
38
+
39
+/** Raw certificate data for all permanent stored certificates */
40
+#undef CERT
41
+#define CERT( _index, _path )						\
42
+	extern char stored_cert_ ## _index ## _data[];			\
43
+	extern char stored_cert_ ## _index ## _len[];			\
44
+	__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"		\
45
+		  "\nstored_cert_" #_index "_data:\n\t"			\
46
+		  ".incbin \"" _path "\"\n\t"				\
47
+		  "\nstored_cert_" #_index "_end:\n\t"			\
48
+		  ".equ stored_cert_" #_index "_len, "			\
49
+			"( stored_cert_" #_index "_end - "		\
50
+			"  stored_cert_" #_index "_data )\n\t"		\
51
+		  ".previous\n\t" );
52
+CERT_ALL
53
+
54
+/** Raw certificate cursors for all permanent stored certificates */
55
+#undef CERT
56
+#define CERT( _index, _path ) {						\
57
+	.data = stored_cert_ ## _index ## _data,			\
58
+	.len = ( size_t ) stored_cert_ ## _index ## _len, 		\
59
+},
60
+static struct asn1_cursor certstore_raw[] = {
61
+	CERT_ALL
62
+};
63
+
64
+/** X.509 certificate structures for all permanent stored certificates */
65
+static struct x509_certificate certstore_certs[ sizeof ( certstore_raw ) /
66
+						sizeof ( certstore_raw[0] ) ];
67
+
68
+/** Certificate store */
69
+struct x509_chain certstore = {
70
+	.refcnt = REF_INIT ( ref_no_free ),
71
+	.links = LIST_HEAD_INIT ( certstore.links ),
72
+};
73
+
74
+/**
75
+ * Mark stored certificate as most recently used
76
+ *
77
+ * @v cert		X.509 certificate
78
+ * @ret cert		X.509 certificate
79
+ */
80
+static struct x509_certificate *
81
+certstore_found ( struct x509_certificate *cert ) {
82
+
83
+	/* Mark as most recently used */
84
+	list_del ( &cert->store.list );
85
+	list_add ( &cert->store.list, &certstore.links );
86
+	DBGC2 ( &certstore, "CERTSTORE found certificate %s\n",
87
+		x509_name ( cert ) );
88
+
89
+	return cert;
90
+}
91
+
92
+/**
93
+ * Find certificate in store
94
+ *
95
+ * @v raw		Raw certificate data
96
+ * @ret cert		X.509 certificate, or NULL if not found
97
+ */
98
+struct x509_certificate * certstore_find ( struct asn1_cursor *raw ) {
99
+	struct x509_certificate *cert;
100
+
101
+	/* Search for certificate within store */
102
+	list_for_each_entry ( cert, &certstore.links, store.list ) {
103
+		if ( asn1_compare ( raw, &cert->raw ) == 0 )
104
+			return certstore_found ( cert );
105
+	}
106
+	return NULL;
107
+}
108
+
109
+/**
110
+ * Find certificate in store corresponding to a private key
111
+ *
112
+ * @v key		Private key
113
+ * @ret cert		X.509 certificate, or NULL if not found
114
+ */
115
+struct x509_certificate * certstore_find_key ( struct asn1_cursor *key ) {
116
+	struct x509_certificate *cert;
117
+
118
+	/* Search for certificate within store */
119
+	list_for_each_entry ( cert, &certstore.links, store.list ) {
120
+		if ( pubkey_match ( cert->signature_algorithm->pubkey,
121
+				    key->data, key->len,
122
+				    cert->subject.public_key.raw.data,
123
+				    cert->subject.public_key.raw.len ) == 0 )
124
+			return certstore_found ( cert );
125
+	}
126
+	return NULL;
127
+}
128
+
129
+/**
130
+ * Add certificate to store
131
+ *
132
+ * @v cert		X.509 certificate
133
+ */
134
+void certstore_add ( struct x509_certificate *cert ) {
135
+
136
+	/* Add certificate to store */
137
+	cert->store.cert = cert;
138
+	x509_get ( cert );
139
+	list_add ( &cert->store.list, &certstore.links );
140
+	DBGC ( &certstore, "CERTSTORE added certificate %s\n",
141
+	       x509_name ( cert ) );
142
+}
143
+
144
+/**
145
+ * Discard a stored certificate
146
+ *
147
+ * @ret discarded	Number of cached items discarded
148
+ */
149
+static unsigned int certstore_discard ( void ) {
150
+	struct x509_certificate *cert;
151
+
152
+	/* Discard the least recently used certificate for which the
153
+	 * only reference is held by the store itself.
154
+	 */
155
+	list_for_each_entry_reverse ( cert, &certstore.links, store.list ) {
156
+		if ( cert->refcnt.count == 0 ) {
157
+			DBGC ( &certstore, "CERTSTORE discarded certificate "
158
+			       "%s\n", x509_name ( cert ) );
159
+			list_del ( &cert->store.list );
160
+			x509_put ( cert );
161
+			return 1;
162
+		}
163
+	}
164
+	return 0;
165
+}
166
+
167
+/** Certificate store cache discarder */
168
+struct cache_discarder certstore_discarder __cache_discarder ( CACHE_NORMAL ) ={
169
+	.discard = certstore_discard,
170
+};
171
+
172
+/**
173
+ * Construct permanent certificate store
174
+ *
175
+ */
176
+static void certstore_init ( void ) {
177
+	struct asn1_cursor *raw;
178
+	struct x509_certificate *cert;
179
+	int i;
180
+	int rc;
181
+
182
+	/* Skip if we have no permanent stored certificates */
183
+	if ( ! sizeof ( certstore_raw ) )
184
+		return;
185
+
186
+	/* Add certificates */
187
+	for ( i = 0 ; i < ( int ) ( sizeof ( certstore_raw ) /
188
+				    sizeof ( certstore_raw[0] ) ) ; i++ ) {
189
+
190
+		/* Skip if certificate already present in store */
191
+		raw = &certstore_raw[i];
192
+		if ( ( cert = certstore_find ( raw ) ) != NULL ) {
193
+			DBGC ( &certstore, "CERTSTORE permanent certificate %d "
194
+			       "is a duplicate of %s\n", i, x509_name ( cert ));
195
+			continue;
196
+		}
197
+
198
+		/* Parse certificate */
199
+		cert = &certstore_certs[i];
200
+		ref_init ( &cert->refcnt, ref_no_free );
201
+		if ( ( rc = x509_parse ( cert, raw ) ) != 0 ) {
202
+			DBGC ( &certstore, "CERTSTORE could not parse "
203
+			       "permanent certificate %d: %s\n",
204
+			       i, strerror ( rc ) );
205
+			continue;
206
+		}
207
+
208
+		/* Add certificate to store.  Certificate will never
209
+		 * be discarded from the store, since we retain a
210
+		 * permanent reference to it.
211
+		 */
212
+		certstore_add ( cert );
213
+		DBGC ( &certstore, "CERTSTORE permanent certificate %d is %s\n",
214
+		       i, x509_name ( cert ) );
215
+	}
216
+}
217
+
218
+/** Certificate store initialisation function */
219
+struct init_fn certstore_init_fn __init_fn ( INIT_LATE ) = {
220
+	.initialise = certstore_init,
221
+};
222
+
223
+/** Additional certificate setting */
224
+static struct setting cert_setting __setting ( SETTING_CRYPTO, cert ) = {
225
+	.name = "cert",
226
+	.description = "Certificate",
227
+	.tag = DHCP_EB_CERT,
228
+	.type = &setting_type_hex,
229
+};
230
+
231
+/**
232
+ * Apply certificate store configuration settings
233
+ *
234
+ * @ret rc		Return status code
235
+ */
236
+static int certstore_apply_settings ( void ) {
237
+	static struct x509_certificate *cert = NULL;
238
+	struct x509_certificate *old_cert;
239
+	void *cert_data;
240
+	int len;
241
+	int rc;
242
+
243
+	/* Record any existing additional certificate */
244
+	old_cert = cert;
245
+	cert = NULL;
246
+
247
+	/* Add additional certificate, if any */
248
+	if ( ( len = fetch_raw_setting_copy ( NULL, &cert_setting,
249
+					      &cert_data ) ) >= 0 ) {
250
+		if ( ( rc = x509_certificate ( cert_data, len, &cert ) ) == 0 ){
251
+			DBGC ( &certstore, "CERTSTORE added additional "
252
+			       "certificate %s\n", x509_name ( cert ) );
253
+		} else {
254
+			DBGC ( &certstore, "CERTSTORE could not parse "
255
+			       "additional certificate: %s\n",
256
+			       strerror ( rc ) );
257
+			/* Do not fail; leave as an unusable certificate */
258
+		}
259
+		free ( cert_data );
260
+	}
261
+
262
+	/* Free old additional certificiate.  Do this after reparsing
263
+	 * the additional certificate; in the common case that the
264
+	 * certificate has not changed, this will allow the stored
265
+	 * certificate to be reused.
266
+	 */
267
+	x509_put ( old_cert );
268
+
269
+	return 0;
270
+}
271
+
272
+/** Certificate store settings applicator */
273
+struct settings_applicator certstore_applicator __settings_applicator = {
274
+	.apply = certstore_apply_settings,
275
+};

+ 0
- 170
src/crypto/clientcert.c View File

@@ -1,170 +0,0 @@
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., 51 Franklin Street, Fifth Floor, Boston, MA
17
- * 02110-1301, USA.
18
- */
19
-
20
-FILE_LICENCE ( GPL2_OR_LATER );
21
-
22
-#include <stdint.h>
23
-#include <stdlib.h>
24
-#include <string.h>
25
-#include <ipxe/dhcp.h>
26
-#include <ipxe/settings.h>
27
-#include <ipxe/clientcert.h>
28
-
29
-/** @file
30
- *
31
- * Client certificate store
32
- *
33
- * Life would in theory be easier if we could use a single file to
34
- * hold both the certificate and corresponding private key.
35
- * Unfortunately, the only common format which supports this is
36
- * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my
37
- * codebase.  See, for reference and amusement:
38
- *
39
- *    http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html
40
- *
41
- */
42
-
43
-/* Sanity checks */
44
-#if defined(CERTIFICATE) && ! defined(PRIVATE_KEY)
45
-#warning "Attempting to embed certificate with no corresponding private key"
46
-#endif
47
-#if defined(PRIVATE_KEY) && ! defined(CERTIFICATE)
48
-#warning "Attempting to embed private key with no corresponding certificate"
49
-#endif
50
-
51
-/* Allow client certificates to be overridden if not explicitly specified */
52
-#ifdef CERTIFICATE
53
-#define ALLOW_CERT_OVERRIDE 0
54
-#else
55
-#define ALLOW_CERT_OVERRIDE 1
56
-#endif
57
-
58
-/* Raw client certificate data */
59
-extern char client_certificate_data[];
60
-extern char client_certificate_len[];
61
-__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
62
-	  "\nclient_certificate_data:\n\t"
63
-#ifdef CERTIFICATE
64
-	  ".incbin \"" CERTIFICATE "\"\n\t"
65
-#endif /* CERTIFICATE */
66
-	  ".size client_certificate_data, ( . - client_certificate_data )\n\t"
67
-	  ".equ client_certificate_len, ( . - client_certificate_data )\n\t"
68
-	  ".previous\n\t" );
69
-
70
-/* Raw client private key data */
71
-extern char client_private_key_data[];
72
-extern char client_private_key_len[];
73
-__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
74
-	  "\nclient_private_key_data:\n\t"
75
-#ifdef PRIVATE_KEY
76
-	  ".incbin \"" PRIVATE_KEY "\"\n\t"
77
-#endif /* PRIVATE_KEY */
78
-	  ".size client_private_key_data, ( . - client_private_key_data )\n\t"
79
-	  ".equ client_private_key_len, ( . - client_private_key_data )\n\t"
80
-	  ".previous\n\t" );
81
-
82
-/** Client certificate */
83
-struct client_certificate client_certificate = {
84
-	.data = client_certificate_data,
85
-	.len = ( ( size_t ) client_certificate_len ),
86
-};
87
-
88
-/** Client private key */
89
-struct client_private_key client_private_key = {
90
-	.data = client_private_key_data,
91
-	.len = ( ( size_t ) client_private_key_len ),
92
-};
93
-
94
-/** Client certificate setting */
95
-static struct setting cert_setting __setting ( SETTING_CRYPTO, cert ) = {
96
-	.name = "cert",
97
-	.description = "Client certificate",
98
-	.tag = DHCP_EB_CERT,
99
-	.type = &setting_type_hex,
100
-};
101
-
102
-/** Client private key setting */
103
-static struct setting privkey_setting __setting ( SETTING_CRYPTO, privkey ) = {
104
-	.name = "privkey",
105
-	.description = "Client private key",
106
-	.tag = DHCP_EB_KEY,
107
-	.type = &setting_type_hex,
108
-};
109
-
110
-/**
111
- * Apply client certificate store configuration settings
112
- *
113
- * @ret rc		Return status code
114
- */
115
-static int clientcert_apply_settings ( void ) {
116
-	static void *cert = NULL;
117
-	static void *key = NULL;
118
-	int len;
119
-
120
-	/* Allow client certificate to be overridden only if
121
-	 * not explicitly specified at build time.
122
-	 */
123
-	if ( ALLOW_CERT_OVERRIDE ) {
124
-
125
-		/* Restore default client certificate */
126
-		client_certificate.data = client_certificate_data;
127
-		client_certificate.len = ( ( size_t ) client_certificate_len );
128
-
129
-		/* Fetch new client certificate, if any */
130
-		free ( cert );
131
-		if ( ( len = fetch_raw_setting_copy ( NULL, &cert_setting,
132
-						      &cert ) ) >= 0 ) {
133
-			client_certificate.data = cert;
134
-			client_certificate.len = len;
135
-		}
136
-
137
-		/* Restore default client private key */
138
-		client_private_key.data = client_private_key_data;
139
-		client_private_key.len = ( ( size_t ) client_private_key_len );
140
-
141
-		/* Fetch new client private key, if any */
142
-		free ( key );
143
-		if ( ( len = fetch_raw_setting_copy ( NULL, &privkey_setting,
144
-						      &key ) ) >= 0 ) {
145
-			client_private_key.data = key;
146
-			client_private_key.len = len;
147
-		}
148
-	}
149
-
150
-	/* Debug */
151
-	if ( have_client_certificate() ) {
152
-		DBGC ( &client_certificate, "CLIENTCERT using %s "
153
-		       "certificate:\n", ( cert ? "external" : "built-in" ) );
154
-		DBGC_HDA ( &client_certificate, 0, client_certificate.data,
155
-			   client_certificate.len );
156
-		DBGC ( &client_certificate, "CLIENTCERT using %s private "
157
-		       "key:\n", ( key ? "external" : "built-in" ) );
158
-		DBGC_HDA ( &client_certificate, 0, client_private_key.data,
159
-			   client_private_key.len );
160
-	} else {
161
-		DBGC ( &client_certificate, "CLIENTCERT has no certificate\n" );
162
-	}
163
-
164
-	return 0;
165
-}
166
-
167
-/** Client certificate store settings applicator */
168
-struct settings_applicator clientcert_applicator __settings_applicator = {
169
-	.apply = clientcert_apply_settings,
170
-};

+ 12
- 7
src/crypto/cms.c View File

@@ -617,18 +617,21 @@ static int cms_verify_digest ( struct cms_signature *sig,
617 617
  * @v data		Signed data
618 618
  * @v len		Length of signed data
619 619
  * @v time		Time at which to validate certificates
620
- * @v root		Root certificate store, or NULL to use default
620
+ * @v store		Certificate store, or NULL to use default
621
+ * @v root		Root certificate list, or NULL to use default
621 622
  * @ret rc		Return status code
622 623
  */
623 624
 static int cms_verify_signer_info ( struct cms_signature *sig,
624 625
 				    struct cms_signer_info *info,
625 626
 				    userptr_t data, size_t len,
626
-				    time_t time, struct x509_root *root ) {
627
+				    time_t time, struct x509_chain *store,
628
+				    struct x509_root *root ) {
627 629
 	struct x509_certificate *cert;
628 630
 	int rc;
629 631
 
630 632
 	/* Validate certificate chain */
631
-	if ( ( rc = x509_validate_chain ( info->chain, time, root ) ) != 0 ) {
633
+	if ( ( rc = x509_validate_chain ( info->chain, time, store,
634
+					  root ) ) != 0 ) {
632 635
 		DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
633 636
 		       sig, info, strerror ( rc ) );
634 637
 		return rc;
@@ -667,11 +670,13 @@ static int cms_verify_signer_info ( struct cms_signature *sig,
667 670
  * @v len		Length of signed data
668 671
  * @v name		Required common name, or NULL to check all signatures
669 672
  * @v time		Time at which to validate certificates
670
- * @v root		Root certificate store, or NULL to use default
673
+ * @v store		Certificate store, or NULL to use default
674
+ * @v root		Root certificate list, or NULL to use default
671 675
  * @ret rc		Return status code
672 676
  */
673 677
 int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
674
-		 const char *name, time_t time, struct x509_root *root ) {
678
+		 const char *name, time_t time, struct x509_chain *store,
679
+		 struct x509_root *root ) {
675 680
 	struct cms_signer_info *info;
676 681
 	struct x509_certificate *cert;
677 682
 	int count = 0;
@@ -682,8 +687,8 @@ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
682 687
 		cert = x509_first ( info->chain );
683 688
 		if ( name && ( x509_check_name ( cert, name ) != 0 ) )
684 689
 			continue;
685
-		if ( ( rc = cms_verify_signer_info ( sig, info, data, len,
686
-						     time, root ) ) != 0 )
690
+		if ( ( rc = cms_verify_signer_info ( sig, info, data, len, time,
691
+						     store, root ) ) != 0 )
687 692
 			return rc;
688 693
 		count++;
689 694
 	}

+ 118
- 0
src/crypto/privkey.c View File

@@ -0,0 +1,118 @@
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., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <stdint.h>
23
+#include <stdlib.h>
24
+#include <string.h>
25
+#include <ipxe/dhcp.h>
26
+#include <ipxe/settings.h>
27
+#include <ipxe/x509.h>
28
+#include <ipxe/privkey.h>
29
+
30
+/** @file
31
+ *
32
+ * Private key
33
+ *
34
+ * Life would in theory be easier if we could use a single file to
35
+ * hold both the certificate and corresponding private key.
36
+ * Unfortunately, the only common format which supports this is
37
+ * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my
38
+ * codebase.  See, for reference and amusement:
39
+ *
40
+ *    http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html
41
+ */
42
+
43
+/* Allow private key to be overridden if not explicitly specified */
44
+#ifdef PRIVATE_KEY
45
+#define ALLOW_KEY_OVERRIDE 0
46
+#else
47
+#define ALLOW_KEY_OVERRIDE 1
48
+#endif
49
+
50
+/* Raw private key data */
51
+extern char private_key_data[];
52
+extern char private_key_len[];
53
+__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
54
+	  "\nprivate_key_data:\n\t"
55
+#ifdef PRIVATE_KEY
56
+	  ".incbin \"" PRIVATE_KEY "\"\n\t"
57
+#endif /* PRIVATE_KEY */
58
+	  ".size private_key_data, ( . - private_key_data )\n\t"
59
+	  ".equ private_key_len, ( . - private_key_data )\n\t"
60
+	  ".previous\n\t" );
61
+
62
+/** Private key */
63
+struct asn1_cursor private_key = {
64
+	.data = private_key_data,
65
+	.len = ( ( size_t ) private_key_len ),
66
+};
67
+
68
+/** Private key setting */
69
+static struct setting privkey_setting __setting ( SETTING_CRYPTO, privkey ) = {
70
+	.name = "privkey",
71
+	.description = "Private key",
72
+	.tag = DHCP_EB_KEY,
73
+	.type = &setting_type_hex,
74
+};
75
+
76
+/**
77
+ * Apply private key configuration settings
78
+ *
79
+ * @ret rc		Return status code
80
+ */
81
+static int privkey_apply_settings ( void ) {
82
+	static void *key_data = NULL;
83
+	int len;
84
+
85
+	/* Allow private key to be overridden only if not explicitly
86
+	 * specified at build time.
87
+	 */
88
+	if ( ALLOW_KEY_OVERRIDE ) {
89
+
90
+		/* Restore default private key */
91
+		private_key.data = private_key_data;
92
+		private_key.len = ( ( size_t ) private_key_len );
93
+
94
+		/* Fetch new private key, if any */
95
+		free ( key_data );
96
+		if ( ( len = fetch_raw_setting_copy ( NULL, &privkey_setting,
97
+						      &key_data ) ) >= 0 ) {
98
+			private_key.data = key_data;
99
+			private_key.len = len;
100
+		}
101
+	}
102
+
103
+	/* Debug */
104
+	if ( private_key.len ) {
105
+		DBGC ( &private_key, "PRIVKEY using %s private key:\n",
106
+		       ( key_data ? "external" : "built-in" ) );
107
+		DBGC_HDA ( &private_key, 0, private_key.data, private_key.len );
108
+	} else {
109
+		DBGC ( &private_key, "PRIVKEY has no private key\n" );
110
+	}
111
+
112
+	return 0;
113
+}
114
+
115
+/** Private key settings applicator */
116
+struct settings_applicator privkey_applicator __settings_applicator = {
117
+	.apply = privkey_apply_settings,
118
+};

+ 32
- 61
src/crypto/x509.c View File

@@ -24,7 +24,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
24 24
 #include <errno.h>
25 25
 #include <assert.h>
26 26
 #include <ipxe/list.h>
27
-#include <ipxe/malloc.h>
28 27
 #include <ipxe/asn1.h>
29 28
 #include <ipxe/crypto.h>
30 29
 #include <ipxe/md5.h>
@@ -32,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
32 31
 #include <ipxe/sha256.h>
33 32
 #include <ipxe/rsa.h>
34 33
 #include <ipxe/rootcert.h>
34
+#include <ipxe/certstore.h>
35 35
 #include <ipxe/x509.h>
36 36
 
37 37
 /** @file
@@ -107,9 +107,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
107 107
 	__einfo_error ( EINFO_EACCES_WRONG_NAME )
108 108
 #define EINFO_EACCES_WRONG_NAME \
109 109
 	__einfo_uniqify ( EINFO_EACCES, 0x0a, "Incorrect certificate name" )
110
-
111
-/** Certificate cache */
112
-static LIST_HEAD ( x509_cache );
110
+#define EACCES_USELESS \
111
+	__einfo_error ( EINFO_EACCES_USELESS )
112
+#define EINFO_EACCES_USELESS \
113
+	__einfo_uniqify ( EINFO_EACCES, 0x0b, "No usable certificates" )
113 114
 
114 115
 /**
115 116
  * Get X.509 certificate name (for debugging)
@@ -130,32 +131,6 @@ const char * x509_name ( struct x509_certificate *cert ) {
130 131
 	return buf;
131 132
 }
132 133
 
133
-/**
134
- * Discard a cached certificate
135
- *
136
- * @ret discarded	Number of cached items discarded
137
- */
138
-static unsigned int x509_discard ( void ) {
139
-	struct x509_certificate *cert;
140
-
141
-	/* Discard the least recently used certificate for which the
142
-	 * only reference is held by the cache itself.
143
-	 */
144
-	list_for_each_entry_reverse ( cert, &x509_cache, list ) {
145
-		if ( cert->refcnt.count == 0 ) {
146
-			list_del ( &cert->list );
147
-			x509_put ( cert );
148
-			return 1;
149
-		}
150
-	}
151
-	return 0;
152
-}
153
-
154
-/** X.509 cache discarder */
155
-struct cache_discarder x509_discarder __cache_discarder ( CACHE_NORMAL ) = {
156
-	.discard = x509_discard,
157
-};
158
-
159 134
 /** "commonName" object identifier */
160 135
 static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME };
161 136
 
@@ -955,8 +930,8 @@ static int x509_parse_tbscertificate ( struct x509_certificate *cert,
955 930
  * @v raw		ASN.1 cursor
956 931
  * @ret rc		Return status code
957 932
  */
958
-static int x509_parse ( struct x509_certificate *cert,
959
-			const struct asn1_cursor *raw ) {
933
+int x509_parse ( struct x509_certificate *cert,
934
+		 const struct asn1_cursor *raw ) {
960 935
 	struct x509_signature *signature = &cert->signature;
961 936
 	struct asn1_algorithm **signature_algorithm = &signature->algorithm;
962 937
 	struct asn1_bit_string *signature_value = &signature->value;
@@ -1032,22 +1007,12 @@ int x509_certificate ( const void *data, size_t len,
1032 1007
 	cursor.len = len;
1033 1008
 	asn1_shrink_any ( &cursor );
1034 1009
 
1035
-	/* Search for certificate within cache */
1036
-	list_for_each_entry ( (*cert), &x509_cache, list ) {
1037
-		if ( asn1_compare ( &cursor, &(*cert)->raw ) == 0 ) {
1038
-
1039
-			DBGC2 ( *cert, "X509 %p \"%s\" cache hit\n",
1040
-				*cert, x509_name ( *cert ) );
1010
+	/* Return stored certificate, if present */
1011
+	if ( ( *cert = certstore_find ( &cursor ) ) != NULL ) {
1041 1012
 
1042
-			/* Mark as most recently used */
1043
-			list_del ( &(*cert)->list );
1044
-			list_add ( &(*cert)->list, &x509_cache );
1045
-
1046
-			/* Add caller's reference */
1047
-			x509_get ( *cert );
1048
-
1049
-			return 0;
1050
-		}
1013
+		/* Add caller's reference */
1014
+		x509_get ( *cert );
1015
+		return 0;
1051 1016
 	}
1052 1017
 
1053 1018
 	/* Allocate and initialise certificate */
@@ -1055,7 +1020,6 @@ int x509_certificate ( const void *data, size_t len,
1055 1020
 	if ( ! *cert )
1056 1021
 		return -ENOMEM;
1057 1022
 	ref_init ( &(*cert)->refcnt, NULL );
1058
-	INIT_LIST_HEAD ( &(*cert)->list );
1059 1023
 	raw = ( *cert + 1 );
1060 1024
 
1061 1025
 	/* Copy raw data */
@@ -1069,9 +1033,8 @@ int x509_certificate ( const void *data, size_t len,
1069 1033
 		return rc;
1070 1034
 	}
1071 1035
 
1072
-	/* Add certificate to cache */
1073
-	x509_get ( *cert );
1074
-	list_add ( &(*cert)->list, &x509_cache );
1036
+	/* Add certificate to store */
1037
+	certstore_add ( *cert );
1075 1038
 
1076 1039
 	return 0;
1077 1040
 }
@@ -1221,7 +1184,7 @@ void x509_fingerprint ( struct x509_certificate *cert,
1221 1184
  * Check X.509 root certificate
1222 1185
  *
1223 1186
  * @v cert		X.509 certificate
1224
- * @v root		X.509 root certificate store
1187
+ * @v root		X.509 root certificate list
1225 1188
  * @ret rc		Return status code
1226 1189
  */
1227 1190
 int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ) {
@@ -1282,7 +1245,7 @@ int x509_check_time ( struct x509_certificate *cert, time_t time ) {
1282 1245
  * @v cert		X.509 certificate
1283 1246
  * @v issuer		Issuing X.509 certificate (or NULL)
1284 1247
  * @v time		Time at which to validate certificate
1285
- * @v root		Root certificate store, or NULL to use default
1248
+ * @v root		Root certificate list, or NULL to use default
1286 1249
  * @ret rc		Return status code
1287 1250
  *
1288 1251
  * The issuing certificate must have already been validated.
@@ -1533,7 +1496,7 @@ int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) {
1533 1496
 	cert = x509_last ( chain );
1534 1497
 	if ( ! cert ) {
1535 1498
 		DBGC ( chain, "X509 chain %p has no certificates\n", chain );
1536
-		return -EINVAL;
1499
+		return -EACCES_EMPTY;
1537 1500
 	}
1538 1501
 
1539 1502
 	/* Append certificates, in order */
@@ -1560,17 +1523,23 @@ int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) {
1560 1523
  *
1561 1524
  * @v chain		X.509 certificate chain
1562 1525
  * @v time		Time at which to validate certificates
1563
- * @v root		Root certificate store, or NULL to use default
1526
+ * @v store		Certificate store, or NULL to use default
1527
+ * @v root		Root certificate list, or NULL to use default
1564 1528
  * @ret rc		Return status code
1565 1529
  */
1566 1530
 int x509_validate_chain ( struct x509_chain *chain, time_t time,
1567
-			  struct x509_root *root ) {
1531
+			  struct x509_chain *store, struct x509_root *root ) {
1568 1532
 	struct x509_certificate *issuer = NULL;
1569 1533
 	struct x509_link *link;
1570 1534
 	int rc;
1571 1535
 
1572
-	/* Error to be used if chain contains no certifictes */
1573
-	rc = -EACCES_EMPTY;
1536
+	/* Use default certificate store if none specified */
1537
+	if ( ! store )
1538
+		store = &certstore;
1539
+
1540
+	/* Append any applicable certificates from the certificate store */
1541
+	if ( ( rc = x509_auto_append ( chain, store ) ) != 0 )
1542
+		return rc;
1574 1543
 
1575 1544
 	/* Find first certificate that can be validated as a
1576 1545
 	 * standalone (i.e.  is already valid, or can be validated as
@@ -1600,7 +1569,9 @@ int x509_validate_chain ( struct x509_chain *chain, time_t time,
1600 1569
 		return 0;
1601 1570
 	}
1602 1571
 
1603
-	DBGC ( chain, "X509 chain %p found no valid certificates: %s\n",
1604
-	       chain, strerror ( rc ) );
1605
-	return rc;
1572
+	DBGC ( chain, "X509 chain %p found no usable certificates\n", chain );
1573
+	return -EACCES_USELESS;
1606 1574
 }
1575
+
1576
+/* Drag in certificate store */
1577
+REQUIRE_OBJECT ( certstore );

+ 21
- 0
src/include/ipxe/certstore.h View File

@@ -0,0 +1,21 @@
1
+#ifndef _IPXE_CERTSTORE_H
2
+#define _IPXE_CERTSTORE_H
3
+
4
+/** @file
5
+ *
6
+ * Certificate store
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <ipxe/asn1.h>
13
+#include <ipxe/x509.h>
14
+
15
+extern struct x509_chain certstore;
16
+
17
+extern struct x509_certificate * certstore_find ( struct asn1_cursor *raw );
18
+extern struct x509_certificate * certstore_find_key ( struct asn1_cursor *key );
19
+extern void certstore_add ( struct x509_certificate *cert );
20
+
21
+#endif /* _IPXE_CERTSTORE_H */

+ 0
- 43
src/include/ipxe/clientcert.h View File

@@ -1,43 +0,0 @@
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 */

+ 2
- 1
src/include/ipxe/cms.h View File

@@ -70,6 +70,7 @@ cms_put ( struct cms_signature *sig ) {
70 70
 extern int cms_signature ( const void *data, size_t len,
71 71
 			   struct cms_signature **sig );
72 72
 extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
73
-			const char *name, time_t time, struct x509_root *root );
73
+			const char *name, time_t time, struct x509_chain *store,
74
+			struct x509_root *root );
74 75
 
75 76
 #endif /* _IPXE_CMS_H */

+ 16
- 0
src/include/ipxe/privkey.h View File

@@ -0,0 +1,16 @@
1
+#ifndef _IPXE_PRIVKEY_H
2
+#define _IPXE_PRIVKEY_H
3
+
4
+/** @file
5
+ *
6
+ * Private key
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <ipxe/asn1.h>
13
+
14
+extern struct asn1_cursor private_key;
15
+
16
+#endif /* _IPXE_PRIVKEY_H */

+ 2
- 2
src/include/ipxe/tls.h View File

@@ -241,8 +241,8 @@ struct tls_session {
241 241
 	struct digest_algorithm *handshake_digest;
242 242
 	/** Digest algorithm context used for handshake verification */
243 243
 	uint8_t *handshake_ctx;
244
-	/** Public-key algorithm used for Certificate Verify (if sent) */
245
-	struct pubkey_algorithm *verify_pubkey;
244
+	/** Client certificate (if used) */
245
+	struct x509_certificate *cert;
246 246
 
247 247
 	/** Server certificate chain */
248 248
 	struct x509_chain *chain;

+ 22
- 19
src/include/ipxe/x509.h View File

@@ -156,12 +156,29 @@ struct x509_extensions {
156 156
 	struct x509_authority_info_access auth_info;
157 157
 };
158 158
 
159
+/** A link in an X.509 certificate chain */
160
+struct x509_link {
161
+	/** List of links */
162
+	struct list_head list;
163
+	/** Certificate */
164
+	struct x509_certificate *cert;
165
+};
166
+
167
+/** An X.509 certificate chain */
168
+struct x509_chain {
169
+	/** Reference count */
170
+	struct refcnt refcnt;
171
+	/** List of links */
172
+	struct list_head links;
173
+};
174
+
159 175
 /** An X.509 certificate */
160 176
 struct x509_certificate {
161 177
 	/** Reference count */
162 178
 	struct refcnt refcnt;
163
-	/** List of certificates in cache */
164
-	struct list_head list;
179
+
180
+	/** Link in certificate store */
181
+	struct x509_link store;
165 182
 
166 183
 	/** Certificate has been validated */
167 184
 	int valid;
@@ -212,22 +229,6 @@ x509_put ( struct x509_certificate *cert ) {
212 229
 	ref_put ( &cert->refcnt );
213 230
 }
214 231
 
215
-/** A link in an X.509 certificate chain */
216
-struct x509_link {
217
-	/** List of links */
218
-	struct list_head list;
219
-	/** Certificate */
220
-	struct x509_certificate *cert;
221
-};
222
-
223
-/** An X.509 certificate chain */
224
-struct x509_chain {
225
-	/** Reference count */
226
-	struct refcnt refcnt;
227
-	/** List of links */
228
-	struct list_head links;
229
-};
230
-
231 232
 /**
232 233
  * Get reference to X.509 certificate chain
233 234
  *
@@ -331,7 +332,8 @@ struct x509_root {
331 332
 };
332 333
 
333 334
 extern const char * x509_name ( struct x509_certificate *cert );
334
-
335
+extern int x509_parse ( struct x509_certificate *cert,
336
+			const struct asn1_cursor *raw );
335 337
 extern int x509_certificate ( const void *data, size_t len,
336 338
 			      struct x509_certificate **cert );
337 339
 extern int x509_validate ( struct x509_certificate *cert,
@@ -347,6 +349,7 @@ extern int x509_append_raw ( struct x509_chain *chain, const void *data,
347 349
 extern int x509_auto_append ( struct x509_chain *chain,
348 350
 			      struct x509_chain *certs );
349 351
 extern int x509_validate_chain ( struct x509_chain *chain, time_t time,
352
+				 struct x509_chain *store,
350 353
 				 struct x509_root *root );
351 354
 
352 355
 /* Functions exposed only for unit testing */

+ 34
- 40
src/net/tls.c View File

@@ -43,7 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
43 43
 #include <ipxe/xfer.h>
44 44
 #include <ipxe/open.h>
45 45
 #include <ipxe/x509.h>
46
-#include <ipxe/clientcert.h>
46
+#include <ipxe/privkey.h>
47
+#include <ipxe/certstore.h>
47 48
 #include <ipxe/rbg.h>
48 49
 #include <ipxe/validator.h>
49 50
 #include <ipxe/tls.h>
@@ -157,6 +158,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
157 158
 #define EINFO_EPERM_VERIFY						\
158 159
 	__einfo_uniqify ( EINFO_EPERM, 0x02,				\
159 160
 			  "Handshake verification failed" )
161
+#define EPERM_CLIENT_CERT __einfo_error ( EINFO_EPERM_CLIENT_CERT )
162
+#define EINFO_EPERM_CLIENT_CERT						\
163
+	__einfo_uniqify ( EINFO_EPERM, 0x03,				\
164
+			  "No suitable client certificate available" )
160 165
 #define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION )
161 166
 #define EINFO_EPROTO_VERSION						\
162 167
 	__einfo_uniqify ( EINFO_EPROTO, 0x01,				\
@@ -307,6 +312,7 @@ static void free_tls ( struct refcnt *refcnt ) {
307 312
 		list_del ( &iobuf->list );
308 313
 		free_iob ( iobuf );
309 314
 	}
315
+	x509_put ( tls->cert );
310 316
 	x509_chain_put ( tls->chain );
311 317
 
312 318
 	/* Free TLS structure itself */
@@ -1030,41 +1036,16 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
1030 1036
  * @ret rc		Return status code
1031 1037
  */
1032 1038
 static int tls_send_certificate ( struct tls_session *tls ) {
1033
-	int num_certificates = ( have_client_certificate() ? 1 : 0 );
1034 1039
 	struct {
1035 1040
 		uint32_t type_length;
1036 1041
 		uint8_t length[3];
1037 1042
 		struct {
1038 1043
 			uint8_t length[3];
1039
-			uint8_t data[ client_certificate.len ];
1040
-		} __attribute__ (( packed )) certificates[num_certificates];
1044
+			uint8_t data[ tls->cert->raw.len ];
1045
+		} __attribute__ (( packed )) certificates[1];
1041 1046
 	} __attribute__ (( packed )) *certificate;
1042
-	struct x509_certificate *cert;
1043 1047
 	int rc;
1044 1048
 
1045
-	/* If we have a certificate to send, determine the applicable
1046
-	 * public-key algorithm and schedule transmission of
1047
-	 * CertificateVerify.
1048
-	 */
1049
-	if ( num_certificates ) {
1050
-
1051
-		/* Parse certificate to determine public-key algorithm */
1052
-		if ( ( rc = x509_certificate ( client_certificate.data,
1053
-					       client_certificate.len,
1054
-					       &cert ) ) != 0 ) {
1055
-			DBGC ( tls, "TLS %p could not parse client "
1056
-			       "certificate: %s\n", tls, strerror ( rc ) );
1057
-			return rc;
1058
-		}
1059
-		tls->verify_pubkey = cert->signature_algorithm->pubkey;
1060
-		x509_put ( cert );
1061
-		cert = NULL;
1062
-
1063
-		/* Schedule CertificateVerify transmission */
1064
-		tls->tx_pending |= TLS_TX_CERTIFICATE_VERIFY;
1065
-		tls_tx_resume ( tls );
1066
-	}
1067
-
1068 1049
 	/* Allocate storage for Certificate record (which may be too
1069 1050
 	 * large for the stack).
1070 1051
 	 */
@@ -1079,13 +1060,11 @@ static int tls_send_certificate ( struct tls_session *tls ) {
1079 1060
 			  sizeof ( certificate->type_length ) ) );
1080 1061
 	tls_set_uint24 ( certificate->length,
1081 1062
 			 sizeof ( certificate->certificates ) );
1082
-	if ( num_certificates ) {
1083
-		tls_set_uint24 ( certificate->certificates[0].length,
1084
-				 sizeof ( certificate->certificates[0].data ) );
1085
-		memcpy ( certificate->certificates[0].data,
1086
-			 client_certificate.data,
1063
+	tls_set_uint24 ( certificate->certificates[0].length,
1087 1064
 			 sizeof ( certificate->certificates[0].data ) );
1088
-	}
1065
+	memcpy ( certificate->certificates[0].data,
1066
+		 tls->cert->raw.data,
1067
+		 sizeof ( certificate->certificates[0].data ) );
1089 1068
 
1090 1069
 	/* Transmit record */
1091 1070
 	rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) );
@@ -1148,7 +1127,8 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) {
1148 1127
  */
1149 1128
 static int tls_send_certificate_verify ( struct tls_session *tls ) {
1150 1129
 	struct digest_algorithm *digest = tls->handshake_digest;
1151
-	struct pubkey_algorithm *pubkey = tls->verify_pubkey;
1130
+	struct x509_certificate *cert = tls->cert;
1131
+	struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey;
1152 1132
 	uint8_t digest_out[ digest->digestsize ];
1153 1133
 	uint8_t ctx[ pubkey->ctxsize ];
1154 1134
 	struct tls_signature_hash_algorithm *sig_hash = NULL;
@@ -1158,8 +1138,8 @@ static int tls_send_certificate_verify ( struct tls_session *tls ) {
1158 1138
 	tls_verify_handshake ( tls, digest_out );
1159 1139
 
1160 1140
 	/* Initialise public-key algorithm */
1161
-	if ( ( rc = pubkey_init ( pubkey, ctx, client_private_key.data,
1162
-				  client_private_key.len ) ) != 0 ) {
1141
+	if ( ( rc = pubkey_init ( pubkey, ctx, private_key.data,
1142
+				  private_key.len ) ) != 0 ) {
1163 1143
 		DBGC ( tls, "TLS %p could not initialise %s client private "
1164 1144
 		       "key: %s\n", tls, pubkey->name, strerror ( rc ) );
1165 1145
 		goto err_pubkey_init;
@@ -1541,9 +1521,19 @@ static int tls_new_certificate_request ( struct tls_session *tls,
1541 1521
 	 * in parsing the Certificate Request.
1542 1522
 	 */
1543 1523
 
1544
-	/* Schedule Certificate transmission */
1545
-	tls->tx_pending |= TLS_TX_CERTIFICATE;
1546
-	tls_tx_resume ( tls );
1524
+	/* Free any existing client certificate */
1525
+	x509_put ( tls->cert );
1526
+
1527
+	/* Determine client certificate to be sent */
1528
+	tls->cert = certstore_find_key ( &private_key );
1529
+	if ( ! tls->cert ) {
1530
+		DBGC ( tls, "TLS %p could not find certificate corresponding "
1531
+		       "to private key\n", tls );
1532
+		return -EPERM_CLIENT_CERT;
1533
+	}
1534
+	x509_get ( tls->cert );
1535
+	DBGC ( tls, "TLS %p sending client certificate %s\n",
1536
+	       tls, x509_name ( tls->cert ) );
1547 1537
 
1548 1538
 	return 0;
1549 1539
 }
@@ -2469,6 +2459,10 @@ static void tls_validator_done ( struct tls_session *tls, int rc ) {
2469 2459
 	tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
2470 2460
 			     TLS_TX_CHANGE_CIPHER |
2471 2461
 			     TLS_TX_FINISHED );
2462
+	if ( tls->cert ) {
2463
+		tls->tx_pending |= ( TLS_TX_CERTIFICATE |
2464
+				     TLS_TX_CERTIFICATE_VERIFY );
2465
+	}
2472 2466
 	tls_tx_resume ( tls );
2473 2467
 
2474 2468
 	return;

+ 1
- 1
src/net/validator.c View File

@@ -458,7 +458,7 @@ static void validator_step ( struct validator *validator ) {
458 458
 	 * previously.
459 459
 	 */
460 460
 	now = time ( NULL );
461
-	if ( ( rc = x509_validate_chain ( validator->chain, now,
461
+	if ( ( rc = x509_validate_chain ( validator->chain, now, NULL,
462 462
 					  NULL ) ) == 0 ) {
463 463
 		validator_finished ( validator, 0 );
464 464
 		return;

+ 29
- 17
src/tests/cms_test.c View File

@@ -1305,7 +1305,13 @@ static uint8_t root_crt_fingerprint[] =
1305 1305
 		      0x96, 0xe7, 0xa8, 0x6d, 0x63, 0x2d, 0x32, 0x38,
1306 1306
 		      0xaf, 0x00, 0xc4, 0x1a, 0xfc, 0xd8, 0xac, 0xc3 );
1307 1307
 
1308
-/** Certificate store containing the iPXE self-test root CA */
1308
+/** Empty certificate store */
1309
+static struct x509_chain empty_store = {
1310
+	.refcnt = REF_INIT ( ref_no_free ),
1311
+	.links = LIST_HEAD_INIT ( empty_store.links ),
1312
+};
1313
+
1314
+/** Root certificate list containing the iPXE self-test root CA */
1309 1315
 static struct x509_root test_root = {
1310 1316
 	.digest = &cms_test_algorithm,
1311 1317
 	.count = 1,
@@ -1349,12 +1355,13 @@ static time_t test_expired = 1375573111ULL; /* Sat Aug  3 23:38:31 2013 */
1349 1355
  * @v code		Test signed code
1350 1356
  * @v name		Test verification name
1351 1357
  * @v time		Test verification time
1352
- * @v root		Test root certificate store
1358
+ * @v store		Test certificate store
1359
+ * @v root		Test root certificate list
1353 1360
  */
1354
-#define cms_verify_ok( sgn, code, name, time, root ) do {		\
1361
+#define cms_verify_ok( sgn, code, name, time, store, root ) do {	\
1355 1362
 	x509_invalidate_chain ( (sgn)->sig->certificates );		\
1356 1363
 	ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ),	\
1357
-			  (code)->len, name, time, root ) == 0 );	\
1364
+			  (code)->len, name, time, store, root ) == 0 );\
1358 1365
 	} while ( 0 )
1359 1366
 
1360 1367
 /**
@@ -1364,12 +1371,13 @@ static time_t test_expired = 1375573111ULL; /* Sat Aug  3 23:38:31 2013 */
1364 1371
  * @v code		Test signed code
1365 1372
  * @v name		Test verification name
1366 1373
  * @v time		Test verification time
1367
- * @v root		Test root certificate store
1374
+ * @v store		Test certificate store
1375
+ * @v root		Test root certificate list
1368 1376
  */
1369
-#define cms_verify_fail_ok( sgn, code, name, time, root ) do {		\
1377
+#define cms_verify_fail_ok( sgn, code, name, time, store, root ) do {	\
1370 1378
 	x509_invalidate_chain ( (sgn)->sig->certificates );		\
1371 1379
 	ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ),	\
1372
-			  (code)->len, name, time, root ) != 0 );	\
1380
+			  (code)->len, name, time, store, root ) != 0 );\
1373 1381
 	} while ( 0 )
1374 1382
 
1375 1383
 /**
@@ -1385,38 +1393,42 @@ static void cms_test_exec ( void ) {
1385 1393
 	cms_signature_ok ( &nonsigned_sig );
1386 1394
 
1387 1395
 	/* Check good signature */
1396
+	cms_verify_ok ( &codesigned_sig, &test_code, "codesign.test.ipxe.org",
1397
+			test_time, &empty_store, &test_root );
1388 1398
 	cms_verify_ok ( &codesigned_sig, &test_code,
1389
-			"codesign.test.ipxe.org", test_time, &test_root );
1390
-	cms_verify_ok ( &codesigned_sig, &test_code,
1391
-			NULL, test_time, &test_root );
1399
+			NULL, test_time, &empty_store, &test_root );
1392 1400
 
1393 1401
 	/* Check incorrect signer name */
1394 1402
 	cms_verify_fail_ok ( &codesigned_sig, &test_code,
1395
-			     "wrongname.test.ipxe.org", test_time, &test_root );
1403
+			     "wrongname.test.ipxe.org", test_time,
1404
+			     &empty_store, &test_root );
1396 1405
 
1397 1406
 	/* Check non-code-signing certificate */
1398 1407
 	cms_verify_fail_ok ( &genericsigned_sig, &test_code,
1399
-			     NULL, test_time, &test_root );
1408
+			     NULL, test_time, &empty_store, &test_root );
1400 1409
 
1401 1410
 	/* Check non-signing certificate */
1402 1411
 	cms_verify_fail_ok ( &nonsigned_sig, &test_code,
1403
-			     NULL, test_time, &test_root );
1412
+			     NULL, test_time, &empty_store, &test_root );
1404 1413
 
1405 1414
 	/* Check broken chain */
1406 1415
 	cms_verify_fail_ok ( &brokenchain_sig, &test_code,
1407
-			     NULL, test_time, &test_root );
1416
+			     NULL, test_time, &empty_store, &test_root );
1408 1417
 
1409 1418
 	/* Check untrusted signature */
1410 1419
 	cms_verify_fail_ok ( &codesigned_sig, &test_code,
1411
-			     NULL, test_time, &dummy_root );
1420
+			     NULL, test_time, &empty_store, &dummy_root );
1412 1421
 
1413 1422
 	/* Check incorrect signed content */
1414 1423
 	cms_verify_fail_ok ( &codesigned_sig, &bad_code,
1415
-			     NULL, test_time, &test_root );
1424
+			     NULL, test_time, &empty_store, &test_root );
1416 1425
 
1417 1426
 	/* Check expired signature */
1418 1427
 	cms_verify_fail_ok ( &codesigned_sig, &test_code,
1419
-			     NULL, test_expired, &test_root );
1428
+			     NULL, test_expired, &empty_store, &test_root );
1429
+
1430
+	/* Sanity check */
1431
+	assert ( list_empty ( &empty_store.links ) );
1420 1432
 
1421 1433
 	/* Drop signature references */
1422 1434
 	cms_put ( nonsigned_sig.sig );

+ 38
- 20
src/tests/x509_test.c View File

@@ -654,14 +654,20 @@ CHAIN ( useless_chain, &useless_crt, &leaf_crt,	&intermediate_crt, &root_crt );
654 654
 CHAIN ( bad_path_len_chain, &bad_path_len_crt, &useless_crt, &leaf_crt,
655 655
 	&intermediate_crt, &root_crt );
656 656
 
657
-/** Certificate store containing the iPXE self-test root CA */
657
+/** Empty certificate store */
658
+static struct x509_chain empty_store = {
659
+	.refcnt = REF_INIT ( ref_no_free ),
660
+	.links = LIST_HEAD_INIT ( empty_store.links ),
661
+};
662
+
663
+/** Root certificate list containing the iPXE self-test root CA */
658 664
 static struct x509_root test_root = {
659 665
 	.digest = &x509_test_algorithm,
660 666
 	.count = 1,
661 667
 	.fingerprints = root_crt_fingerprint,
662 668
 };
663 669
 
664
-/** Certificate store containing the iPXE self-test intermediate CA */
670
+/** Root certificate list containing the iPXE self-test intermediate CA */
665 671
 static struct x509_root intermediate_root = {
666 672
 	.digest = &x509_test_algorithm,
667 673
 	.count = 1,
@@ -813,12 +819,13 @@ static time_t test_ca_expired = 2205014905ULL; /* Wed Nov 16 00:08:25 2039 */
813 819
  *
814 820
  * @v chn		Test certificate chain
815 821
  * @v time		Test certificate validation time
816
- * @v root		Test root certificate store
822
+ * @v store		Test certificate store
823
+ * @v root		Test root certificate list
817 824
  */
818
-#define x509_validate_chain_ok( chn, time, root ) do {			\
825
+#define x509_validate_chain_ok( chn, time, store, root ) do {		\
819 826
 	x509_invalidate_chain ( (chn)->chain );				\
820 827
 	ok ( x509_validate_chain ( (chn)->chain, (time),		\
821
-				   (root) ) == 0 );			\
828
+				   (store), (root) ) == 0 );		\
822 829
 	} while ( 0 )
823 830
 
824 831
 /**
@@ -826,12 +833,13 @@ static time_t test_ca_expired = 2205014905ULL; /* Wed Nov 16 00:08:25 2039 */
826 833
  *
827 834
  * @v chn		Test certificate chain
828 835
  * @v time		Test certificate validation time
829
- * @v root		Test root certificate store
836
+ * @v store		Test certificate store
837
+ * @v root		Test root certificate list
830 838
  */
831
-#define x509_validate_chain_fail_ok( chn, time, root ) do {		\
839
+#define x509_validate_chain_fail_ok( chn, time, store, root ) do {	\
832 840
 	x509_invalidate_chain ( (chn)->chain );				\
833 841
 	ok ( x509_validate_chain ( (chn)->chain, (time),		\
834
-				   (root) ) != 0 );			\
842
+				   (store), (root) ) != 0 );		\
835 843
 	} while ( 0 )
836 844
 
837 845
 /**
@@ -898,25 +906,35 @@ static void x509_test_exec ( void ) {
898 906
 	x509_chain_ok ( &bad_path_len_chain );
899 907
 
900 908
 	/* Check certificate chains */
901
-	x509_validate_chain_ok ( &server_chain, test_time, &test_root );
902
-	x509_validate_chain_ok ( &server_chain, test_time, &intermediate_root );
903
-	x509_validate_chain_fail_ok ( &server_chain, test_time, &dummy_root );
909
+	x509_validate_chain_ok ( &server_chain, test_time,
910
+				 &empty_store, &test_root );
911
+	x509_validate_chain_ok ( &server_chain, test_time,
912
+				 &empty_store, &intermediate_root );
913
+	x509_validate_chain_fail_ok ( &server_chain, test_time,
914
+				      &empty_store, &dummy_root );
904 915
 	x509_validate_chain_fail_ok ( &broken_server_chain, test_time,
905
-				      &test_root );
916
+				      &empty_store, &test_root );
906 917
 	x509_validate_chain_fail_ok ( &incomplete_server_chain, test_time,
907
-				      &test_root );
918
+				      &empty_store, &test_root );
908 919
 	x509_validate_chain_ok ( &incomplete_server_chain, test_time,
909
-				 &intermediate_root );
910
-	x509_validate_chain_fail_ok ( &not_ca_chain, test_time, &test_root );
911
-	x509_validate_chain_ok ( &useless_chain, test_time, &test_root );
920
+				 &empty_store, &intermediate_root );
921
+	x509_validate_chain_fail_ok ( &not_ca_chain, test_time,
922
+				      &empty_store, &test_root );
923
+	x509_validate_chain_ok ( &useless_chain, test_time,
924
+				 &empty_store, &test_root );
912 925
 	x509_validate_chain_fail_ok ( &bad_path_len_chain, test_time,
913
-				      &test_root );
926
+				      &empty_store, &test_root );
914 927
 
915 928
 	/* Check certificate chain expiry times */
916
-	x509_validate_chain_fail_ok ( &server_chain, test_expired, &test_root );
917
-	x509_validate_chain_ok ( &useless_chain, test_expired, &test_root );
929
+	x509_validate_chain_fail_ok ( &server_chain, test_expired,
930
+				      &empty_store, &test_root );
931
+	x509_validate_chain_ok ( &useless_chain, test_expired,
932
+				 &empty_store, &test_root );
918 933
 	x509_validate_chain_fail_ok ( &useless_chain, test_ca_expired,
919
-				      &test_root );
934
+				      &empty_store, &test_root );
935
+
936
+	/* Sanity check */
937
+	assert ( list_empty ( &empty_store.links ) );
920 938
 
921 939
 	/* Drop chain references */
922 940
 	x509_chain_put ( bad_path_len_chain.chain );

+ 1
- 1
src/usr/imgtrust.c View File

@@ -84,7 +84,7 @@ int imgverify ( struct image *image, struct image *signature,
84 84
 	/* Use signature to verify image */
85 85
 	now = time ( NULL );
86 86
 	if ( ( rc = cms_verify ( sig, image->data, image->len,
87
-				 name, now, NULL ) ) != 0 )
87
+				 name, now, NULL, NULL ) ) != 0 )
88 88
 		goto err_verify;
89 89
 
90 90
 	/* Drop reference to signature */

Loading…
Cancel
Save