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