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