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 {
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,
79 if (cursor == NULL || cursor->buffer == NULL || cursor->length < 2) {
84 cursor->tag = cursor->buffer[0];
85 if (cursor->tag != tag) {
91 if ((cursor->tag & 0x1F) == 0x1F) {
92 /* Long tag format not used in CMS syntax */
97 if ((cursor->buffer[1] & 0x80) == 0) {
98 /* Short form: length is 0..127 */
100 cursor->val_size = cursor->buffer[1];
102 /* Long form: length encoded as [0x80+nbytes][length bytes] */
103 uint32_t nbytes = cursor->buffer[1] & 0x7F;
107 /* Indefinite length not allowed in DER encoding */
111 if (2 + nbytes > cursor->length) {
112 /* Header length overflows image buffer */
116 if (nbytes > sizeof (uint32_t)) {
117 /* Length encoding too big */
121 cursor->hdr_size = 2 + nbytes;
122 cursor->val_size = 0;
123 for (offset = 2; offset < cursor->hdr_size; offset++) {
125 (cursor->val_size << 8) | cursor->buffer[offset];
129 if ((cursor->hdr_size + cursor->val_size) > cursor->length) {
130 /* Length overflows image buffer */
150 EFSYS_PROBE1(fail1, efx_rc_t, rc);
155 /* Enter nested ASN.1 TLV (contained in value of current TLV) */
156 static __checkReturn efx_rc_t
158 __inout efx_asn1_cursor_t *cursor,
163 if (cursor == NULL) {
168 if (ASN1_TAG_IS_PRIM(tag)) {
169 /* Cannot enter a primitive tag */
173 rc = efx_asn1_parse_header_match_tag(cursor, tag);
175 /* Invalid TLV or wrong tag */
179 /* Limit cursor range to nested TLV */
180 cursor->buffer += cursor->hdr_size;
181 cursor->length = cursor->val_size;
190 EFSYS_PROBE1(fail1, efx_rc_t, rc);
196 * Check that the current ASN.1 TLV matches the given tag and value.
197 * Advance cursor to next TLV on a successful match.
199 static __checkReturn efx_rc_t
200 efx_asn1_match_tag_value(
201 __inout efx_asn1_cursor_t *cursor,
203 __in const void *valp,
204 __in uint32_t val_size)
208 if (cursor == NULL) {
212 rc = efx_asn1_parse_header_match_tag(cursor, tag);
214 /* Invalid TLV or wrong tag */
217 if (cursor->val_size != val_size) {
218 /* Value size is different */
222 if (memcmp(cursor->buffer + cursor->hdr_size, valp, val_size) != 0) {
223 /* Value content is different */
227 cursor->buffer += cursor->hdr_size + cursor->val_size;
228 cursor->length -= cursor->hdr_size + cursor->val_size;
239 EFSYS_PROBE1(fail1, efx_rc_t, rc);
244 /* Advance cursor to next TLV */
245 static __checkReturn efx_rc_t
247 __inout efx_asn1_cursor_t *cursor,
252 if (cursor == NULL) {
257 rc = efx_asn1_parse_header_match_tag(cursor, tag);
259 /* Invalid TLV or wrong tag */
262 cursor->buffer += cursor->hdr_size + cursor->val_size;
263 cursor->length -= cursor->hdr_size + cursor->val_size;
270 EFSYS_PROBE1(fail1, efx_rc_t, rc);
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,
280 __out uint8_t **valp,
281 __out uint32_t *val_sizep)
285 if (cursor == NULL || valp == NULL || val_sizep == NULL) {
290 rc = efx_asn1_parse_header_match_tag(cursor, tag);
292 /* Invalid TLV or wrong tag */
295 *valp = cursor->buffer + cursor->hdr_size;
296 *val_sizep = cursor->val_size;
303 EFSYS_PROBE1(fail1, efx_rc_t, rc);
310 * Utility routines for parsing CMS headers (see RFC2315, PKCS#7)
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 };
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 };
321 /* SignedData structure version */
322 static const uint8_t SignedData_Version[] =
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).
331 static __checkReturn efx_rc_t
332 efx_check_signed_image_header(
334 __in uint32_t buffer_size,
335 __out uint32_t *content_offsetp,
336 __out uint32_t *content_lengthp)
338 efx_asn1_cursor_t cursor;
343 if (content_offsetp == NULL || content_lengthp == NULL) {
347 cursor.buffer = (uint8_t *)bufferp;
348 cursor.length = buffer_size;
351 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
355 /* ContextInfo.contentType */
356 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
357 PKCS7_SignedData, sizeof (PKCS7_SignedData));
361 /* ContextInfo.content */
362 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
367 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
371 /* SignedData.version */
372 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_INTEGER,
373 SignedData_Version, sizeof (SignedData_Version));
377 /* SignedData.digestAlgorithms */
378 rc = efx_asn1_skip_tag(&cursor, ASN1_TAG_SET);
382 /* SignedData.encapContentInfo */
383 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
387 /* SignedData.encapContentInfo.econtentType */
388 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
389 PKCS7_Data, sizeof (PKCS7_Data));
393 /* SignedData.encapContentInfo.econtent */
394 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
399 * The octet string contains the image header, image code bytes and
400 * image trailer CRC (same as unsigned image layout).
404 rc = efx_asn1_get_tag_value(&cursor, ASN1_TAG_OCTET_STRING,
409 if ((valp == NULL) || (val_size == 0)) {
413 if (valp < (uint8_t *)bufferp) {
417 if ((valp + val_size) > ((uint8_t *)bufferp + buffer_size)) {
422 *content_offsetp = (uint32_t)(valp - (uint8_t *)bufferp);
423 *content_lengthp = val_size;
454 EFSYS_PROBE1(fail1, efx_rc_t, rc);
459 static __checkReturn efx_rc_t
460 efx_check_unsigned_image(
462 __in uint32_t buffer_size)
464 efx_image_header_t *header;
465 efx_image_trailer_t *trailer;
469 EFX_STATIC_ASSERT(sizeof (*header) == EFX_IMAGE_HEADER_SIZE);
470 EFX_STATIC_ASSERT(sizeof (*trailer) == EFX_IMAGE_TRAILER_SIZE);
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))) {
478 header = (efx_image_header_t *)bufferp;
480 if (header->eih_magic != EFX_IMAGE_HEADER_MAGIC) {
486 * Check image header version is same or higher than lowest required
489 if (header->eih_version < EFX_IMAGE_HEADER_VERSION) {
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)) {
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);
505 crc = efx_crc32_calculate(0, (uint8_t *)header,
506 (header->eih_size + header->eih_code_size));
508 if (trailer->eit_crc != crc) {
524 EFSYS_PROBE1(fail1, efx_rc_t, rc);
529 __checkReturn efx_rc_t
530 efx_check_reflash_image(
532 __in uint32_t buffer_size,
533 __out efx_image_info_t *infop)
535 efx_image_format_t format = EFX_IMAGE_FORMAT_NO_IMAGE;
536 uint32_t image_offset;
542 EFSYS_ASSERT(infop != NULL);
547 memset(infop, 0, sizeof (*infop));
549 if (bufferp == NULL || buffer_size == 0) {
555 * Check if the buffer contains an image in signed format, and if so,
556 * locate the image header.
558 rc = efx_check_signed_image_header(bufferp, buffer_size,
559 &image_offset, &image_size);
562 * Buffer holds signed image format. Check that the encapsulated
563 * content is in unsigned image format.
565 format = EFX_IMAGE_FORMAT_SIGNED;
567 /* Check if the buffer holds image in unsigned image format */
568 format = EFX_IMAGE_FORMAT_UNSIGNED;
570 image_size = buffer_size;
572 if (image_offset + image_size > buffer_size) {
576 imagep = (uint8_t *)bufferp + image_offset;
578 /* Check unsigned image layout (image header, code, image trailer) */
579 rc = efx_check_unsigned_image(imagep, image_size);
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;
597 infop->eii_format = EFX_IMAGE_FORMAT_INVALID;
598 infop->eii_imagep = NULL;
599 infop->eii_image_size = 0;
602 EFSYS_PROBE1(fail1, efx_rc_t, rc);
607 __checkReturn efx_rc_t
608 efx_build_signed_image_write_buffer(
609 __out_bcount(buffer_size)
611 __in uint32_t buffer_size,
612 __in efx_image_info_t *infop,
613 __out efx_image_header_t **headerpp)
615 signed_image_chunk_hdr_t chunk_hdr;
620 } cms_header, image_header, code, image_trailer, signature;
623 EFSYS_ASSERT((infop != NULL) && (headerpp != NULL));
625 if ((bufferp == NULL) || (buffer_size == 0) ||
626 (infop == NULL) || (headerpp == NULL)) {
627 /* Invalid arguments */
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 */
643 /* Locate image chunks in original signed image */
644 cms_header.offset = 0;
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))) {
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))) {
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))) {
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))) {
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))) {
685 EFSYS_ASSERT3U(infop->eii_image_size, ==, cms_header.size +
686 image_header.size + code.size + image_trailer.size +
691 * Build signed image partition, inserting chunk headers.
693 * Signed Image: Image in NVRAM partition:
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: |-->--+ |
711 * | +-----------------+ |
712 * | | reflash trailer |<------+
713 * | +-----------------+
714 * | | chunk header: |
715 * | | SIGNATURE |->-+
716 * | +-----------------+ |
717 * | | signature |<--+
718 * | +-----------------+
720 * | +-----------------+
721 * +-<-| chunk header: |
723 * +-----------------+
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.
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.
737 memset(bufferp, 0xFF, buffer_size);
739 EFX_STATIC_ASSERT(sizeof (chunk_hdr) == SIGNED_IMAGE_CHUNK_HDR_LEN);
740 memset(&chunk_hdr, 0, SIGNED_IMAGE_CHUNK_HDR_LEN);
745 if (buffer_size < SIGNED_IMAGE_CHUNK_HDR_LEN) {
749 hdr_offset = buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN;
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;
757 memcpy(bufferp + hdr_offset, &chunk_hdr, sizeof (chunk_hdr));
759 if ((chunk_hdr.len > buffer_size) ||
760 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
764 memcpy(bufferp + chunk_hdr.offset,
765 infop->eii_imagep + cms_header.offset,
771 hdr_offset = chunk_hdr.offset + chunk_hdr.len;
772 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
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;
782 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
784 if ((chunk_hdr.len > buffer_size) ||
785 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
789 memcpy(bufferp + chunk_hdr.offset,
790 infop->eii_imagep + image_header.offset,
793 *headerpp = (efx_image_header_t *)(bufferp + chunk_hdr.offset);
798 hdr_offset = chunk_hdr.offset + chunk_hdr.len;
799 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
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;
809 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
811 if ((chunk_hdr.len > buffer_size) ||
812 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
816 memcpy(bufferp + chunk_hdr.offset,
817 infop->eii_imagep + code.offset,
821 * Image trailer (CRC)
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;
829 hdr_offset = code.size;
830 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
835 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
837 if ((chunk_hdr.len > buffer_size) ||
838 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
842 memcpy((uint8_t *)bufferp + chunk_hdr.offset,
843 infop->eii_imagep + image_trailer.offset,
849 hdr_offset = chunk_hdr.offset + chunk_hdr.len;
850 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
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;
860 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
862 if ((chunk_hdr.len > buffer_size) ||
863 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
867 memcpy(bufferp + chunk_hdr.offset,
868 infop->eii_imagep + signature.offset,
906 EFSYS_PROBE1(fail1, efx_rc_t, rc);
913 #endif /* EFSYS_OPT_IMAGE_LAYOUT */
915 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */