1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2017-2018 Solarflare Communications Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * The views and conclusions contained in the software and documentation are
29 * those of the authors and should not be interpreted as representing official
30 * policies, either expressed or implied, of the FreeBSD Project.
31 */
32
33 #include <sys/cdefs.h>
34 #include "efx.h"
35 #include "efx_impl.h"
36
37 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
38
39 #if EFSYS_OPT_IMAGE_LAYOUT
40
41 /*
42 * Utility routines to support limited parsing of ASN.1 tags. This is not a
43 * general purpose ASN.1 parser, but is sufficient to locate the required
44 * objects in a signed image with CMS headers.
45 */
46
47 /* DER encodings for ASN.1 tags (see ITU-T X.690) */
48 #define ASN1_TAG_INTEGER (0x02)
49 #define ASN1_TAG_OCTET_STRING (0x04)
50 #define ASN1_TAG_OBJ_ID (0x06)
51 #define ASN1_TAG_SEQUENCE (0x30)
52 #define ASN1_TAG_SET (0x31)
53
54 #define ASN1_TAG_IS_PRIM(tag) ((tag & 0x20) == 0)
55
56 #define ASN1_TAG_PRIM_CONTEXT(n) (0x80 + (n))
57 #define ASN1_TAG_CONS_CONTEXT(n) (0xA0 + (n))
58
59 typedef struct efx_asn1_cursor_s {
60 uint8_t *buffer;
61 uint32_t length;
62
63 uint8_t tag;
64 uint32_t hdr_size;
65 uint32_t val_size;
66 } efx_asn1_cursor_t;
67
68 /* Parse header of DER encoded ASN.1 TLV and match tag */
69 static __checkReturn efx_rc_t
efx_asn1_parse_header_match_tag(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag)70 efx_asn1_parse_header_match_tag(
71 __inout efx_asn1_cursor_t *cursor,
72 __in uint8_t tag)
73 {
74 efx_rc_t rc;
75
76 if (cursor == NULL || cursor->buffer == NULL || cursor->length < 2) {
77 rc = EINVAL;
78 goto fail1;
79 }
80
81 cursor->tag = cursor->buffer[0];
82 if (cursor->tag != tag) {
83 /* Tag not matched */
84 rc = ENOENT;
85 goto fail2;
86 }
87
88 if ((cursor->tag & 0x1F) == 0x1F) {
89 /* Long tag format not used in CMS syntax */
90 rc = EINVAL;
91 goto fail3;
92 }
93
94 if ((cursor->buffer[1] & 0x80) == 0) {
95 /* Short form: length is 0..127 */
96 cursor->hdr_size = 2;
97 cursor->val_size = cursor->buffer[1];
98 } else {
99 /* Long form: length encoded as [0x80+nbytes][length bytes] */
100 uint32_t nbytes = cursor->buffer[1] & 0x7F;
101 uint32_t offset;
102
103 if (nbytes == 0) {
104 /* Indefinite length not allowed in DER encoding */
105 rc = EINVAL;
106 goto fail4;
107 }
108 if (2 + nbytes > cursor->length) {
109 /* Header length overflows image buffer */
110 rc = EINVAL;
111 goto fail6;
112 }
113 if (nbytes > sizeof (uint32_t)) {
114 /* Length encoding too big */
115 rc = E2BIG;
116 goto fail5;
117 }
118 cursor->hdr_size = 2 + nbytes;
119 cursor->val_size = 0;
120 for (offset = 2; offset < cursor->hdr_size; offset++) {
121 cursor->val_size =
122 (cursor->val_size << 8) | cursor->buffer[offset];
123 }
124 }
125
126 if ((cursor->hdr_size + cursor->val_size) > cursor->length) {
127 /* Length overflows image buffer */
128 rc = E2BIG;
129 goto fail7;
130 }
131
132 return (0);
133
134 fail7:
135 EFSYS_PROBE(fail7);
136 fail6:
137 EFSYS_PROBE(fail6);
138 fail5:
139 EFSYS_PROBE(fail5);
140 fail4:
141 EFSYS_PROBE(fail4);
142 fail3:
143 EFSYS_PROBE(fail3);
144 fail2:
145 EFSYS_PROBE(fail2);
146 fail1:
147 EFSYS_PROBE1(fail1, efx_rc_t, rc);
148
149 return (rc);
150 }
151
152 /* Enter nested ASN.1 TLV (contained in value of current TLV) */
153 static __checkReturn efx_rc_t
efx_asn1_enter_tag(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag)154 efx_asn1_enter_tag(
155 __inout efx_asn1_cursor_t *cursor,
156 __in uint8_t tag)
157 {
158 efx_rc_t rc;
159
160 if (cursor == NULL) {
161 rc = EINVAL;
162 goto fail1;
163 }
164
165 if (ASN1_TAG_IS_PRIM(tag)) {
166 /* Cannot enter a primitive tag */
167 rc = ENOTSUP;
168 goto fail2;
169 }
170 rc = efx_asn1_parse_header_match_tag(cursor, tag);
171 if (rc != 0) {
172 /* Invalid TLV or wrong tag */
173 goto fail3;
174 }
175
176 /* Limit cursor range to nested TLV */
177 cursor->buffer += cursor->hdr_size;
178 cursor->length = cursor->val_size;
179
180 return (0);
181
182 fail3:
183 EFSYS_PROBE(fail3);
184 fail2:
185 EFSYS_PROBE(fail2);
186 fail1:
187 EFSYS_PROBE1(fail1, efx_rc_t, rc);
188
189 return (rc);
190 }
191
192 /*
193 * Check that the current ASN.1 TLV matches the given tag and value.
194 * Advance cursor to next TLV on a successful match.
195 */
196 static __checkReturn efx_rc_t
efx_asn1_match_tag_value(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag,__in const void * valp,__in uint32_t val_size)197 efx_asn1_match_tag_value(
198 __inout efx_asn1_cursor_t *cursor,
199 __in uint8_t tag,
200 __in const void *valp,
201 __in uint32_t val_size)
202 {
203 efx_rc_t rc;
204
205 if (cursor == NULL) {
206 rc = EINVAL;
207 goto fail1;
208 }
209 rc = efx_asn1_parse_header_match_tag(cursor, tag);
210 if (rc != 0) {
211 /* Invalid TLV or wrong tag */
212 goto fail2;
213 }
214 if (cursor->val_size != val_size) {
215 /* Value size is different */
216 rc = EINVAL;
217 goto fail3;
218 }
219 if (memcmp(cursor->buffer + cursor->hdr_size, valp, val_size) != 0) {
220 /* Value content is different */
221 rc = EINVAL;
222 goto fail4;
223 }
224 cursor->buffer += cursor->hdr_size + cursor->val_size;
225 cursor->length -= cursor->hdr_size + cursor->val_size;
226
227 return (0);
228
229 fail4:
230 EFSYS_PROBE(fail4);
231 fail3:
232 EFSYS_PROBE(fail3);
233 fail2:
234 EFSYS_PROBE(fail2);
235 fail1:
236 EFSYS_PROBE1(fail1, efx_rc_t, rc);
237
238 return (rc);
239 }
240
241 /* Advance cursor to next TLV */
242 static __checkReturn efx_rc_t
efx_asn1_skip_tag(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag)243 efx_asn1_skip_tag(
244 __inout efx_asn1_cursor_t *cursor,
245 __in uint8_t tag)
246 {
247 efx_rc_t rc;
248
249 if (cursor == NULL) {
250 rc = EINVAL;
251 goto fail1;
252 }
253
254 rc = efx_asn1_parse_header_match_tag(cursor, tag);
255 if (rc != 0) {
256 /* Invalid TLV or wrong tag */
257 goto fail2;
258 }
259 cursor->buffer += cursor->hdr_size + cursor->val_size;
260 cursor->length -= cursor->hdr_size + cursor->val_size;
261
262 return (0);
263
264 fail2:
265 EFSYS_PROBE(fail2);
266 fail1:
267 EFSYS_PROBE1(fail1, efx_rc_t, rc);
268
269 return (rc);
270 }
271
272 /* Return pointer to value octets and value size from current TLV */
273 static __checkReturn efx_rc_t
efx_asn1_get_tag_value(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag,__out uint8_t ** valp,__out uint32_t * val_sizep)274 efx_asn1_get_tag_value(
275 __inout efx_asn1_cursor_t *cursor,
276 __in uint8_t tag,
277 __out uint8_t **valp,
278 __out uint32_t *val_sizep)
279 {
280 efx_rc_t rc;
281
282 if (cursor == NULL || valp == NULL || val_sizep == NULL) {
283 rc = EINVAL;
284 goto fail1;
285 }
286
287 rc = efx_asn1_parse_header_match_tag(cursor, tag);
288 if (rc != 0) {
289 /* Invalid TLV or wrong tag */
290 goto fail2;
291 }
292 *valp = cursor->buffer + cursor->hdr_size;
293 *val_sizep = cursor->val_size;
294
295 return (0);
296
297 fail2:
298 EFSYS_PROBE(fail2);
299 fail1:
300 EFSYS_PROBE1(fail1, efx_rc_t, rc);
301
302 return (rc);
303 }
304
305 /*
306 * Utility routines for parsing CMS headers (see RFC2315, PKCS#7)
307 */
308
309 /* OID 1.2.840.113549.1.7.2 */
310 static const uint8_t PKCS7_SignedData[] =
311 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };
312
313 /* OID 1.2.840.113549.1.7.1 */
314 static const uint8_t PKCS7_Data[] =
315 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
316
317 /* SignedData structure version */
318 static const uint8_t SignedData_Version[] =
319 { 0x03 };
320
321 /*
322 * Check for a valid image in signed image format. This uses CMS syntax
323 * (see RFC2315, PKCS#7) to provide signatures, and certificates required
324 * to validate the signatures. The encapsulated content is in unsigned image
325 * format (reflash header, image code, trailer checksum).
326 */
327 static __checkReturn efx_rc_t
efx_check_signed_image_header(__in void * bufferp,__in uint32_t buffer_size,__out uint32_t * content_offsetp,__out uint32_t * content_lengthp)328 efx_check_signed_image_header(
329 __in void *bufferp,
330 __in uint32_t buffer_size,
331 __out uint32_t *content_offsetp,
332 __out uint32_t *content_lengthp)
333 {
334 efx_asn1_cursor_t cursor;
335 uint8_t *valp;
336 uint32_t val_size;
337 efx_rc_t rc;
338
339 if (content_offsetp == NULL || content_lengthp == NULL) {
340 rc = EINVAL;
341 goto fail1;
342 }
343 cursor.buffer = (uint8_t *)bufferp;
344 cursor.length = buffer_size;
345
346 /* ContextInfo */
347 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
348 if (rc != 0)
349 goto fail2;
350
351 /* ContextInfo.contentType */
352 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
353 PKCS7_SignedData, sizeof (PKCS7_SignedData));
354 if (rc != 0)
355 goto fail3;
356
357 /* ContextInfo.content */
358 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
359 if (rc != 0)
360 goto fail4;
361
362 /* SignedData */
363 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
364 if (rc != 0)
365 goto fail5;
366
367 /* SignedData.version */
368 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_INTEGER,
369 SignedData_Version, sizeof (SignedData_Version));
370 if (rc != 0)
371 goto fail6;
372
373 /* SignedData.digestAlgorithms */
374 rc = efx_asn1_skip_tag(&cursor, ASN1_TAG_SET);
375 if (rc != 0)
376 goto fail7;
377
378 /* SignedData.encapContentInfo */
379 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
380 if (rc != 0)
381 goto fail8;
382
383 /* SignedData.encapContentInfo.econtentType */
384 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
385 PKCS7_Data, sizeof (PKCS7_Data));
386 if (rc != 0)
387 goto fail9;
388
389 /* SignedData.encapContentInfo.econtent */
390 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
391 if (rc != 0)
392 goto fail10;
393
394 /*
395 * The octet string contains the image header, image code bytes and
396 * image trailer CRC (same as unsigned image layout).
397 */
398 valp = NULL;
399 val_size = 0;
400 rc = efx_asn1_get_tag_value(&cursor, ASN1_TAG_OCTET_STRING,
401 &valp, &val_size);
402 if (rc != 0)
403 goto fail11;
404
405 if ((valp == NULL) || (val_size == 0)) {
406 rc = EINVAL;
407 goto fail12;
408 }
409 if (valp < (uint8_t *)bufferp) {
410 rc = EINVAL;
411 goto fail13;
412 }
413 if ((valp + val_size) > ((uint8_t *)bufferp + buffer_size)) {
414 rc = EINVAL;
415 goto fail14;
416 }
417
418 *content_offsetp = (uint32_t)(valp - (uint8_t *)bufferp);
419 *content_lengthp = val_size;
420
421 return (0);
422
423 fail14:
424 EFSYS_PROBE(fail14);
425 fail13:
426 EFSYS_PROBE(fail13);
427 fail12:
428 EFSYS_PROBE(fail12);
429 fail11:
430 EFSYS_PROBE(fail11);
431 fail10:
432 EFSYS_PROBE(fail10);
433 fail9:
434 EFSYS_PROBE(fail9);
435 fail8:
436 EFSYS_PROBE(fail8);
437 fail7:
438 EFSYS_PROBE(fail7);
439 fail6:
440 EFSYS_PROBE(fail6);
441 fail5:
442 EFSYS_PROBE(fail5);
443 fail4:
444 EFSYS_PROBE(fail4);
445 fail3:
446 EFSYS_PROBE(fail3);
447 fail2:
448 EFSYS_PROBE(fail2);
449 fail1:
450 EFSYS_PROBE1(fail1, efx_rc_t, rc);
451
452 return (rc);
453 }
454
455 static __checkReturn efx_rc_t
efx_check_unsigned_image(__in void * bufferp,__in uint32_t buffer_size)456 efx_check_unsigned_image(
457 __in void *bufferp,
458 __in uint32_t buffer_size)
459 {
460 efx_image_header_t *header;
461 efx_image_trailer_t *trailer;
462 uint32_t crc;
463 efx_rc_t rc;
464
465 EFX_STATIC_ASSERT(sizeof (*header) == EFX_IMAGE_HEADER_SIZE);
466 EFX_STATIC_ASSERT(sizeof (*trailer) == EFX_IMAGE_TRAILER_SIZE);
467
468 /* Must have at least enough space for required image header fields */
469 if (buffer_size < (EFX_FIELD_OFFSET(efx_image_header_t, eih_size) +
470 sizeof (header->eih_size))) {
471 rc = ENOSPC;
472 goto fail1;
473 }
474 header = (efx_image_header_t *)bufferp;
475
476 if (header->eih_magic != EFX_IMAGE_HEADER_MAGIC) {
477 rc = EINVAL;
478 goto fail2;
479 }
480
481 /*
482 * Check image header version is same or higher than lowest required
483 * version.
484 */
485 if (header->eih_version < EFX_IMAGE_HEADER_VERSION) {
486 rc = EINVAL;
487 goto fail3;
488 }
489
490 /* Buffer must have space for image header, code and image trailer. */
491 if (buffer_size < (header->eih_size + header->eih_code_size +
492 EFX_IMAGE_TRAILER_SIZE)) {
493 rc = ENOSPC;
494 goto fail4;
495 }
496
497 /* Check CRC from image buffer matches computed CRC. */
498 trailer = (efx_image_trailer_t *)((uint8_t *)header +
499 header->eih_size + header->eih_code_size);
500
501 crc = efx_crc32_calculate(0, (uint8_t *)header,
502 (header->eih_size + header->eih_code_size));
503
504 if (trailer->eit_crc != crc) {
505 rc = EINVAL;
506 goto fail5;
507 }
508
509 return (0);
510
511 fail5:
512 EFSYS_PROBE(fail5);
513 fail4:
514 EFSYS_PROBE(fail4);
515 fail3:
516 EFSYS_PROBE(fail3);
517 fail2:
518 EFSYS_PROBE(fail2);
519 fail1:
520 EFSYS_PROBE1(fail1, efx_rc_t, rc);
521
522 return (rc);
523 }
524
525 __checkReturn efx_rc_t
efx_check_reflash_image(__in void * bufferp,__in uint32_t buffer_size,__out efx_image_info_t * infop)526 efx_check_reflash_image(
527 __in void *bufferp,
528 __in uint32_t buffer_size,
529 __out efx_image_info_t *infop)
530 {
531 efx_image_format_t format = EFX_IMAGE_FORMAT_NO_IMAGE;
532 uint32_t image_offset;
533 uint32_t image_size;
534 void *imagep;
535 efx_rc_t rc;
536
537 EFSYS_ASSERT(infop != NULL);
538 if (infop == NULL) {
539 rc = EINVAL;
540 goto fail1;
541 }
542 memset(infop, 0, sizeof (*infop));
543
544 if (bufferp == NULL || buffer_size == 0) {
545 rc = EINVAL;
546 goto fail2;
547 }
548
549 /*
550 * Check if the buffer contains an image in signed format, and if so,
551 * locate the image header.
552 */
553 rc = efx_check_signed_image_header(bufferp, buffer_size,
554 &image_offset, &image_size);
555 if (rc == 0) {
556 /*
557 * Buffer holds signed image format. Check that the encapsulated
558 * content is in unsigned image format.
559 */
560 format = EFX_IMAGE_FORMAT_SIGNED;
561 } else {
562 /* Check if the buffer holds image in unsigned image format */
563 format = EFX_IMAGE_FORMAT_UNSIGNED;
564 image_offset = 0;
565 image_size = buffer_size;
566 }
567 if (image_offset + image_size > buffer_size) {
568 rc = E2BIG;
569 goto fail3;
570 }
571 imagep = (uint8_t *)bufferp + image_offset;
572
573 /* Check unsigned image layout (image header, code, image trailer) */
574 rc = efx_check_unsigned_image(imagep, image_size);
575 if (rc != 0)
576 goto fail4;
577
578 /* Return image details */
579 infop->eii_format = format;
580 infop->eii_imagep = bufferp;
581 infop->eii_image_size = buffer_size;
582 infop->eii_headerp = (efx_image_header_t *)imagep;
583
584 return (0);
585
586 fail4:
587 EFSYS_PROBE(fail4);
588 fail3:
589 EFSYS_PROBE(fail3);
590 fail2:
591 EFSYS_PROBE(fail2);
592 infop->eii_format = EFX_IMAGE_FORMAT_INVALID;
593 infop->eii_imagep = NULL;
594 infop->eii_image_size = 0;
595
596 fail1:
597 EFSYS_PROBE1(fail1, efx_rc_t, rc);
598
599 return (rc);
600 }
601
602 __checkReturn efx_rc_t
efx_build_signed_image_write_buffer(__out_bcount (buffer_size)uint8_t * bufferp,__in uint32_t buffer_size,__in efx_image_info_t * infop,__out efx_image_header_t ** headerpp)603 efx_build_signed_image_write_buffer(
604 __out_bcount(buffer_size)
605 uint8_t *bufferp,
606 __in uint32_t buffer_size,
607 __in efx_image_info_t *infop,
608 __out efx_image_header_t **headerpp)
609 {
610 signed_image_chunk_hdr_t chunk_hdr;
611 uint32_t hdr_offset;
612 struct {
613 uint32_t offset;
614 uint32_t size;
615 } cms_header, image_header, code, image_trailer, signature;
616 efx_rc_t rc;
617
618 EFSYS_ASSERT((infop != NULL) && (headerpp != NULL));
619
620 if ((bufferp == NULL) || (buffer_size == 0) ||
621 (infop == NULL) || (headerpp == NULL)) {
622 /* Invalid arguments */
623 rc = EINVAL;
624 goto fail1;
625 }
626 if ((infop->eii_format != EFX_IMAGE_FORMAT_SIGNED) ||
627 (infop->eii_imagep == NULL) ||
628 (infop->eii_headerp == NULL) ||
629 ((uint8_t *)infop->eii_headerp < (uint8_t *)infop->eii_imagep) ||
630 (infop->eii_image_size < EFX_IMAGE_HEADER_SIZE) ||
631 ((size_t)((uint8_t *)infop->eii_headerp - infop->eii_imagep) >
632 (infop->eii_image_size - EFX_IMAGE_HEADER_SIZE))) {
633 /* Invalid image info */
634 rc = EINVAL;
635 goto fail2;
636 }
637
638 /* Locate image chunks in original signed image */
639 cms_header.offset = 0;
640 cms_header.size =
641 (uint32_t)((uint8_t *)infop->eii_headerp - infop->eii_imagep);
642 if ((cms_header.size > buffer_size) ||
643 (cms_header.offset > (buffer_size - cms_header.size))) {
644 rc = EINVAL;
645 goto fail3;
646 }
647
648 image_header.offset = cms_header.offset + cms_header.size;
649 image_header.size = infop->eii_headerp->eih_size;
650 if ((image_header.size > buffer_size) ||
651 (image_header.offset > (buffer_size - image_header.size))) {
652 rc = EINVAL;
653 goto fail4;
654 }
655
656 code.offset = image_header.offset + image_header.size;
657 code.size = infop->eii_headerp->eih_code_size;
658 if ((code.size > buffer_size) ||
659 (code.offset > (buffer_size - code.size))) {
660 rc = EINVAL;
661 goto fail5;
662 }
663
664 image_trailer.offset = code.offset + code.size;
665 image_trailer.size = EFX_IMAGE_TRAILER_SIZE;
666 if ((image_trailer.size > buffer_size) ||
667 (image_trailer.offset > (buffer_size - image_trailer.size))) {
668 rc = EINVAL;
669 goto fail6;
670 }
671
672 signature.offset = image_trailer.offset + image_trailer.size;
673 signature.size = (uint32_t)(infop->eii_image_size - signature.offset);
674 if ((signature.size > buffer_size) ||
675 (signature.offset > (buffer_size - signature.size))) {
676 rc = EINVAL;
677 goto fail7;
678 }
679
680 EFSYS_ASSERT3U(infop->eii_image_size, ==, cms_header.size +
681 image_header.size + code.size + image_trailer.size +
682 signature.size);
683
684 /* BEGIN CSTYLED */
685 /*
686 * Build signed image partition, inserting chunk headers.
687 *
688 * Signed Image: Image in NVRAM partition:
689 *
690 * +-----------------+ +-----------------+
691 * | CMS header | | mcfw.update |<----+
692 * +-----------------+ | | |
693 * | reflash header | +-----------------+ |
694 * +-----------------+ | chunk header: |-->--|-+
695 * | mcfw.update | | REFLASH_TRAILER | | |
696 * | | +-----------------+ | |
697 * +-----------------+ +-->| CMS header | | |
698 * | reflash trailer | | +-----------------+ | |
699 * +-----------------+ | | chunk header: |->-+ | |
700 * | signature | | | REFLASH_HEADER | | | |
701 * +-----------------+ | +-----------------+ | | |
702 * | | reflash header |<--+ | |
703 * | +-----------------+ | |
704 * | | chunk header: |-->--+ |
705 * | | IMAGE | |
706 * | +-----------------+ |
707 * | | reflash trailer |<------+
708 * | +-----------------+
709 * | | chunk header: |
710 * | | SIGNATURE |->-+
711 * | +-----------------+ |
712 * | | signature |<--+
713 * | +-----------------+
714 * | | ...unused... |
715 * | +-----------------+
716 * +-<-| chunk header: |
717 * >-->| CMS_HEADER |
718 * +-----------------+
719 *
720 * Each chunk header gives the partition offset and length of the image
721 * chunk's data. The image chunk data is immediately followed by the
722 * chunk header for the next chunk.
723 *
724 * The data chunk for the firmware code must be at the start of the
725 * partition (needed for the bootloader). The first chunk header in the
726 * chain (for the CMS header) is stored at the end of the partition. The
727 * chain of chunk headers maintains the same logical order of image
728 * chunks as the original signed image file. This set of constraints
729 * results in the layout used for the data chunks and chunk headers.
730 */
731 /* END CSTYLED */
732 memset(bufferp, 0xFF, buffer_size);
733
734 EFX_STATIC_ASSERT(sizeof (chunk_hdr) == SIGNED_IMAGE_CHUNK_HDR_LEN);
735 memset(&chunk_hdr, 0, SIGNED_IMAGE_CHUNK_HDR_LEN);
736
737 /*
738 * CMS header
739 */
740 if (buffer_size < SIGNED_IMAGE_CHUNK_HDR_LEN) {
741 rc = ENOSPC;
742 goto fail8;
743 }
744 hdr_offset = buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN;
745
746 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
747 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
748 chunk_hdr.id = SIGNED_IMAGE_CHUNK_CMS_HEADER;
749 chunk_hdr.offset = code.size + SIGNED_IMAGE_CHUNK_HDR_LEN;
750 chunk_hdr.len = cms_header.size;
751
752 memcpy(bufferp + hdr_offset, &chunk_hdr, sizeof (chunk_hdr));
753
754 if ((chunk_hdr.len > buffer_size) ||
755 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
756 rc = ENOSPC;
757 goto fail9;
758 }
759 memcpy(bufferp + chunk_hdr.offset,
760 infop->eii_imagep + cms_header.offset,
761 cms_header.size);
762
763 /*
764 * Image header
765 */
766 hdr_offset = chunk_hdr.offset + chunk_hdr.len;
767 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
768 rc = ENOSPC;
769 goto fail10;
770 }
771 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
772 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
773 chunk_hdr.id = SIGNED_IMAGE_CHUNK_REFLASH_HEADER;
774 chunk_hdr.offset = hdr_offset + SIGNED_IMAGE_CHUNK_HDR_LEN;
775 chunk_hdr.len = image_header.size;
776
777 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
778
779 if ((chunk_hdr.len > buffer_size) ||
780 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
781 rc = ENOSPC;
782 goto fail11;
783 }
784 memcpy(bufferp + chunk_hdr.offset,
785 infop->eii_imagep + image_header.offset,
786 image_header.size);
787
788 *headerpp = (efx_image_header_t *)(bufferp + chunk_hdr.offset);
789
790 /*
791 * Firmware code
792 */
793 hdr_offset = chunk_hdr.offset + chunk_hdr.len;
794 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
795 rc = ENOSPC;
796 goto fail12;
797 }
798 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
799 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
800 chunk_hdr.id = SIGNED_IMAGE_CHUNK_IMAGE;
801 chunk_hdr.offset = 0;
802 chunk_hdr.len = code.size;
803
804 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
805
806 if ((chunk_hdr.len > buffer_size) ||
807 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
808 rc = ENOSPC;
809 goto fail13;
810 }
811 memcpy(bufferp + chunk_hdr.offset,
812 infop->eii_imagep + code.offset,
813 code.size);
814
815 /*
816 * Image trailer (CRC)
817 */
818 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
819 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
820 chunk_hdr.id = SIGNED_IMAGE_CHUNK_REFLASH_TRAILER;
821 chunk_hdr.offset = hdr_offset + SIGNED_IMAGE_CHUNK_HDR_LEN;
822 chunk_hdr.len = image_trailer.size;
823
824 hdr_offset = code.size;
825 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
826 rc = ENOSPC;
827 goto fail14;
828 }
829
830 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
831
832 if ((chunk_hdr.len > buffer_size) ||
833 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
834 rc = ENOSPC;
835 goto fail15;
836 }
837 memcpy((uint8_t *)bufferp + chunk_hdr.offset,
838 infop->eii_imagep + image_trailer.offset,
839 image_trailer.size);
840
841 /*
842 * Signature
843 */
844 hdr_offset = chunk_hdr.offset + chunk_hdr.len;
845 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
846 rc = ENOSPC;
847 goto fail16;
848 }
849 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
850 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
851 chunk_hdr.id = SIGNED_IMAGE_CHUNK_SIGNATURE;
852 chunk_hdr.offset = chunk_hdr.offset + SIGNED_IMAGE_CHUNK_HDR_LEN;
853 chunk_hdr.len = signature.size;
854
855 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
856
857 if ((chunk_hdr.len > buffer_size) ||
858 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
859 rc = ENOSPC;
860 goto fail17;
861 }
862 memcpy(bufferp + chunk_hdr.offset,
863 infop->eii_imagep + signature.offset,
864 signature.size);
865
866 return (0);
867
868 fail17:
869 EFSYS_PROBE(fail17);
870 fail16:
871 EFSYS_PROBE(fail16);
872 fail15:
873 EFSYS_PROBE(fail15);
874 fail14:
875 EFSYS_PROBE(fail14);
876 fail13:
877 EFSYS_PROBE(fail13);
878 fail12:
879 EFSYS_PROBE(fail12);
880 fail11:
881 EFSYS_PROBE(fail11);
882 fail10:
883 EFSYS_PROBE(fail10);
884 fail9:
885 EFSYS_PROBE(fail9);
886 fail8:
887 EFSYS_PROBE(fail8);
888 fail7:
889 EFSYS_PROBE(fail7);
890 fail6:
891 EFSYS_PROBE(fail6);
892 fail5:
893 EFSYS_PROBE(fail5);
894 fail4:
895 EFSYS_PROBE(fail4);
896 fail3:
897 EFSYS_PROBE(fail3);
898 fail2:
899 EFSYS_PROBE(fail2);
900 fail1:
901 EFSYS_PROBE1(fail1, efx_rc_t, rc);
902
903 return (rc);
904 }
905
906 #endif /* EFSYS_OPT_IMAGE_LAYOUT */
907
908 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
909