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 */ 911