iPXE
pccrr.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2026 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdio.h>
28#include <string.h>
29#include <errno.h>
30#include <ipxe/uri.h>
31#include <ipxe/open.h>
32#include <ipxe/http.h>
33#include <ipxe/base16.h>
34#include <ipxe/pccrc.h>
35#include <ipxe/pccrr.h>
36
37/** @file
38 *
39 * Peer Content Caching and Retrieval: Retrieval Protocol [MS-PCCRR]
40 *
41 * The MS-PCCRR specification defines an HTTP POST request/response
42 * pair for retrieving an encrypted block from a peer (with the
43 * decryption keys provided separately via the content information).
44 *
45 * The HTTP POST request parameters serve only to identify the block:
46 * the actual response body is effectively a static encrypted blob.
47 *
48 * We define an additional (non-standard) retrieval protocol in which
49 * the block is identified solely using the request URI, with the
50 * response being the same content that would be returned as the HTTP
51 * POST response body. This allows for encrypted blocks to be
52 * retrieved from a static source such as AWS S3 or a local FAT
53 * filesystem, without requiring a peer that can understand the
54 * retrieval protocol HTTP POST request format.
55 *
56 * We define the static request URI format as:
57 *
58 * <base>/xx/xxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy-b.blk
59 *
60 * where
61 *
62 * - `xxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy` is the segment ID (HoHoDK)
63 * as a lower-case hexadecimal string
64 *
65 * - `xx` is the first two characters (i.e. the first byte) of the
66 * segment ID
67 *
68 * - `b` is the block index within the segment (which will always
69 * be zero when using MS-PCCRC version 2 content information), as
70 * an unpadded decimal string
71 *
72 * - the extension `.blk` represents a block file
73 *
74 * This path format is designed to allow for efficient storage in a
75 * local FAT filesystem (by limiting both the number of directories
76 * and the number of entries within each directory).
77 *
78 */
79
80/**
81 * Open retrieval protocol connection using HTTP POST
82 *
83 * @v xfer Data transfer interface
84 * @v location Peer location
85 * @v digestsize Digest size
86 * @v id Segment identifier
87 * @v block Block index
88 * @ret rc Return status code
89 */
90static int peerdist_open_post ( struct interface *xfer, const char *location,
91 size_t digestsize, const uint8_t *id,
92 unsigned int block ) {
93 char uri_string[ 7 /* "http://" */ + strlen ( location ) +
94 sizeof ( PEERDIST_MAGIC_PATH /* includes NUL */ ) ];
96 struct http_request_content content;
97 struct uri *uri;
98 int rc;
99
100 /* Construct block fetch request */
101 memset ( &req, 0, sizeof ( req ) );
102 req.getblks.hdr.version.raw = htonl ( PEERDIST_MSG_GETBLKS_VERSION );
103 req.getblks.hdr.type = htonl ( PEERDIST_MSG_GETBLKS_TYPE );
104 req.getblks.hdr.len = htonl ( sizeof ( req ) );
105 req.getblks.hdr.algorithm = htonl ( PEERDIST_MSG_AES_128_CBC );
106 req.segment.segment.digestsize = htonl ( digestsize );
107 memcpy ( req.segment.id, id, digestsize );
108 req.ranges.ranges.count = htonl ( 1 );
109 req.ranges.range[0].first = htonl ( block );
110 req.ranges.range[0].count = htonl ( 1 );
111
112 /* Construct POST request content */
113 memset ( &content, 0, sizeof ( content ) );
114 content.data = &req;
115 content.len = sizeof ( req );
116
117 /* Construct URI string */
118 snprintf ( uri_string, sizeof ( uri_string ),
119 ( "http://%s" PEERDIST_MAGIC_PATH ), location );
120
121 /* Parse URI */
122 uri = parse_uri ( uri_string );
123 if ( ! uri ) {
124 rc = -ENOMEM;
125 goto err_uri;
126 }
127
128 /* Initiate HTTP POST to retrieve block */
129 if ( ( rc = http_open ( xfer, &http_post, uri, NULL,
130 &content ) ) != 0 ) {
131 DBGC ( xfer, "PCCRR %p could not open %s: %s\n",
132 xfer, uri_string, strerror ( rc ) );
133 goto err_open;
134 }
135
136 err_open:
137 uri_put ( uri );
138 err_uri:
139 return rc;
140}
141
142/** PeerDist retrieval protocol using HTTP POST */
144 .name = "POST",
145 .open = peerdist_open_post,
146};
147
148/**
149 * Open retrieval protocol connection using HTTP GET or local file
150 *
151 * @v xfer Data transfer interface
152 * @v location Peer location
153 * @v digestsize Digest size
154 * @v id Segment identifier
155 * @v block Block index
156 * @ret rc Return status code
157 */
158static int peerdist_open_get ( struct interface *xfer, const char *location,
159 size_t digestsize, const uint8_t *id,
160 unsigned int block ) {
161 char uri_string[ strlen ( location ) + 4 /* "/xx/" */ +
162 ( 2 * PEERDIST_DIGEST_MAX_SIZE ) + 1 /* "-" */ +
163 10 /* block number */ + 4 /* ".blk" */ +
164 1 /* NUL */ ];
165 size_t len;
166 int rc;
167
168 /* Construct URI string */
170 len = snprintf ( uri_string, sizeof ( uri_string ), "%s/%02x/",
171 location, id[0] );
172 assert ( len < sizeof ( uri_string ) );
173 len += base16_encode ( id, digestsize, ( uri_string + len ),
174 ( sizeof ( uri_string ) - len ) );
175 assert ( len < sizeof ( uri_string ) );
176 snprintf ( ( uri_string + len ), ( sizeof ( uri_string ) - len ),
177 "-%d.blk", block );
178
179 /* Open URI */
180 if ( ( rc = xfer_open_uri_string ( xfer, uri_string ) ) != 0 ) {
181 DBGC ( xfer, "PCCRR %p could not open %s: %s\n",
182 xfer, uri_string, strerror ( rc ) );
183 return rc;
184 }
185
186 return 0;
187}
188
189/** PeerDist retrieval protocol using HTTP GET or local file */
191 .name = "GET",
192 .open = peerdist_open_get,
193};
#define NULL
NULL pointer (VOID *).
Definition Base.h:321
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned char uint8_t
Definition stdint.h:10
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
Base16 encoding.
ring len
Length.
Definition dwmac.h:226
Error codes.
#define DBGC(...)
Definition compiler.h:530
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define ENOMEM
Not enough space.
Definition errno.h:578
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:951
Hyper Text Transport Protocol.
int http_open(struct interface *xfer, struct http_method *method, struct uri *uri, struct http_request_range *range, struct http_request_content *content)
Open HTTP transaction.
Definition httpcore.c:665
#define htonl(value)
Definition byteswap.h:134
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
uint8_t block[3][8]
DES-encrypted blocks.
Definition mschapv2.h:1
int xfer_open_uri_string(struct interface *intf, const char *uri_string)
Open URI string.
Definition open.c:125
Data transfer interface opening.
Peer Content Caching and Retrieval: Content Identification [MS-PCCRC].
#define PEERDIST_DIGEST_MAX_SIZE
Maximum digest size for any supported algorithm.
Definition pccrc.h:298
struct peerdist_retrieval peerdist_get
PeerDist retrieval protocol using HTTP GET or local file.
Definition pccrr.c:190
static int peerdist_open_get(struct interface *xfer, const char *location, size_t digestsize, const uint8_t *id, unsigned int block)
Open retrieval protocol connection using HTTP GET or local file.
Definition pccrr.c:158
struct peerdist_retrieval peerdist_post
PeerDist retrieval protocol using HTTP POST.
Definition pccrr.c:143
static int peerdist_open_post(struct interface *xfer, const char *location, size_t digestsize, const uint8_t *id, unsigned int block)
Open retrieval protocol connection using HTTP POST.
Definition pccrr.c:90
Peer Content Caching and Retrieval: Retrieval Protocol [MS-PCCRR].
#define peerdist_msg_getblks_t(digestsize, count, vrf_len)
Retrieval protocol block fetch request.
Definition pccrr.h:268
#define PEERDIST_MAGIC_PATH
Magic retrieval URI path.
Definition pccrr.h:20
#define PEERDIST_MSG_GETBLKS_VERSION
Retrieval protocol block fetch request version.
Definition pccrr.h:277
@ PEERDIST_MSG_AES_128_CBC
AES-128 in CBC mode.
Definition pccrr.h:174
#define PEERDIST_MSG_GETBLKS_TYPE
Retrieval protocol block fetch request type.
Definition pccrr.h:280
uint32_t digestsize
Digest size (i.e.
Definition pccrr.h:1
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
size_t strlen(const char *src)
Get length of string.
Definition string.c:244
HTTP request content descriptor.
Definition http.h:151
size_t len
Content length.
Definition http.h:157
const void * data
Content data (if any).
Definition http.h:155
An object interface.
Definition interface.h:125
A retrieval protocol mechanism.
Definition pccrr.h:356
A Uniform Resource Identifier.
Definition uri.h:65
struct uri * parse_uri(const char *uri_string)
Parse URI.
Definition uri.c:297
Uniform Resource Identifiers.
static void uri_put(struct uri *uri)
Decrement URI reference count.
Definition uri.h:206
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383