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 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 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 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 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 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 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 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 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 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