2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2017-2018 Solarflare Communications Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
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.
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.
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.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
39 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
41 #if EFSYS_OPT_IMAGE_LAYOUT
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.
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)
56 #define ASN1_TAG_IS_PRIM(tag) ((tag & 0x20) == 0)
58 #define ASN1_TAG_PRIM_CONTEXT(n) (0x80 + (n))
59 #define ASN1_TAG_CONS_CONTEXT(n) (0xA0 + (n))
61 typedef struct efx_asn1_cursor_s {
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,
78 if (cursor == NULL || cursor->buffer == NULL || cursor->length < 2) {
83 cursor->tag = cursor->buffer[0];
84 if (cursor->tag != tag) {
90 if ((cursor->tag & 0x1F) == 0x1F) {
91 /* Long tag format not used in CMS syntax */
96 if ((cursor->buffer[1] & 0x80) == 0) {
97 /* Short form: length is 0..127 */
99 cursor->val_size = cursor->buffer[1];
101 /* Long form: length encoded as [0x80+nbytes][length bytes] */
102 uint32_t nbytes = cursor->buffer[1] & 0x7F;
106 /* Indefinite length not allowed in DER encoding */
110 if (2 + nbytes > cursor->length) {
111 /* Header length overflows image buffer */
115 if (nbytes > sizeof (uint32_t)) {
116 /* Length encoding too big */
120 cursor->hdr_size = 2 + nbytes;
121 cursor->val_size = 0;
122 for (offset = 2; offset < cursor->hdr_size; offset++) {
124 (cursor->val_size << 8) | cursor->buffer[offset];
128 if ((cursor->hdr_size + cursor->val_size) > cursor->length) {
129 /* Length overflows image buffer */
149 EFSYS_PROBE1(fail1, efx_rc_t, rc);
154 /* Enter nested ASN.1 TLV (contained in value of current TLV) */
155 static __checkReturn efx_rc_t
157 __inout efx_asn1_cursor_t *cursor,
162 if (cursor == NULL) {
167 if (ASN1_TAG_IS_PRIM(tag)) {
168 /* Cannot enter a primitive tag */
172 rc = efx_asn1_parse_header_match_tag(cursor, tag);
174 /* Invalid TLV or wrong tag */
178 /* Limit cursor range to nested TLV */
179 cursor->buffer += cursor->hdr_size;
180 cursor->length = cursor->val_size;
189 EFSYS_PROBE1(fail1, efx_rc_t, rc);
195 * Check that the current ASN.1 TLV matches the given tag and value.
196 * Advance cursor to next TLV on a successful match.
198 static __checkReturn efx_rc_t
199 efx_asn1_match_tag_value(
200 __inout efx_asn1_cursor_t *cursor,
202 __in const void *valp,
203 __in uint32_t val_size)
207 if (cursor == NULL) {
211 rc = efx_asn1_parse_header_match_tag(cursor, tag);
213 /* Invalid TLV or wrong tag */
216 if (cursor->val_size != val_size) {
217 /* Value size is different */
221 if (memcmp(cursor->buffer + cursor->hdr_size, valp, val_size) != 0) {
222 /* Value content is different */
226 cursor->buffer += cursor->hdr_size + cursor->val_size;
227 cursor->length -= cursor->hdr_size + cursor->val_size;
238 EFSYS_PROBE1(fail1, efx_rc_t, rc);
243 /* Advance cursor to next TLV */
244 static __checkReturn efx_rc_t
246 __inout efx_asn1_cursor_t *cursor,
251 if (cursor == NULL) {
256 rc = efx_asn1_parse_header_match_tag(cursor, tag);
258 /* Invalid TLV or wrong tag */
261 cursor->buffer += cursor->hdr_size + cursor->val_size;
262 cursor->length -= cursor->hdr_size + cursor->val_size;
269 EFSYS_PROBE1(fail1, efx_rc_t, rc);
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,
279 __out uint8_t **valp,
280 __out uint32_t *val_sizep)
284 if (cursor == NULL || valp == NULL || val_sizep == NULL) {
289 rc = efx_asn1_parse_header_match_tag(cursor, tag);
291 /* Invalid TLV or wrong tag */
294 *valp = cursor->buffer + cursor->hdr_size;
295 *val_sizep = cursor->val_size;
302 EFSYS_PROBE1(fail1, efx_rc_t, rc);
308 * Utility routines for parsing CMS headers (see RFC2315, PKCS#7)
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 };
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 };
319 /* SignedData structure version */
320 static const uint8_t SignedData_Version[] =
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).
329 static __checkReturn efx_rc_t
330 efx_check_signed_image_header(
332 __in uint32_t buffer_size,
333 __out uint32_t *content_offsetp,
334 __out uint32_t *content_lengthp)
336 efx_asn1_cursor_t cursor;
341 if (content_offsetp == NULL || content_lengthp == NULL) {
345 cursor.buffer = (uint8_t *)bufferp;
346 cursor.length = buffer_size;
349 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
353 /* ContextInfo.contentType */
354 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
355 PKCS7_SignedData, sizeof (PKCS7_SignedData));
359 /* ContextInfo.content */
360 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
365 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
369 /* SignedData.version */
370 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_INTEGER,
371 SignedData_Version, sizeof (SignedData_Version));
375 /* SignedData.digestAlgorithms */
376 rc = efx_asn1_skip_tag(&cursor, ASN1_TAG_SET);
380 /* SignedData.encapContentInfo */
381 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
385 /* SignedData.encapContentInfo.econtentType */
386 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
387 PKCS7_Data, sizeof (PKCS7_Data));
391 /* SignedData.encapContentInfo.econtent */
392 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
397 * The octet string contains the image header, image code bytes and
398 * image trailer CRC (same as unsigned image layout).
402 rc = efx_asn1_get_tag_value(&cursor, ASN1_TAG_OCTET_STRING,
407 if ((valp == NULL) || (val_size == 0)) {
411 if (valp < (uint8_t *)bufferp) {
415 if ((valp + val_size) > ((uint8_t *)bufferp + buffer_size)) {
420 *content_offsetp = (uint32_t)(valp - (uint8_t *)bufferp);
421 *content_lengthp = val_size;
452 EFSYS_PROBE1(fail1, efx_rc_t, rc);
457 static __checkReturn efx_rc_t
458 efx_check_unsigned_image(
460 __in uint32_t buffer_size)
462 efx_image_header_t *header;
463 efx_image_trailer_t *trailer;
467 EFX_STATIC_ASSERT(sizeof (*header) == EFX_IMAGE_HEADER_SIZE);
468 EFX_STATIC_ASSERT(sizeof (*trailer) == EFX_IMAGE_TRAILER_SIZE);
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))) {
476 header = (efx_image_header_t *)bufferp;
478 if (header->eih_magic != EFX_IMAGE_HEADER_MAGIC) {
484 * Check image header version is same or higher than lowest required
487 if (header->eih_version < EFX_IMAGE_HEADER_VERSION) {
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)) {
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);
503 crc = efx_crc32_calculate(0, (uint8_t *)header,
504 (header->eih_size + header->eih_code_size));
506 if (trailer->eit_crc != crc) {
522 EFSYS_PROBE1(fail1, efx_rc_t, rc);
527 __checkReturn efx_rc_t
528 efx_check_reflash_image(
530 __in uint32_t buffer_size,
531 __out efx_image_info_t *infop)
533 efx_image_format_t format = EFX_IMAGE_FORMAT_NO_IMAGE;
534 uint32_t image_offset;
539 EFSYS_ASSERT(infop != NULL);
544 memset(infop, 0, sizeof (*infop));
546 if (bufferp == NULL || buffer_size == 0) {
552 * Check if the buffer contains an image in signed format, and if so,
553 * locate the image header.
555 rc = efx_check_signed_image_header(bufferp, buffer_size,
556 &image_offset, &image_size);
559 * Buffer holds signed image format. Check that the encapsulated
560 * content is in unsigned image format.
562 format = EFX_IMAGE_FORMAT_SIGNED;
564 /* Check if the buffer holds image in unsigned image format */
565 format = EFX_IMAGE_FORMAT_UNSIGNED;
567 image_size = buffer_size;
569 if (image_offset + image_size > buffer_size) {
573 imagep = (uint8_t *)bufferp + image_offset;
575 /* Check unsigned image layout (image header, code, image trailer) */
576 rc = efx_check_unsigned_image(imagep, image_size);
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;
594 infop->eii_format = EFX_IMAGE_FORMAT_INVALID;
595 infop->eii_imagep = NULL;
596 infop->eii_image_size = 0;
599 EFSYS_PROBE1(fail1, efx_rc_t, rc);
604 __checkReturn efx_rc_t
605 efx_build_signed_image_write_buffer(
606 __out_bcount(buffer_size)
608 __in uint32_t buffer_size,
609 __in efx_image_info_t *infop,
610 __out efx_image_header_t **headerpp)
612 signed_image_chunk_hdr_t chunk_hdr;
617 } cms_header, image_header, code, image_trailer, signature;
620 EFSYS_ASSERT((infop != NULL) && (headerpp != NULL));
622 if ((bufferp == NULL) || (buffer_size == 0) ||
623 (infop == NULL) || (headerpp == NULL)) {
624 /* Invalid arguments */
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 */
640 /* Locate image chunks in original signed image */
641 cms_header.offset = 0;
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))) {
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))) {
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))) {
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))) {
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))) {
682 EFSYS_ASSERT3U(infop->eii_image_size, ==, cms_header.size +
683 image_header.size + code.size + image_trailer.size +
688 * Build signed image partition, inserting chunk headers.
690 * Signed Image: Image in NVRAM partition:
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: |-->--+ |
708 * | +-----------------+ |
709 * | | reflash trailer |<------+
710 * | +-----------------+
711 * | | chunk header: |
712 * | | SIGNATURE |->-+
713 * | +-----------------+ |
714 * | | signature |<--+
715 * | +-----------------+
717 * | +-----------------+
718 * +-<-| chunk header: |
720 * +-----------------+
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.
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.
734 memset(bufferp, 0xFF, buffer_size);
736 EFX_STATIC_ASSERT(sizeof (chunk_hdr) == SIGNED_IMAGE_CHUNK_HDR_LEN);
737 memset(&chunk_hdr, 0, SIGNED_IMAGE_CHUNK_HDR_LEN);
742 if (buffer_size < SIGNED_IMAGE_CHUNK_HDR_LEN) {
746 hdr_offset = buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN;
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;
754 memcpy(bufferp + hdr_offset, &chunk_hdr, sizeof (chunk_hdr));
756 if ((chunk_hdr.len > buffer_size) ||
757 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
761 memcpy(bufferp + chunk_hdr.offset,
762 infop->eii_imagep + cms_header.offset,
768 hdr_offset = chunk_hdr.offset + chunk_hdr.len;
769 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
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;
779 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
781 if ((chunk_hdr.len > buffer_size) ||
782 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
786 memcpy(bufferp + chunk_hdr.offset,
787 infop->eii_imagep + image_header.offset,
790 *headerpp = (efx_image_header_t *)(bufferp + chunk_hdr.offset);
795 hdr_offset = chunk_hdr.offset + chunk_hdr.len;
796 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
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;
806 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
808 if ((chunk_hdr.len > buffer_size) ||
809 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
813 memcpy(bufferp + chunk_hdr.offset,
814 infop->eii_imagep + code.offset,
818 * Image trailer (CRC)
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;
826 hdr_offset = code.size;
827 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
832 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
834 if ((chunk_hdr.len > buffer_size) ||
835 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
839 memcpy((uint8_t *)bufferp + chunk_hdr.offset,
840 infop->eii_imagep + image_trailer.offset,
846 hdr_offset = chunk_hdr.offset + chunk_hdr.len;
847 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
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;
857 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
859 if ((chunk_hdr.len > buffer_size) ||
860 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
864 memcpy(bufferp + chunk_hdr.offset,
865 infop->eii_imagep + signature.offset,
903 EFSYS_PROBE1(fail1, efx_rc_t, rc);
908 #endif /* EFSYS_OPT_IMAGE_LAYOUT */
910 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */