From 688646fe6d034e98fe7cbcc9403a2d0f70434f40 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 7 Nov 2022 18:09:09 +0000 Subject: [tls] Add GCM cipher suites Signed-off-by: Michael Brown --- src/config/config_crypto.c | 12 ++++++++++++ src/config/crypto.h | 3 +++ 2 files changed, 15 insertions(+) (limited to 'src/config') diff --git a/src/config/config_crypto.c b/src/config/config_crypto.c index 440bf4ce1..fa1996a55 100644 --- a/src/config/config_crypto.c +++ b/src/config/config_crypto.c @@ -124,3 +124,15 @@ REQUIRE_OBJECT ( rsa_aes_cbc_sha1 ); defined ( CRYPTO_DIGEST_SHA256 ) REQUIRE_OBJECT ( rsa_aes_cbc_sha256 ); #endif + +/* RSA, AES-GCM, and SHA-256 */ +#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \ + defined ( CRYPTO_DIGEST_SHA256 ) +REQUIRE_OBJECT ( rsa_aes_gcm_sha256 ); +#endif + +/* RSA, AES-GCM, and SHA-384 */ +#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \ + defined ( CRYPTO_DIGEST_SHA384 ) +REQUIRE_OBJECT ( rsa_aes_gcm_sha384 ); +#endif diff --git a/src/config/crypto.h b/src/config/crypto.h index 7c0251758..76bf14d41 100644 --- a/src/config/crypto.h +++ b/src/config/crypto.h @@ -18,6 +18,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** AES-CBC block cipher */ #define CRYPTO_CIPHER_AES_CBC +/** AES-GCM block cipher */ +#define CRYPTO_CIPHER_AES_GCM + /** MD4 digest algorithm */ //#define CRYPTO_DIGEST_MD4 -- cgit v1.2.3-55-g7522 From dc16de3204d1956d4fd17808e6d34ac926bbe932 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 5 Feb 2023 13:07:30 +0000 Subject: [lldp] Add support for the Link Layer Discovery Protocol Add support for recording LLDP packets and exposing TLV values via the settings mechanism. LLDP settings are encoded as ${netX.lldp/....} where is the TLV type is the starting offset within the TLV value is the length (or zero to read the from to the end) , if it has a non-zero value, is the subtype byte string of length to match at the start of the TLV value, up to a maximum matched length of 4 bytes is the index of the entry matching and to be accessed, with zero indicating the first matching entry The is designed to accommodate both matching of the OUI within an organization-specific TLV (e.g. 0x0080c2 for IEEE 802.1 TLVs) and of a subtype byte as found within many TLVs. This encoding allows most LLDP values to be extracted easily. For example System name: ${netX.lldp/5.0.0.0:string} System description: ${netX.lldp/6.0.0.0:string} Port description: ${netX.lldp/4.0.0.0:string} Port interface name: ${netX.lldp/5.2.0.1.0:string} Chassis MAC address: ${netX.lldp/4.1.0.1.0:hex} Management IPv4 address: ${netX.lldp/5.1.8.0.2.4:ipv4} Port VLAN ID: ${netX.lldp/0x0080c2.1.127.0.4.2:int16} Port VLAN name: ${netX.lldp/0x0080c2.3.127.0.7.0:string} Maximum frame size: ${netX.lldp/0x00120f.4.127.0.4.2:uint16} Originally-implemented-by: Marin Hannache Signed-off-by: Michael Brown --- src/config/config_ethernet.c | 3 + src/config/general.h | 1 + src/include/ipxe/errfile.h | 1 + src/include/ipxe/if_ether.h | 1 + src/include/ipxe/lldp.h | 97 ++++++++++++ src/net/lldp.c | 340 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 443 insertions(+) create mode 100644 src/include/ipxe/lldp.h create mode 100644 src/net/lldp.c (limited to 'src/config') diff --git a/src/config/config_ethernet.c b/src/config/config_ethernet.c index 8a663c923..c1b35bfe6 100644 --- a/src/config/config_ethernet.c +++ b/src/config/config_ethernet.c @@ -49,3 +49,6 @@ REQUIRE_OBJECT ( eth_slow ); #ifdef NET_PROTO_EAPOL REQUIRE_OBJECT ( eapol ); #endif +#ifdef NET_PROTO_LLDP +REQUIRE_OBJECT ( lldp ); +#endif diff --git a/src/config/general.h b/src/config/general.h index 2d15f500a..e9ceaff57 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -40,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define NET_PROTO_STP /* Spanning Tree protocol */ #define NET_PROTO_LACP /* Link Aggregation control protocol */ #define NET_PROTO_EAPOL /* EAP over LAN protocol */ +#undef NET_PROTO_LLDP /* Link Layer Discovery protocol */ /* * PXE support diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 7c3b0c43b..d7b6ea1bd 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -295,6 +295,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_ntp ( ERRFILE_NET | 0x00490000 ) #define ERRFILE_httpntlm ( ERRFILE_NET | 0x004a0000 ) #define ERRFILE_eap ( ERRFILE_NET | 0x004b0000 ) +#define ERRFILE_lldp ( ERRFILE_NET | 0x004c0000 ) #define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/include/ipxe/if_ether.h b/src/include/ipxe/if_ether.h index 58d91b976..c1168b10e 100644 --- a/src/include/ipxe/if_ether.h +++ b/src/include/ipxe/if_ether.h @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ETH_P_SLOW 0x8809 /* Ethernet slow protocols */ #define ETH_P_EAPOL 0x888E /* 802.1X EAP over LANs */ #define ETH_P_AOE 0x88A2 /* ATA over Ethernet */ +#define ETH_P_LLDP 0x88CC /* Link Layer Discovery Protocol */ #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ diff --git a/src/include/ipxe/lldp.h b/src/include/ipxe/lldp.h new file mode 100644 index 000000000..9951d3b8f --- /dev/null +++ b/src/include/ipxe/lldp.h @@ -0,0 +1,97 @@ +#ifndef _IPXE_LLDP_H +#define _IPXE_LLDP_H + +/** @file + * + * Link Layer Discovery Protocol + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** An LLDP TLV header */ +struct lldp_tlv { + /** Type and length */ + uint16_t type_len; + /** Data */ + uint8_t data[0]; +} __attribute__ (( packed )); + +/** + * Extract LLDP TLV type + * + * @v type_len Type and length + * @ret type Type + */ +#define LLDP_TLV_TYPE( type_len ) ( (type_len) >> 9 ) + +/** + * Extract LLDP TLV length + * + * @v type_len Type and length + * @ret len Length + */ +#define LLDP_TLV_LEN( type_len ) ( (type_len) & 0x01ff ) + +/** End of LLDP data unit */ +#define LLDP_TYPE_END 0x00 + +/** LLDP settings block name */ +#define LLDP_SETTINGS_NAME "lldp" + +/** + * Construct LLDP setting tag + * + * LLDP settings are encoded as + * + * ${netX.lldp/....} + * + * where + * + * is the TLV type + * + * is the starting offset within the TLV value + * + * is the length (or zero to read the from to the end) + * + * , if it has a non-zero value, is the subtype byte string + * of length to match at the start of the TLV value, up to + * a maximum matched length of 4 bytes + * + * is the index of the entry matching and to + * be accessed, with zero indicating the first matching entry + * + * The is designed to accommodate both matching of the OUI + * within an organization-specific TLV (e.g. 0x0080c2 for IEEE 802.1 + * TLVs) and of a subtype byte as found within many TLVs. + * + * This encoding allows most LLDP values to be extracted easily. For + * example + * + * System name: ${netX.lldp/5.0.0.0:string} + * + * System description: ${netX.lldp/6.0.0.0:string} + * + * Port description: ${netX.lldp/4.0.0.0:string} + * + * Port interface name: ${netX.lldp/5.2.0.1.0:string} + * + * Chassis MAC address: ${netX.lldp/4.1.0.1.0:hex} + * + * Management IPv4 address: ${netX.lldp/5.1.8.0.2.4:ipv4} + * + * Port VLAN ID: ${netX.lldp/0x0080c2.1.127.0.4.2:int16} + * + * Port VLAN name: ${netX.lldp/0x0080c2.3.127.0.7.0:string} + * + * Maximum frame size: ${netX.lldp/0x00120f.4.127.0.4.2:uint16} + * + */ +#define LLDP_TAG( prefix, type, index, offset, length ) \ + ( ( ( ( uint64_t ) (prefix) ) << 32 ) | \ + ( (type) << 24 ) | ( (index) << 16 ) | \ + ( (offset) << 8 ) | ( (length) << 0 ) ) + +#endif /* _IPXE_LLDP_H */ diff --git a/src/net/lldp.c b/src/net/lldp.c new file mode 100644 index 000000000..72e3ecdf6 --- /dev/null +++ b/src/net/lldp.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2023 Michael Brown . + * + * 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. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * Link Layer Discovery Protocol + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** An LLDP settings block */ +struct lldp_settings { + /** Reference counter */ + struct refcnt refcnt; + /** Settings interface */ + struct settings settings; + /** List of LLDP settings blocks */ + struct list_head list; + /** Name */ + const char *name; + /** LLDP data */ + void *data; + /** Length of LLDP data */ + size_t len; +}; + +/** LLDP settings scope */ +static const struct settings_scope lldp_settings_scope; + +/** List of LLDP settings blocks */ +static LIST_HEAD ( lldp_settings ); + +/** + * Free LLDP settings block + * + * @v refcnt Reference counter + */ +static void lldp_free ( struct refcnt *refcnt ) { + struct lldp_settings *lldpset = + container_of ( refcnt, struct lldp_settings, refcnt ); + + DBGC ( lldpset, "LLDP %s freed\n", lldpset->name ); + list_del ( &lldpset->list ); + free ( lldpset->data ); + free ( lldpset ); +} + +/** + * Find LLDP settings block + * + * @v netdev Network device + * @ret lldpset LLDP settings block + */ +static struct lldp_settings * lldp_find ( struct net_device *netdev ) { + struct lldp_settings *lldpset; + + /* Find matching LLDP settings block */ + list_for_each_entry ( lldpset, &lldp_settings, list ) { + if ( netdev_settings ( netdev ) == lldpset->settings.parent ) + return lldpset; + } + + return NULL; +} + +/** + * Check applicability of LLDP setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @ret applies Setting applies within this settings block + */ +static int lldp_applies ( struct settings *settings __unused, + const struct setting *setting ) { + + return ( setting->scope == &lldp_settings_scope ); +} + +/** + * Fetch value of LLDP setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v buf Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int lldp_fetch ( struct settings *settings, + struct setting *setting, + void *buf, size_t len ) { + struct lldp_settings *lldpset = + container_of ( settings, struct lldp_settings, settings ); + union { + uint32_t high; + uint8_t raw[4]; + } tag_prefix; + uint32_t tag_low; + uint8_t tag_type; + uint8_t tag_index; + uint8_t tag_offset; + uint8_t tag_length; + const void *match; + const void *data; + size_t match_len; + size_t remaining; + const struct lldp_tlv *tlv; + unsigned int tlv_type_len; + unsigned int tlv_type; + unsigned int tlv_len; + + /* Parse setting tag */ + tag_prefix.high = htonl ( setting->tag >> 32 ); + tag_low = setting->tag; + tag_type = ( tag_low >> 24 ); + tag_index = ( tag_low >> 16 ); + tag_offset = ( tag_low >> 8 ); + tag_length = ( tag_low >> 0 ); + + /* Identify match prefix */ + match_len = tag_offset; + if ( match_len > sizeof ( tag_prefix ) ) + match_len = sizeof ( tag_prefix ); + if ( ! tag_prefix.high ) + match_len = 0; + match = &tag_prefix.raw[ sizeof ( tag_prefix ) - match_len ]; + + /* Locate matching TLV */ + for ( data = lldpset->data, remaining = lldpset->len ; remaining ; + data += tlv_len, remaining -= tlv_len ) { + + /* Parse TLV header */ + if ( remaining < sizeof ( *tlv ) ) { + DBGC ( lldpset, "LLDP %s underlength TLV header\n", + lldpset->name ); + DBGC_HDA ( lldpset, 0, data, remaining ); + break; + } + tlv = data; + data += sizeof ( *tlv ); + remaining -= sizeof ( *tlv ); + tlv_type_len = ntohs ( tlv->type_len ); + tlv_type = LLDP_TLV_TYPE ( tlv_type_len ); + if ( tlv_type == LLDP_TYPE_END ) + break; + tlv_len = LLDP_TLV_LEN ( tlv_type_len ); + if ( remaining < tlv_len ) { + DBGC ( lldpset, "LLDP %s underlength TLV value\n", + lldpset->name ); + DBGC_HDA ( lldpset, 0, data, remaining ); + break; + } + DBGC2 ( lldpset, "LLDP %s found type %d:\n", + lldpset->name, tlv_type ); + DBGC2_HDA ( lldpset, 0, data, tlv_len ); + + /* Check for matching tag type */ + if ( tlv_type != tag_type ) + continue; + + /* Check for matching prefix */ + if ( tlv_len < match_len ) + continue; + if ( memcmp ( data, match, match_len ) != 0 ) + continue; + + /* Check for matching index */ + if ( tag_index-- ) + continue; + + /* Skip offset */ + if ( tlv_len < tag_offset ) + return 0; + data += tag_offset; + tlv_len -= tag_offset; + + /* Set type if not already specified */ + if ( ! setting->type ) { + setting->type = ( tag_length ? &setting_type_hex : + &setting_type_string ); + } + + /* Extract value */ + if ( tag_length && ( tlv_len > tag_length ) ) + tlv_len = tag_length; + if ( len > tlv_len ) + len = tlv_len; + memcpy ( buf, data, len ); + return tlv_len; + } + + return -ENOENT; +} + +/** LLDP settings operations */ +static struct settings_operations lldp_settings_operations = { + .applies = lldp_applies, + .fetch = lldp_fetch, +}; + +/** + * Process LLDP packet + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v ll_dest Link-layer destination address + * @v ll_source Link-layer source address + * @v flags Packet flags + * @ret rc Return status code + */ +static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev, + const void *ll_dest, const void *ll_source, + unsigned int flags __unused ) { + struct lldp_settings *lldpset; + size_t len; + void *data; + int rc; + + /* Find matching LLDP settings block */ + lldpset = lldp_find ( netdev ); + if ( ! lldpset ) { + DBGC ( netdev, "LLDP %s has no \"%s\" settings block\n", + netdev->name, LLDP_SETTINGS_NAME ); + rc = -ENOENT; + goto err_find; + } + + /* Create trimmed copy of received LLDP data */ + len = iob_len ( iobuf ); + data = malloc ( len ); + if ( ! data ) { + rc = -ENOMEM; + goto err_alloc; + } + memcpy ( data, iobuf->data, len ); + + /* Free any existing LLDP data */ + free ( lldpset->data ); + + /* Transfer data to LLDP settings block */ + lldpset->data = data; + lldpset->len = len; + data = NULL; + DBGC2 ( lldpset, "LLDP %s src %s ", + lldpset->name, netdev->ll_protocol->ntoa ( ll_source ) ); + DBGC2 ( lldpset, "dst %s\n", netdev->ll_protocol->ntoa ( ll_dest ) ); + DBGC2_HDA ( lldpset, 0, lldpset->data, lldpset->len ); + + /* Success */ + rc = 0; + + free ( data ); + err_alloc: + err_find: + free_iob ( iobuf ); + return rc; +} + +/** LLDP protocol */ +struct net_protocol lldp_protocol __net_protocol = { + .name = "LLDP", + .net_proto = htons ( ETH_P_LLDP ), + .rx = lldp_rx, +}; + +/** + * Create LLDP settings block + * + * @v netdev Network device + * @ret rc Return status code + */ +static int lldp_probe ( struct net_device *netdev ) { + struct lldp_settings *lldpset; + int rc; + + /* Allocate LLDP settings block */ + lldpset = zalloc ( sizeof ( *lldpset ) ); + if ( ! lldpset ) { + rc = -ENOMEM; + goto err_alloc; + } + ref_init ( &lldpset->refcnt, lldp_free ); + settings_init ( &lldpset->settings, &lldp_settings_operations, + &lldpset->refcnt, &lldp_settings_scope ); + list_add_tail ( &lldpset->list, &lldp_settings ); + lldpset->name = netdev->name; + + /* Register settings */ + if ( ( rc = register_settings ( &lldpset->settings, netdev_settings ( netdev ), + LLDP_SETTINGS_NAME ) ) != 0 ) { + DBGC ( lldpset, "LLDP %s could not register settings: %s\n", + lldpset->name, strerror ( rc ) ); + goto err_register; + } + DBGC ( lldpset, "LLDP %s registered\n", lldpset->name ); + + ref_put ( &lldpset->refcnt ); + return 0; + + unregister_settings ( &lldpset->settings ); + err_register: + ref_put ( &lldpset->refcnt ); + err_alloc: + return rc; +} + +/** LLDP driver */ +struct net_driver lldp_driver __net_driver = { + .name = "LLDP", + .probe = lldp_probe, +}; -- cgit v1.2.3-55-g7522 From 7cc305f7b4fb3508e64afa8c4c54bee1fff1f405 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 5 Feb 2023 18:53:03 +0000 Subject: [efi] Enable NET_PROTO_LLDP by default Requested-by: Christian I. Nilsson Signed-off-by: Michael Brown --- src/config/defaults/efi.h | 1 + src/config/general.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src/config') diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index efa801819..625ae055c 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define FDT_EFI #define NET_PROTO_IPV6 /* IPv6 protocol */ +#define NET_PROTO_LLDP /* Link Layer Discovery protocol */ #define DOWNLOAD_PROTO_FILE /* Local filesystem access */ diff --git a/src/config/general.h b/src/config/general.h index e9ceaff57..72a6a9a1b 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -40,7 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define NET_PROTO_STP /* Spanning Tree protocol */ #define NET_PROTO_LACP /* Link Aggregation control protocol */ #define NET_PROTO_EAPOL /* EAP over LAN protocol */ -#undef NET_PROTO_LLDP /* Link Layer Discovery protocol */ +//#define NET_PROTO_LLDP /* Link Layer Discovery protocol */ /* * PXE support -- cgit v1.2.3-55-g7522 From 9f17d1116d27696ec76c48c5c77df34cba521380 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 17 Feb 2023 16:56:11 +0000 Subject: [rng] Allow entropy source to be selected at runtime As noted in commit 3c83843 ("[rng] Check for several functioning RTC interrupts"), experimentation shows that Hyper-V cannot be trusted to reliably generate RTC interrupts. (As noted in commit f3ba0fb ("[hyperv] Provide timer based on the 10MHz time reference count MSR"), Hyper-V appears to suffer from a general problem in reliably generating any legacy interrupts.) An alternative entropy source is therefore required for an image that may be used in a Hyper-V Gen1 virtual machine. The x86 RDRAND instruction provides a suitable alternative entropy source, but may not be supported by all CPUs. We must therefore allow for multiple entropy sources to be compiled in, with the single active entropy source selected only at runtime. Restructure the internal entropy API to allow a working entropy source to be detected and chosen at runtime. Enable the RDRAND entropy source for all x86 builds, since it is likely to be substantially faster than any other source. Signed-off-by: Michael Brown --- src/arch/arm/include/bits/entropy.h | 12 - src/arch/loong64/include/bits/entropy.h | 12 - src/arch/x86/core/rdrand.c | 32 ++- src/arch/x86/include/bits/entropy.h | 15 - src/arch/x86/include/ipxe/rdrand.h | 37 --- src/arch/x86/include/ipxe/rtc_entropy.h | 62 ----- src/arch/x86/interface/pcbios/rtc_entropy.c | 38 ++- src/config/config_entropy.c | 48 ++++ src/config/defaults/efi.h | 1 + src/config/defaults/linux.h | 4 + src/config/defaults/pcbios.h | 1 + src/crypto/entropy.c | 283 +++++++------------ src/crypto/null_entropy.c | 40 --- src/include/ipxe/efi/efi_entropy.h | 35 --- src/include/ipxe/entropy.h | 414 +++++++++++++++++++++------- src/include/ipxe/linux/linux_entropy.h | 34 --- src/include/ipxe/null_entropy.h | 52 ---- src/interface/efi/efi_entropy.c | 19 +- src/interface/linux/linux_entropy.c | 20 +- 19 files changed, 540 insertions(+), 619 deletions(-) delete mode 100644 src/arch/arm/include/bits/entropy.h delete mode 100644 src/arch/loong64/include/bits/entropy.h delete mode 100644 src/arch/x86/include/bits/entropy.h delete mode 100644 src/arch/x86/include/ipxe/rdrand.h delete mode 100644 src/arch/x86/include/ipxe/rtc_entropy.h create mode 100644 src/config/config_entropy.c delete mode 100644 src/crypto/null_entropy.c delete mode 100644 src/include/ipxe/efi/efi_entropy.h delete mode 100644 src/include/ipxe/linux/linux_entropy.h delete mode 100644 src/include/ipxe/null_entropy.h (limited to 'src/config') diff --git a/src/arch/arm/include/bits/entropy.h b/src/arch/arm/include/bits/entropy.h deleted file mode 100644 index 75fdc90ea..000000000 --- a/src/arch/arm/include/bits/entropy.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_ENTROPY_H -#define _BITS_ENTROPY_H - -/** @file - * - * ARM-specific entropy API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_ENTROPY_H */ diff --git a/src/arch/loong64/include/bits/entropy.h b/src/arch/loong64/include/bits/entropy.h deleted file mode 100644 index 8d3726930..000000000 --- a/src/arch/loong64/include/bits/entropy.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _BITS_ENTROPY_H -#define _BITS_ENTROPY_H - -/** @file - * - * LoongArch64-specific entropy API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#endif /* _BITS_ENTROPY_H */ diff --git a/src/arch/x86/core/rdrand.c b/src/arch/x86/core/rdrand.c index 29605ab2f..850ab1f11 100644 --- a/src/arch/x86/core/rdrand.c +++ b/src/arch/x86/core/rdrand.c @@ -32,12 +32,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include + +struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED ); /** Number of times to retry RDRAND instruction */ #define RDRAND_RETRY_COUNT 16 /** Colour for debug messages */ -#define colour CPUID_FEATURES_INTEL_ECX_RDRAND +#define colour &rdrand_entropy /** * Enable entropy gathering @@ -54,16 +57,15 @@ static int rdrand_entropy_enable ( void ) { return -ENOTSUP; } - return 0; -} - -/** - * Disable entropy gathering - * - */ -static void rdrand_entropy_disable ( void ) { + /* Data returned by RDRAND is theoretically full entropy, up + * to a security strength of 128 bits, so assume that each + * sample contains exactly 8 bits of entropy. + */ + if ( DRBG_SECURITY_STRENGTH > 128 ) + return -ENOTSUP; + entropy_init ( &rdrand_entropy, MIN_ENTROPY ( 8.0 ) ); - /* Nothing to do */ + return 0; } /** @@ -93,7 +95,9 @@ static int rdrand_get_noise ( noise_sample_t *noise ) { return 0; } -PROVIDE_ENTROPY_INLINE ( rdrand, min_entropy_per_sample ); -PROVIDE_ENTROPY ( rdrand, entropy_enable, rdrand_entropy_enable ); -PROVIDE_ENTROPY ( rdrand, entropy_disable, rdrand_entropy_disable ); -PROVIDE_ENTROPY ( rdrand, get_noise, rdrand_get_noise ); +/** Hardware random number generator entropy source */ +struct entropy_source rdrand_entropy __entropy_source ( ENTROPY_PREFERRED ) = { + .name = "rdrand", + .enable = rdrand_entropy_enable, + .get_noise = rdrand_get_noise, +}; diff --git a/src/arch/x86/include/bits/entropy.h b/src/arch/x86/include/bits/entropy.h deleted file mode 100644 index 7accea33f..000000000 --- a/src/arch/x86/include/bits/entropy.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _BITS_ENTROPY_H -#define _BITS_ENTROPY_H - -/** @file - * - * x86-specific entropy API implementations - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include -#include - -#endif /* _BITS_ENTROPY_H */ diff --git a/src/arch/x86/include/ipxe/rdrand.h b/src/arch/x86/include/ipxe/rdrand.h deleted file mode 100644 index c9c170fb0..000000000 --- a/src/arch/x86/include/ipxe/rdrand.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _IPXE_RDRAND_H -#define _IPXE_RDRAND_H - -/** @file - * - * Hardware random number generator - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include -#include - -#ifdef ENTROPY_RDRAND -#define ENTROPY_PREFIX_rdrand -#else -#define ENTROPY_PREFIX_rdrand __rdrand_ -#endif - -/** - * min-entropy per sample - * - * @ret min_entropy min-entropy of each sample - */ -static inline __always_inline min_entropy_t -ENTROPY_INLINE ( rdrand, min_entropy_per_sample ) ( void ) { - - /* Data returned by RDRAND is theoretically full entropy, up - * to a security strength of 128 bits. - */ - if ( DRBG_SECURITY_STRENGTH > 128 ) - return 0; - return MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) ); -} - -#endif /* _IPXE_RDRAND_H */ diff --git a/src/arch/x86/include/ipxe/rtc_entropy.h b/src/arch/x86/include/ipxe/rtc_entropy.h deleted file mode 100644 index 581abcd3e..000000000 --- a/src/arch/x86/include/ipxe/rtc_entropy.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef _IPXE_RTC_ENTROPY_H -#define _IPXE_RTC_ENTROPY_H - -/** @file - * - * RTC-based entropy source - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include - -#ifdef ENTROPY_RTC -#define ENTROPY_PREFIX_rtc -#else -#define ENTROPY_PREFIX_rtc __rtc_ -#endif - -/** - * min-entropy per sample - * - * @ret min_entropy min-entropy of each sample - */ -static inline __always_inline min_entropy_t -ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) { - - /* The min-entropy has been measured on several platforms - * using the entropy_sample test code. Modelling the samples - * as independent, and using a confidence level of 99.99%, the - * measurements were as follows: - * - * qemu-kvm : 7.38 bits - * VMware : 7.46 bits - * Physical hardware : 2.67 bits - * - * We choose the lowest of these (2.67 bits) and apply a 50% - * safety margin to allow for some potential non-independence - * of samples. - */ - return MIN_ENTROPY ( 1.3 ); -} - -extern uint8_t rtc_sample ( void ); - -/** - * Get noise sample - * - * @ret noise Noise sample - * @ret rc Return status code - */ -static inline __always_inline int -ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) { - - /* Get sample */ - *noise = rtc_sample(); - - /* Always successful */ - return 0; -} - -#endif /* _IPXE_RTC_ENTROPY_H */ diff --git a/src/arch/x86/interface/pcbios/rtc_entropy.c b/src/arch/x86/interface/pcbios/rtc_entropy.c index c400d8a78..8f47ff6b8 100644 --- a/src/arch/x86/interface/pcbios/rtc_entropy.c +++ b/src/arch/x86/interface/pcbios/rtc_entropy.c @@ -39,6 +39,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL ); + /** Maximum time to wait for an RTC interrupt, in milliseconds */ #define RTC_MAX_WAIT_MS 100 @@ -203,6 +205,21 @@ static int rtc_entropy_enable ( void ) { if ( ( rc = rtc_entropy_check() ) != 0 ) goto err_check; + /* The min-entropy has been measured on several platforms + * using the entropy_sample test code. Modelling the samples + * as independent, and using a confidence level of 99.99%, the + * measurements were as follows: + * + * qemu-kvm : 7.38 bits + * VMware : 7.46 bits + * Physical hardware : 2.67 bits + * + * We choose the lowest of these (2.67 bits) and apply a 50% + * safety margin to allow for some potential non-independence + * of samples. + */ + entropy_init ( &rtc_entropy, MIN_ENTROPY ( 1.3 ) ); + return 0; err_check: @@ -226,11 +243,12 @@ static void rtc_entropy_disable ( void ) { } /** - * Measure a single RTC tick + * Get noise sample * - * @ret delta Length of RTC tick (in TSC units) + * @ret noise Noise sample + * @ret rc Return status code */ -uint8_t rtc_sample ( void ) { +static int rtc_get_noise ( noise_sample_t *noise ) { uint32_t before; uint32_t after; uint32_t temp; @@ -265,10 +283,14 @@ uint8_t rtc_sample ( void ) { : "=a" ( after ), "=d" ( before ), "=Q" ( temp ) : "2" ( 0 ) ); - return ( after - before ); + *noise = ( after - before ); + return 0; } -PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample ); -PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable ); -PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable ); -PROVIDE_ENTROPY_INLINE ( rtc, get_noise ); +/** RTC entropy source */ +struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL ) = { + .name = "rtc", + .enable = rtc_entropy_enable, + .disable = rtc_entropy_disable, + .get_noise = rtc_get_noise, +}; diff --git a/src/config/config_entropy.c b/src/config/config_entropy.c new file mode 100644 index 000000000..e96019a58 --- /dev/null +++ b/src/config/config_entropy.c @@ -0,0 +1,48 @@ +/* + * 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 (at your option) 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. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** @file + * + * Entropy configuration options + * + */ + +PROVIDE_REQUIRING_SYMBOL(); + +/* + * Drag in entropy sources + */ +#ifdef ENTROPY_RTC +REQUIRE_OBJECT ( rtc_entropy ); +#endif +#ifdef ENTROPY_EFI +REQUIRE_OBJECT ( efi_entropy ); +#endif +#ifdef ENTROPY_LINUX +REQUIRE_OBJECT ( linux_entropy ); +#endif +#ifdef ENTROPY_RDRAND +REQUIRE_OBJECT ( rdrand ); +#endif diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 625ae055c..16c561660 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -50,6 +50,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #if defined ( __i386__ ) || defined ( __x86_64__ ) #define IOAPI_X86 #define NAP_EFIX86 +#define ENTROPY_RDRAND #define CPUID_CMD /* x86 CPU feature detection command */ #define UNSAFE_STD /* Avoid setting direction flag */ #endif diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h index 5c4106d30..21de2a2e2 100644 --- a/src/config/defaults/linux.h +++ b/src/config/defaults/linux.h @@ -33,4 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define SANBOOT_PROTO_FCP #define SANBOOT_PROTO_HTTP +#if defined ( __i386__ ) || defined ( __x86_64__ ) +#define ENTROPY_RDRAND +#endif + #endif /* CONFIG_DEFAULTS_LINUX_H */ diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 83835805a..ee342d41b 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define SMBIOS_PCBIOS #define SANBOOT_PCBIOS #define ENTROPY_RTC +#define ENTROPY_RDRAND #define TIME_RTC #define REBOOT_PCBIOS #define ACPI_RSDP diff --git a/src/crypto/entropy.c b/src/crypto/entropy.c index ced6fd921..204e6bb1e 100644 --- a/src/crypto/entropy.c +++ b/src/crypto/entropy.c @@ -50,46 +50,61 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST \ __einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" ) +/** Current entropy source */ +static struct entropy_source *entropy_source; + /** - * Calculate cutoff value for the repetition count test - * - * @ret cutoff Cutoff value + * Enable entropy gathering * - * This is the cutoff value for the Repetition Count Test defined in - * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2. + * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) unsigned int -repetition_count_cutoff ( void ) { - double max_repetitions; - unsigned int cutoff; +int entropy_enable ( void ) { + int rc; - /* The cutoff formula for the repetition test is: - * - * C = ( 1 + ( -log2(W) / H_min ) ) - * - * where W is set at 2^(-30) (in ANS X9.82 Part 2 (October - * 2011 Draft) Section 8.5.2.1.3.1). - */ - max_repetitions = ( 1 + ( MIN_ENTROPY ( 30 ) / - min_entropy_per_sample() ) ); + /* Enable selected source, if applicable */ + if ( entropy_source ) { - /* Round up to a whole number of repetitions. We don't have - * the ceil() function available, so do the rounding by hand. - */ - cutoff = max_repetitions; - if ( cutoff < max_repetitions ) - cutoff++; - linker_assert ( ( cutoff >= max_repetitions ), rounding_error ); - - /* Floating-point operations are not allowed in iPXE since we - * never set up a suitable environment. Abort the build - * unless the calculated number of repetitions is a - * compile-time constant. - */ - linker_assert ( __builtin_constant_p ( cutoff ), - repetition_count_cutoff_not_constant ); + /* Enable entropy source */ + if ( ( rc = entropy_source->enable() ) != 0 ) { + DBGC ( &entropy_source, "ENTROPY could not enable " + "source \"%s\": %s\n", entropy_source->name, + strerror ( rc ) ); + return rc; + } - return cutoff; + /* Sanity checks */ + assert ( entropy_source->min_entropy_per_sample > 0 ); + assert ( entropy_source->repetition_count_cutoff > 0 ); + assert ( entropy_source->adaptive_proportion_cutoff > 0 ); + assert ( entropy_source->startup_test_count > 0 ); + + return 0; + } + + /* Find the first working source */ + rc = -ENOENT; + for_each_table_entry ( entropy_source, ENTROPY_SOURCES ) { + if ( ( rc = entropy_enable() ) == 0 ) { + DBGC ( &entropy_source, "ENTROPY using source \"%s\"\n", + entropy_source->name ); + break; + } + } + return rc; +} + +/** + * Disable entropy gathering + * + */ +void entropy_disable ( void ) { + + /* Sanity check */ + assert ( entropy_source != NULL ); + + /* Disable entropy gathering, if applicable */ + if ( entropy_source->disable ) + entropy_source->disable(); } /** @@ -104,6 +119,8 @@ repetition_count_cutoff ( void ) { static int repetition_count_test ( noise_sample_t sample ) { static noise_sample_t most_recent_sample; static unsigned int repetition_count = 0; + unsigned int repetition_count_cutoff = + entropy_source->repetition_count_cutoff; /* A = the most recently seen sample value * B = the number of times that value A has been seen in a row @@ -124,7 +141,7 @@ static int repetition_count_test ( noise_sample_t sample ) { /* i. If B >= C, then an error condition is raised * due to a failure of the test */ - if ( repetition_count >= repetition_count_cutoff() ) + if ( repetition_count >= repetition_count_cutoff ) return -EPIPE_REPETITION_COUNT_TEST; } else { @@ -141,117 +158,6 @@ static int repetition_count_test ( noise_sample_t sample ) { return 0; } -/** - * Window size for the adaptive proportion test - * - * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows - * five possible window sizes: 16, 64, 256, 4096 and 65536. - * - * We expect to generate relatively few (<256) entropy samples during - * a typical iPXE run; the use of a large window size would mean that - * the test would never complete a single cycle. We use a window size - * of 64, which is the smallest window size that permits values of - * H_min down to one bit per sample. - */ -#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64 - -/** - * Combine adaptive proportion test window size and min-entropy - * - * @v n N (window size) - * @v h H (min-entropy) - * @ret n_h (N,H) combined value - */ -#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) ) - -/** - * Define a row of the adaptive proportion cutoff table - * - * @v h H (min-entropy) - * @v c16 Cutoff for N=16 - * @v c64 Cutoff for N=64 - * @v c256 Cutoff for N=256 - * @v c4096 Cutoff for N=4096 - * @v c65536 Cutoff for N=65536 - */ -#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536) \ - case APC_N_H ( 16, h ) : return c16; \ - case APC_N_H ( 64, h ) : return c64; \ - case APC_N_H ( 256, h ) : return c256; \ - case APC_N_H ( 4096, h ) : return c4096; \ - case APC_N_H ( 65536, h ) : return c65536; - -/** Value used to represent "N/A" in adaptive proportion cutoff table */ -#define APC_NA 0 - -/** - * Look up value in adaptive proportion test cutoff table - * - * @v n N (window size) - * @v h H (min-entropy) - * @ret cutoff Cutoff - * - * This is the table of cutoff values defined in ANS X9.82 Part 2 - * (October 2011 Draft) Section 8.5.2.1.3.1.2. - */ -static inline __attribute__ (( always_inline )) unsigned int -adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) { - switch ( APC_N_H ( n, h ) ) { - APC_TABLE_ROW ( 1, APC_NA, 51, 168, 2240, 33537 ); - APC_TABLE_ROW ( 2, APC_NA, 35, 100, 1193, 17053 ); - APC_TABLE_ROW ( 3, 10, 24, 61, 643, 8705 ); - APC_TABLE_ROW ( 4, 8, 16, 38, 354, 4473 ); - APC_TABLE_ROW ( 5, 6, 12, 25, 200, 2321 ); - APC_TABLE_ROW ( 6, 5, 9, 17, 117, 1220 ); - APC_TABLE_ROW ( 7, 4, 7, 15, 71, 653 ); - APC_TABLE_ROW ( 8, 4, 5, 9, 45, 358 ); - APC_TABLE_ROW ( 9, 3, 4, 7, 30, 202 ); - APC_TABLE_ROW ( 10, 3, 4, 5, 21, 118 ); - APC_TABLE_ROW ( 11, 2, 3, 4, 15, 71 ); - APC_TABLE_ROW ( 12, 2, 3, 4, 11, 45 ); - APC_TABLE_ROW ( 13, 2, 2, 3, 9, 30 ); - APC_TABLE_ROW ( 14, 2, 2, 3, 7, 21 ); - APC_TABLE_ROW ( 15, 1, 2, 2, 6, 15 ); - APC_TABLE_ROW ( 16, 1, 2, 2, 5, 11 ); - APC_TABLE_ROW ( 17, 1, 1, 2, 4, 9 ); - APC_TABLE_ROW ( 18, 1, 1, 2, 4, 7 ); - APC_TABLE_ROW ( 19, 1, 1, 1, 3, 6 ); - APC_TABLE_ROW ( 20, 1, 1, 1, 3, 5 ); - default: - return APC_NA; - } -} - -/** - * Calculate cutoff value for the adaptive proportion test - * - * @ret cutoff Cutoff value - * - * This is the cutoff value for the Adaptive Proportion Test defined - * in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2. - */ -static inline __attribute__ (( always_inline )) unsigned int -adaptive_proportion_cutoff ( void ) { - unsigned int h; - unsigned int n; - unsigned int cutoff; - - /* Look up cutoff value in cutoff table */ - n = ADAPTIVE_PROPORTION_WINDOW_SIZE; - h = ( min_entropy_per_sample() / MIN_ENTROPY_SCALE ); - cutoff = adaptive_proportion_cutoff_lookup ( n, h ); - - /* Fail unless cutoff value is a build-time constant */ - linker_assert ( __builtin_constant_p ( cutoff ), - adaptive_proportion_cutoff_not_constant ); - - /* Fail if cutoff value is N/A */ - linker_assert ( ( cutoff != APC_NA ), - adaptive_proportion_cutoff_not_applicable ); - - return cutoff; -} - /** * Perform adaptive proportion test * @@ -265,6 +171,8 @@ static int adaptive_proportion_test ( noise_sample_t sample ) { static noise_sample_t current_counted_sample; static unsigned int sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE; static unsigned int repetition_count; + unsigned int adaptive_proportion_cutoff = + entropy_source->adaptive_proportion_cutoff; /* A = the sample value currently being counted * B = the number of samples examined in this run of the test so far @@ -312,7 +220,7 @@ static int adaptive_proportion_test ( noise_sample_t sample ) { * condition, because the test has * detected a failure */ - if ( repetition_count > adaptive_proportion_cutoff() ) + if ( repetition_count > adaptive_proportion_cutoff ) return -EPIPE_ADAPTIVE_PROPORTION_TEST; } @@ -321,6 +229,23 @@ static int adaptive_proportion_test ( noise_sample_t sample ) { return 0; } +/** + * Get noise sample + * + * @ret noise Noise sample + * @ret rc Return status code + * + * This is the GetNoise function defined in ANS X9.82 Part 2 + * (October 2011 Draft) Section 6.5.2. + */ +int get_noise ( noise_sample_t *noise ) { + + /* Sanity check */ + assert ( entropy_source != NULL ); + + return entropy_source->get_noise ( noise ); +} + /** * Get entropy sample * @@ -334,6 +259,9 @@ static int get_entropy ( entropy_sample_t *entropy ) { static int rc = 0; noise_sample_t noise; + /* Sanity check */ + assert ( entropy_source != NULL ); + /* Any failure is permanent */ if ( rc != 0 ) return rc; @@ -357,31 +285,6 @@ static int get_entropy ( entropy_sample_t *entropy ) { return 0; } -/** - * Calculate number of samples required for startup tests - * - * @ret num_samples Number of samples required - * - * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires - * that at least one full cycle of the continuous tests must be - * performed at start-up. - */ -static inline __attribute__ (( always_inline )) unsigned int -startup_test_count ( void ) { - unsigned int num_samples; - - /* At least max(N,C) samples shall be generated by the noise - * source for start-up testing. - */ - num_samples = repetition_count_cutoff(); - if ( num_samples < adaptive_proportion_cutoff() ) - num_samples = adaptive_proportion_cutoff(); - linker_assert ( __builtin_constant_p ( num_samples ), - startup_test_count_not_constant ); - - return num_samples; -} - /** * Create next nonce value * @@ -402,7 +305,7 @@ static uint32_t make_next_nonce ( void ) { /** * Obtain entropy input temporary buffer * - * @v num_samples Number of entropy samples + * @v min_entropy Min-entropy required * @v tmp Temporary buffer * @v tmp_len Length of temporary buffer * @ret rc Return status code @@ -412,11 +315,8 @@ static uint32_t make_next_nonce ( void ) { * and condensing each entropy source output after each GetEntropy * call) as defined in ANS X9.82 Part 4 (April 2011 Draft) Section * 13.3.4.2. - * - * To minimise code size, the number of samples required is calculated - * at compilation time. */ -int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, +int get_entropy_input_tmp ( min_entropy_t min_entropy, uint8_t *tmp, size_t tmp_len ) { static unsigned int startup_tested = 0; struct { @@ -424,6 +324,8 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, entropy_sample_t sample; } __attribute__ (( packed )) data;; uint8_t df_buf[tmp_len]; + min_entropy_t entropy_total; + unsigned int num_samples; unsigned int i; int rc; @@ -432,22 +334,20 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, return rc; /* Perform mandatory startup tests, if not yet performed */ - for ( ; startup_tested < startup_test_count() ; startup_tested++ ) { + for ( ; startup_tested < entropy_source->startup_test_count ; + startup_tested++ ) { if ( ( rc = get_entropy ( &data.sample ) ) != 0 ) goto err_get_entropy; } - /* 3. entropy_total = 0 - * - * (Nothing to do; the number of entropy samples required has - * already been precalculated.) - */ + /* 3. entropy_total = 0 */ + entropy_total = MIN_ENTROPY ( 0 ); /* 4. tmp = a fixed n-bit value, such as 0^n */ memset ( tmp, 0, tmp_len ); /* 5. While ( entropy_total < min_entropy ) */ - while ( num_samples-- ) { + for ( num_samples = 0 ; entropy_total < min_entropy ; num_samples++ ) { /* 5.1. ( status, entropy_bitstring, assessed_entropy ) * = GetEntropy() * 5.2. If status indicates an error, return ( status, Null ) @@ -466,19 +366,24 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, for ( i = 0 ; i < tmp_len ; i++ ) tmp[i] ^= df_buf[i]; - /* 5.5. entropy_total = entropy_total + assessed_entropy - * - * (Nothing to do; the number of entropy samples - * required has already been precalculated.) - */ + /* 5.5. entropy_total = entropy_total + assessed_entropy */ + entropy_total += entropy_source->min_entropy_per_sample; } /* Disable entropy gathering */ entropy_disable(); + DBGC ( &entropy_source, "ENTROPY gathered %d bits in %d samples\n", + ( min_entropy / MIN_ENTROPY_SCALE ), num_samples ); return 0; err_get_entropy: entropy_disable(); return rc; } + +/* Drag in objects via entropy_enable */ +REQUIRING_SYMBOL ( entropy_enable ); + +/* Drag in entropy configuration */ +REQUIRE_OBJECT ( config_entropy ); diff --git a/src/crypto/null_entropy.c b/src/crypto/null_entropy.c deleted file mode 100644 index d1e1a6f73..000000000 --- a/src/crypto/null_entropy.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2012 Michael Brown . - * - * 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. - * - * You can also choose to distribute this program under the terms of - * the Unmodified Binary Distribution Licence (as given in the file - * COPYING.UBDL), provided that you have satisfied its requirements. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -/** @file - * - * Nonexistent entropy source - * - * - * This source provides no entropy and must NOT be used in a - * security-sensitive environment. - */ - -#include - -PROVIDE_ENTROPY_INLINE ( null, min_entropy_per_sample ); -PROVIDE_ENTROPY_INLINE ( null, entropy_enable ); -PROVIDE_ENTROPY_INLINE ( null, entropy_disable ); -PROVIDE_ENTROPY_INLINE ( null, get_noise ); diff --git a/src/include/ipxe/efi/efi_entropy.h b/src/include/ipxe/efi/efi_entropy.h deleted file mode 100644 index 5b16fd7f9..000000000 --- a/src/include/ipxe/efi/efi_entropy.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _IPXE_EFI_ENTROPY_H -#define _IPXE_EFI_ENTROPY_H - -/** @file - * - * EFI entropy source - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include - -#ifdef ENTROPY_EFI -#define ENTROPY_PREFIX_efi -#else -#define ENTROPY_PREFIX_efi __efi_ -#endif - -/** - * min-entropy per sample - * - * @ret min_entropy min-entropy of each sample - */ -static inline __always_inline min_entropy_t -ENTROPY_INLINE ( efi, min_entropy_per_sample ) ( void ) { - - /* We use essentially the same mechanism as for the BIOS - * RTC-based entropy source, and so assume the same - * min-entropy per sample. - */ - return MIN_ENTROPY ( 1.3 ); -} - -#endif /* _IPXE_EFI_ENTROPY_H */ diff --git a/src/include/ipxe/entropy.h b/src/include/ipxe/entropy.h index d2e3ce501..108c37669 100644 --- a/src/include/ipxe/entropy.h +++ b/src/include/ipxe/entropy.h @@ -12,40 +12,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include +#include #include -/** - * Calculate static inline entropy API function name - * - * @v _prefix Subsystem prefix - * @v _api_func API function - * @ret _subsys_func Subsystem API function - */ -#define ENTROPY_INLINE( _subsys, _api_func ) \ - SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func ) - -/** - * Provide a entropy API implementation - * - * @v _prefix Subsystem prefix - * @v _api_func API function - * @v _func Implementing function - */ -#define PROVIDE_ENTROPY( _subsys, _api_func, _func ) \ - PROVIDE_SINGLE_API ( ENTROPY_PREFIX_ ## _subsys, _api_func, _func ) - -/** - * Provide a static inline entropy API implementation - * - * @v _prefix Subsystem prefix - * @v _api_func API function - */ -#define PROVIDE_ENTROPY_INLINE( _subsys, _api_func ) \ - PROVIDE_SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func ) - /** A noise sample */ typedef uint8_t noise_sample_t; @@ -71,56 +42,93 @@ typedef unsigned int min_entropy_t; #define MIN_ENTROPY( bits ) \ ( ( min_entropy_t ) ( (bits) * MIN_ENTROPY_SCALE ) ) -/* Include all architecture-independent entropy API headers */ -#include -#include -#include +/** An entropy source */ +struct entropy_source { + /** Name */ + const char *name; + /** + * min-entropy per sample + * + * min-entropy is defined in ANS X9.82 Part 1-2006 Section 8.3 and in + * NIST SP 800-90 Appendix C.3 as + * + * H_min = -log2 ( p_max ) + * + * where p_max is the probability of the most likely sample value. + * + * Filled in by entropy_init(). + */ + min_entropy_t min_entropy_per_sample; + /** + * Repetition count test cutoff value + * + * This is the cutoff value for the Repetition Count Test + * defined in ANS X9.82 Part 2 (October 2011 Draft) Section + * 8.5.2.1.2. + * + * Filled in by entropy_init(). + */ + unsigned int repetition_count_cutoff; + /** + * Adaptive proportion test cutoff value + * + * This is the cutoff value for the Adaptive Proportion Test + * defined in ANS X9.82 Part 2 (October 2011 Draft) Section + * 8.5.2.1.3.1.2. + * + * Filled in by entropy_init(). + */ + unsigned int adaptive_proportion_cutoff; + /** + * Startup test count + * + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 + * requires that at least one full cycle of the continuous + * tests must be performed at start-up. + */ + unsigned int startup_test_count; + /** + * Enable entropy gathering + * + * @ret rc Return status code + */ + int ( * enable ) ( void ); + /** + * Disable entropy gathering + * + */ + void ( * disable ) ( void ); + /** + * Get noise sample + * + * @ret noise Noise sample + * @ret rc Return status code + * + * This is the GetNoise function defined in ANS X9.82 Part 2 + * (October 2011 Draft) Section 6.5.2. + */ + int ( * get_noise ) ( noise_sample_t *noise ); +}; -/* Include all architecture-dependent entropy API headers */ -#include +/** Entropy source table */ +#define ENTROPY_SOURCES __table ( struct entropy_source, "entropy_sources" ) -/** - * Enable entropy gathering - * - * @ret rc Return status code - */ -int entropy_enable ( void ); +/** Declare an entropy source */ +#define __entropy_source( order ) __table_entry ( ENTROPY_SOURCES, order ) -/** - * Disable entropy gathering +/** @defgroup entropy_source_order Entropy source order * + * @{ */ -void entropy_disable ( void ); -/** - * min-entropy per sample - * - * @ret min_entropy min-entropy of each sample - * - * min-entropy is defined in ANS X9.82 Part 1-2006 Section 8.3 and in - * NIST SP 800-90 Appendix C.3 as - * - * H_min = -log2 ( p_max ) - * - * where p_max is the probability of the most likely sample value. - * - * This must be a compile-time constant. - */ -min_entropy_t min_entropy_per_sample ( void ); +#define ENTROPY_PREFERRED 01 /**< Preferred entropy source */ +#define ENTROPY_NORMAL 02 /**< Normal entropy source */ +#define ENTROPY_FALLBACK 03 /**< Fallback entropy source */ -/** - * Get noise sample - * - * @ret noise Noise sample - * @ret rc Return status code - * - * This is the GetNoise function defined in ANS X9.82 Part 2 - * (October 2011 Draft) Section 6.5.2. - */ -int get_noise ( noise_sample_t *noise ); +/** @} */ -extern int get_entropy_input_tmp ( unsigned int num_samples, - uint8_t *tmp, size_t tmp_len ); +extern int get_entropy_input_tmp ( min_entropy_t min_entropy, uint8_t *tmp, + size_t tmp_len ); /** Use SHA-256 as the underlying hash algorithm for Hash_df * @@ -145,8 +153,8 @@ extern int get_entropy_input_tmp ( unsigned int num_samples, * each entropy source output after each GetEntropy call) as defined * in ANS X9.82 Part 4 (April 2011 Draft) Section 13.3.4.2. * - * To minimise code size, the number of samples required is calculated - * at compilation time. + * This function is inlined since the entropy amount and length inputs + * are always compile-time constants. */ static inline __attribute__ (( always_inline )) int get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, @@ -154,41 +162,16 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, size_t tmp_len = ( ( ( min_entropy_bits * 2 ) + 7 ) / 8 ); uint8_t tmp_buf[ tmp_len ]; uint8_t *tmp = ( ( tmp_len > max_len ) ? tmp_buf : data ); - double min_samples; - unsigned int num_samples; unsigned int n; int rc; - /* Sanity checks */ - linker_assert ( ( min_entropy_per_sample() <= - MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) ) ), - min_entropy_per_sample_is_impossibly_high ); + /* Sanity check */ linker_assert ( ( min_entropy_bits <= ( 8 * max_len ) ), entropy_buffer_too_small ); /* Round up minimum entropy to an integral number of bytes */ min_entropy_bits = ( ( min_entropy_bits + 7 ) & ~7 ); - /* Calculate number of samples required to contain sufficient entropy */ - min_samples = ( MIN_ENTROPY ( min_entropy_bits ) / - min_entropy_per_sample() ); - - /* Round up to a whole number of samples. We don't have the - * ceil() function available, so do the rounding by hand. - */ - num_samples = min_samples; - if ( num_samples < min_samples ) - num_samples++; - linker_assert ( ( num_samples >= min_samples ), rounding_error ); - - /* Floating-point operations are not allowed in iPXE since we - * never set up a suitable environment. Abort the build - * unless the calculated number of samples is a compile-time - * constant. - */ - linker_assert ( __builtin_constant_p ( num_samples ), - num_samples_not_constant ); - /* (Unnumbered). The output length of the hash function shall * meet or exceed the security strength indicated by the * min_entropy parameter. @@ -218,8 +201,10 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, linker_assert ( __builtin_constant_p ( tmp_len ), tmp_len_not_constant ); linker_assert ( ( n == ( 8 * tmp_len ) ), tmp_len_mismatch ); - if ( ( rc = get_entropy_input_tmp ( num_samples, tmp, tmp_len ) ) != 0 ) + if ( ( rc = get_entropy_input_tmp ( MIN_ENTROPY ( min_entropy_bits ), + tmp, tmp_len ) ) != 0 ) { return rc; + } /* 6. If ( n < min_length ), then tmp = tmp || 0^(min_length-n) * 7. If ( n > max_length ), then tmp = df ( tmp, max_length ) @@ -242,4 +227,231 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, } } +/** + * Calculate cutoff value for the repetition count test + * + * @v min_entropy_per_sample Min-entropy per sample + * @ret cutoff Cutoff value + * + * This is the cutoff value for the Repetition Count Test defined in + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2. + */ +static inline __attribute__ (( always_inline )) unsigned int +entropy_repetition_count_cutoff ( min_entropy_t min_entropy_per_sample ) { + double max_repetitions; + unsigned int cutoff; + + /* The cutoff formula for the repetition test is: + * + * C = ( 1 + ( -log2(W) / H_min ) ) + * + * where W is set at 2^(-30) (in ANS X9.82 Part 2 (October + * 2011 Draft) Section 8.5.2.1.3.1). + */ + max_repetitions = ( 1 + ( MIN_ENTROPY ( 30 ) / + min_entropy_per_sample ) ); + + /* Round up to a whole number of repetitions. We don't have + * the ceil() function available, so do the rounding by hand. + */ + cutoff = max_repetitions; + if ( cutoff < max_repetitions ) + cutoff++; + linker_assert ( ( cutoff >= max_repetitions ), rounding_error ); + + /* Floating-point operations are not allowed in iPXE since we + * never set up a suitable environment. Abort the build + * unless the calculated number of repetitions is a + * compile-time constant. + */ + linker_assert ( __builtin_constant_p ( cutoff ), + repetition_count_cutoff_not_constant ); + + return cutoff; +} + +/** + * Window size for the adaptive proportion test + * + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows + * five possible window sizes: 16, 64, 256, 4096 and 65536. + * + * We expect to generate relatively few (<256) entropy samples during + * a typical iPXE run; the use of a large window size would mean that + * the test would never complete a single cycle. We use a window size + * of 64, which is the smallest window size that permits values of + * H_min down to one bit per sample. + */ +#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64 + +/** + * Combine adaptive proportion test window size and min-entropy + * + * @v n N (window size) + * @v h H (min-entropy) + * @ret n_h (N,H) combined value + */ +#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) ) + +/** + * Define a row of the adaptive proportion cutoff table + * + * @v h H (min-entropy) + * @v c16 Cutoff for N=16 + * @v c64 Cutoff for N=64 + * @v c256 Cutoff for N=256 + * @v c4096 Cutoff for N=4096 + * @v c65536 Cutoff for N=65536 + */ +#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536) \ + case APC_N_H ( 16, h ) : return c16; \ + case APC_N_H ( 64, h ) : return c64; \ + case APC_N_H ( 256, h ) : return c256; \ + case APC_N_H ( 4096, h ) : return c4096; \ + case APC_N_H ( 65536, h ) : return c65536; + +/** Value used to represent "N/A" in adaptive proportion cutoff table */ +#define APC_NA 0 + +/** + * Look up value in adaptive proportion test cutoff table + * + * @v n N (window size) + * @v h H (min-entropy) + * @ret cutoff Cutoff + * + * This is the table of cutoff values defined in ANS X9.82 Part 2 + * (October 2011 Draft) Section 8.5.2.1.3.1.2. + */ +static inline __attribute__ (( always_inline )) unsigned int +entropy_adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) { + switch ( APC_N_H ( n, h ) ) { + APC_TABLE_ROW ( 1, APC_NA, 51, 168, 2240, 33537 ); + APC_TABLE_ROW ( 2, APC_NA, 35, 100, 1193, 17053 ); + APC_TABLE_ROW ( 3, 10, 24, 61, 643, 8705 ); + APC_TABLE_ROW ( 4, 8, 16, 38, 354, 4473 ); + APC_TABLE_ROW ( 5, 6, 12, 25, 200, 2321 ); + APC_TABLE_ROW ( 6, 5, 9, 17, 117, 1220 ); + APC_TABLE_ROW ( 7, 4, 7, 15, 71, 653 ); + APC_TABLE_ROW ( 8, 4, 5, 9, 45, 358 ); + APC_TABLE_ROW ( 9, 3, 4, 7, 30, 202 ); + APC_TABLE_ROW ( 10, 3, 4, 5, 21, 118 ); + APC_TABLE_ROW ( 11, 2, 3, 4, 15, 71 ); + APC_TABLE_ROW ( 12, 2, 3, 4, 11, 45 ); + APC_TABLE_ROW ( 13, 2, 2, 3, 9, 30 ); + APC_TABLE_ROW ( 14, 2, 2, 3, 7, 21 ); + APC_TABLE_ROW ( 15, 1, 2, 2, 6, 15 ); + APC_TABLE_ROW ( 16, 1, 2, 2, 5, 11 ); + APC_TABLE_ROW ( 17, 1, 1, 2, 4, 9 ); + APC_TABLE_ROW ( 18, 1, 1, 2, 4, 7 ); + APC_TABLE_ROW ( 19, 1, 1, 1, 3, 6 ); + APC_TABLE_ROW ( 20, 1, 1, 1, 3, 5 ); + default: + return APC_NA; + } +} + +/** + * Calculate cutoff value for the adaptive proportion test + * + * @v min_entropy_per_sample Min-entropy per sample + * @ret cutoff Cutoff value + * + * This is the cutoff value for the Adaptive Proportion Test defined + * in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2. + */ +static inline __attribute__ (( always_inline )) unsigned int +entropy_adaptive_proportion_cutoff ( min_entropy_t min_entropy_per_sample ) { + unsigned int h; + unsigned int n; + unsigned int cutoff; + + /* Look up cutoff value in cutoff table */ + n = ADAPTIVE_PROPORTION_WINDOW_SIZE; + h = ( min_entropy_per_sample / MIN_ENTROPY_SCALE ); + cutoff = entropy_adaptive_proportion_cutoff_lookup ( n, h ); + + /* Fail unless cutoff value is a compile-time constant */ + linker_assert ( __builtin_constant_p ( cutoff ), + adaptive_proportion_cutoff_not_constant ); + + /* Fail if cutoff value is N/A */ + linker_assert ( ( cutoff != APC_NA ), + adaptive_proportion_cutoff_not_applicable ); + + return cutoff; +} + +/** + * Calculate number of samples required for startup tests + * + * @v repetition_count_cutoff Repetition count test cutoff value + * @v adaptive_proportion_cutoff Adaptive proportion test cutoff value + * @ret num_samples Number of samples required + * + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires + * that at least one full cycle of the continuous tests must be + * performed at start-up. + */ +static inline __attribute__ (( always_inline )) unsigned int +entropy_startup_test_count ( unsigned int repetition_count_cutoff, + unsigned int adaptive_proportion_cutoff ) { + unsigned int num_samples; + + /* At least max(N,C) samples shall be generated by the noise + * source for start-up testing. + */ + num_samples = repetition_count_cutoff; + if ( num_samples < adaptive_proportion_cutoff ) + num_samples = adaptive_proportion_cutoff; + linker_assert ( __builtin_constant_p ( num_samples ), + startup_test_count_not_constant ); + + return num_samples; +} + +/** + * Initialise entropy source + * + * @v source Entropy source + * @v min_entropy_per_sample Min-entropy per sample + * + * The cutoff value calculations for the repetition count test and the + * adaptive proportion test are provided as static inline functions + * since the results will always be compile-time constants. + */ +static inline __attribute__ (( always_inline )) void +entropy_init ( struct entropy_source *source, + min_entropy_t min_entropy_per_sample ) { + unsigned int repetition_count_cutoff; + unsigned int adaptive_proportion_cutoff; + unsigned int startup_test_count; + + /* Sanity check */ + linker_assert ( min_entropy_per_sample > MIN_ENTROPY ( 0 ), + min_entropy_per_sample_is_zero ); + linker_assert ( ( min_entropy_per_sample <= + MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) ) ), + min_entropy_per_sample_is_impossibly_high ); + + /* Calculate test cutoff values */ + repetition_count_cutoff = + entropy_repetition_count_cutoff ( min_entropy_per_sample ); + adaptive_proportion_cutoff = + entropy_adaptive_proportion_cutoff ( min_entropy_per_sample ); + startup_test_count = + entropy_startup_test_count ( repetition_count_cutoff, + adaptive_proportion_cutoff ); + + /* Record min-entropy per sample and test cutoff values */ + source->min_entropy_per_sample = min_entropy_per_sample; + source->repetition_count_cutoff = repetition_count_cutoff; + source->adaptive_proportion_cutoff = adaptive_proportion_cutoff; + source->startup_test_count = startup_test_count; +} + +extern int entropy_enable ( void ); +extern void entropy_disable ( void ); +extern int get_noise ( noise_sample_t *noise ); + #endif /* _IPXE_ENTROPY_H */ diff --git a/src/include/ipxe/linux/linux_entropy.h b/src/include/ipxe/linux/linux_entropy.h deleted file mode 100644 index ea8c1f16c..000000000 --- a/src/include/ipxe/linux/linux_entropy.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _IPXE_LINUX_ENTROPY_H -#define _IPXE_LINUX_ENTROPY_H - -/** @file - * - * /dev/random-based entropy source - * - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#ifdef ENTROPY_LINUX -#define ENTROPY_PREFIX_linux -#else -#define ENTROPY_PREFIX_linux __linux_ -#endif - -/** - * min-entropy per sample - * - * @ret min_entropy min-entropy of each sample - */ -static inline __always_inline min_entropy_t -ENTROPY_INLINE ( linux, min_entropy_per_sample ) ( void ) { - - /* linux_get_noise() reads a single byte from /dev/random, - * which is supposed to block until a sufficient amount of - * entropy is available. We therefore assume that each sample - * contains exactly 8 bits of entropy. - */ - return MIN_ENTROPY ( 8.0 ); -} - -#endif /* _IPXE_LINUX_ENTROPY_H */ diff --git a/src/include/ipxe/null_entropy.h b/src/include/ipxe/null_entropy.h deleted file mode 100644 index 5a6bb6218..000000000 --- a/src/include/ipxe/null_entropy.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _IPXE_NULL_ENTROPY_H -#define _IPXE_NULL_ENTROPY_H - -/** @file - * - * Nonexistent entropy source - * - * This source provides no entropy and must NOT be used in a - * security-sensitive environment. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include - -#ifdef ENTROPY_NULL -#define ENTROPY_PREFIX_null -#else -#define ENTROPY_PREFIX_null __null_ -#endif - -static inline __always_inline int -ENTROPY_INLINE ( null, entropy_enable ) ( void ) { - /* Do nothing */ - return 0; -} - -static inline __always_inline void -ENTROPY_INLINE ( null, entropy_disable ) ( void ) { - /* Do nothing */ -} - -static inline __always_inline min_entropy_t -ENTROPY_INLINE ( null, min_entropy_per_sample ) ( void ) { - /* Actual amount of min-entropy is zero. To avoid - * division-by-zero errors and to allow compilation of - * entropy-consuming code, pretend to have 1 bit of entropy in - * each sample. - */ - return MIN_ENTROPY ( 1.0 ); -} - -static inline __always_inline int -ENTROPY_INLINE ( null, get_noise ) ( noise_sample_t *noise ) { - - /* All sample values are constant */ - *noise = 0x01; - - return 0; -} - -#endif /* _IPXE_NULL_ENTROPY_H */ diff --git a/src/interface/efi/efi_entropy.c b/src/interface/efi/efi_entropy.c index 1e8ddfb68..e5c393562 100644 --- a/src/interface/efi/efi_entropy.c +++ b/src/interface/efi/efi_entropy.c @@ -36,6 +36,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +struct entropy_source efi_entropy __entropy_source ( ENTROPY_NORMAL ); + /** Random number generator protocol */ static EFI_RNG_PROTOCOL *efirng; EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng ); @@ -91,6 +93,12 @@ static int efi_entropy_enable ( void ) { return rc; } + /* We use essentially the same mechanism as for the BIOS + * RTC-based entropy source, and so assume the same + * min-entropy per sample. + */ + entropy_init ( &efi_entropy, MIN_ENTROPY ( 1.3 ) ); + return 0; } @@ -235,7 +243,10 @@ static int efi_get_noise ( noise_sample_t *noise ) { return 0; } -PROVIDE_ENTROPY_INLINE ( efi, min_entropy_per_sample ); -PROVIDE_ENTROPY ( efi, entropy_enable, efi_entropy_enable ); -PROVIDE_ENTROPY ( efi, entropy_disable, efi_entropy_disable ); -PROVIDE_ENTROPY ( efi, get_noise, efi_get_noise ); +/** EFI entropy source */ +struct entropy_source efi_entropy __entropy_source ( ENTROPY_NORMAL ) = { + .name = "efi", + .enable = efi_entropy_enable, + .disable = efi_entropy_disable, + .get_noise = efi_get_noise, +}; diff --git a/src/interface/linux/linux_entropy.c b/src/interface/linux/linux_entropy.c index 257e993a0..f24969794 100644 --- a/src/interface/linux/linux_entropy.c +++ b/src/interface/linux/linux_entropy.c @@ -34,6 +34,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +struct entropy_source linux_entropy __entropy_source ( ENTROPY_NORMAL ); + /** Entropy source filename */ static const char entropy_filename[] = "/dev/random"; @@ -55,6 +57,13 @@ static int linux_entropy_enable ( void ) { return entropy_fd; } + /* linux_get_noise() reads a single byte from /dev/random, + * which is supposed to block until a sufficient amount of + * entropy is available. We therefore assume that each sample + * contains exactly 8 bits of entropy. + */ + entropy_init ( &linux_entropy, MIN_ENTROPY ( 8.0 ) ); + return 0; } @@ -95,7 +104,10 @@ static int linux_get_noise ( noise_sample_t *noise ) { return 0; } -PROVIDE_ENTROPY_INLINE ( linux, min_entropy_per_sample ); -PROVIDE_ENTROPY ( linux, entropy_enable, linux_entropy_enable ); -PROVIDE_ENTROPY ( linux, entropy_disable, linux_entropy_disable ); -PROVIDE_ENTROPY ( linux, get_noise, linux_get_noise ); +/** Linux entropy source */ +struct entropy_source linux_entropy __entropy_source ( ENTROPY_NORMAL ) = { + .name = "linux", + .enable = linux_entropy_enable, + .disable = linux_entropy_disable, + .get_noise = linux_get_noise, +}; -- cgit v1.2.3-55-g7522 From 471599dc7721d454b6658062c901b52038a78be2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 20 Feb 2023 14:08:49 +0000 Subject: [efi] Split out EFI_RNG_PROTOCOL as a separate entropy source Commit 7ca801d ("[efi] Use the EFI_RNG_PROTOCOL as an entropy source if available") added EFI_RNG_PROTOCOL as an alternative entropy source via an ad-hoc mechanism specific to efi_entropy.c. Split out EFI_RNG_PROTOCOL to a separate entropy source, and allow the entropy core to handle the selection of RDRAND, EFI_RNG_PROTOCOL, or timer ticks as the active source. The fault detection logic added in commit a87537d ("[efi] Detect and disable seriously broken EFI_RNG_PROTOCOL implementations") may be removed completely, since the failure will already be detected by the generic ANS X9.82-mandated repetition count test and will now be handled gracefully by the entropy core. Signed-off-by: Michael Brown --- src/config/config_entropy.c | 5 +- src/config/defaults/efi.h | 3 +- src/include/ipxe/errfile.h | 1 + src/interface/efi/efi_entropy.c | 95 ++------------------------------ src/interface/efi/efi_rng.c | 118 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 92 deletions(-) create mode 100644 src/interface/efi/efi_rng.c (limited to 'src/config') diff --git a/src/config/config_entropy.c b/src/config/config_entropy.c index e96019a58..9f12f1fa3 100644 --- a/src/config/config_entropy.c +++ b/src/config/config_entropy.c @@ -37,9 +37,12 @@ PROVIDE_REQUIRING_SYMBOL(); #ifdef ENTROPY_RTC REQUIRE_OBJECT ( rtc_entropy ); #endif -#ifdef ENTROPY_EFI +#ifdef ENTROPY_EFITICK REQUIRE_OBJECT ( efi_entropy ); #endif +#ifdef ENTROPY_EFIRNG +REQUIRE_OBJECT ( efi_rng ); +#endif #ifdef ENTROPY_LINUX REQUIRE_OBJECT ( linux_entropy ); #endif diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 16c561660..8e53b9ab6 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -19,7 +19,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define SMBIOS_EFI #define SANBOOT_EFI #define BOFM_EFI -#define ENTROPY_EFI +#define ENTROPY_EFITICK +#define ENTROPY_EFIRNG #define TIME_EFI #define REBOOT_EFI #define ACPI_EFI diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index d7b6ea1bd..e6fd8524e 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -403,6 +403,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_pci_cmd ( ERRFILE_OTHER | 0x00590000 ) #define ERRFILE_dhe ( ERRFILE_OTHER | 0x005a0000 ) #define ERRFILE_efi_cmdline ( ERRFILE_OTHER | 0x005b0000 ) +#define ERRFILE_efi_rng ( ERRFILE_OTHER | 0x005c0000 ) /** @} */ diff --git a/src/interface/efi/efi_entropy.c b/src/interface/efi/efi_entropy.c index e5c393562..cda1c3640 100644 --- a/src/interface/efi/efi_entropy.c +++ b/src/interface/efi/efi_entropy.c @@ -25,10 +25,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include #include #include -#include /** @file * @@ -36,24 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ -struct entropy_source efi_entropy __entropy_source ( ENTROPY_NORMAL ); - -/** Random number generator protocol */ -static EFI_RNG_PROTOCOL *efirng; -EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng ); - -/** Minimum number of bytes to request from RNG - * - * The UEFI spec states (for no apparently good reason) that "When a - * Deterministic Random Bit Generator (DRBG) is used on the output of - * a (raw) entropy source, its security level must be at least 256 - * bits." The EDK2 codebase (mis)interprets this to mean that the - * call to GetRNG() should fail if given a buffer less than 32 bytes. - * - * Incidentally, nothing in the EFI RNG protocol provides any way to - * report the actual amount of entropy returned by GetRNG(). - */ -#define EFI_ENTROPY_RNG_LEN 32 +struct entropy_source efitick_entropy __entropy_source ( ENTROPY_FALLBACK ); /** Time (in 100ns units) to delay waiting for timer tick * @@ -78,9 +59,6 @@ static int efi_entropy_enable ( void ) { EFI_STATUS efirc; int rc; - DBGC ( &tick, "ENTROPY %s RNG protocol\n", - ( efirng ? "has" : "has no" ) ); - /* Drop to external TPL to allow timer tick event to take place */ bs->RestoreTPL ( efi_external_tpl ); @@ -97,7 +75,7 @@ static int efi_entropy_enable ( void ) { * RTC-based entropy source, and so assume the same * min-entropy per sample. */ - entropy_init ( &efi_entropy, MIN_ENTROPY ( 1.3 ) ); + entropy_init ( &efitick_entropy, MIN_ENTROPY ( 1.3 ) ); return 0; } @@ -155,7 +133,7 @@ static int efi_entropy_tick ( void ) { * @ret noise Noise sample * @ret rc Return status code */ -static int efi_get_noise_ticks ( noise_sample_t *noise ) { +static int efi_get_noise ( noise_sample_t *noise ) { int before; int after; int rc; @@ -180,72 +158,9 @@ static int efi_get_noise_ticks ( noise_sample_t *noise ) { return 0; } -/** - * Get noise sample from RNG protocol - * - * @ret noise Noise sample - * @ret rc Return status code - */ -static int efi_get_noise_rng ( noise_sample_t *noise ) { - static uint8_t prev[EFI_ENTROPY_RNG_LEN]; - uint8_t buf[EFI_ENTROPY_RNG_LEN]; - EFI_STATUS efirc; - int rc; - - /* Fail if we have no EFI RNG protocol */ - if ( ! efirng ) - return -ENOTSUP; - - /* Get the minimum allowed number of random bytes */ - if ( ( efirc = efirng->GetRNG ( efirng, NULL, EFI_ENTROPY_RNG_LEN, - buf ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( &tick, "ENTROPY could not read from RNG: %s\n", - strerror ( rc ) ); - return rc; - } - - /* Fail (and permanently disable the EFI RNG) if we get - * consecutive identical results. - */ - if ( memcmp ( buf, prev, sizeof ( buf ) ) == 0 ) { - DBGC ( &tick, "ENTROPY detected broken EFI RNG:\n" ); - DBGC_HDA ( &tick, 0, buf, sizeof ( buf ) ); - efirng = NULL; - return -EIO; - } - memcpy ( prev, buf, sizeof ( prev ) ); - - /* Reduce random bytes to a single noise sample. This seems - * like overkill, but we have no way of knowing how much - * entropy is actually present in the bytes returned by the - * RNG protocol. - */ - *noise = crc32_le ( 0, buf, sizeof ( buf ) ); - - return 0; -} - -/** - * Get noise sample - * - * @ret noise Noise sample - * @ret rc Return status code - */ -static int efi_get_noise ( noise_sample_t *noise ) { - int rc; - - /* Try RNG first, falling back to timer ticks */ - if ( ( ( rc = efi_get_noise_rng ( noise ) ) != 0 ) && - ( ( rc = efi_get_noise_ticks ( noise ) ) != 0 ) ) - return rc; - - return 0; -} - /** EFI entropy source */ -struct entropy_source efi_entropy __entropy_source ( ENTROPY_NORMAL ) = { - .name = "efi", +struct entropy_source efitick_entropy __entropy_source ( ENTROPY_FALLBACK ) = { + .name = "efitick", .enable = efi_entropy_enable, .disable = efi_entropy_disable, .get_noise = efi_get_noise, diff --git a/src/interface/efi/efi_rng.c b/src/interface/efi/efi_rng.c new file mode 100644 index 000000000..b76a6fc0d --- /dev/null +++ b/src/interface/efi/efi_rng.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015 Michael Brown . + * + * 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 (at your option) 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. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** @file + * + * EFI random number generator protocol entropy source + * + */ + +struct entropy_source efirng_entropy __entropy_source ( ENTROPY_NORMAL ); + +/** Random number generator protocol */ +static EFI_RNG_PROTOCOL *efirng; +EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng ); + +/** Minimum number of bytes to request from RNG + * + * The UEFI spec states (for no apparently good reason) that "When a + * Deterministic Random Bit Generator (DRBG) is used on the output of + * a (raw) entropy source, its security level must be at least 256 + * bits." The EDK2 codebase (mis)interprets this to mean that the + * call to GetRNG() should fail if given a buffer less than 32 bytes. + * + * Incidentally, nothing in the EFI RNG protocol provides any way to + * report the actual amount of entropy returned by GetRNG(). + */ +#define EFIRNG_LEN 32 + +/** + * Enable entropy gathering + * + * @ret rc Return status code + */ +static int efirng_enable ( void ) { + + /* Check for RNG protocol support */ + if ( ! efirng ) { + DBGC ( &efirng, "EFIRNG has no RNG protocol\n" ); + return -ENOTSUP; + } + + /* Nothing in the EFI specification provides any clue as to + * how much entropy will be returned by GetRNG(). Make a + * totally uninformed (and conservative guess) that each + * sample will contain at least one bit of entropy. + */ + entropy_init ( &efirng_entropy, MIN_ENTROPY ( 1.0 ) ); + + return 0; +} + +/** + * Get noise sample from RNG protocol + * + * @ret noise Noise sample + * @ret rc Return status code + */ +static int efirng_get_noise ( noise_sample_t *noise ) { + uint8_t buf[EFIRNG_LEN]; + EFI_STATUS efirc; + int rc; + + /* Sanity check */ + assert ( efirng != NULL ); + + /* Get the minimum allowed number of random bytes */ + if ( ( efirc = efirng->GetRNG ( efirng, NULL, sizeof ( buf ), + buf ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efirng, "ENTROPY could not read from RNG: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Reduce random bytes to a single noise sample. This seems + * like overkill, but we have no way of knowing how much + * entropy is actually present in the bytes returned by the + * RNG protocol. + */ + *noise = crc32_le ( 0, buf, sizeof ( buf ) ); + + return 0; +} + +/** EFI random number generator protocol entropy source */ +struct entropy_source efirng_entropy __entropy_source ( ENTROPY_NORMAL ) = { + .name = "efirng", + .enable = efirng_enable, + .get_noise = efirng_get_noise, +}; -- cgit v1.2.3-55-g7522 From 33cb56cf1b7a7138542fe18fd86898fdca2e8f0a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 28 Feb 2023 16:22:19 +0000 Subject: [params] Rename "form parameter" to "request parameter" Prepare for the parameter mechanism to be generalised to specifying request parameters that are passed via mechanisms other than an application/x-www-form-urlencoded form. Signed-off-by: Michael Brown --- src/config/general.h | 2 +- src/core/params.c | 10 +++++----- src/core/parseopt.c | 2 +- src/hci/commands/param_cmd.c | 4 ++-- src/include/ipxe/params.h | 16 ++++++++-------- src/include/ipxe/uri.h | 2 +- src/tests/uri_test.c | 22 +++++++++++----------- 7 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src/config') diff --git a/src/config/general.h b/src/config/general.h index 72a6a9a1b..e75a2affd 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -150,7 +150,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); //#define POWEROFF_CMD /* Power off command */ //#define IMAGE_TRUST_CMD /* Image trust management commands */ //#define PCI_CMD /* PCI commands */ -//#define PARAM_CMD /* Form parameter commands */ +//#define PARAM_CMD /* Request parameter commands */ //#define NEIGHBOUR_CMD /* Neighbour management commands */ //#define PING_CMD /* Ping command */ //#define CONSOLE_CMD /* Console command */ diff --git a/src/core/params.c b/src/core/params.c index e1f66acca..23206bef6 100644 --- a/src/core/params.c +++ b/src/core/params.c @@ -25,7 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** @file * - * Form parameters + * Request parameters * */ @@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); static LIST_HEAD ( parameters ); /** - * Free form parameter list + * Free request parameter list * * @v refcnt Reference count */ @@ -60,7 +60,7 @@ static void free_parameters ( struct refcnt *refcnt ) { } /** - * Find form parameter list by name + * Find request parameter list by name * * @v name Parameter list name (may be NULL) * @ret params Parameter list, or NULL if not found @@ -78,7 +78,7 @@ struct parameters * find_parameters ( const char *name ) { } /** - * Create form parameter list + * Create request parameter list * * @v name Parameter list name (may be NULL) * @ret params Parameter list, or NULL on failure @@ -118,7 +118,7 @@ struct parameters * create_parameters ( const char *name ) { } /** - * Add form parameter + * Add request parameter * * @v params Parameter list * @v key Parameter key diff --git a/src/core/parseopt.c b/src/core/parseopt.c index 007080088..1dbfc7aef 100644 --- a/src/core/parseopt.c +++ b/src/core/parseopt.c @@ -302,7 +302,7 @@ int parse_autovivified_setting ( char *text, struct named_setting *setting ) { } /** - * Parse form parameter list name + * Parse request parameter list name * * @v text Text * @ret params Parameter list diff --git a/src/hci/commands/param_cmd.c b/src/hci/commands/param_cmd.c index bff04f2ff..9e3260de1 100644 --- a/src/hci/commands/param_cmd.c +++ b/src/hci/commands/param_cmd.c @@ -25,7 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** @file * - * Form parameter commands + * Request parameter commands * */ @@ -154,7 +154,7 @@ static int param_exec ( int argc, char **argv ) { return rc; } -/** Form parameter commands */ +/** Request parameter commands */ struct command param_commands[] __command = { { .name = "params", diff --git a/src/include/ipxe/params.h b/src/include/ipxe/params.h index dd3292efc..955f57acc 100644 --- a/src/include/ipxe/params.h +++ b/src/include/ipxe/params.h @@ -3,7 +3,7 @@ /** @file * - * Form parameters + * Request parameters * */ @@ -12,7 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** A form parameter list */ +/** A request parameter list */ struct parameters { /** Reference count */ struct refcnt refcnt; @@ -24,9 +24,9 @@ struct parameters { struct list_head entries; }; -/** A form parameter */ +/** A request parameter */ struct parameter { - /** List of form parameters */ + /** List of request parameters */ struct list_head list; /** Key */ const char *key; @@ -35,7 +35,7 @@ struct parameter { }; /** - * Increment form parameter list reference count + * Increment request parameter list reference count * * @v params Parameter list, or NULL * @ret params Parameter list as passed in @@ -47,7 +47,7 @@ params_get ( struct parameters *params ) { } /** - * Decrement form parameter list reference count + * Decrement request parameter list reference count * * @v params Parameter list, or NULL */ @@ -57,7 +57,7 @@ params_put ( struct parameters *params ) { } /** - * Claim ownership of form parameter list + * Claim ownership of request parameter list * * @v params Parameter list * @ret params Parameter list @@ -71,7 +71,7 @@ claim_parameters ( struct parameters *params ) { return params; } -/** Iterate over all form parameters in a list */ +/** Iterate over all request parameters in a list */ #define for_each_param( param, params ) \ list_for_each_entry ( (param), &(params)->entries, list ) diff --git a/src/include/ipxe/uri.h b/src/include/ipxe/uri.h index e5b7c8616..a94b525e1 100644 --- a/src/include/ipxe/uri.h +++ b/src/include/ipxe/uri.h @@ -84,7 +84,7 @@ struct uri { const char *equery; /** Fragment (with original URI encoding) */ const char *efragment; - /** Form parameters */ + /** Request parameters */ struct parameters *params; } __attribute__ (( packed )); diff --git a/src/tests/uri_test.c b/src/tests/uri_test.c index 338f479cd..5e7060323 100644 --- a/src/tests/uri_test.c +++ b/src/tests/uri_test.c @@ -92,7 +92,7 @@ struct uri_churi_test { const char *expected; }; -/** A form parameter URI test list */ +/** A request parameter URI test list */ struct uri_params_test_list { /** Key */ const char *key; @@ -100,7 +100,7 @@ struct uri_params_test_list { const char *value; }; -/** A form parameter URI test */ +/** A request parameter URI test */ struct uri_params_test { /** URI string */ const char *string; @@ -403,9 +403,9 @@ static void uri_churi_okx ( struct uri_churi_test *test, const char *file, #define uri_churi_ok( test ) uri_churi_okx ( test, __FILE__, __LINE__ ) /** - * Report form parameter URI test list result + * Report request parameter URI test list result * - * @v test Form parameter URI test + * @v test Request parameter URI test * @v uri URI * @v file Test code file * @v line Test code line @@ -437,9 +437,9 @@ static void uri_params_list_okx ( struct uri_params_test *test, uri_params_list_okx ( test, __FILE__, __LINE__ ) /** - * Report form parameter URI test result + * Report request parameter URI test result * - * @v test Form parameter URI test + * @v test Request parameter URI test * @v file Test code file * @v line Test code line */ @@ -879,7 +879,7 @@ static struct uri_churi_test uri_churi[] = { } }; -/** Form parameter URI test list */ +/** Request parameter URI test list */ static struct uri_params_test_list uri_params_list[] = { { "vendor", @@ -899,7 +899,7 @@ static struct uri_params_test_list uri_params_list[] = { } }; -/** Form parameter URI test */ +/** Request parameter URI test */ static struct uri_params_test uri_params = { "http://boot.ipxe.org/demo/boot.php##params", { @@ -912,7 +912,7 @@ static struct uri_params_test uri_params = { uri_params_list, }; -/** Named form parameter URI test list */ +/** Named request parameter URI test list */ static struct uri_params_test_list uri_named_params_list[] = { { "mac", @@ -928,7 +928,7 @@ static struct uri_params_test_list uri_named_params_list[] = { } }; -/** Named form parameter URI test */ +/** Named request parameter URI test */ static struct uri_params_test uri_named_params = { "http://192.168.100.4:3001/register##params=foo", { @@ -996,7 +996,7 @@ static void uri_test_exec ( void ) { /* Current working URI tests */ uri_churi_ok ( uri_churi ); - /* Form parameter URI tests */ + /* Request parameter URI tests */ uri_params_ok ( &uri_params ); uri_params_ok ( &uri_named_params ); } -- cgit v1.2.3-55-g7522