summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Rettberg2019-03-28 15:47:25 +0100
committerSimon Rettberg2019-03-28 15:47:25 +0100
commiteee6810fbe26652d4cacdf14a19c1c421eea953c (patch)
treeaad4a6b01220d33c804a28549efae1e39cf185ca /src
parent[efi] Add very ugly hack to use HW RNG on EFI (diff)
parent[intel] Add PCI ID for I219-V and -LM 6 to 9 (diff)
downloadipxe-eee6810fbe26652d4cacdf14a19c1c421eea953c.tar.gz
ipxe-eee6810fbe26652d4cacdf14a19c1c421eea953c.tar.xz
ipxe-eee6810fbe26652d4cacdf14a19c1c421eea953c.zip
Merge branch 'master' into openslx
Diffstat (limited to 'src')
-rw-r--r--src/crypto/ocsp.c42
-rw-r--r--src/drivers/net/intel.c8
-rw-r--r--src/include/ipxe/efi/efi_blacklist.h13
-rw-r--r--src/include/ipxe/errfile.h1
-rw-r--r--src/include/ipxe/ocsp.h4
-rw-r--r--src/include/ipxe/tls.h45
-rw-r--r--src/interface/efi/efi_blacklist.c237
-rw-r--r--src/interface/efi/efiprefix.c6
-rw-r--r--src/net/tcp.c21
-rw-r--r--src/net/tls.c318
-rw-r--r--src/net/validator.c175
11 files changed, 800 insertions, 70 deletions
diff --git a/src/crypto/ocsp.c b/src/crypto/ocsp.c
index b83f4c035..2c747fb39 100644
--- a/src/crypto/ocsp.c
+++ b/src/crypto/ocsp.c
@@ -145,7 +145,7 @@ static void ocsp_free ( struct refcnt *refcnt ) {
static int ocsp_request ( struct ocsp_check *ocsp ) {
struct digest_algorithm *digest = &ocsp_digest_algorithm;
struct asn1_builder *builder = &ocsp->request.builder;
- struct asn1_cursor *cert_id = &ocsp->request.cert_id;
+ struct asn1_cursor *cert_id_tail = &ocsp->request.cert_id_tail;
uint8_t digest_ctx[digest->ctxsize];
uint8_t name_digest[digest->digestsize];
uint8_t pubkey_digest[digest->digestsize];
@@ -186,12 +186,14 @@ static int ocsp_request ( struct ocsp_check *ocsp ) {
DBGC2_HDA ( ocsp, 0, builder->data, builder->len );
/* Parse certificate ID for comparison with response */
- cert_id->data = builder->data;
- cert_id->len = builder->len;
- if ( ( rc = ( asn1_enter ( cert_id, ASN1_SEQUENCE ),
- asn1_enter ( cert_id, ASN1_SEQUENCE ),
- asn1_enter ( cert_id, ASN1_SEQUENCE ),
- asn1_enter ( cert_id, ASN1_SEQUENCE ) ) ) != 0 ) {
+ cert_id_tail->data = builder->data;
+ cert_id_tail->len = builder->len;
+ if ( ( rc = ( asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+ asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+ asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+ asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+ asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+ asn1_skip ( cert_id_tail, ASN1_SEQUENCE ) ) ) != 0 ) {
DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n",
ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
return rc;
@@ -475,15 +477,31 @@ static int ocsp_parse_responder_id ( struct ocsp_check *ocsp,
static int ocsp_parse_cert_id ( struct ocsp_check *ocsp,
const struct asn1_cursor *raw ) {
struct asn1_cursor cursor;
+ struct asn1_algorithm *algorithm;
+ int rc;
- /* Check certID matches request */
+ /* Check certID algorithm */
memcpy ( &cursor, raw, sizeof ( cursor ) );
- asn1_shrink_any ( &cursor );
- if ( asn1_compare ( &cursor, &ocsp->request.cert_id ) != 0 ) {
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+ if ( ( rc = asn1_digest_algorithm ( &cursor, &algorithm ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" certID unknown algorithm: %s\n",
+ ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
+ return rc;
+ }
+ if ( algorithm->digest != &ocsp_digest_algorithm ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" certID wrong algorithm %s\n",
+ ocsp, x509_name ( ocsp->cert ),
+ algorithm->digest->name );
+ return -EACCES_CERT_MISMATCH;
+ }
+
+ /* Check remaining certID fields */
+ asn1_skip ( &cursor, ASN1_SEQUENCE );
+ if ( asn1_compare ( &cursor, &ocsp->request.cert_id_tail ) != 0 ) {
DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n",
ocsp, x509_name ( ocsp->cert ) );
- DBGC_HDA ( ocsp, 0, ocsp->request.cert_id.data,
- ocsp->request.cert_id.len );
+ DBGC_HDA ( ocsp, 0, ocsp->request.cert_id_tail.data,
+ ocsp->request.cert_id_tail.len );
DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
return -EACCES_CERT_MISMATCH;
}
diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c
index a2e6d535b..bb0b673b9 100644
--- a/src/drivers/net/intel.c
+++ b/src/drivers/net/intel.c
@@ -1146,9 +1146,17 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x15b7, "i219lm-2", "I219-LM (2)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15b8, "i219v-2", "I219-V (2)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15b9, "i219lm-3", "I219-LM (3)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15bb, "i219lm-7", "I219-LM (7)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15bc, "i219v-7", "I219-V (7)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15bd, "i219lm-6", "I219-LM (6)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15be, "i219v-6", "I219-V (6)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15d6, "i219v-5", "I219-V (5)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15d7, "i219lm-4", "I219-LM (4)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15d8, "i219v-4", "I219-V (4)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15df, "i219lm-8", "I219-LM (8)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15e0, "i219v-8", "I219-V (8)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15e1, "i219lm-9", "I219-LM (9)", INTEL_I219 ),
+ PCI_ROM ( 0x8086, 0x15e2, "i219v-9", "I219-V (9)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15e3, "i219lm-5", "I219-LM (5)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x1f41, "i354", "I354", INTEL_NO_ASDE ),
PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
diff --git a/src/include/ipxe/efi/efi_blacklist.h b/src/include/ipxe/efi/efi_blacklist.h
new file mode 100644
index 000000000..c5a5a61dc
--- /dev/null
+++ b/src/include/ipxe/efi/efi_blacklist.h
@@ -0,0 +1,13 @@
+#ifndef _IPXE_EFI_BLACKLIST_H
+#define _IPXE_EFI_BLACKLIST_H
+
+/** @file
+ *
+ * EFI driver blacklist
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+extern void efi_unload_blacklist ( void );
+
+#endif /* _IPXE_EFI_BLACKLIST_H */
diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h
index 596491a1f..ce67fc66d 100644
--- a/src/include/ipxe/errfile.h
+++ b/src/include/ipxe/errfile.h
@@ -375,6 +375,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_cert_cmd ( ERRFILE_OTHER | 0x004f0000 )
#define ERRFILE_acpi_settings ( ERRFILE_OTHER | 0x00500000 )
#define ERRFILE_ntlm ( ERRFILE_OTHER | 0x00510000 )
+#define ERRFILE_efi_blacklist ( ERRFILE_OTHER | 0x00520000 )
/** @} */
diff --git a/src/include/ipxe/ocsp.h b/src/include/ipxe/ocsp.h
index be0bddc50..9eb70b2cc 100644
--- a/src/include/ipxe/ocsp.h
+++ b/src/include/ipxe/ocsp.h
@@ -42,8 +42,8 @@ struct ocsp_check;
struct ocsp_request {
/** Request builder */
struct asn1_builder builder;
- /** Certificate ID */
- struct asn1_cursor cert_id;
+ /** Certificate ID (excluding hashAlgorithm) */
+ struct asn1_cursor cert_id_tail;
};
/** An OCSP responder */
diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h
index b1e702e18..febbdc589 100644
--- a/src/include/ipxe/tls.h
+++ b/src/include/ipxe/tls.h
@@ -63,6 +63,7 @@ struct tls_header {
#define TLS_HELLO_REQUEST 0
#define TLS_CLIENT_HELLO 1
#define TLS_SERVER_HELLO 2
+#define TLS_NEW_SESSION_TICKET 4
#define TLS_CERTIFICATE 11
#define TLS_SERVER_KEY_EXCHANGE 12
#define TLS_CERTIFICATE_REQUEST 13
@@ -108,6 +109,9 @@ struct tls_header {
/* TLS signature algorithms extension */
#define TLS_SIGNATURE_ALGORITHMS 13
+/* TLS session ticket extension */
+#define TLS_SESSION_TICKET 35
+
/* TLS renegotiation information extension */
#define TLS_RENEGOTIATION_INFO 0xff01
@@ -242,13 +246,48 @@ struct md5_sha1_digest {
/** MD5+SHA1 digest size */
#define MD5_SHA1_DIGEST_SIZE sizeof ( struct md5_sha1_digest )
-/** A TLS connection */
-struct tls_connection {
+/** A TLS session */
+struct tls_session {
/** Reference counter */
struct refcnt refcnt;
+ /** List of sessions */
+ struct list_head list;
/** Server name */
const char *name;
+ /** Session ID */
+ uint8_t id[32];
+ /** Length of session ID */
+ size_t id_len;
+ /** Session ticket */
+ void *ticket;
+ /** Length of session ticket */
+ size_t ticket_len;
+ /** Master secret */
+ uint8_t master_secret[48];
+
+ /** List of connections */
+ struct list_head conn;
+};
+
+/** A TLS connection */
+struct tls_connection {
+ /** Reference counter */
+ struct refcnt refcnt;
+
+ /** Session */
+ struct tls_session *session;
+ /** List of connections within the same session */
+ struct list_head list;
+ /** Session ID */
+ uint8_t session_id[32];
+ /** Length of session ID */
+ size_t session_id_len;
+ /** New session ticket */
+ void *new_session_ticket;
+ /** Length of new session ticket */
+ size_t new_session_ticket_len;
+
/** Plaintext stream */
struct interface plainstream;
/** Ciphertext stream */
@@ -296,6 +335,8 @@ struct tls_connection {
struct pending_operation client_negotiation;
/** Server security negotiation pending operation */
struct pending_operation server_negotiation;
+ /** Certificate validation pending operation */
+ struct pending_operation validation;
/** TX sequence number */
uint64_t tx_seq;
diff --git a/src/interface/efi/efi_blacklist.c b/src/interface/efi/efi_blacklist.c
new file mode 100644
index 000000000..292b28e8c
--- /dev/null
+++ b/src/interface/efi/efi_blacklist.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2019 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/settings.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/DriverBinding.h>
+#include <ipxe/efi/Protocol/LoadedImage.h>
+#include <ipxe/efi/Protocol/ComponentName.h>
+#include <ipxe/efi/efi_blacklist.h>
+
+/** @file
+ *
+ * EFI driver blacklist
+ *
+ */
+
+/** A blacklisted driver */
+struct efi_blacklist {
+ /** Name */
+ const char *name;
+ /**
+ * Check if driver is blacklisted
+ *
+ * @v binding Driver binding protocol
+ * @v loaded Loaded image protocol
+ * @v wtf Component name protocol, if present
+ * @ret blacklisted Driver is the blacklisted driver
+ */
+ int ( * blacklist ) ( EFI_DRIVER_BINDING_PROTOCOL *binding,
+ EFI_LOADED_IMAGE_PROTOCOL *loaded,
+ EFI_COMPONENT_NAME_PROTOCOL *wtf );
+};
+
+/**
+ * Blacklist Dell Ip4ConfigDxe driver
+ *
+ * @v binding Driver binding protocol
+ * @v loaded Loaded image protocol
+ * @v wtf Component name protocol, if present
+ * @ret blacklisted Driver is the blacklisted driver
+ */
+static int
+efi_blacklist_dell_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
+ EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
+ EFI_COMPONENT_NAME_PROTOCOL *wtf ) {
+ static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver";
+ static const char dell[] = "Dell Inc.";
+ char manufacturer[ sizeof ( dell ) ];
+ CHAR16 *name;
+
+ /* Check driver name */
+ if ( ! wtf )
+ return 0;
+ if ( wtf->GetDriverName ( wtf, "eng", &name ) != 0 )
+ return 0;
+ if ( memcmp ( name, ip4cfg, sizeof ( ip4cfg ) ) != 0 )
+ return 0;
+
+ /* Check manufacturer */
+ fetch_string_setting ( NULL, &manufacturer_setting, manufacturer,
+ sizeof ( manufacturer ) );
+ if ( strcmp ( manufacturer, dell ) != 0 )
+ return 0;
+
+ return 1;
+}
+
+/** Blacklisted drivers */
+static struct efi_blacklist efi_blacklists[] = {
+ {
+ .name = "Dell Ip4Config",
+ .blacklist = efi_blacklist_dell_ip4config,
+ },
+};
+
+/**
+ * Find driver blacklisting, if any
+ *
+ * @v driver Driver binding handle
+ * @ret blacklist Driver blacklisting, or NULL
+ * @ret rc Return status code
+ */
+static int efi_blacklist ( EFI_HANDLE driver,
+ struct efi_blacklist **blacklist ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ union {
+ EFI_DRIVER_BINDING_PROTOCOL *binding;
+ void *interface;
+ } binding;
+ union {
+ EFI_LOADED_IMAGE_PROTOCOL *loaded;
+ void *interface;
+ } loaded;
+ union {
+ EFI_COMPONENT_NAME_PROTOCOL *wtf;
+ void *interface;
+ } wtf;
+ unsigned int i;
+ EFI_HANDLE image;
+ EFI_STATUS efirc;
+ int rc;
+
+ DBGC2 ( &efi_blacklists, "EFIBL checking %s\n",
+ efi_handle_name ( driver ) );
+
+ /* Mark as not blacklisted */
+ *blacklist = NULL;
+
+ /* Open driver binding protocol */
+ if ( ( efirc = bs->OpenProtocol (
+ driver, &efi_driver_binding_protocol_guid,
+ &binding.interface, efi_image_handle, driver,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( driver, "EFIBL %s could not open driver binding "
+ "protocol: %s\n", efi_handle_name ( driver ),
+ strerror ( rc ) );
+ goto err_binding;
+ }
+ image = binding.binding->ImageHandle;
+
+ /* Open loaded image protocol */
+ if ( ( efirc = bs->OpenProtocol (
+ image, &efi_loaded_image_protocol_guid,
+ &loaded.interface, efi_image_handle, image,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( driver, "EFIBL %s could not open",
+ efi_handle_name ( driver ) );
+ DBGC ( driver, " %s loaded image protocol: %s\n",
+ efi_handle_name ( image ), strerror ( rc ) );
+ goto err_loaded;
+ }
+
+ /* Open component name protocol, if present*/
+ if ( ( efirc = bs->OpenProtocol (
+ driver, &efi_component_name_protocol_guid,
+ &wtf.interface, efi_image_handle, driver,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
+ /* Ignore failure; is not required to be present */
+ wtf.interface = NULL;
+ }
+
+ /* Check blacklistings */
+ for ( i = 0 ; i < ( sizeof ( efi_blacklists ) /
+ sizeof ( efi_blacklists[0] ) ) ; i++ ) {
+ if ( efi_blacklists[i].blacklist ( binding.binding,
+ loaded.loaded, wtf.wtf ) ) {
+ *blacklist = &efi_blacklists[i];
+ break;
+ }
+ }
+
+ /* Success */
+ rc = 0;
+
+ /* Close protocols */
+ if ( wtf.wtf ) {
+ bs->CloseProtocol ( driver, &efi_component_name_protocol_guid,
+ efi_image_handle, driver );
+ }
+ bs->CloseProtocol ( image, &efi_loaded_image_protocol_guid,
+ efi_image_handle, image );
+ err_loaded:
+ bs->CloseProtocol ( driver, &efi_driver_binding_protocol_guid,
+ efi_image_handle, driver );
+ err_binding:
+ return rc;
+}
+
+/**
+ * Unload any blacklisted drivers
+ *
+ */
+void efi_unload_blacklist ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_blacklist *blacklist;
+ EFI_HANDLE *drivers;
+ EFI_HANDLE driver;
+ UINTN num_drivers;
+ unsigned int i;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Locate all driver binding protocol handles */
+ if ( ( efirc = bs->LocateHandleBuffer (
+ ByProtocol, &efi_driver_binding_protocol_guid,
+ NULL, &num_drivers, &drivers ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &efi_blacklists, "EFIBL could not list all drivers: "
+ "%s\n", strerror ( rc ) );
+ return;
+ }
+
+ /* Unload any blacklisted drivers */
+ for ( i = 0 ; i < num_drivers ; i++ ) {
+ driver = drivers[i];
+ if ( ( rc = efi_blacklist ( driver, &blacklist ) ) != 0 ) {
+ DBGC ( driver, "EFIBL could not determine "
+ "blacklisting for %s: %s\n",
+ efi_handle_name ( driver ), strerror ( rc ) );
+ continue;
+ }
+ if ( ! blacklist )
+ continue;
+ DBGC ( driver, "EFIBL unloading %s (%s)\n",
+ efi_handle_name ( driver ), blacklist->name );
+ if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) {
+ DBGC ( driver, "EFIBL could not unload %s: %s\n",
+ efi_handle_name ( driver ), strerror ( rc ) );
+ }
+ }
+
+ /* Free handle list */
+ bs->FreePool ( drivers );
+}
diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c
index 18b931e68..de3572c75 100644
--- a/src/interface/efi/efiprefix.c
+++ b/src/interface/efi/efiprefix.c
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/efi/efi_snp.h>
#include <ipxe/efi/efi_autoboot.h>
#include <ipxe/efi/efi_watchdog.h>
+#include <ipxe/efi/efi_blacklist.h>
/**
* EFI entry point
@@ -75,6 +76,10 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
*/
static int efi_probe ( struct root_device *rootdev __unused ) {
+ /* Unloaded any blacklisted drivers */
+ efi_unload_blacklist();
+
+ /* Connect our drivers */
return efi_driver_connect_all();
}
@@ -85,6 +90,7 @@ static int efi_probe ( struct root_device *rootdev __unused ) {
*/
static void efi_remove ( struct root_device *rootdev __unused ) {
+ /* Disconnect our drivers */
efi_driver_disconnect_all();
}
diff --git a/src/net/tcp.c b/src/net/tcp.c
index c445100ad..6bba44282 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -17,6 +17,7 @@
#include <ipxe/netdevice.h>
#include <ipxe/profile.h>
#include <ipxe/process.h>
+#include <ipxe/job.h>
#include <ipxe/tcpip.h>
#include <ipxe/tcp.h>
@@ -1704,10 +1705,30 @@ static int tcp_xfer_deliver ( struct tcp_connection *tcp,
return 0;
}
+/**
+ * Report job progress
+ *
+ * @v tcp TCP connection
+ * @v progress Progress report to fill in
+ * @ret ongoing_rc Ongoing job status code (if known)
+ */
+static int tcp_progress ( struct tcp_connection *tcp,
+ struct job_progress *progress ) {
+
+ /* Report connection in progress if applicable */
+ if ( ! TCP_HAS_BEEN_ESTABLISHED ( tcp->tcp_state ) ) {
+ snprintf ( progress->message, sizeof ( progress->message ),
+ "connecting" );
+ }
+
+ return 0;
+}
+
/** TCP data transfer interface operations */
static struct interface_operation tcp_xfer_operations[] = {
INTF_OP ( xfer_deliver, struct tcp_connection *, tcp_xfer_deliver ),
INTF_OP ( xfer_window, struct tcp_connection *, tcp_xfer_window ),
+ INTF_OP ( job_progress, struct tcp_connection *, tcp_progress ),
INTF_OP ( intf_close, struct tcp_connection *, tcp_xfer_close ),
};
diff --git a/src/net/tls.c b/src/net/tls.c
index 9d994cd77..746274d61 100644
--- a/src/net/tls.c
+++ b/src/net/tls.c
@@ -47,6 +47,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/certstore.h>
#include <ipxe/rbg.h>
#include <ipxe/validator.h>
+#include <ipxe/job.h>
#include <ipxe/tls.h>
/* Disambiguate the various error causes */
@@ -102,9 +103,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINFO_EINVAL_MAC \
__einfo_uniqify ( EINFO_EINVAL, 0x0d, \
"Invalid MAC" )
+#define EINVAL_TICKET __einfo_error ( EINFO_EINVAL_TICKET )
+#define EINFO_EINVAL_TICKET \
+ __einfo_uniqify ( EINFO_EINVAL, 0x0e, \
+ "Invalid New Session Ticket record")
#define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
#define EINFO_EIO_ALERT \
- __einfo_uniqify ( EINFO_EINVAL, 0x01, \
+ __einfo_uniqify ( EINFO_EIO, 0x01, \
"Unknown alert level" )
#define ENOMEM_CONTEXT __einfo_error ( EINFO_ENOMEM_CONTEXT )
#define EINFO_ENOMEM_CONTEXT \
@@ -175,6 +180,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
__einfo_uniqify ( EINFO_EPROTO, 0x01, \
"Illegal protocol version upgrade" )
+/** List of TLS session */
+static LIST_HEAD ( tls_sessions );
+
+static void tls_tx_resume_all ( struct tls_session *session );
static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type,
const void *data, size_t len );
static void tls_clear_cipher ( struct tls_connection *tls,
@@ -308,6 +317,28 @@ struct rsa_digestinfo_prefix rsa_md5_sha1_prefix __rsa_digestinfo_prefix = {
*/
/**
+ * Free TLS session
+ *
+ * @v refcnt Reference counter
+ */
+static void free_tls_session ( struct refcnt *refcnt ) {
+ struct tls_session *session =
+ container_of ( refcnt, struct tls_session, refcnt );
+
+ /* Sanity check */
+ assert ( list_empty ( &session->conn ) );
+
+ /* Remove from list of sessions */
+ list_del ( &session->list );
+
+ /* Free session ticket */
+ free ( session->ticket );
+
+ /* Free session */
+ free ( session );
+}
+
+/**
* Free TLS connection
*
* @v refcnt Reference counter
@@ -315,10 +346,12 @@ struct rsa_digestinfo_prefix rsa_md5_sha1_prefix __rsa_digestinfo_prefix = {
static void free_tls ( struct refcnt *refcnt ) {
struct tls_connection *tls =
container_of ( refcnt, struct tls_connection, refcnt );
+ struct tls_session *session = tls->session;
struct io_buffer *iobuf;
struct io_buffer *tmp;
/* Free dynamically-allocated resources */
+ free ( tls->new_session_ticket );
tls_clear_cipher ( tls, &tls->tx_cipherspec );
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
tls_clear_cipher ( tls, &tls->rx_cipherspec );
@@ -330,8 +363,12 @@ static void free_tls ( struct refcnt *refcnt ) {
x509_put ( tls->cert );
x509_chain_put ( tls->chain );
+ /* Drop reference to session */
+ assert ( list_empty ( &tls->list ) );
+ ref_put ( &session->refcnt );
+
/* Free TLS structure itself */
- free ( tls );
+ free ( tls );
}
/**
@@ -345,6 +382,7 @@ static void tls_close ( struct tls_connection *tls, int rc ) {
/* Remove pending operations, if applicable */
pending_put ( &tls->client_negotiation );
pending_put ( &tls->server_negotiation );
+ pending_put ( &tls->validation );
/* Remove process */
process_del ( &tls->process );
@@ -353,6 +391,13 @@ static void tls_close ( struct tls_connection *tls, int rc ) {
intf_shutdown ( &tls->cipherstream, rc );
intf_shutdown ( &tls->plainstream, rc );
intf_shutdown ( &tls->validator, rc );
+
+ /* Remove from session */
+ list_del ( &tls->list );
+ INIT_LIST_HEAD ( &tls->list );
+
+ /* Resume all other connections, in case we were the lead connection */
+ tls_tx_resume_all ( tls->session );
}
/******************************************************************************
@@ -906,6 +951,7 @@ static void tls_restart ( struct tls_connection *tls ) {
assert ( ! tls->tx_pending );
assert ( ! is_pending ( &tls->client_negotiation ) );
assert ( ! is_pending ( &tls->server_negotiation ) );
+ assert ( ! is_pending ( &tls->validation ) );
/* (Re)initialise handshake context */
digest_init ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx );
@@ -929,6 +975,18 @@ static void tls_tx_resume ( struct tls_connection *tls ) {
}
/**
+ * Resume TX state machine for all connections within a session
+ *
+ * @v session TLS session
+ */
+static void tls_tx_resume_all ( struct tls_session *session ) {
+ struct tls_connection *tls;
+
+ list_for_each_entry ( tls, &session->conn, list )
+ tls_tx_resume ( tls );
+}
+
+/**
* Transmit Handshake record
*
* @v tls TLS connection
@@ -953,11 +1011,14 @@ static int tls_send_handshake ( struct tls_connection *tls,
* @ret rc Return status code
*/
static int tls_send_client_hello ( struct tls_connection *tls ) {
+ struct tls_session *session = tls->session;
+ size_t name_len = strlen ( session->name );
struct {
uint32_t type_length;
uint16_t version;
uint8_t random[32];
uint8_t session_id_len;
+ uint8_t session_id[tls->session_id_len];
uint16_t cipher_suite_len;
uint16_t cipher_suites[TLS_NUM_CIPHER_SUITES];
uint8_t compression_methods_len;
@@ -971,7 +1032,7 @@ static int tls_send_client_hello ( struct tls_connection *tls ) {
struct {
uint8_t type;
uint16_t len;
- uint8_t name[ strlen ( tls->name ) ];
+ uint8_t name[name_len];
} __attribute__ (( packed )) list[1];
} __attribute__ (( packed )) server_name;
uint16_t max_fragment_length_type;
@@ -993,18 +1054,27 @@ static int tls_send_client_hello ( struct tls_connection *tls ) {
uint8_t data[ tls->secure_renegotiation ?
sizeof ( tls->verify.client ) :0];
} __attribute__ (( packed )) renegotiation_info;
+ uint16_t session_ticket_type;
+ uint16_t session_ticket_len;
+ struct {
+ uint8_t data[session->ticket_len];
+ } __attribute__ (( packed )) session_ticket;
} __attribute__ (( packed )) extensions;
} __attribute__ (( packed )) hello;
struct tls_cipher_suite *suite;
struct tls_signature_hash_algorithm *sighash;
unsigned int i;
+ /* Construct record */
memset ( &hello, 0, sizeof ( hello ) );
hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) |
htonl ( sizeof ( hello ) -
sizeof ( hello.type_length ) ) );
hello.version = htons ( tls->version );
memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) );
+ hello.session_id_len = tls->session_id_len;
+ memcpy ( hello.session_id, tls->session_id,
+ sizeof ( hello.session_id ) );
hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) );
i = 0 ; for_each_table_entry ( suite, TLS_CIPHER_SUITES )
hello.cipher_suites[i++] = suite->code;
@@ -1018,7 +1088,7 @@ static int tls_send_client_hello ( struct tls_connection *tls ) {
hello.extensions.server_name.list[0].type = TLS_SERVER_NAME_HOST_NAME;
hello.extensions.server_name.list[0].len
= htons ( sizeof ( hello.extensions.server_name.list[0].name ));
- memcpy ( hello.extensions.server_name.list[0].name, tls->name,
+ memcpy ( hello.extensions.server_name.list[0].name, session->name,
sizeof ( hello.extensions.server_name.list[0].name ) );
hello.extensions.max_fragment_length_type
= htons ( TLS_MAX_FRAGMENT_LENGTH );
@@ -1042,6 +1112,11 @@ static int tls_send_client_hello ( struct tls_connection *tls ) {
= sizeof ( hello.extensions.renegotiation_info.data );
memcpy ( hello.extensions.renegotiation_info.data, tls->verify.client,
sizeof ( hello.extensions.renegotiation_info.data ) );
+ hello.extensions.session_ticket_type = htons ( TLS_SESSION_TICKET );
+ hello.extensions.session_ticket_len
+ = htons ( sizeof ( hello.extensions.session_ticket ) );
+ memcpy ( hello.extensions.session_ticket.data, session->ticket,
+ sizeof ( hello.extensions.session_ticket.data ) );
return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
}
@@ -1513,8 +1588,34 @@ static int tls_new_server_hello ( struct tls_connection *tls,
if ( ( rc = tls_select_cipher ( tls, hello_b->cipher_suite ) ) != 0 )
return rc;
- /* Generate secrets */
- tls_generate_master_secret ( tls );
+ /* Reuse or generate master secret */
+ if ( hello_a->session_id_len &&
+ ( hello_a->session_id_len == tls->session_id_len ) &&
+ ( memcmp ( session_id, tls->session_id,
+ tls->session_id_len ) == 0 ) ) {
+
+ /* Session ID match: reuse master secret */
+ DBGC ( tls, "TLS %p resuming session ID:\n", tls );
+ DBGC_HDA ( tls, 0, tls->session_id, tls->session_id_len );
+
+ } else {
+
+ /* Generate new master secret */
+ tls_generate_master_secret ( tls );
+
+ /* Record new session ID, if present */
+ if ( hello_a->session_id_len &&
+ ( hello_a->session_id_len <= sizeof ( tls->session_id ))){
+ tls->session_id_len = hello_a->session_id_len;
+ memcpy ( tls->session_id, session_id,
+ tls->session_id_len );
+ DBGC ( tls, "TLS %p new session ID:\n", tls );
+ DBGC_HDA ( tls, 0, tls->session_id,
+ tls->session_id_len );
+ }
+ }
+
+ /* Generate keys */
if ( ( rc = tls_generate_keys ( tls ) ) != 0 )
return rc;
@@ -1546,6 +1647,57 @@ static int tls_new_server_hello ( struct tls_connection *tls,
}
/**
+ * Receive New Session Ticket handshake record
+ *
+ * @v tls TLS connection
+ * @v data Plaintext handshake record
+ * @v len Length of plaintext handshake record
+ * @ret rc Return status code
+ */
+static int tls_new_session_ticket ( struct tls_connection *tls,
+ const void *data, size_t len ) {
+ const struct {
+ uint32_t lifetime;
+ uint16_t len;
+ uint8_t ticket[0];
+ } __attribute__ (( packed )) *new_session_ticket = data;
+ size_t ticket_len;
+
+ /* Parse header */
+ if ( sizeof ( *new_session_ticket ) > len ) {
+ DBGC ( tls, "TLS %p received underlength New Session Ticket\n",
+ tls );
+ DBGC_HD ( tls, data, len );
+ return -EINVAL_TICKET;
+ }
+ ticket_len = ntohs ( new_session_ticket->len );
+ if ( ticket_len > ( len - sizeof ( *new_session_ticket ) ) ) {
+ DBGC ( tls, "TLS %p received overlength New Session Ticket\n",
+ tls );
+ DBGC_HD ( tls, data, len );
+ return -EINVAL_TICKET;
+ }
+
+ /* Free any unapplied new session ticket */
+ free ( tls->new_session_ticket );
+ tls->new_session_ticket = NULL;
+ tls->new_session_ticket_len = 0;
+
+ /* Record ticket */
+ tls->new_session_ticket = malloc ( ticket_len );
+ if ( ! tls->new_session_ticket )
+ return -ENOMEM;
+ memcpy ( tls->new_session_ticket, new_session_ticket->ticket,
+ ticket_len );
+ tls->new_session_ticket_len = ticket_len;
+ DBGC ( tls, "TLS %p new session ticket:\n", tls );
+ DBGC_HDA ( tls, 0, tls->new_session_ticket,
+ tls->new_session_ticket_len );
+
+ return 0;
+}
+
+/**
* Parse certificate chain
*
* @v tls TLS connection
@@ -1725,6 +1877,7 @@ static int tls_new_server_hello_done ( struct tls_connection *tls,
"%s\n", tls, strerror ( rc ) );
return rc;
}
+ pending_get ( &tls->validation );
return 0;
}
@@ -1739,6 +1892,7 @@ static int tls_new_server_hello_done ( struct tls_connection *tls,
*/
static int tls_new_finished ( struct tls_connection *tls,
const void *data, size_t len ) {
+ struct tls_session *session = tls->session;
struct digest_algorithm *digest = tls->handshake_digest;
const struct {
uint8_t verify_data[ sizeof ( tls->verify.server ) ];
@@ -1767,6 +1921,39 @@ static int tls_new_finished ( struct tls_connection *tls,
/* Mark server as finished */
pending_put ( &tls->server_negotiation );
+ /* If we are resuming a session (i.e. if the server Finished
+ * arrives before the client Finished is sent), then schedule
+ * transmission of Change Cipher and Finished.
+ */
+ if ( is_pending ( &tls->client_negotiation ) ) {
+ tls->tx_pending |= ( TLS_TX_CHANGE_CIPHER | TLS_TX_FINISHED );
+ tls_tx_resume ( tls );
+ }
+
+ /* Record session ID, ticket, and master secret, if applicable */
+ if ( tls->session_id_len || tls->new_session_ticket_len ) {
+ memcpy ( session->master_secret, tls->master_secret,
+ sizeof ( session->master_secret ) );
+ }
+ if ( tls->session_id_len ) {
+ session->id_len = tls->session_id_len;
+ memcpy ( session->id, tls->session_id, sizeof ( session->id ) );
+ }
+ if ( tls->new_session_ticket_len ) {
+ free ( session->ticket );
+ session->ticket = tls->new_session_ticket;
+ session->ticket_len = tls->new_session_ticket_len;
+ tls->new_session_ticket = NULL;
+ tls->new_session_ticket_len = 0;
+ }
+
+ /* Move to end of session's connection list and allow other
+ * connections to start making progress.
+ */
+ list_del ( &tls->list );
+ list_add_tail ( &tls->list, &session->conn );
+ tls_tx_resume_all ( session );
+
/* Send notification of a window change */
xfer_window_changed ( &tls->plainstream );
@@ -1822,6 +2009,10 @@ static int tls_new_handshake ( struct tls_connection *tls,
case TLS_SERVER_HELLO:
rc = tls_new_server_hello ( tls, payload, payload_len );
break;
+ case TLS_NEW_SESSION_TICKET:
+ rc = tls_new_session_ticket ( tls, payload,
+ payload_len );
+ break;
case TLS_CERTIFICATE:
rc = tls_new_certificate ( tls, payload, payload_len );
break;
@@ -2383,12 +2574,31 @@ static int tls_plainstream_deliver ( struct tls_connection *tls,
return rc;
}
+/**
+ * Report job progress
+ *
+ * @v tls TLS connection
+ * @v progress Progress report to fill in
+ * @ret ongoing_rc Ongoing job status code (if known)
+ */
+static int tls_progress ( struct tls_connection *tls,
+ struct job_progress *progress ) {
+
+ /* Return cipherstream or validator progress as applicable */
+ if ( is_pending ( &tls->validation ) ) {
+ return job_progress ( &tls->validator, progress );
+ } else {
+ return job_progress ( &tls->cipherstream, progress );
+ }
+}
+
/** TLS plaintext stream interface operations */
static struct interface_operation tls_plainstream_ops[] = {
INTF_OP ( xfer_deliver, struct tls_connection *,
tls_plainstream_deliver ),
INTF_OP ( xfer_window, struct tls_connection *,
tls_plainstream_window ),
+ INTF_OP ( job_progress, struct tls_connection *, tls_progress ),
INTF_OP ( intf_close, struct tls_connection *, tls_close ),
};
@@ -2608,10 +2818,14 @@ static struct interface_descriptor tls_cipherstream_desc =
* @v rc Reason for completion
*/
static void tls_validator_done ( struct tls_connection *tls, int rc ) {
+ struct tls_session *session = tls->session;
struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
struct x509_certificate *cert;
+ /* Mark validation as complete */
+ pending_put ( &tls->validation );
+
/* Close validator interface */
intf_restart ( &tls->validator, rc );
@@ -2628,9 +2842,9 @@ static void tls_validator_done ( struct tls_connection *tls, int rc ) {
assert ( cert != NULL );
/* Verify server name */
- if ( ( rc = x509_check_name ( cert, tls->name ) ) != 0 ) {
+ if ( ( rc = x509_check_name ( cert, session->name ) ) != 0 ) {
DBGC ( tls, "TLS %p server certificate does not match %s: %s\n",
- tls, tls->name, strerror ( rc ) );
+ tls, session->name, strerror ( rc ) );
goto err;
}
@@ -2682,6 +2896,8 @@ static struct interface_descriptor tls_validator_desc =
* @v tls TLS connection
*/
static void tls_tx_step ( struct tls_connection *tls ) {
+ struct tls_session *session = tls->session;
+ struct tls_connection *conn;
int rc;
/* Wait for cipherstream to become ready */
@@ -2690,6 +2906,32 @@ static void tls_tx_step ( struct tls_connection *tls ) {
/* Send first pending transmission */
if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) {
+ /* Serialise server negotiations within a session, to
+ * provide a consistent view of session IDs and
+ * session tickets.
+ */
+ list_for_each_entry ( conn, &session->conn, list ) {
+ if ( conn == tls )
+ break;
+ if ( is_pending ( &conn->server_negotiation ) )
+ return;
+ }
+ /* Record or generate session ID and associated master secret */
+ if ( session->id_len ) {
+ /* Attempt to resume an existing session */
+ memcpy ( tls->session_id, session->id,
+ sizeof ( tls->session_id ) );
+ tls->session_id_len = session->id_len;
+ memcpy ( tls->master_secret, session->master_secret,
+ sizeof ( tls->master_secret ) );
+ } else {
+ /* No existing session: use a random session ID */
+ assert ( sizeof ( tls->session_id ) ==
+ sizeof ( tls->client_random ) );
+ memcpy ( tls->session_id, &tls->client_random,
+ sizeof ( tls->session_id ) );
+ tls->session_id_len = sizeof ( tls->session_id );
+ }
/* Send Client Hello */
if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
DBGC ( tls, "TLS %p could not send Client Hello: %s\n",
@@ -2768,6 +3010,60 @@ static struct process_descriptor tls_process_desc =
/******************************************************************************
*
+ * Session management
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Find or create session for TLS connection
+ *
+ * @v tls TLS connection
+ * @v name Server name
+ * @ret rc Return status code
+ */
+static int tls_session ( struct tls_connection *tls, const char *name ) {
+ struct tls_session *session;
+ char *name_copy;
+ int rc;
+
+ /* Find existing matching session, if any */
+ list_for_each_entry ( session, &tls_sessions, list ) {
+ if ( strcmp ( name, session->name ) == 0 ) {
+ ref_get ( &session->refcnt );
+ tls->session = session;
+ DBGC ( tls, "TLS %p joining session %s\n", tls, name );
+ return 0;
+ }
+ }
+
+ /* Create new session */
+ session = zalloc ( sizeof ( *session ) + strlen ( name )
+ + 1 /* NUL */ );
+ if ( ! session ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ ref_init ( &session->refcnt, free_tls_session );
+ name_copy = ( ( ( void * ) session ) + sizeof ( *session ) );
+ strcpy ( name_copy, name );
+ session->name = name_copy;
+ INIT_LIST_HEAD ( &session->conn );
+ list_add ( &session->list, &tls_sessions );
+
+ /* Record session */
+ tls->session = session;
+
+ DBGC ( tls, "TLS %p created session %s\n", tls, name );
+ return 0;
+
+ ref_put ( &session->refcnt );
+ err_alloc:
+ return rc;
+}
+
+/******************************************************************************
+ *
* Instantiator
*
******************************************************************************
@@ -2786,7 +3082,7 @@ int add_tls ( struct interface *xfer, const char *name,
}
memset ( tls, 0, sizeof ( *tls ) );
ref_init ( &tls->refcnt, free_tls );
- tls->name = name;
+ INIT_LIST_HEAD ( &tls->list );
intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt );
intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt );
intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt );
@@ -2809,6 +3105,9 @@ int add_tls ( struct interface *xfer, const char *name,
( sizeof ( tls->pre_master_secret.random ) ) ) ) != 0 ) {
goto err_random;
}
+ if ( ( rc = tls_session ( tls, name ) ) != 0 )
+ goto err_session;
+ list_add_tail ( &tls->list, &tls->session->conn );
/* Start negotiation */
tls_restart ( tls );
@@ -2819,6 +3118,7 @@ int add_tls ( struct interface *xfer, const char *name,
ref_put ( &tls->refcnt );
return 0;
+ err_session:
err_random:
ref_put ( &tls->refcnt );
err_alloc:
diff --git a/src/net/validator.c b/src/net/validator.c
index 40f778c7d..f6b03ff41 100644
--- a/src/net/validator.c
+++ b/src/net/validator.c
@@ -40,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/base64.h>
#include <ipxe/crc32.h>
#include <ipxe/ocsp.h>
+#include <ipxe/job.h>
#include <ipxe/validator.h>
#include <config/crypto.h>
@@ -49,6 +50,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
+struct validator;
+
+/** A certificate validator action */
+struct validator_action {
+ /** Name */
+ const char *name;
+ /** Action to take upon completed transfer */
+ int ( * done ) ( struct validator *validator, const void *data,
+ size_t len );
+};
+
/** A certificate validator */
struct validator {
/** Reference count */
@@ -67,12 +79,31 @@ struct validator {
struct ocsp_check *ocsp;
/** Data buffer */
struct xfer_buffer buffer;
- /** Action to take upon completed transfer */
- int ( * done ) ( struct validator *validator, const void *data,
- size_t len );
+
+ /** Current action */
+ const struct validator_action *action;
+ /** Current certificate
+ *
+ * This will always be present within the certificate chain
+ * and so this pointer does not hold a reference to the
+ * certificate.
+ */
+ struct x509_certificate *cert;
};
/**
+ * Get validator name (for debug messages)
+ *
+ * @v validator Certificate validator
+ * @ret name Validator name
+ */
+static const char * validator_name ( struct validator *validator ) {
+
+ /* Use name of first certificate in chain */
+ return x509_name ( x509_first ( validator->chain ) );
+}
+
+/**
* Free certificate validator
*
* @v refcnt Reference count
@@ -81,7 +112,8 @@ static void validator_free ( struct refcnt *refcnt ) {
struct validator *validator =
container_of ( refcnt, struct validator, refcnt );
- DBGC2 ( validator, "VALIDATOR %p freed\n", validator );
+ DBGC2 ( validator, "VALIDATOR %p \"%s\" freed\n",
+ validator, validator_name ( validator ) );
x509_chain_put ( validator->chain );
ocsp_put ( validator->ocsp );
xferbuf_free ( &validator->buffer );
@@ -110,8 +142,29 @@ static void validator_finished ( struct validator *validator, int rc ) {
*
*/
+/**
+ * Report job progress
+ *
+ * @v validator Certificate validator
+ * @v progress Progress report to fill in
+ * @ret ongoing_rc Ongoing job status code (if known)
+ */
+static int validator_progress ( struct validator *validator,
+ struct job_progress *progress ) {
+
+ /* Report current action, if applicable */
+ if ( validator->action ) {
+ snprintf ( progress->message, sizeof ( progress->message ),
+ "%s %s", validator->action->name,
+ x509_name ( validator->cert ) );
+ }
+
+ return 0;
+}
+
/** Certificate validator job control interface operations */
static struct interface_operation validator_job_operations[] = {
+ INTF_OP ( job_progress, struct validator *, validator_progress ),
INTF_OP ( intf_close, struct validator *, validator_finished ),
};
@@ -165,8 +218,9 @@ static int validator_append ( struct validator *validator,
/* Enter certificateSet */
if ( ( rc = asn1_enter ( &cursor, ASN1_SET ) ) != 0 ) {
- DBGC ( validator, "VALIDATOR %p could not enter "
- "certificateSet: %s\n", validator, strerror ( rc ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" could not enter "
+ "certificateSet: %s\n", validator,
+ validator_name ( validator ), strerror ( rc ) );
goto err_certificateset;
}
@@ -176,15 +230,16 @@ static int validator_append ( struct validator *validator,
/* Add certificate to chain */
if ( ( rc = x509_append_raw ( certs, cursor.data,
cursor.len ) ) != 0 ) {
- DBGC ( validator, "VALIDATOR %p could not append "
- "certificate: %s\n",
- validator, strerror ( rc) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" could not "
+ "append certificate: %s\n", validator,
+ validator_name ( validator ), strerror ( rc) );
DBGC_HDA ( validator, 0, cursor.data, cursor.len );
return rc;
}
cert = x509_last ( certs );
- DBGC ( validator, "VALIDATOR %p found certificate %s\n",
- validator, x509_name ( cert ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" found certificate ",
+ validator, validator_name ( validator ) );
+ DBGC ( validator, "%s\n", x509_name ( cert ) );
/* Move to next certificate */
asn1_skip_any ( &cursor );
@@ -193,15 +248,17 @@ static int validator_append ( struct validator *validator,
/* Append certificates to chain */
last = x509_last ( validator->chain );
if ( ( rc = x509_auto_append ( validator->chain, certs ) ) != 0 ) {
- DBGC ( validator, "VALIDATOR %p could not append "
- "certificates: %s\n", validator, strerror ( rc ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" could not append "
+ "certificates: %s\n", validator,
+ validator_name ( validator ), strerror ( rc ) );
goto err_auto_append;
}
/* Check that at least one certificate has been added */
if ( last == x509_last ( validator->chain ) ) {
- DBGC ( validator, "VALIDATOR %p failed to append any "
- "applicable certificates\n", validator );
+ DBGC ( validator, "VALIDATOR %p \"%s\" failed to append any "
+ "applicable certificates\n", validator,
+ validator_name ( validator ) );
rc = -EACCES;
goto err_no_progress;
}
@@ -219,15 +276,22 @@ static int validator_append ( struct validator *validator,
return rc;
}
+/** Cross-signing certificate download validator action */
+static const struct validator_action validator_crosscert = {
+ .name = "XCRT",
+ .done = validator_append,
+};
+
/**
* Start download of cross-signing certificate
*
* @v validator Certificate validator
- * @v issuer Required issuer
+ * @v cert X.509 certificate
* @ret rc Return status code
*/
static int validator_start_download ( struct validator *validator,
- const struct asn1_cursor *issuer ) {
+ struct x509_certificate *cert ) {
+ const struct asn1_cursor *issuer = &cert->issuer.raw;
const char *crosscert;
char *crosscert_copy;
char *uri_string;
@@ -261,17 +325,21 @@ static int validator_start_download ( struct validator *validator,
crosscert, crc );
base64_encode ( issuer->data, issuer->len, ( uri_string + len ),
( uri_string_len - len ) );
- DBGC ( validator, "VALIDATOR %p downloading cross-signed certificate "
- "from %s\n", validator, uri_string );
+ DBGC ( validator, "VALIDATOR %p \"%s\" downloading ",
+ validator, validator_name ( validator ) );
+ DBGC ( validator, "\"%s\" cross-signature from %s\n",
+ x509_name ( cert ), uri_string );
/* Set completion handler */
- validator->done = validator_append;
+ validator->action = &validator_crosscert;
+ validator->cert = cert;
/* Open URI */
if ( ( rc = xfer_open_uri_string ( &validator->xfer,
uri_string ) ) != 0 ) {
- DBGC ( validator, "VALIDATOR %p could not open %s: %s\n",
- validator, uri_string, strerror ( rc ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" could not open %s: "
+ "%s\n", validator, validator_name ( validator ),
+ uri_string, strerror ( rc ) );
goto err_open_uri_string;
}
@@ -307,16 +375,18 @@ static int validator_ocsp_validate ( struct validator *validator,
/* Record OCSP response */
if ( ( rc = ocsp_response ( validator->ocsp, data, len ) ) != 0 ) {
- DBGC ( validator, "VALIDATOR %p could not record OCSP "
- "response: %s\n", validator, strerror ( rc ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" could not record OCSP "
+ "response: %s\n", validator,
+ validator_name ( validator ),strerror ( rc ) );
return rc;
}
/* Validate OCSP response */
now = time ( NULL );
if ( ( rc = ocsp_validate ( validator->ocsp, now ) ) != 0 ) {
- DBGC ( validator, "VALIDATOR %p could not validate OCSP "
- "response: %s\n", validator, strerror ( rc ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" could not validate "
+ "OCSP response: %s\n", validator,
+ validator_name ( validator ), strerror ( rc ) );
return rc;
}
@@ -327,6 +397,12 @@ static int validator_ocsp_validate ( struct validator *validator,
return 0;
}
+/** OCSP validator action */
+static const struct validator_action validator_ocsp = {
+ .name = "OCSP",
+ .done = validator_ocsp_validate,
+};
+
/**
* Start OCSP check
*
@@ -344,22 +420,27 @@ static int validator_start_ocsp ( struct validator *validator,
/* Create OCSP check */
assert ( validator->ocsp == NULL );
if ( ( rc = ocsp_check ( cert, issuer, &validator->ocsp ) ) != 0 ) {
- DBGC ( validator, "VALIDATOR %p could not create OCSP check: "
- "%s\n", validator, strerror ( rc ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" could not create OCSP "
+ "check: %s\n", validator, validator_name ( validator ),
+ strerror ( rc ) );
return rc;
}
/* Set completion handler */
- validator->done = validator_ocsp_validate;
+ validator->action = &validator_ocsp;
+ validator->cert = cert;
/* Open URI */
uri_string = validator->ocsp->uri_string;
- DBGC ( validator, "VALIDATOR %p performing OCSP check at %s\n",
- validator, uri_string );
+ DBGC ( validator, "VALIDATOR %p \"%s\" checking ",
+ validator, validator_name ( validator ) );
+ DBGC ( validator, "\"%s\" via %s\n",
+ x509_name ( cert ), uri_string );
if ( ( rc = xfer_open_uri_string ( &validator->xfer,
uri_string ) ) != 0 ) {
- DBGC ( validator, "VALIDATOR %p could not open %s: %s\n",
- validator, uri_string, strerror ( rc ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" could not open %s: "
+ "%s\n", validator, validator_name ( validator ),
+ uri_string, strerror ( rc ) );
return rc;
}
@@ -385,16 +466,18 @@ static void validator_xfer_close ( struct validator *validator, int rc ) {
/* Check for errors */
if ( rc != 0 ) {
- DBGC ( validator, "VALIDATOR %p transfer failed: %s\n",
- validator, strerror ( rc ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" transfer failed: %s\n",
+ validator, validator_name ( validator ),
+ strerror ( rc ) );
goto err_transfer;
}
- DBGC2 ( validator, "VALIDATOR %p transfer complete\n", validator );
+ DBGC2 ( validator, "VALIDATOR %p \"%s\" transfer complete\n",
+ validator, validator_name ( validator ) );
/* Process completed download */
- assert ( validator->done != NULL );
- if ( ( rc = validator->done ( validator, validator->buffer.data,
- validator->buffer.len ) ) != 0 )
+ assert ( validator->action != NULL );
+ if ( ( rc = validator->action->done ( validator, validator->buffer.data,
+ validator->buffer.len ) ) != 0 )
goto err_append;
/* Free downloaded data */
@@ -426,8 +509,9 @@ static int validator_xfer_deliver ( struct validator *validator,
/* Add data to buffer */
if ( ( rc = xferbuf_deliver ( &validator->buffer, iob_disown ( iobuf ),
meta ) ) != 0 ) {
- DBGC ( validator, "VALIDATOR %p could not receive data: %s\n",
- validator, strerror ( rc ) );
+ DBGC ( validator, "VALIDATOR %p \"%s\" could not receive "
+ "data: %s\n", validator, validator_name ( validator ),
+ strerror ( rc ) );
validator_finished ( validator, rc );
return rc;
}
@@ -471,6 +555,8 @@ static void validator_step ( struct validator *validator ) {
now = time ( NULL );
if ( ( rc = x509_validate_chain ( validator->chain, now, NULL,
NULL ) ) == 0 ) {
+ DBGC ( validator, "VALIDATOR %p \"%s\" validated\n",
+ validator, validator_name ( validator ) );
validator_finished ( validator, 0 );
return;
}
@@ -514,8 +600,7 @@ static void validator_step ( struct validator *validator ) {
/* Otherwise, try to download a suitable cross-signing
* certificate.
*/
- if ( ( rc = validator_start_download ( validator,
- &last->issuer.raw ) ) != 0 ) {
+ if ( ( rc = validator_start_download ( validator, last ) ) != 0 ) {
validator_finished ( validator, rc );
return;
}
@@ -567,8 +652,8 @@ int create_validator ( struct interface *job, struct x509_chain *chain ) {
/* Attach parent interface, mortalise self, and return */
intf_plug_plug ( &validator->job, job );
ref_put ( &validator->refcnt );
- DBGC2 ( validator, "VALIDATOR %p validating X509 chain %p\n",
- validator, validator->chain );
+ DBGC2 ( validator, "VALIDATOR %p \"%s\" validating X509 chain %p\n",
+ validator, validator_name ( validator ), validator->chain );
return 0;
validator_finished ( validator, rc );