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
 NM		:= $(CROSS_COMPILE)nm
34
 NM		:= $(CROSS_COMPILE)nm
35
 OBJDUMP		:= $(CROSS_COMPILE)objdump
35
 OBJDUMP		:= $(CROSS_COMPILE)objdump
36
 OPENSSL		:= openssl
36
 OPENSSL		:= openssl
37
+CSPLIT		:= csplit
37
 PARSEROM	:= ./util/parserom.pl
38
 PARSEROM	:= ./util/parserom.pl
38
 FIXROM		:= ./util/fixrom.pl
39
 FIXROM		:= ./util/fixrom.pl
39
 SYMCHECK	:= ./util/symcheck.pl
40
 SYMCHECK	:= ./util/symcheck.pl

+ 36
- 16
src/Makefile.housekeeping View File

601
 
601
 
602
 CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
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
 CERT_LIST := $(BIN)/.certificate.list
606
 CERT_LIST := $(BIN)/.certificate.list
607
 ifeq ($(wildcard $(CERT_LIST)),)
607
 ifeq ($(wildcard $(CERT_LIST)),)
617
 
617
 
618
 VERYCLEANUP += $(CERT_LIST)
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
 	$(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
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
 endif
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
 ifdef KEY
658
 ifdef KEY
640
 PRIVKEY	:= $(KEY) # Maintain backwards compatibility
659
 PRIVKEY	:= $(KEY) # Maintain backwards compatibility
653
 
672
 
654
 VERYCLEANUP += $(PRIVKEY_LIST)
673
 VERYCLEANUP += $(PRIVKEY_LIST)
655
 
674
 
656
-# Embedded client private key
675
+# Embedded private key
657
 #
676
 #
658
 PRIVKEY_INC := $(BIN)/.private_key.der
677
 PRIVKEY_INC := $(BIN)/.private_key.der
659
 
678
 
661
 $(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST)
680
 $(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST)
662
 	$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
681
 	$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
663
 
682
 
664
-clientcert_DEPS += $(PRIVKEY_INC)
683
+privkey_DEPS += $(PRIVKEY_INC)
665
 endif
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
 # These files use .incbin inline assembly to include a binary file.
692
 # These files use .incbin inline assembly to include a binary file.
674
 # Unfortunately ccache does not detect this dependency and caches
693
 # Unfortunately ccache does not detect this dependency and caches
675
 # builds even when the binary file has changed.
694
 # builds even when the binary file has changed.
676
 #
695
 #
677
 $(BIN)/embedded.% : override CC := env CCACHE_DISABLE=1 $(CC)
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
 # Version number
700
 # Version number
681
 #
701
 #

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

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
-/*
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
  * @v data		Signed data
617
  * @v data		Signed data
618
  * @v len		Length of signed data
618
  * @v len		Length of signed data
619
  * @v time		Time at which to validate certificates
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
  * @ret rc		Return status code
622
  * @ret rc		Return status code
622
  */
623
  */
623
 static int cms_verify_signer_info ( struct cms_signature *sig,
624
 static int cms_verify_signer_info ( struct cms_signature *sig,
624
 				    struct cms_signer_info *info,
625
 				    struct cms_signer_info *info,
625
 				    userptr_t data, size_t len,
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
 	struct x509_certificate *cert;
629
 	struct x509_certificate *cert;
628
 	int rc;
630
 	int rc;
629
 
631
 
630
 	/* Validate certificate chain */
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
 		DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
635
 		DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
633
 		       sig, info, strerror ( rc ) );
636
 		       sig, info, strerror ( rc ) );
634
 		return rc;
637
 		return rc;
667
  * @v len		Length of signed data
670
  * @v len		Length of signed data
668
  * @v name		Required common name, or NULL to check all signatures
671
  * @v name		Required common name, or NULL to check all signatures
669
  * @v time		Time at which to validate certificates
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
  * @ret rc		Return status code
675
  * @ret rc		Return status code
672
  */
676
  */
673
 int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
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
 	struct cms_signer_info *info;
680
 	struct cms_signer_info *info;
676
 	struct x509_certificate *cert;
681
 	struct x509_certificate *cert;
677
 	int count = 0;
682
 	int count = 0;
682
 		cert = x509_first ( info->chain );
687
 		cert = x509_first ( info->chain );
683
 		if ( name && ( x509_check_name ( cert, name ) != 0 ) )
688
 		if ( name && ( x509_check_name ( cert, name ) != 0 ) )
684
 			continue;
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
 			return rc;
692
 			return rc;
688
 		count++;
693
 		count++;
689
 	}
694
 	}

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

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
 #include <errno.h>
24
 #include <errno.h>
25
 #include <assert.h>
25
 #include <assert.h>
26
 #include <ipxe/list.h>
26
 #include <ipxe/list.h>
27
-#include <ipxe/malloc.h>
28
 #include <ipxe/asn1.h>
27
 #include <ipxe/asn1.h>
29
 #include <ipxe/crypto.h>
28
 #include <ipxe/crypto.h>
30
 #include <ipxe/md5.h>
29
 #include <ipxe/md5.h>
32
 #include <ipxe/sha256.h>
31
 #include <ipxe/sha256.h>
33
 #include <ipxe/rsa.h>
32
 #include <ipxe/rsa.h>
34
 #include <ipxe/rootcert.h>
33
 #include <ipxe/rootcert.h>
34
+#include <ipxe/certstore.h>
35
 #include <ipxe/x509.h>
35
 #include <ipxe/x509.h>
36
 
36
 
37
 /** @file
37
 /** @file
107
 	__einfo_error ( EINFO_EACCES_WRONG_NAME )
107
 	__einfo_error ( EINFO_EACCES_WRONG_NAME )
108
 #define EINFO_EACCES_WRONG_NAME \
108
 #define EINFO_EACCES_WRONG_NAME \
109
 	__einfo_uniqify ( EINFO_EACCES, 0x0a, "Incorrect certificate name" )
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
  * Get X.509 certificate name (for debugging)
116
  * Get X.509 certificate name (for debugging)
130
 	return buf;
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
 /** "commonName" object identifier */
134
 /** "commonName" object identifier */
160
 static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME };
135
 static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME };
161
 
136
 
955
  * @v raw		ASN.1 cursor
930
  * @v raw		ASN.1 cursor
956
  * @ret rc		Return status code
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
 	struct x509_signature *signature = &cert->signature;
935
 	struct x509_signature *signature = &cert->signature;
961
 	struct asn1_algorithm **signature_algorithm = &signature->algorithm;
936
 	struct asn1_algorithm **signature_algorithm = &signature->algorithm;
962
 	struct asn1_bit_string *signature_value = &signature->value;
937
 	struct asn1_bit_string *signature_value = &signature->value;
1032
 	cursor.len = len;
1007
 	cursor.len = len;
1033
 	asn1_shrink_any ( &cursor );
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
 	/* Allocate and initialise certificate */
1018
 	/* Allocate and initialise certificate */
1055
 	if ( ! *cert )
1020
 	if ( ! *cert )
1056
 		return -ENOMEM;
1021
 		return -ENOMEM;
1057
 	ref_init ( &(*cert)->refcnt, NULL );
1022
 	ref_init ( &(*cert)->refcnt, NULL );
1058
-	INIT_LIST_HEAD ( &(*cert)->list );
1059
 	raw = ( *cert + 1 );
1023
 	raw = ( *cert + 1 );
1060
 
1024
 
1061
 	/* Copy raw data */
1025
 	/* Copy raw data */
1069
 		return rc;
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
 	return 0;
1039
 	return 0;
1077
 }
1040
 }
1221
  * Check X.509 root certificate
1184
  * Check X.509 root certificate
1222
  *
1185
  *
1223
  * @v cert		X.509 certificate
1186
  * @v cert		X.509 certificate
1224
- * @v root		X.509 root certificate store
1187
+ * @v root		X.509 root certificate list
1225
  * @ret rc		Return status code
1188
  * @ret rc		Return status code
1226
  */
1189
  */
1227
 int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ) {
1190
 int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ) {
1282
  * @v cert		X.509 certificate
1245
  * @v cert		X.509 certificate
1283
  * @v issuer		Issuing X.509 certificate (or NULL)
1246
  * @v issuer		Issuing X.509 certificate (or NULL)
1284
  * @v time		Time at which to validate certificate
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
  * @ret rc		Return status code
1249
  * @ret rc		Return status code
1287
  *
1250
  *
1288
  * The issuing certificate must have already been validated.
1251
  * The issuing certificate must have already been validated.
1533
 	cert = x509_last ( chain );
1496
 	cert = x509_last ( chain );
1534
 	if ( ! cert ) {
1497
 	if ( ! cert ) {
1535
 		DBGC ( chain, "X509 chain %p has no certificates\n", chain );
1498
 		DBGC ( chain, "X509 chain %p has no certificates\n", chain );
1536
-		return -EINVAL;
1499
+		return -EACCES_EMPTY;
1537
 	}
1500
 	}
1538
 
1501
 
1539
 	/* Append certificates, in order */
1502
 	/* Append certificates, in order */
1560
  *
1523
  *
1561
  * @v chain		X.509 certificate chain
1524
  * @v chain		X.509 certificate chain
1562
  * @v time		Time at which to validate certificates
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
  * @ret rc		Return status code
1528
  * @ret rc		Return status code
1565
  */
1529
  */
1566
 int x509_validate_chain ( struct x509_chain *chain, time_t time,
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
 	struct x509_certificate *issuer = NULL;
1532
 	struct x509_certificate *issuer = NULL;
1569
 	struct x509_link *link;
1533
 	struct x509_link *link;
1570
 	int rc;
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
 	/* Find first certificate that can be validated as a
1544
 	/* Find first certificate that can be validated as a
1576
 	 * standalone (i.e.  is already valid, or can be validated as
1545
 	 * standalone (i.e.  is already valid, or can be validated as
1600
 		return 0;
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

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
-#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
 extern int cms_signature ( const void *data, size_t len,
70
 extern int cms_signature ( const void *data, size_t len,
71
 			   struct cms_signature **sig );
71
 			   struct cms_signature **sig );
72
 extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
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
 #endif /* _IPXE_CMS_H */
76
 #endif /* _IPXE_CMS_H */

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

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
 	struct digest_algorithm *handshake_digest;
241
 	struct digest_algorithm *handshake_digest;
242
 	/** Digest algorithm context used for handshake verification */
242
 	/** Digest algorithm context used for handshake verification */
243
 	uint8_t *handshake_ctx;
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
 	/** Server certificate chain */
247
 	/** Server certificate chain */
248
 	struct x509_chain *chain;
248
 	struct x509_chain *chain;

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

156
 	struct x509_authority_info_access auth_info;
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
 /** An X.509 certificate */
175
 /** An X.509 certificate */
160
 struct x509_certificate {
176
 struct x509_certificate {
161
 	/** Reference count */
177
 	/** Reference count */
162
 	struct refcnt refcnt;
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
 	/** Certificate has been validated */
183
 	/** Certificate has been validated */
167
 	int valid;
184
 	int valid;
212
 	ref_put ( &cert->refcnt );
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
  * Get reference to X.509 certificate chain
233
  * Get reference to X.509 certificate chain
233
  *
234
  *
331
 };
332
 };
332
 
333
 
333
 extern const char * x509_name ( struct x509_certificate *cert );
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
 extern int x509_certificate ( const void *data, size_t len,
337
 extern int x509_certificate ( const void *data, size_t len,
336
 			      struct x509_certificate **cert );
338
 			      struct x509_certificate **cert );
337
 extern int x509_validate ( struct x509_certificate *cert,
339
 extern int x509_validate ( struct x509_certificate *cert,
347
 extern int x509_auto_append ( struct x509_chain *chain,
349
 extern int x509_auto_append ( struct x509_chain *chain,
348
 			      struct x509_chain *certs );
350
 			      struct x509_chain *certs );
349
 extern int x509_validate_chain ( struct x509_chain *chain, time_t time,
351
 extern int x509_validate_chain ( struct x509_chain *chain, time_t time,
352
+				 struct x509_chain *store,
350
 				 struct x509_root *root );
353
 				 struct x509_root *root );
351
 
354
 
352
 /* Functions exposed only for unit testing */
355
 /* Functions exposed only for unit testing */

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

43
 #include <ipxe/xfer.h>
43
 #include <ipxe/xfer.h>
44
 #include <ipxe/open.h>
44
 #include <ipxe/open.h>
45
 #include <ipxe/x509.h>
45
 #include <ipxe/x509.h>
46
-#include <ipxe/clientcert.h>
46
+#include <ipxe/privkey.h>
47
+#include <ipxe/certstore.h>
47
 #include <ipxe/rbg.h>
48
 #include <ipxe/rbg.h>
48
 #include <ipxe/validator.h>
49
 #include <ipxe/validator.h>
49
 #include <ipxe/tls.h>
50
 #include <ipxe/tls.h>
157
 #define EINFO_EPERM_VERIFY						\
158
 #define EINFO_EPERM_VERIFY						\
158
 	__einfo_uniqify ( EINFO_EPERM, 0x02,				\
159
 	__einfo_uniqify ( EINFO_EPERM, 0x02,				\
159
 			  "Handshake verification failed" )
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
 #define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION )
165
 #define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION )
161
 #define EINFO_EPROTO_VERSION						\
166
 #define EINFO_EPROTO_VERSION						\
162
 	__einfo_uniqify ( EINFO_EPROTO, 0x01,				\
167
 	__einfo_uniqify ( EINFO_EPROTO, 0x01,				\
307
 		list_del ( &iobuf->list );
312
 		list_del ( &iobuf->list );
308
 		free_iob ( iobuf );
313
 		free_iob ( iobuf );
309
 	}
314
 	}
315
+	x509_put ( tls->cert );
310
 	x509_chain_put ( tls->chain );
316
 	x509_chain_put ( tls->chain );
311
 
317
 
312
 	/* Free TLS structure itself */
318
 	/* Free TLS structure itself */
1030
  * @ret rc		Return status code
1036
  * @ret rc		Return status code
1031
  */
1037
  */
1032
 static int tls_send_certificate ( struct tls_session *tls ) {
1038
 static int tls_send_certificate ( struct tls_session *tls ) {
1033
-	int num_certificates = ( have_client_certificate() ? 1 : 0 );
1034
 	struct {
1039
 	struct {
1035
 		uint32_t type_length;
1040
 		uint32_t type_length;
1036
 		uint8_t length[3];
1041
 		uint8_t length[3];
1037
 		struct {
1042
 		struct {
1038
 			uint8_t length[3];
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
 	} __attribute__ (( packed )) *certificate;
1046
 	} __attribute__ (( packed )) *certificate;
1042
-	struct x509_certificate *cert;
1043
 	int rc;
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
 	/* Allocate storage for Certificate record (which may be too
1049
 	/* Allocate storage for Certificate record (which may be too
1069
 	 * large for the stack).
1050
 	 * large for the stack).
1070
 	 */
1051
 	 */
1079
 			  sizeof ( certificate->type_length ) ) );
1060
 			  sizeof ( certificate->type_length ) ) );
1080
 	tls_set_uint24 ( certificate->length,
1061
 	tls_set_uint24 ( certificate->length,
1081
 			 sizeof ( certificate->certificates ) );
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
 			 sizeof ( certificate->certificates[0].data ) );
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
 	/* Transmit record */
1069
 	/* Transmit record */
1091
 	rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) );
1070
 	rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) );
1148
  */
1127
  */
1149
 static int tls_send_certificate_verify ( struct tls_session *tls ) {
1128
 static int tls_send_certificate_verify ( struct tls_session *tls ) {
1150
 	struct digest_algorithm *digest = tls->handshake_digest;
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
 	uint8_t digest_out[ digest->digestsize ];
1132
 	uint8_t digest_out[ digest->digestsize ];
1153
 	uint8_t ctx[ pubkey->ctxsize ];
1133
 	uint8_t ctx[ pubkey->ctxsize ];
1154
 	struct tls_signature_hash_algorithm *sig_hash = NULL;
1134
 	struct tls_signature_hash_algorithm *sig_hash = NULL;
1158
 	tls_verify_handshake ( tls, digest_out );
1138
 	tls_verify_handshake ( tls, digest_out );
1159
 
1139
 
1160
 	/* Initialise public-key algorithm */
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
 		DBGC ( tls, "TLS %p could not initialise %s client private "
1143
 		DBGC ( tls, "TLS %p could not initialise %s client private "
1164
 		       "key: %s\n", tls, pubkey->name, strerror ( rc ) );
1144
 		       "key: %s\n", tls, pubkey->name, strerror ( rc ) );
1165
 		goto err_pubkey_init;
1145
 		goto err_pubkey_init;
1541
 	 * in parsing the Certificate Request.
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
 	return 0;
1538
 	return 0;
1549
 }
1539
 }
2469
 	tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
2459
 	tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
2470
 			     TLS_TX_CHANGE_CIPHER |
2460
 			     TLS_TX_CHANGE_CIPHER |
2471
 			     TLS_TX_FINISHED );
2461
 			     TLS_TX_FINISHED );
2462
+	if ( tls->cert ) {
2463
+		tls->tx_pending |= ( TLS_TX_CERTIFICATE |
2464
+				     TLS_TX_CERTIFICATE_VERIFY );
2465
+	}
2472
 	tls_tx_resume ( tls );
2466
 	tls_tx_resume ( tls );
2473
 
2467
 
2474
 	return;
2468
 	return;

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

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

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

1305
 		      0x96, 0xe7, 0xa8, 0x6d, 0x63, 0x2d, 0x32, 0x38,
1305
 		      0x96, 0xe7, 0xa8, 0x6d, 0x63, 0x2d, 0x32, 0x38,
1306
 		      0xaf, 0x00, 0xc4, 0x1a, 0xfc, 0xd8, 0xac, 0xc3 );
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
 static struct x509_root test_root = {
1315
 static struct x509_root test_root = {
1310
 	.digest = &cms_test_algorithm,
1316
 	.digest = &cms_test_algorithm,
1311
 	.count = 1,
1317
 	.count = 1,
1349
  * @v code		Test signed code
1355
  * @v code		Test signed code
1350
  * @v name		Test verification name
1356
  * @v name		Test verification name
1351
  * @v time		Test verification time
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
 	x509_invalidate_chain ( (sgn)->sig->certificates );		\
1362
 	x509_invalidate_chain ( (sgn)->sig->certificates );		\
1356
 	ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ),	\
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
 	} while ( 0 )
1365
 	} while ( 0 )
1359
 
1366
 
1360
 /**
1367
 /**
1364
  * @v code		Test signed code
1371
  * @v code		Test signed code
1365
  * @v name		Test verification name
1372
  * @v name		Test verification name
1366
  * @v time		Test verification time
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
 	x509_invalidate_chain ( (sgn)->sig->certificates );		\
1378
 	x509_invalidate_chain ( (sgn)->sig->certificates );		\
1371
 	ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ),	\
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
 	} while ( 0 )
1381
 	} while ( 0 )
1374
 
1382
 
1375
 /**
1383
 /**
1385
 	cms_signature_ok ( &nonsigned_sig );
1393
 	cms_signature_ok ( &nonsigned_sig );
1386
 
1394
 
1387
 	/* Check good signature */
1395
 	/* Check good signature */
1396
+	cms_verify_ok ( &codesigned_sig, &test_code, "codesign.test.ipxe.org",
1397
+			test_time, &empty_store, &test_root );
1388
 	cms_verify_ok ( &codesigned_sig, &test_code,
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
 	/* Check incorrect signer name */
1401
 	/* Check incorrect signer name */
1394
 	cms_verify_fail_ok ( &codesigned_sig, &test_code,
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
 	/* Check non-code-signing certificate */
1406
 	/* Check non-code-signing certificate */
1398
 	cms_verify_fail_ok ( &genericsigned_sig, &test_code,
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
 	/* Check non-signing certificate */
1410
 	/* Check non-signing certificate */
1402
 	cms_verify_fail_ok ( &nonsigned_sig, &test_code,
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
 	/* Check broken chain */
1414
 	/* Check broken chain */
1406
 	cms_verify_fail_ok ( &brokenchain_sig, &test_code,
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
 	/* Check untrusted signature */
1418
 	/* Check untrusted signature */
1410
 	cms_verify_fail_ok ( &codesigned_sig, &test_code,
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
 	/* Check incorrect signed content */
1422
 	/* Check incorrect signed content */
1414
 	cms_verify_fail_ok ( &codesigned_sig, &bad_code,
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
 	/* Check expired signature */
1426
 	/* Check expired signature */
1418
 	cms_verify_fail_ok ( &codesigned_sig, &test_code,
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
 	/* Drop signature references */
1433
 	/* Drop signature references */
1422
 	cms_put ( nonsigned_sig.sig );
1434
 	cms_put ( nonsigned_sig.sig );

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

654
 CHAIN ( bad_path_len_chain, &bad_path_len_crt, &useless_crt, &leaf_crt,
654
 CHAIN ( bad_path_len_chain, &bad_path_len_crt, &useless_crt, &leaf_crt,
655
 	&intermediate_crt, &root_crt );
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
 static struct x509_root test_root = {
664
 static struct x509_root test_root = {
659
 	.digest = &x509_test_algorithm,
665
 	.digest = &x509_test_algorithm,
660
 	.count = 1,
666
 	.count = 1,
661
 	.fingerprints = root_crt_fingerprint,
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
 static struct x509_root intermediate_root = {
671
 static struct x509_root intermediate_root = {
666
 	.digest = &x509_test_algorithm,
672
 	.digest = &x509_test_algorithm,
667
 	.count = 1,
673
 	.count = 1,
813
  *
819
  *
814
  * @v chn		Test certificate chain
820
  * @v chn		Test certificate chain
815
  * @v time		Test certificate validation time
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
 	x509_invalidate_chain ( (chn)->chain );				\
826
 	x509_invalidate_chain ( (chn)->chain );				\
820
 	ok ( x509_validate_chain ( (chn)->chain, (time),		\
827
 	ok ( x509_validate_chain ( (chn)->chain, (time),		\
821
-				   (root) ) == 0 );			\
828
+				   (store), (root) ) == 0 );		\
822
 	} while ( 0 )
829
 	} while ( 0 )
823
 
830
 
824
 /**
831
 /**
826
  *
833
  *
827
  * @v chn		Test certificate chain
834
  * @v chn		Test certificate chain
828
  * @v time		Test certificate validation time
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
 	x509_invalidate_chain ( (chn)->chain );				\
840
 	x509_invalidate_chain ( (chn)->chain );				\
833
 	ok ( x509_validate_chain ( (chn)->chain, (time),		\
841
 	ok ( x509_validate_chain ( (chn)->chain, (time),		\
834
-				   (root) ) != 0 );			\
842
+				   (store), (root) ) != 0 );		\
835
 	} while ( 0 )
843
 	} while ( 0 )
836
 
844
 
837
 /**
845
 /**
898
 	x509_chain_ok ( &bad_path_len_chain );
906
 	x509_chain_ok ( &bad_path_len_chain );
899
 
907
 
900
 	/* Check certificate chains */
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
 	x509_validate_chain_fail_ok ( &broken_server_chain, test_time,
915
 	x509_validate_chain_fail_ok ( &broken_server_chain, test_time,
905
-				      &test_root );
916
+				      &empty_store, &test_root );
906
 	x509_validate_chain_fail_ok ( &incomplete_server_chain, test_time,
917
 	x509_validate_chain_fail_ok ( &incomplete_server_chain, test_time,
907
-				      &test_root );
918
+				      &empty_store, &test_root );
908
 	x509_validate_chain_ok ( &incomplete_server_chain, test_time,
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
 	x509_validate_chain_fail_ok ( &bad_path_len_chain, test_time,
925
 	x509_validate_chain_fail_ok ( &bad_path_len_chain, test_time,
913
-				      &test_root );
926
+				      &empty_store, &test_root );
914
 
927
 
915
 	/* Check certificate chain expiry times */
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
 	x509_validate_chain_fail_ok ( &useless_chain, test_ca_expired,
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
 	/* Drop chain references */
939
 	/* Drop chain references */
922
 	x509_chain_put ( bad_path_len_chain.chain );
940
 	x509_chain_put ( bad_path_len_chain.chain );

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

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

Loading…
Cancel
Save