1 /*
2  * Copyright (C) 2015 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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 /** @file
27  *
28  * Peer Content Caching and Retrieval: Content Identification [MS-PCCRC] tests
29  *
30  */
31 
32 /* Forcibly enable assertions */
33 #undef NDEBUG
34 
35 #include <stdint.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <ipxe/uaccess.h>
39 #include <ipxe/pccrc.h>
40 #include <ipxe/sha256.h>
41 #include <ipxe/sha512.h>
42 #include <ipxe/hmac.h>
43 #include <ipxe/test.h>
44 
45 /** Define inline raw data */
46 #define DATA(...) { __VA_ARGS__ }
47 
48 /**
49  * Define an inline content range
50  *
51  * @v START		Start offset
52  * @v END		End offset
53  * @ret range		Content range
54  */
55 #define RANGE( START, END ) { .start = START, .end = END }
56 
57 /**
58  * Define an inline trimmed content range
59  *
60  * @v START		Start offset
61  * @v END		End offset
62  * @ret trim		Trimmed content range
63  */
64 #define TRIM( START, END ) { .start = START, .end = END }
65 
66 /** A content information test */
67 struct peerdist_info_test {
68 	/** Raw content information */
69 	const void *data;
70 	/** Length of raw content information */
71 	size_t len;
72 	/** Expected digest algorithm */
73 	struct digest_algorithm *expected_digest;
74 	/** Expected digest size */
75 	size_t expected_digestsize;
76 	/** Expected content range */
77 	struct peerdist_range expected_range;
78 	/** Expected trimmed content range */
79 	struct peerdist_range expected_trim;
80 	/** Expected number of segments */
81 	unsigned int expected_segments;
82 };
83 
84 /**
85  * Define a content information test
86  *
87  * @v name		Test name
88  * @v DATA		Raw content information
89  * @v DIGEST		Expected digest algorithm
90  * @v DIGESTSIZE	Expected digest size
91  * @v RANGE		Expected content range
92  * @v TRIM		Expected trimmer content range
93  * @v SEGMENTS		Expected number of segments
94  * @ret test		Content information test
95  *
96  * Raw content information can be obtained from PeerDist-capable web
97  * servers using wget's "--header" option to inject the relevant
98  * PeerDist headers.  For example:
99  *
100  *   wget --header "Accept-Encoding: peerdist" \
101  *        --header "X-P2P-PeerDist: Version=1.0" \
102  *	  http://peerdist.server.address/test.url -O - | xxd -i -c 11
103  *
104  * Version 1 content information can be retrieved using the headers:
105  *
106  *   Accept-Encoding: peerdist
107  *   X-P2P-PeerDist: Version=1.0
108  *
109  * Version 2 content information can be retrieved (from compatible
110  * servers) using the headers:
111  *
112  *   Accept-Encoding: peerdist
113  *   X-P2P-PeerDist: Version=1.1
114  *   X-P2P-PeerDistEx: MinContentInformation=2.0, MaxContentInformation=2.0
115  */
116 #define PEERDIST_INFO_TEST( name, DATA, DIGEST, DIGESTSIZE, RANGE,	\
117 			    TRIM, SEGMENTS )				\
118 	static const uint8_t name ## _data[] = DATA;			\
119 	static struct peerdist_info_test name = {			\
120 		.data = name ## _data,					\
121 		.len = sizeof ( name ## _data ),			\
122 		.expected_digest = DIGEST,				\
123 		.expected_digestsize = DIGESTSIZE,			\
124 		.expected_range = RANGE,				\
125 		.expected_trim = TRIM,					\
126 		.expected_segments = SEGMENTS,				\
127 	}
128 
129 /** A content information segment test */
130 struct peerdist_info_segment_test {
131 	/** Segment index */
132 	unsigned int index;
133 	/** Expected content range */
134 	struct peerdist_range expected_range;
135 	/** Expected number of blocks */
136 	unsigned int expected_blocks;
137 	/** Expected block size */
138 	size_t expected_blksize;
139 	/** Expected segment hash of data */
140 	uint8_t expected_hash[PEERDIST_DIGEST_MAX_SIZE];
141 	/** Expected segment secret */
142 	uint8_t expected_secret[PEERDIST_DIGEST_MAX_SIZE];
143 	/** Expected segment identifier */
144 	uint8_t expected_id[PEERDIST_DIGEST_MAX_SIZE];
145 };
146 
147 /**
148  * Define a content information segment test
149  *
150  * @v name		Test name
151  * @v INDEX		Segment index
152  * @v RANGE		Expected content range
153  * @v BLOCKS		Expected number of blocks
154  * @v BLKSIZE		Expected block size
155  * @v HASH		Expected segment hash of data
156  * @v SECRET		Expected segment secret
157  * @v ID		Expected segment identifier
158  * @ret test		Content information segment test
159  */
160 #define PEERDIST_INFO_SEGMENT_TEST( name, INDEX, RANGE, BLOCKS,		\
161 				    BLKSIZE, HASH, SECRET, ID )		\
162 	static struct peerdist_info_segment_test name = {		\
163 		.index = INDEX,						\
164 		.expected_range = RANGE,				\
165 		.expected_blocks = BLOCKS,				\
166 		.expected_blksize = BLKSIZE,				\
167 		.expected_hash = HASH,					\
168 		.expected_secret = SECRET,				\
169 		.expected_id = ID,					\
170 	}
171 
172 /** A content information block test */
173 struct peerdist_info_block_test {
174 	/** Block index */
175 	unsigned int index;
176 	/** Expected content range */
177 	struct peerdist_range expected_range;
178 	/** Expected trimmed content range */
179 	struct peerdist_range expected_trim;
180 	/** Expected hash of data */
181 	uint8_t expected_hash[PEERDIST_DIGEST_MAX_SIZE];
182 };
183 
184 /**
185  * Define a content information block test
186  *
187  * @v name		Test name
188  * @v INDEX		Block index
189  * @v RANGE		Expected content range
190  * @v TRIM		Expected trimmed content range
191  * @v HASH		Expected hash of data
192  * @ret test		Content information block test
193  */
194 #define PEERDIST_INFO_BLOCK_TEST( name, INDEX, RANGE, TRIM, HASH )	\
195 	static struct peerdist_info_block_test name = {			\
196 		.index = INDEX,						\
197 		.expected_range = RANGE,				\
198 		.expected_trim = TRIM,					\
199 		.expected_hash = HASH,					\
200 	}
201 
202 /**
203  * Define a server passphrase
204  *
205  * @v name		Server passphrase name
206  * @v DATA		Raw server passphrase
207  *
208  * The server passphrase can be exported from a Windows BranchCache
209  * server using the command:
210  *
211  *   netsh branchcache exportkey exported.key somepassword
212  *
213  * and this encrypted exported key can be decrypted using the
214  * oSSL_key_dx or mcrypt_key_dx utilities found in the (prototype)
215  * Prequel project at https://fedorahosted.org/prequel/ :
216  *
217  *   oSSL_key_dx exported.key somepassword
218  *     or
219  *   mcrypt_key_dx exported.key somepassword
220  *
221  * Either command will display both the server passphrase and the
222  * "Server Secret".  Note that this latter is the version 1 server
223  * secret (i.e. the SHA-256 of the server passphrase); the
224  * corresponding version 2 server secret can be obtained by
225  * calculating the truncated SHA-512 of the server passphrase.
226  *
227  * We do not know the server passphrase during normal operation.  We
228  * use it in the self-tests only to check for typos and other errors
229  * in the test vectors, by checking that the segment secret defined in
230  * a content information segment test is as expected.
231  */
232 #define SERVER_PASSPHRASE( name, DATA )					\
233 	static uint8_t name[] = DATA
234 
235 /** Server passphrase used for these test vectors */
236 SERVER_PASSPHRASE ( passphrase,
237       DATA ( 0x2a, 0x3d, 0x73, 0xeb, 0x43, 0x5e, 0x9f, 0x2b, 0x8a, 0x34, 0x42,
238 	     0x67, 0xe7, 0x46, 0x7a, 0x3c, 0x73, 0x85, 0xc6, 0xe0, 0x55, 0xe2,
239 	     0xb4, 0xd3, 0x0d, 0xfe, 0xc7, 0xc3, 0x8b, 0x0e, 0xd7, 0x2c ) );
240 
241 /** IIS logo (iis-85.png) content information version 1 */
242 PEERDIST_INFO_TEST ( iis_85_png_v1,
243 	DATA ( 0x00, 0x01, 0x0c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 	       0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 	       0x00, 0x00, 0x00, 0x00, 0x7e, 0x85, 0x01, 0x00, 0x00, 0x00, 0x01,
246 	       0x00, 0xd8, 0xd9, 0x76, 0x35, 0x4a, 0x48, 0x72, 0xe9, 0x25, 0x76,
247 	       0x18, 0x03, 0xf4, 0x58, 0xd9, 0xda, 0xaa, 0x67, 0xf8, 0xe3, 0x1c,
248 	       0x63, 0x0f, 0xb7, 0x4e, 0x6a, 0x31, 0x2e, 0xf8, 0xa2, 0x5a, 0xba,
249 	       0x11, 0xaf, 0xc0, 0xd7, 0x94, 0x92, 0x43, 0xf9, 0x4f, 0x9c, 0x1f,
250 	       0xab, 0x35, 0xd9, 0xfd, 0x1e, 0x33, 0x1f, 0xcf, 0x78, 0x11, 0xa2,
251 	       0xe0, 0x1d, 0x35, 0x87, 0xb3, 0x8d, 0x77, 0x0a, 0x29, 0xe2, 0x02,
252 	       0x00, 0x00, 0x00, 0x73, 0xc1, 0x8a, 0xb8, 0x54, 0x91, 0x10, 0xf8,
253 	       0xe9, 0x0e, 0x71, 0xbb, 0xc3, 0xab, 0x2a, 0xa8, 0xc4, 0x4d, 0x13,
254 	       0xf4, 0x92, 0x94, 0x99, 0x25, 0x5b, 0x66, 0x0f, 0x24, 0xec, 0x77,
255 	       0x80, 0x0b, 0x97, 0x4b, 0xdd, 0x65, 0x56, 0x7f, 0xde, 0xec, 0xcd,
256 	       0xaf, 0xe4, 0x57, 0xa9, 0x50, 0x3b, 0x45, 0x48, 0xf6, 0x6e, 0xd3,
257 	       0xb1, 0x88, 0xdc, 0xfd, 0xa0, 0xac, 0x38, 0x2b, 0x09, 0x71, 0x1a,
258 	       0xcc ),
259 	&sha256_algorithm, 32, RANGE ( 0, 99710 ), TRIM ( 0, 99710 ), 1 );
260 
261 /** IIS logo (iis-85.png) content information version 1 segment 0 */
262 PEERDIST_INFO_SEGMENT_TEST ( iis_85_png_v1_s0, 0,
263 	RANGE ( 0, 99710 ), 2, 65536,
264 	DATA ( 0xd8, 0xd9, 0x76, 0x35, 0x4a, 0x48, 0x72, 0xe9, 0x25, 0x76, 0x18,
265 	       0x03, 0xf4, 0x58, 0xd9, 0xda, 0xaa, 0x67, 0xf8, 0xe3, 0x1c, 0x63,
266 	       0x0f, 0xb7, 0x4e, 0x6a, 0x31, 0x2e, 0xf8, 0xa2, 0x5a, 0xba ),
267 	DATA ( 0x11, 0xaf, 0xc0, 0xd7, 0x94, 0x92, 0x43, 0xf9, 0x4f, 0x9c, 0x1f,
268 	       0xab, 0x35, 0xd9, 0xfd, 0x1e, 0x33, 0x1f, 0xcf, 0x78, 0x11, 0xa2,
269 	       0xe0, 0x1d, 0x35, 0x87, 0xb3, 0x8d, 0x77, 0x0a, 0x29, 0xe2 ),
270 	DATA ( 0x49, 0x1b, 0x21, 0x7d, 0xbe, 0xe2, 0xb5, 0xf1, 0x2c, 0xa7, 0x9b,
271 	       0x01, 0x5e, 0x06, 0xf4, 0xbb, 0xe6, 0x4f, 0x97, 0x45, 0xba, 0xd7,
272 	       0x86, 0x7a, 0xef, 0x17, 0xde, 0x59, 0x92, 0x7e, 0xdc, 0xe9 ) );
273 
274 /** IIS logo (iis-85.png) content information version 1 segment 0 block 0 */
275 PEERDIST_INFO_BLOCK_TEST ( iis_85_png_v1_s0_b0, 0,
276 	RANGE ( 0, 65536 ),
277 	TRIM ( 0, 65536 ),
278 	DATA ( 0x73, 0xc1, 0x8a, 0xb8, 0x54, 0x91, 0x10, 0xf8, 0xe9, 0x0e, 0x71,
279 	       0xbb, 0xc3, 0xab, 0x2a, 0xa8, 0xc4, 0x4d, 0x13, 0xf4, 0x92, 0x94,
280 	       0x99, 0x25, 0x5b, 0x66, 0x0f, 0x24, 0xec, 0x77, 0x80, 0x0b ) );
281 
282 /** IIS logo (iis-85.png) content information version 1 segment 0 block 1 */
283 PEERDIST_INFO_BLOCK_TEST ( iis_85_png_v1_s0_b1, 1,
284 	RANGE ( 65536, 99710 ),
285 	TRIM ( 65536, 99710 ),
286 	DATA ( 0x97, 0x4b, 0xdd, 0x65, 0x56, 0x7f, 0xde, 0xec, 0xcd, 0xaf, 0xe4,
287 	       0x57, 0xa9, 0x50, 0x3b, 0x45, 0x48, 0xf6, 0x6e, 0xd3, 0xb1, 0x88,
288 	       0xdc, 0xfd, 0xa0, 0xac, 0x38, 0x2b, 0x09, 0x71, 0x1a, 0xcc ) );
289 
290 /** IIS logo (iis-85.png) content information version 2 */
291 PEERDIST_INFO_TEST ( iis_85_png_v2,
292 	DATA ( 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 	       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 	       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 	       0x00, 0x00, 0x88, 0x00, 0x00, 0x99, 0xde, 0xe0, 0xd0, 0xc3, 0x58,
296 	       0xe2, 0x68, 0x4b, 0x62, 0x33, 0x0d, 0x32, 0xb5, 0xf1, 0x97, 0x87,
297 	       0x24, 0xa0, 0xd0, 0xa5, 0x2b, 0xdc, 0x5e, 0x78, 0x1f, 0xae, 0x71,
298 	       0xff, 0x57, 0xa8, 0xbe, 0x3d, 0xd4, 0x58, 0x03, 0x7e, 0xd4, 0x04,
299 	       0x11, 0x6b, 0xb6, 0x16, 0xd9, 0xb1, 0x41, 0x16, 0x08, 0x85, 0x20,
300 	       0xc4, 0x7c, 0xdc, 0x50, 0xab, 0xce, 0xa3, 0xfa, 0xe1, 0x88, 0xa9,
301 	       0x8e, 0xa2, 0x2d, 0xf3, 0xc0, 0x00, 0x00, 0xeb, 0xa0, 0x33, 0x81,
302 	       0xd0, 0xd0, 0xcb, 0x74, 0xf4, 0xb6, 0x13, 0xd8, 0x21, 0x0f, 0x37,
303 	       0xf0, 0x02, 0xa0, 0x6f, 0x39, 0x10, 0x58, 0x60, 0x96, 0xa1, 0x30,
304 	       0xd3, 0x43, 0x98, 0xc0, 0x8e, 0x66, 0xd7, 0xbc, 0xb8, 0xb6, 0xeb,
305 	       0x77, 0x83, 0xe4, 0xf8, 0x07, 0x64, 0x7b, 0x63, 0xf1, 0x46, 0xb5,
306 	       0x2f, 0x4a, 0xc8, 0x9c, 0xcc, 0x7a, 0xbf, 0x5f, 0xa1, 0x1a, 0xca,
307 	       0xfc, 0x2a, 0xcf, 0x50, 0x28, 0x58, 0x6c ),
308 	&sha512_algorithm, 32, RANGE ( 0, 99710 ), TRIM ( 0, 99710 ), 2 );
309 
310 /** IIS logo (iis-85.png) content information version 2 segment 0 */
311 PEERDIST_INFO_SEGMENT_TEST ( iis_85_png_v2_s0, 0,
312 	RANGE ( 0, 39390 ), 1, 39390,
313 	DATA ( 0xe0, 0xd0, 0xc3, 0x58, 0xe2, 0x68, 0x4b, 0x62, 0x33, 0x0d, 0x32,
314 	       0xb5, 0xf1, 0x97, 0x87, 0x24, 0xa0, 0xd0, 0xa5, 0x2b, 0xdc, 0x5e,
315 	       0x78, 0x1f, 0xae, 0x71, 0xff, 0x57, 0xa8, 0xbe, 0x3d, 0xd4 ),
316 	DATA ( 0x58, 0x03, 0x7e, 0xd4, 0x04, 0x11, 0x6b, 0xb6, 0x16, 0xd9, 0xb1,
317 	       0x41, 0x16, 0x08, 0x85, 0x20, 0xc4, 0x7c, 0xdc, 0x50, 0xab, 0xce,
318 	       0xa3, 0xfa, 0xe1, 0x88, 0xa9, 0x8e, 0xa2, 0x2d, 0xf3, 0xc0 ),
319 	DATA ( 0x33, 0x71, 0xbb, 0xea, 0xdd, 0xb6, 0x23, 0x53, 0xad, 0xce, 0xf9,
320 	       0x70, 0xa0, 0x6f, 0xdf, 0x65, 0x00, 0x1e, 0x04, 0x21, 0xf4, 0xc7,
321 	       0x10, 0x82, 0x76, 0xb0, 0xc3, 0x7a, 0x9f, 0x9e, 0xc1, 0x0f ) );
322 
323 /** IIS logo (iis-85.png) content information version 2 segment 0 block 0 */
324 PEERDIST_INFO_BLOCK_TEST ( iis_85_png_v2_s0_b0, 0,
325 	RANGE ( 0, 39390 ),
326 	TRIM ( 0, 39390 ),
327 	DATA ( 0xe0, 0xd0, 0xc3, 0x58, 0xe2, 0x68, 0x4b, 0x62, 0x33, 0x0d, 0x32,
328 	       0xb5, 0xf1, 0x97, 0x87, 0x24, 0xa0, 0xd0, 0xa5, 0x2b, 0xdc, 0x5e,
329 	       0x78, 0x1f, 0xae, 0x71, 0xff, 0x57, 0xa8, 0xbe, 0x3d, 0xd4 ) );
330 
331 /** IIS logo (iis-85.png) content information version 2 segment 1 */
332 PEERDIST_INFO_SEGMENT_TEST ( iis_85_png_v2_s1, 1,
333 	RANGE ( 39390, 99710 ), 1, 60320,
334 	DATA ( 0x33, 0x81, 0xd0, 0xd0, 0xcb, 0x74, 0xf4, 0xb6, 0x13, 0xd8, 0x21,
335 	       0x0f, 0x37, 0xf0, 0x02, 0xa0, 0x6f, 0x39, 0x10, 0x58, 0x60, 0x96,
336 	       0xa1, 0x30, 0xd3, 0x43, 0x98, 0xc0, 0x8e, 0x66, 0xd7, 0xbc ),
337 	DATA ( 0xb8, 0xb6, 0xeb, 0x77, 0x83, 0xe4, 0xf8, 0x07, 0x64, 0x7b, 0x63,
338 	       0xf1, 0x46, 0xb5, 0x2f, 0x4a, 0xc8, 0x9c, 0xcc, 0x7a, 0xbf, 0x5f,
339 	       0xa1, 0x1a, 0xca, 0xfc, 0x2a, 0xcf, 0x50, 0x28, 0x58, 0x6c ),
340 	DATA ( 0xd7, 0xe9, 0x24, 0x42, 0x5e, 0x8f, 0x4f, 0x88, 0xf0, 0x1d, 0xc6,
341 	       0xa9, 0xbb, 0x1b, 0xc3, 0x7b, 0xe1, 0x13, 0xec, 0x79, 0x17, 0xc7,
342 	       0x45, 0xd4, 0x96, 0x5c, 0x2b, 0x55, 0xfa, 0x16, 0x3a, 0x6e ) );
343 
344 /** IIS logo (iis-85.png) content information version 2 segment 1 block 0 */
345 PEERDIST_INFO_BLOCK_TEST ( iis_85_png_v2_s1_b0, 0,
346 	RANGE ( 39390, 99710 ),
347 	TRIM ( 39390, 99710 ),
348 	DATA ( 0x33, 0x81, 0xd0, 0xd0, 0xcb, 0x74, 0xf4, 0xb6, 0x13, 0xd8, 0x21,
349 	       0x0f, 0x37, 0xf0, 0x02, 0xa0, 0x6f, 0x39, 0x10, 0x58, 0x60, 0x96,
350 	       0xa1, 0x30, 0xd3, 0x43, 0x98, 0xc0, 0x8e, 0x66, 0xd7, 0xbc ) );
351 
352 /**
353  * Report content information test result
354  *
355  * @v test		Content information test
356  * @v info		Content information to fill in
357  * @v file		Test code file
358  * @v line		Test code line
359  */
peerdist_info_okx(struct peerdist_info_test * test,struct peerdist_info * info,const char * file,unsigned int line)360 static void peerdist_info_okx ( struct peerdist_info_test *test,
361 				struct peerdist_info *info,
362 				const char *file, unsigned int line ) {
363 
364 	/* Parse content information */
365 	okx ( peerdist_info ( virt_to_user ( test->data ), test->len,
366 			      info ) == 0, file, line );
367 
368 	/* Verify content information */
369 	okx ( info->raw.data == virt_to_user ( test->data ), file, line );
370 	okx ( info->raw.len == test->len, file, line );
371 	okx ( info->digest == test->expected_digest, file, line );
372 	okx ( info->digestsize == test->expected_digestsize, file, line );
373 	okx ( info->range.start == test->expected_range.start, file, line );
374 	okx ( info->range.end == test->expected_range.end, file, line );
375 	okx ( info->trim.start == test->expected_trim.start, file, line );
376 	okx ( info->trim.end == test->expected_trim.end, file, line );
377 	okx ( info->trim.start >= info->range.start, file, line );
378 	okx ( info->trim.end <= info->range.end, file, line );
379 	okx ( info->segments == test->expected_segments, file, line );
380 }
381 #define peerdist_info_ok( test, info ) \
382 	peerdist_info_okx ( test, info, __FILE__, __LINE__ )
383 
384 /**
385  * Report content information segment test result
386  *
387  * @v test		Content information segment test
388  * @v info		Content information
389  * @v segment		Segment information to fill in
390  * @v file		Test code file
391  * @v line		Test code line
392  */
peerdist_info_segment_okx(struct peerdist_info_segment_test * test,const struct peerdist_info * info,struct peerdist_info_segment * segment,const char * file,unsigned int line)393 static void peerdist_info_segment_okx ( struct peerdist_info_segment_test *test,
394 					const struct peerdist_info *info,
395 					struct peerdist_info_segment *segment,
396 					const char *file, unsigned int line ) {
397 	size_t digestsize = info->digestsize;
398 
399 	/* Parse content information segment */
400 	okx ( peerdist_info_segment ( info, segment, test->index ) == 0,
401 	      file, line );
402 
403 	/* Verify content information segment */
404 	okx ( segment->info == info, file, line );
405 	okx ( segment->index == test->index, file, line );
406 	okx ( segment->range.start == test->expected_range.start, file, line );
407 	okx ( segment->range.end == test->expected_range.end, file, line );
408 	okx ( segment->blocks == test->expected_blocks, file, line );
409 	okx ( segment->blksize == test->expected_blksize, file, line );
410 	okx ( memcmp ( segment->hash, test->expected_hash,
411 		       digestsize ) == 0, file, line );
412 	okx ( memcmp ( segment->secret, test->expected_secret,
413 		       digestsize ) == 0, file, line );
414 	okx ( memcmp ( segment->id, test->expected_id,
415 		       digestsize ) == 0, file, line );
416 }
417 #define peerdist_info_segment_ok( test, info, segment ) \
418 	peerdist_info_segment_okx ( test, info, segment, __FILE__, __LINE__ )
419 
420 /**
421  * Report content information block test result
422  *
423  * @v test		Content information block test
424  * @v segment		Segment information
425  * @v block		Block information to fill in
426  * @v file		Test code file
427  * @v line		Test code line
428  */
429 static void
peerdist_info_block_okx(struct peerdist_info_block_test * test,const struct peerdist_info_segment * segment,struct peerdist_info_block * block,const char * file,unsigned int line)430 peerdist_info_block_okx ( struct peerdist_info_block_test *test,
431 			  const struct peerdist_info_segment *segment,
432 			  struct peerdist_info_block *block,
433 			  const char *file, unsigned int line ) {
434 	const struct peerdist_info *info = segment->info;
435 	size_t digestsize = info->digestsize;
436 
437 	/* Parse content information block */
438 	okx ( peerdist_info_block ( segment, block, test->index ) == 0,
439 	      file, line );
440 
441 	/* Verify content information block */
442 	okx ( block->segment == segment, file, line );
443 	okx ( block->index == test->index, file, line );
444 	okx ( block->range.start == test->expected_range.start, file, line );
445 	okx ( block->range.end == test->expected_range.end, file, line );
446 	okx ( block->trim.start == test->expected_trim.start, file, line );
447 	okx ( block->trim.end == test->expected_trim.end, file, line );
448 	okx ( memcmp ( block->hash, test->expected_hash,
449 		       digestsize ) == 0, file, line );
450 }
451 #define peerdist_info_block_ok( test, segment, block ) \
452 	peerdist_info_block_okx ( test, segment, block, __FILE__, __LINE__ )
453 
454 /**
455  * Report server passphrase test result
456  *
457  * @v test		Content information segment test
458  * @v info		Content information
459  * @v pass		Server passphrase
460  * @v pass_len		Length of server passphrase
461  * @v file		Test code file
462  * @v line		Test code line
463  */
464 static void
peerdist_info_passphrase_okx(struct peerdist_info_segment_test * test,const struct peerdist_info * info,uint8_t * pass,size_t pass_len,const char * file,unsigned int line)465 peerdist_info_passphrase_okx ( struct peerdist_info_segment_test *test,
466 			       const struct peerdist_info *info,
467 			       uint8_t *pass, size_t pass_len,
468 			       const char *file, unsigned int line ) {
469 	struct digest_algorithm *digest = info->digest;
470 	uint8_t ctx[digest->ctxsize];
471 	uint8_t secret[digest->digestsize];
472 	uint8_t expected[digest->digestsize];
473 	size_t digestsize = info->digestsize;
474 	size_t secretsize = digestsize;
475 
476 	/* Calculate server secret */
477 	digest_init ( digest, ctx );
478 	digest_update ( digest, ctx, pass, pass_len );
479 	digest_final ( digest, ctx, secret );
480 
481 	/* Calculate expected segment secret */
482 	hmac_init ( digest, ctx, secret, &secretsize );
483 	assert ( secretsize == digestsize );
484 	hmac_update ( digest, ctx, test->expected_hash, digestsize );
485 	hmac_final ( digest, ctx, secret, &secretsize, expected );
486 	assert ( secretsize == digestsize );
487 
488 	/* Verify segment secret */
489 	okx ( memcmp ( test->expected_secret, expected, digestsize ) == 0,
490 	      file, line );
491 }
492 #define peerdist_info_passphrase_ok( test, info, pass, pass_len )	\
493 	peerdist_info_passphrase_okx ( test, info, pass, pass_len,	\
494 				       __FILE__, __LINE__ )
495 
496 /**
497  * Perform content information self-tests
498  *
499  */
peerdist_info_test_exec(void)500 static void peerdist_info_test_exec ( void ) {
501 	struct peerdist_info info;
502 	struct peerdist_info_segment segment;
503 	struct peerdist_info_block block;
504 
505 	/* IIS logo (iis-85.png) content information version 1 */
506 	peerdist_info_ok ( &iis_85_png_v1, &info );
507 	peerdist_info_passphrase_ok ( &iis_85_png_v1_s0, &info,
508 				      passphrase, sizeof ( passphrase ) );
509 	peerdist_info_segment_ok ( &iis_85_png_v1_s0, &info, &segment );
510 	peerdist_info_block_ok ( &iis_85_png_v1_s0_b0, &segment, &block );
511 	peerdist_info_block_ok ( &iis_85_png_v1_s0_b1, &segment, &block );
512 
513 	/* IIS logo (iis-85.png) content information version 2 */
514 	peerdist_info_ok ( &iis_85_png_v2, &info );
515 	peerdist_info_passphrase_ok ( &iis_85_png_v2_s0, &info,
516 				      passphrase, sizeof ( passphrase ) );
517 	peerdist_info_segment_ok ( &iis_85_png_v2_s0, &info, &segment );
518 	peerdist_info_block_ok ( &iis_85_png_v2_s0_b0, &segment, &block );
519 	peerdist_info_passphrase_ok ( &iis_85_png_v2_s1, &info,
520 				      passphrase, sizeof ( passphrase ) );
521 	peerdist_info_segment_ok ( &iis_85_png_v2_s1, &info, &segment );
522 	peerdist_info_block_ok ( &iis_85_png_v2_s1_b0, &segment, &block );
523 }
524 
525 /** Content information self-test */
526 struct self_test peerdist_info_test __self_test = {
527 	.name = "pccrc",
528 	.exec = peerdist_info_test_exec,
529 };
530