From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4F66CEB64D7 for ; Sat, 17 Jun 2023 00:37:23 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id AEA35847C7; Sat, 17 Jun 2023 02:37:20 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="dJxRdeGw"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 52CA686281; Sat, 17 Jun 2023 02:37:18 +0200 (CEST) Received: from mail-pg1-x52f.google.com (mail-pg1-x52f.google.com [IPv6:2607:f8b0:4864:20::52f]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 1142D847B6 for ; Sat, 17 Jun 2023 02:37:10 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=takahiro.akashi@linaro.org Received: by mail-pg1-x52f.google.com with SMTP id 41be03b00d2f7-543a37c5c03so258420a12.1 for ; Fri, 16 Jun 2023 17:37:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1686962228; x=1689554228; h=in-reply-to:content-transfer-encoding:content-disposition :mime-version:references:mail-followup-to:message-id:subject:cc:to :from:date:from:to:cc:subject:date:message-id:reply-to; bh=kSLPCGJak8JkrHCvQcbnWpUwF+L6mhfEyB9EiEpbtLI=; b=dJxRdeGwUl8FSbJZX+GawLSOVTuX788NCEcJNHcS8PeVBLWl/8Cl9xcov7JMZvgOHV OWUsgobvSNRYg+cQkgK1JL3+Krvteco8NBQxlnjYVoHlwvYyPAMSy/NBHnVUHOMgu4lO JPURH6saqzEy2uDHlv3YHoBGYDym7Exp8koNulwksspk7pTDfUfh44DlEHYSG1xMMuVp kA9bcUdFQx87qT7PqYQdeAtuDV3EeAPUF2MsZD0fZLAQMFQQvavrrcP+JdnDODXOGyyd g++k5j5RHNrVtTHfW3MPalZkz0gs4+M2XMxkjGyRL17FBC9nemLyxDJ7uJudbmWpZYQf 0OCw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686962228; x=1689554228; h=in-reply-to:content-transfer-encoding:content-disposition :mime-version:references:mail-followup-to:message-id:subject:cc:to :from:date:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=kSLPCGJak8JkrHCvQcbnWpUwF+L6mhfEyB9EiEpbtLI=; b=gICj8zd+vF1zU3gBDIAwhDrveRfRtST3xUKFxN9lmI0GbTuAEgYOcVaLcvTIyX0qPu FdLed0R8+vmh5DJyM68kphNOSccTmSD5TD+/B0MVifq3sTcbLzlNvipNwu2e8OaFN9mp q62ZEWOBxu2PP/K43nHRiPMwYVztwZ/cNFFCdXWg5wHQlv/D9XL2b3dIZLRZus4cb0pZ jFFVcN3Ok8/cLWAAR8p09315av/ZTVOMTwZIk1637cF7SpYzAkMEBXj4jP5Hp/rXIZXW h/ylP1UqyXq8MkpZgVW6CpBUBDo12HTjv1cfEMvyQyEeIbeoEWPQtM76uDs5bxPJGdfP zvUw== X-Gm-Message-State: AC+VfDxfsCbwvSPykuX19HZZN2sGBoHntyUokfJ2guax06g31oAbo6gz irjLt7hj8yPMqJaBmcRkHcjC3A== X-Google-Smtp-Source: ACHHUZ7FwzAIr1MNACpRY6/5Ek1Eh4ALyJUV8jGmKXVyr+ArfOfxOSPBO1PXcAY98A3pHM56PZKsPA== X-Received: by 2002:a17:90b:4c92:b0:25b:de63:f193 with SMTP id my18-20020a17090b4c9200b0025bde63f193mr4040019pjb.4.1686962227930; Fri, 16 Jun 2023 17:37:07 -0700 (PDT) Received: from laputa ([2400:4050:c3e1:100:df74:66da:3671:b619]) by smtp.gmail.com with ESMTPSA id mj1-20020a17090b368100b00246f9725ffcsm1909301pjb.33.2023.06.16.17.37.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 16 Jun 2023 17:37:07 -0700 (PDT) Date: Sat, 17 Jun 2023 09:37:03 +0900 From: AKASHI Takahiro To: "Schmidt, Malte" Cc: Sughosh Ganu , Stefan Herbrechtsmeier , u-boot@lists.denx.de, Malte Schmidt , Stefan Herbrechtsmeier , Etienne Carriere , Heinrich Schuchardt , Ilias Apalodimas , Masahisa Kojima Subject: Re: [PATCH 2/5] mkeficapsule: add support for multiple payloads inside capsule Message-ID: Mail-Followup-To: AKASHI Takahiro , "Schmidt, Malte" , Sughosh Ganu , Stefan Herbrechtsmeier , u-boot@lists.denx.de, Malte Schmidt , Stefan Herbrechtsmeier , Etienne Carriere , Heinrich Schuchardt , Ilias Apalodimas , Masahisa Kojima References: <20230616113426.13976-1-stefan.herbrechtsmeier-oss@weidmueller.com> <20230616113426.13976-3-stefan.herbrechtsmeier-oss@weidmueller.com> <7e15d6dc-a6ea-25da-1216-372534a7fabc@weidmueller.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean On Fri, Jun 16, 2023 at 03:32:59PM +0200, Schmidt, Malte wrote: > Hi Sughos, > > one other question. Do you know what the advantage of mkeficapsule tool over > the EDK2 GenerateCapsule tool is? It seems like reinventing the wheel > for me. Simply because I didn't want to have a dependency on EDK2 package when users use U-Boot as EFI framework. (In other words, make it self-contained?) -Takahiro Akashi > Best Regards > Malte > > Am 16.06.2023 um 14:59 schrieb Schmidt, Malte: > > Hi Sughos, > > > > Am 16.06.2023 um 14:32 schrieb Sughosh Ganu: > > > On Fri, 16 Jun 2023 at 17:56, Sughosh Ganu > > > wrote: > > > > hi Stefan, > > > > > > > > On Fri, 16 Jun 2023 at 17:04, Stefan Herbrechtsmeier > > > > wrote: > > > > > From: Malte Schmidt > > > > > > > > > > The UEFI [1] specification allows multiple payloads inside the capsule > > > > > body. Add support for this. The command line arguments are kept > > > > > backwards-compatible. > > > > > > > > > > [1] https://uefi.org/specs/UEFI/2.10/index.html > > > > I am trying to upstream support for specifying the capsule parameters > > > > for multiple payloads through a config file [1]. This is on similar > > > > lines to the support in the Edk2 GenerateCapule tool where multiple > > > > payloads can be specified through a json file. I think you can base > > > > your changes on my series. > > > Btw, with the support being added for getting the capsule parameters > > > through a config file, I believe your changes would be pretty much > > > simplified. Instead of passing all those parameters through the > > > command line, they can instead be read from the config file and used > > > to generate a single capsule file consisting of multiple payloads. > > > That would be a much simpler implementation. > > > > > > -sughosh > > thanks for the heads up. So your opinion is that we only support multiple > > payloads via config files and not the command line? I think it does not > > hurt to have both options available. > > > > I plan to rebase my code on yours once it nears the finish line. I still > > have a suggsetion for it which I will post in a sec. > > > > Best Regards > > Malte > > > > -sughosh > > > > > > > > [1] - https://lore.kernel.org/u-boot/20230613103806.812065-1-sughosh.ganu@linaro.org/T/#mc8c0500863bd3a1580c572679370a565f8d7f2c8 > > > > > > > > > Signed-off-by: Malte Schmidt > > > > > Signed-off-by: Stefan Herbrechtsmeier > > > > > > > > > > --- > > > > > > > > > >   tools/eficapsule.h   |   5 - > > > > >   tools/mkeficapsule.c | 636 > > > > > ++++++++++++++++++++++++++++++++----------- > > > > >   2 files changed, 475 insertions(+), 166 deletions(-) > > > > > > > > > > diff --git a/tools/eficapsule.h b/tools/eficapsule.h > > > > > index 753fb73313..001af3217c 100644 > > > > > --- a/tools/eficapsule.h > > > > > +++ b/tools/eficapsule.h > > > > > @@ -138,9 +138,4 @@ struct fmp_payload_header { > > > > >          uint32_t lowest_supported_version; > > > > >   }; > > > > > > > > > > -struct fmp_payload_header_params { > > > > > -       bool have_header; > > > > > -       uint32_t fw_version; > > > > > -}; > > > > > - > > > > >   #endif /* _EFI_CAPSULE_H */ > > > > > diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c > > > > > index b8db00b16b..1a4de0f092 100644 > > > > > --- a/tools/mkeficapsule.c > > > > > +++ b/tools/mkeficapsule.c > > > > > @@ -29,7 +29,7 @@ static const char *tool_name = "mkeficapsule"; > > > > >   efi_guid_t efi_guid_fm_capsule = > > > > > EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; > > > > >   efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; > > > > > > > > > > -static const char *opts_short = "g:i:I:v:p:c:m:o:dhAR"; > > > > > +static const char *opts_short = "g:i:b:I:v:p:c:m:o:dhAR"; > > > > > > > > > >   enum { > > > > >          CAPSULE_NORMAL_BLOB = 0, > > > > > @@ -40,6 +40,7 @@ enum { > > > > >   static struct option options[] = { > > > > >          {"guid", required_argument, NULL, 'g'}, > > > > >          {"index", required_argument, NULL, 'i'}, > > > > > +       {"image_blob", required_argument, NULL, 'b'}, > > > > >          {"instance", required_argument, NULL, 'I'}, > > > > >          {"fw-version", required_argument, NULL, 'v'}, > > > > >          {"private-key", required_argument, NULL, 'p'}, > > > > > @@ -55,21 +56,22 @@ static struct option options[] = { > > > > > > > > > >   static void print_usage(void) > > > > >   { > > > > > -       fprintf(stderr, "Usage: %s [options] > > > > blob> \n" > > > > > +       fprintf(stderr, "Usage: %s [options] [ > > > > blob>] \n" > > > > >                  "Options:\n" > > > > > > > > > > -               "\t-g, --guid > > > > string>    guid for image blob type\n" > > > > > -               "\t-i, --index          update image index\n" > > > > > -               "\t-I, --instance > > > > >    update hardware instance\n" > > > > > -               "\t-v, --fw-version firmware version\n" > > > > > -               "\t-p, --private-key > > > > file> private key file\n" > > > > > -               "\t-c, --certificate > > > > file> signer's certificate file\n" > > > > > -               "\t-m, --monotonic-count monotonic count\n" > > > > > -               "\t-d, > > > > > --dump_sig              dump signature > > > > > (*.p7)\n" > > > > > -               "\t-A, --fw-accept  firmware > > > > > accept capsule, requires GUID, no image blob\n" > > > > > -               "\t-R, --fw-revert  firmware > > > > > revert capsule, takes no GUID, no image blob\n" > > > > > -               "\t-o, --capoemflag Capsule > > > > > OEM Flag, an integer between 0x0000 and 0xffff\n" > > > > > -               "\t-h, > > > > > --help                  print a help > > > > > message\n", > > > > > +               "\t-g, --guid > > > > > comma-separated list of guids for image blob types\n" > > > > > +               "\t-i, --index > > > > > comma-separated list of update image indices\n" > > > > > +               "\t-b, --image_blob > > > > list> comma-separated list of image blobs\n" > > > > > +               "\t-I, --instance > > > > list> comma-separated list of update hardware instances\n" > > > > > +               "\t-v, --fw-version > > > > list> comma-separated list of firmware versions\n" > > > > > +               "\t-p, --private-key > > > > file>              private key file\n" > > > > > +               "\t-c, --certificate > > > > file>                 signer's certificate > > > > > file\n" > > > > > +               "\t-m, --monotonic-count > > > > >   comma-separated list of monotonic > > > > > counts\n" > > > > > +               "\t-d, --dump_sig                                > > > > > dump signature (*.p7)\n" > > > > > +               "\t-A, --fw-accept   > > > > > firmware accept capsule, requires GUID, no image blob\n" > > > > > +               "\t-R, --fw-revert   > > > > > firmware revert capsule, takes no GUID, no image blob\n" > > > > > +               "\t-o, --capoemflag  capsule > > > > > OEM Flag, an integer between 0x0000 and 0xffff\n" > > > > > +               "\t-h, --help        print a help message\n", > > > > >                  tool_name); > > > > >   } > > > > > > > > > > @@ -336,16 +338,18 @@ static int create_auth_data(struct > > > > > auth_context *ctx) > > > > >    * @path:      Path to a capsule file > > > > >    * @signature: Signature data > > > > >    * @sig_size:  Size of signature data > > > > > + * @index:     The payload index the signature belongs to > > > > >    * > > > > >    * Signature data pointed to by @signature will be saved into > > > > > - * a file whose file name is @path with ".p7" suffix. > > > > > + * a file whose file name is @path with "_.p7" suffix. > > > > > + * If index is negative the suffix is ".p7" (for backwards > > > > > compatibility). > > > > >    * > > > > >    * Return: > > > > >    * * 0  - on success > > > > >    * * -1 - on failure > > > > >    */ > > > > >   static int dump_signature(const char *path, const uint8_t > > > > > *signature, > > > > > -                         size_t sig_size) > > > > > +                         size_t sig_size, int index) > > > > >   { > > > > >          char *sig_path; > > > > >          FILE *f; > > > > > @@ -356,7 +360,11 @@ static int dump_signature(const char > > > > > *path, const uint8_t *signature, > > > > >          if (!sig_path) > > > > >                  return ret; > > > > > > > > > > -       sprintf(sig_path, "%s.p7", path); > > > > > +       if (index < 0) > > > > > +               sprintf(sig_path, "%s.p7", path); > > > > > +       else > > > > > +               sprintf(sig_path, "%s_%d.p7", path, index); > > > > > + > > > > >          f = fopen(sig_path, "w"); > > > > >          if (!f) > > > > >                  goto err; > > > > > @@ -386,14 +394,15 @@ static void free_sig_data(struct > > > > > auth_context *ctx) > > > > >   /** > > > > >    * create_fwbin - create an uefi capsule file > > > > >    * @path:      Path to a created capsule file > > > > > - * @bin:       Path to a firmware binary to encapsulate > > > > > - * @guid:      GUID of related FMP driver > > > > > - * @index:     Index number in capsule > > > > > + * @bins:      Paths to firmware binaries to encapsulate, an array > > > > > + * @guids:     GUIDs of related FMP drivers, an array > > > > > + * @indices:   Index numbers in capsule, an array > > > > >    * @instance:  Instance number in capsule > > > > >    * @mcount:    Monotonic count in authentication information > > > > > + * @size:      Size of the arrays > > > > >    * @private_file:      Path to a private key file > > > > >    * @cert_file: Path to a certificate file > > > > > - * @oemflags:  Capsule OEM Flags, bits 0-15 > > > > > + * @oemflags:  Capsule OEM Flags, bits 0-15 > > > > >    * > > > > >    * This function actually does the job of creating an > > > > > uefi capsule file. > > > > >    * All the arguments must be supplied. > > > > > @@ -404,78 +413,87 @@ static void free_sig_data(struct > > > > > auth_context *ctx) > > > > >    * * 0  - on success > > > > >    * * -1 - on failure > > > > >    */ > > > > > -static int create_fwbin(const char *path, const char *bin, > > > > > -                       const efi_guid_t *guid, unsigned long index, > > > > > -                       unsigned long instance, > > > > > -                       const struct > > > > > fmp_payload_header_params *fmp_ph_params, > > > > > -                       uint64_t mcount, > > > > > -                       const char > > > > > *privkey_file, const char *cert_file, > > > > > -                       uint16_t oemflags) > > > > > +static int create_fwbin(const char *path, const char **bins, > > > > > +                       const > > > > > efi_guid_t *guids, const unsigned long *indices, > > > > > +                       const unsigned long *instances, > > > > > +                       const unsigned > > > > > long *fw_versions, const unsigned long *mcounts, > > > > > +                       int size, const char *privkey_file, > > > > > +                       const char *cert_file, uint16_t oemflags) > > > > >   { > > > > >          struct efi_capsule_header header; > > > > >          struct efi_firmware_management_capsule_header capsule; > > > > > -       struct efi_firmware_management_capsule_image_header image; > > > > > -       struct auth_context auth_context; > > > > > +       struct > > > > > efi_firmware_management_capsule_image_header images[size]; > > > > > +       struct auth_context auth_contexts[size]; > > > > >          FILE *f; > > > > > -       uint8_t *data, *new_data, *buf; > > > > > -       off_t bin_size; > > > > > -       uint64_t offset; > > > > > +       uint8_t *data_list[size], > > > > > *new_data_list[size], *buf_list[size]; > > > > > +       off_t bin_sizes[size]; > > > > > +       uint64_t offsets[size]; > > > > >          int ret; > > > > > -       struct fmp_payload_header payload_header; > > > > > +       struct fmp_payload_header payload_headers[size]; > > > > > > > > > >   #ifdef DEBUG > > > > >          fprintf(stderr, "For output: %s\n", path); > > > > > -       fprintf(stderr, "\tbin: %s\n\ttype: %pUl\n", bin, guid); > > > > > -       fprintf(stderr, "\tindex: %lu\n\tinstance: > > > > > %lu\n", index, instance); > > > > > +       for (int i = 0; i < size; i++) { > > > > > +               fprintf(stderr, "\tpayload no: %d\n", i); > > > > > +               fprintf(stderr, "\t\tbin: > > > > > %s\n\t\ttype: %pUl\n", bins[i], guids[i]); > > > > > +               fprintf(stderr, "\t\tindex: > > > > > %lu\n\t\tinstance: %lu\n", indices[i], instances[i]); > > > > > +       } > > > > >   #endif > > > > > -       auth_context.sig_size = 0; > > > > >          f = NULL; > > > > > -       data = NULL; > > > > > -       new_data = NULL; > > > > >          ret = -1; > > > > > > > > > > -       /* > > > > > -        * read a firmware binary > > > > > -        */ > > > > > -       if (read_bin_file(bin, &data, &bin_size)) > > > > > -               goto err; > > > > > +       for (int i = 0; i < size; i++) { > > > > > +               auth_contexts[i].sig_size = 0; > > > > > +               data_list[i] = NULL; > > > > > +               new_data_list[i] = NULL; > > > > > +       } > > > > > > > > > > -       buf = data; > > > > > +       for (int i = 0; i < size; i++) { > > > > > +               int dump_index = (size == 1) ? -1 : i; > > > > > > > > > > -       /* insert fmp payload header right before the payload */ > > > > > -       if (fmp_ph_params->have_header) { > > > > > -               new_data = malloc(bin_size + sizeof(payload_header)); > > > > > -               if (!new_data) > > > > > +               /* > > > > > +                * read a firmware binary > > > > > +                */ > > > > > +               if (read_bin_file(bins[i], > > > > > &data_list[i], &bin_sizes[i])) > > > > >                          goto err; > > > > > > > > > > -               payload_header.signature = FMP_PAYLOAD_HDR_SIGNATURE; > > > > > -               payload_header.header_size = sizeof(payload_header); > > > > > -               payload_header.fw_version = fmp_ph_params->fw_version; > > > > > -               > > > > > payload_header.lowest_supported_version = 0; /* not used */ > > > > > -               memcpy(new_data, > > > > > &payload_header, sizeof(payload_header)); > > > > > -               memcpy(new_data + > > > > > sizeof(payload_header), data, bin_size); > > > > > -               buf = new_data; > > > > > -               bin_size += sizeof(payload_header); > > > > > -       } > > > > > - > > > > > -       /* first, calculate signature to determine its size */ > > > > > -       if (privkey_file && cert_file) { > > > > > -               auth_context.key_file = privkey_file; > > > > > -               auth_context.cert_file = cert_file; > > > > > -               auth_context.auth.monotonic_count = mcount; > > > > > -               auth_context.image_data = buf; > > > > > -               auth_context.image_size = bin_size; > > > > > - > > > > > -               if (create_auth_data(&auth_context)) { > > > > > -                       > > > > > fprintf(stderr, "Signing firmware image failed\n"); > > > > > -                       goto err; > > > > > +               buf_list[i] = data_list[i]; > > > > > +               /* insert fmp payload header > > > > > right before the payload */ > > > > > +               if (fw_versions) { > > > > > +                       > > > > > new_data_list[i] = malloc(bin_sizes[i] + > > > > > sizeof(payload_headers[i])); > > > > > +                       if (!new_data_list[i]) > > > > > +                               goto err; > > > > > + > > > > > +                       > > > > > payload_headers[i].signature = FMP_PAYLOAD_HDR_SIGNATURE; > > > > > +                       > > > > > payload_headers[i].header_size = sizeof(payload_headers[i]); > > > > > +                       > > > > > payload_headers[i].fw_version = fw_versions[i]; > > > > > + payload_headers[i].lowest_supported_version = 0; /* not used */ > > > > > +                       > > > > > memcpy(new_data_list[i], (payload_headers + i), > > > > > sizeof(payload_headers[i])); > > > > > +                       > > > > > memcpy(new_data_list[i] + sizeof(payload_headers[i]), > > > > > data_list[i], > > > > > +                              bin_sizes[i]); > > > > > +                       buf_list[i] = new_data_list[i]; > > > > > +                       bin_sizes[i] += sizeof(payload_headers[i]); > > > > >                  } > > > > > > > > > > -               if (dump_sig && > > > > > -                   dump_signature(path, auth_context.sig_data, > > > > > -                                  auth_context.sig_size)) { > > > > > -                       > > > > > fprintf(stderr, "Creating signature file failed\n"); > > > > > -                       goto err; > > > > > +               /* calculate signature to determine its size */ > > > > > +               if (privkey_file && cert_file) { > > > > > +                       auth_contexts[i].key_file = privkey_file; > > > > > +                       auth_contexts[i].cert_file = cert_file; > > > > > + auth_contexts[i].auth.monotonic_count = mcounts[i]; > > > > > +                       auth_contexts[i].image_data = buf_list[i]; > > > > > +                       auth_contexts[i].image_size = bin_sizes[i]; > > > > > + > > > > > +                       if (create_auth_data(&auth_contexts[i])) { > > > > > +                               > > > > > fprintf(stderr, "Signing firmware image failed\n"); > > > > > +                               goto err; > > > > > +                       } > > > > > + > > > > > +                       if (dump_sig && > > > > > +                           > > > > > dump_signature(path, auth_contexts[i].sig_data, > > > > > + auth_contexts[i].sig_size, dump_index)) { > > > > > +                               > > > > > fprintf(stderr, "Creating signature file failed\n"); > > > > > +                               goto err; > > > > > +                       } > > > > >                  } > > > > >          } > > > > > > > > > > @@ -498,81 +516,87 @@ static int create_fwbin(const char > > > > > *path, const char *bin, > > > > >          if (oemflags) > > > > >                  header.flags |= oemflags; > > > > >          header.capsule_image_size = sizeof(header) > > > > > -                                       > > > > > + sizeof(capsule) + sizeof(uint64_t) > > > > > -                                       + sizeof(image) > > > > > -                                       + bin_size; > > > > > -       if (auth_context.sig_size) > > > > > -               header.capsule_image_size += sizeof(auth_context.auth) > > > > > -                               + auth_context.sig_size; > > > > > +                                       + sizeof(capsule) > > > > > +                                       > > > > > + size * sizeof(uint64_t); /* size of item_offset_list */ > > > > > +       for (int i = 0; i < size; i++) { > > > > > +               offsets[i] = > > > > > header.capsule_image_size - sizeof(header); > > > > > +               header.capsule_image_size += sizeof(images[i]) > > > > > +                                       + bin_sizes[i]; > > > > > +               if (auth_contexts[i].sig_size) > > > > > +                       > > > > > header.capsule_image_size += sizeof(auth_contexts[i].auth) > > > > > +                                       + auth_contexts[i].sig_size; > > > > > +       } > > > > >          if (write_capsule_file(f, &header, sizeof(header), > > > > >                                 "Capsule header")) > > > > >                  goto err; > > > > > > > > > >          /* > > > > >           * firmware capsule header > > > > > -        * This capsule has only one firmware capsule image. > > > > >           */ > > > > >          capsule.version = 0x00000001; > > > > >          capsule.embedded_driver_count = 0; > > > > > -       capsule.payload_item_count = 1; > > > > > +       capsule.payload_item_count = size; > > > > >          if (write_capsule_file(f, &capsule, sizeof(capsule), > > > > >                                 "Firmware capsule header")) > > > > >                  goto err; > > > > > > > > > > -       offset = sizeof(capsule) + sizeof(uint64_t); > > > > > -       if (write_capsule_file(f, &offset, sizeof(offset), > > > > > -                              "Offset to capsule image")) > > > > > +       if (write_capsule_file(f, &offsets, size * sizeof(uint64_t), > > > > > +                              "Offsets to capsule images")) > > > > >                  goto err; > > > > > > > > > > -       /* > > > > > -        * firmware capsule image header > > > > > -        */ > > > > > -       image.version = 0x00000003; > > > > > -       memcpy(&image.update_image_type_id, guid, sizeof(*guid)); > > > > > -       image.update_image_index = index; > > > > > -       image.reserved[0] = 0; > > > > > -       image.reserved[1] = 0; > > > > > -       image.reserved[2] = 0; > > > > > -       image.update_image_size = bin_size; > > > > > -       if (auth_context.sig_size) > > > > > -               image.update_image_size += sizeof(auth_context.auth) > > > > > -                               + auth_context.sig_size; > > > > > -       image.update_vendor_code_size = 0; /* none */ > > > > > -       image.update_hardware_instance = instance; > > > > > -       image.image_capsule_support = 0; > > > > > -       if (auth_context.sig_size) > > > > > -               image.image_capsule_support |= > > > > > CAPSULE_SUPPORT_AUTHENTICATION; > > > > > -       if (write_capsule_file(f, &image, sizeof(image), > > > > > -                              "Firmware capsule image header")) > > > > > -               goto err; > > > > > - > > > > > -       /* > > > > > -        * signature > > > > > -        */ > > > > > -       if (auth_context.sig_size) { > > > > > -               if (write_capsule_file(f, &auth_context.auth, > > > > > - sizeof(auth_context.auth), > > > > > -                                      "Authentication header")) > > > > > +       for (int i = 0; i < size; i++) { > > > > > +               /* > > > > > +                * firmware capsule image header > > > > > +                */ > > > > > +               images[i].version = 0x00000003; > > > > > +               > > > > > memcpy(&images[i].update_image_type_id, &guids[i], > > > > > sizeof(guids[i])); > > > > > +               images[i].update_image_index = indices[i]; > > > > > +               images[i].reserved[0] = 0; > > > > > +               images[i].reserved[1] = 0; > > > > > +               images[i].reserved[2] = 0; > > > > > +               images[i].update_image_size = bin_sizes[i]; > > > > > +               if (auth_contexts[i].sig_size) > > > > > +                       > > > > > images[i].update_image_size += sizeof(auth_contexts[i].auth) > > > > > +                                       + auth_contexts[i].sig_size; > > > > > +               images[i].update_vendor_code_size = 0; /* none */ > > > > > +               images[i].update_hardware_instance = instances[i]; > > > > > +               images[i].image_capsule_support = 0; > > > > > +               if (auth_contexts[i].sig_size) > > > > > +                       > > > > > images[i].image_capsule_support |= > > > > > CAPSULE_SUPPORT_AUTHENTICATION; > > > > > +               if (write_capsule_file(f, > > > > > &images[i], sizeof(images[i]), > > > > > +                                      > > > > > "Firmware capsule image header")) > > > > >                          goto err; > > > > > > > > > > -               if (write_capsule_file(f, auth_context.sig_data, > > > > > - auth_context.sig_size, "Signature")) > > > > > +               /* > > > > > +                * signature > > > > > +                */ > > > > > +               if (auth_contexts[i].sig_size) { > > > > > +                       if > > > > > (write_capsule_file(f, &auth_contexts[i].auth, > > > > > + sizeof(auth_contexts[i].auth), > > > > > + "Authentication header")) > > > > > +                               goto err; > > > > > + > > > > > +                       if > > > > > (write_capsule_file(f, auth_contexts[i].sig_data, > > > > > + auth_contexts[i].sig_size, "Signature")) > > > > > +                               goto err; > > > > > +               } > > > > > + > > > > > +               /* > > > > > +                * firmware binary > > > > > +                */ > > > > > +               if (write_capsule_file(f, > > > > > buf_list[i], bin_sizes[i], "Firmware binary")) > > > > >                          goto err; > > > > >          } > > > > > > > > > > -       /* > > > > > -        * firmware binary > > > > > -        */ > > > > > -       if (write_capsule_file(f, buf, bin_size, "Firmware binary")) > > > > > -               goto err; > > > > > - > > > > >          ret = 0; > > > > >   err: > > > > >          if (f) > > > > >                  fclose(f); > > > > > -       free_sig_data(&auth_context); > > > > > -       free(data); > > > > > -       free(new_data); > > > > > +       for (int i = 0; i < size; i++) { > > > > > +               free_sig_data(&auth_contexts[i]); > > > > > +               free(data_list[i]); > > > > > +               free(new_data_list[i]); > > > > > +       } > > > > > > > > > >          return ret; > > > > >   } > > > > > @@ -652,6 +676,228 @@ err: > > > > >          return ret; > > > > >   } > > > > > > > > > > +/** > > > > > + * count_items - count number of items in list > > > > > + * @list:      Pointer to a string > > > > > + * @separator: Separator used to separate list items > > > > > + * > > > > > + * Count the number of items in a list. The list items > > > > > + * are separated by a separator character inside the string. > > > > > + * Trailing white spaces are not allowed except if it is > > > > > the separator. > > > > > + * > > > > > + * Return: > > > > > + * The item count. > > > > > + */ > > > > > +int count_items(const char *list, char separator) > > > > > +{ > > > > > +       const char *c; > > > > > +       int count = 0; > > > > > + > > > > > +       if (!*list) > > > > > +               return 0; > > > > > + > > > > > +       for (c = list; *c; c++) { > > > > > +               if (*c == separator) > > > > > +                       count++; > > > > > +       } > > > > > +       /* correct count if no trailing separator present */ > > > > > +       if (*(c - 1) != separator) > > > > > +               count++; > > > > > + > > > > > +       return count; > > > > > +} > > > > > + > > > > > +/** > > > > > + * update_itemcount - update item count > > > > > + * @count:     The count to be updated > > > > > + * @list:      The item list > > > > > + * @separator: List separator > > > > > + * > > > > > + * Initialize the count if it is uninitialized (negative value). > > > > > + * Check that the list contains at least one item. > > > > > + * Check if an already initialized count is consistent with > > > > > the list count. > > > > > + * > > > > > + * Return: > > > > > + * * 0 - on success > > > > > + * * -1 - if a check fails > > > > > + */ > > > > > +int update_itemcount(int *count, const char *list, char separator) > > > > > +{ > > > > > +       int current_count = count_items(list, separator); > > > > > + > > > > > +       if (*count < 0) > > > > > +               *count = current_count; > > > > > + > > > > > +       if (*count == 0 || > > > > > +           *count != current_count) > > > > > +               return -1; > > > > > + > > > > > +       return 0; > > > > > +} > > > > > + > > > > > +/** > > > > > + * split_list - split list into elements > > > > > + * @elements:  Pointer to string array > > > > > + * @size:      The array size > > > > > + * @list:      The item list > > > > > + * @separator: List separator > > > > > + * > > > > > + * Split a comma-separated list into its elements. > > > > > + * > > > > > + * Return: > > > > > + * * 0 - on success > > > > > + * * -1 - on failure > > > > > + */ > > > > > +int split_list(char **elements, int size, char *list, char separator) > > > > > +{ > > > > > +       const char separator_str[] = {separator, '\0'}; > > > > > +       char *end; > > > > > + > > > > > +       for (int i = 0; i < size; i++) { > > > > > +               elements[i] = strsep(&list, separator_str); > > > > > +               if (!elements[i]) > > > > > +                       return -1; > > > > > +       } > > > > > + > > > > > +       end = strsep(&list, separator_str);  /* NULL > > > > > or empty string expected */ > > > > > +       if (end && *end) > > > > > +               return -1; > > > > > + > > > > > +       return 0; > > > > > +} > > > > > + > > > > > +/** > > > > > + * alloc_array - allocate memory for array > > > > > + * @count:     The number of elements > > > > > + * @obj_size:  The size of a single element > > > > > + * @name:      The name of the array > > > > > + * > > > > > + * This is a wrapper for malloc which prints an error > > > > > + * message on failure. > > > > > + * > > > > > + *  Return: > > > > > + * * Pointer to the allocated memory on success > > > > > + * * NULL on failure > > > > > + */ > > > > > +void *alloc_array(unsigned int count, size_t obj_size, > > > > > const char *name) > > > > > +{ > > > > > +       void *array; > > > > > + > > > > > +       array = malloc(count * obj_size); > > > > > +       if (!array) > > > > > +               fprintf(stderr, "Could not > > > > > allocate memory for %s\n", name); > > > > > + > > > > > +       return array; > > > > > +} > > > > > + > > > > > +/** > > > > > + * init_guids - populate guid array > > > > > + * @elements:  String array of elements to be converted > > > > > + * @size:      The array size > > > > > + * @name:      The name of the array > > > > > + * > > > > > + * Allocate and populate an array of guid structs. The list > > > > > contains the UUIDs > > > > > + * to convert and store in the array. Upon failure an error > > > > > message is > > > > > + * printed. > > > > > + * > > > > > + * Return: > > > > > + * * The initialized GUID array on success > > > > > + * * NULL on failure > > > > > + */ > > > > > +efi_guid_t *init_guids(const char **elements, unsigned int size, > > > > > +                      const char *name) > > > > > +{ > > > > > +       efi_guid_t *guids; > > > > > + > > > > > +       guids = alloc_array(size, sizeof(efi_guid_t), name); > > > > > +       if (!guids) > > > > > +               return NULL; > > > > > + > > > > > +       for (int i = 0; i < size; i++) { > > > > > +               if (uuid_parse(elements[i], > > > > > (unsigned char *)(guids + i))) { > > > > > +                       fprintf(stderr, "Wrong %s format\n", name); > > > > > +                       free(guids); > > > > > +                       return NULL; > > > > > +               } > > > > > +               convert_uuid_to_guid((unsigned char *)(guids + i)); > > > > > +       } > > > > > + > > > > > +       return guids; > > > > > +} > > > > > + > > > > > +/** > > > > > + * init_uls - populate unsigned long array > > > > > + * @elements:  String array of elements to be converted > > > > > + * @size:      The array size > > > > > + * @name:      The name of the array > > > > > + * > > > > > + * Allocate and populate an array of unsgined longs. Upon failure an > > > > > + * error message is printed. > > > > > + * > > > > > + * Return: > > > > > + * * The initialized array on success > > > > > + * * NULL on failure > > > > > + */ > > > > > +unsigned long *init_uls(const char **elements, unsigned int size, > > > > > +                       const char *name) > > > > > +{ > > > > > +       unsigned long *array; > > > > > + > > > > > +       array = alloc_array(size, sizeof(unsigned long), name); > > > > > +       if (!array) > > > > > +               return NULL; > > > > > +       for (int i = 0; i < size; i++) > > > > > +               array[i] = strtoul(elements[i], NULL, 0); > > > > > + > > > > > +       return array; > > > > > +} > > > > > + > > > > > +/** > > > > > + * init_list - parse list and allocate elements > > > > > + * @listcount: The list count to be checked and updated > > > > > + * @list:      The list to be parsed > > > > > + * @separator: The list separator > > > > > + * @name:      The name of the list > > > > > + * @multiple_times:    List encountered multiple times > > > > > + * > > > > > + * Routine for command line argument lists. > > > > > + * Parse the string list and count the list elements. > > > > > + * Initialize the listcount if it is uninitialized (negative value). > > > > > + * Check that the list contains at least one item. > > > > > + * Check if an already initialized count is consistent with > > > > > the list count. > > > > > + * Allocate the string array and populate it with the list elements. > > > > > + * The array should be freed in the calling function. > > > > > + * Upon failure an error message is printed and the program exits. > > > > > + * > > > > > + *  Return: > > > > > + * * The initialized array on success > > > > > + * * NULL on failure > > > > > + */ > > > > > +char **init_list(int *listcount, char *list, char separator, > > > > > +                bool multiple_times, char *name) > > > > > +{ > > > > > +       char **elements; > > > > > + > > > > > +       if (multiple_times) { > > > > > +               fprintf(stderr, "%s specified > > > > > multiple times\n", name); > > > > > +               return NULL; > > > > > +       } > > > > > +       if (update_itemcount(listcount, list, separator)) { > > > > > +               fprintf(stderr, "List count > > > > > not consistent with previous or list not provided\n"); > > > > > +               return NULL; > > > > > +       } > > > > > +       elements = alloc_array(*listcount, sizeof(char *), name); > > > > > +       if (!elements) > > > > > +               return NULL; > > > > > +       if (split_list(elements, *listcount, list, separator)) { > > > > > +               fprintf(stderr, "Could not parse %s list\n", name); > > > > > +               free(elements); > > > > > +               return NULL; > > > > > +       } > > > > > + > > > > > +       return elements; > > > > > +} > > > > > + > > > > >   /** > > > > >    * main - main entry function of mkeficapsule > > > > >    * @argc:      Number of arguments > > > > > @@ -666,24 +912,27 @@ err: > > > > >    */ > > > > >   int main(int argc, char **argv) > > > > >   { > > > > > -       efi_guid_t *guid; > > > > > -       unsigned char uuid_buf[16]; > > > > > -       unsigned long index, instance; > > > > > -       uint64_t mcount; > > > > > +       const char separator = ','; > > > > > +       const efi_guid_t *guids; /* an array */ > > > > > +       const unsigned long *indices, *instances, > > > > > *mcounts, *fw_versions; /* arrays */ > > > > >          unsigned long oemflags; > > > > > +       const char **blob_paths, **elements;  /* string arrays */ > > > > >          const char *privkey_file, *cert_file; > > > > > -       int c, idx; > > > > > -       struct fmp_payload_header_params fmp_ph_params = { 0 }; > > > > > +       int listcount, c, idx; > > > > > > > > > > -       guid = NULL; > > > > > -       index = 0; > > > > > -       instance = 0; > > > > > -       mcount = 0; > > > > > +       guids = NULL; > > > > > +       indices = NULL; > > > > > +       instances = NULL; > > > > > +       mcounts = NULL; > > > > > +       oemflags = 0; > > > > > +       blob_paths = NULL; > > > > >          privkey_file = NULL; > > > > >          cert_file = NULL; > > > > > +       elements = NULL; > > > > > +       listcount = -1; > > > > > +       fw_versions = NULL; > > > > >          dump_sig = 0; > > > > >          capsule_type = CAPSULE_NORMAL_BLOB; > > > > > -       oemflags = 0; > > > > >          for (;;) { > > > > >                  c = getopt_long(argc, argv, > > > > > opts_short, options, &idx); > > > > >                  if (c == -1) > > > > > @@ -691,27 +940,62 @@ int main(int argc, char **argv) > > > > > > > > > >                  switch (c) { > > > > >                  case 'g': > > > > > -                       if (guid) { > > > > > -                               fprintf(stderr, > > > > > -                                       > > > > > "Image type already specified\n"); > > > > > +                       elements = > > > > > (const char **)init_list(&listcount, optarg, separator, > > > > > !!guids, > > > > > + "GUID"); > > > > > +                       if (!elements) > > > > >                                  exit(EXIT_FAILURE); > > > > > -                       } > > > > > -                       if (uuid_parse(optarg, uuid_buf)) { > > > > > -                               > > > > > fprintf(stderr, "Wrong guid format\n"); > > > > > + > > > > > +                       guids = > > > > > init_guids(elements, listcount, "GUID"); > > > > > +                       if (!guids) > > > > >                                  exit(EXIT_FAILURE); > > > > > -                       } > > > > > -                       convert_uuid_to_guid(uuid_buf); > > > > > -                       guid = (efi_guid_t *)uuid_buf; > > > > > + > > > > > +                       free(elements); > > > > > +                       elements = NULL; > > > > >                          break; > > > > >                  case 'i': > > > > > -                       index = strtoul(optarg, NULL, 0); > > > > > +                       elements = > > > > > (const char **)init_list(&listcount, optarg, separator, > > > > > + !!indices, "index"); > > > > > +                       if (!elements) > > > > > +                               exit(EXIT_FAILURE); > > > > > + > > > > > +                       indices = > > > > > init_uls(elements, listcount, "index"); > > > > > +                       if (!indices) > > > > > +                               exit(EXIT_FAILURE); > > > > > + > > > > > +                       free(elements); > > > > > +                       elements = NULL; > > > > > +                       break; > > > > > +               case 'b': > > > > > +                       blob_paths = > > > > > (const char **)init_list(&listcount, optarg, separator, > > > > > + !!blob_paths, "blob path"); > > > > > +                       if (!blob_paths) > > > > > +                               exit(EXIT_FAILURE); > > > > >                          break; > > > > >                  case 'I': > > > > > -                       instance = strtoul(optarg, NULL, 0); > > > > > +                       elements = > > > > > (const char **)init_list(&listcount, optarg, separator, > > > > > + !!instances, "instance"); > > > > > +                       if (!elements) > > > > > +                               exit(EXIT_FAILURE); > > > > > + > > > > > +                       instances = > > > > > init_uls(elements, listcount, "instance"); > > > > > +                       if (!instances) > > > > > +                               exit(EXIT_FAILURE); > > > > > + > > > > > +                       free(elements); > > > > > +                       elements = NULL; > > > > >                          break; > > > > >                  case 'v': > > > > > -                       > > > > > fmp_ph_params.fw_version = strtoul(optarg, NULL, 0); > > > > > -                       fmp_ph_params.have_header = true; > > > > > +                       elements = > > > > > (const char **)init_list(&listcount, optarg, separator, > > > > > + !!fw_versions, "firmware version"); > > > > > +                       if (!elements) > > > > > +                               exit(EXIT_FAILURE); > > > > > + > > > > > +                       fw_versions = > > > > > init_uls(elements, listcount, "firmware version"); > > > > > +                       if (!fw_versions) > > > > > +                               exit(EXIT_FAILURE); > > > > > + > > > > > +                       free(elements); > > > > > +                       elements = NULL; > > > > >                          break; > > > > >                  case 'p': > > > > >                          if (privkey_file) { > > > > > @@ -730,7 +1014,17 @@ int main(int argc, char **argv) > > > > >                          cert_file = optarg; > > > > >                          break; > > > > >                  case 'm': > > > > > -                       mcount = strtoul(optarg, NULL, 0); > > > > > +                       elements = > > > > > (const char **)init_list(&listcount, optarg, separator, > > > > > + !!mcounts, "monotonic count"); > > > > > +                       if (!elements) > > > > > +                               exit(EXIT_FAILURE); > > > > > + > > > > > +                       mcounts = > > > > > init_uls(elements, listcount, "monotonic count"); > > > > > +                       if (!mcounts) > > > > > +                               exit(EXIT_FAILURE); > > > > > + > > > > > +                       free(elements); > > > > > +                       elements = NULL; > > > > >                          break; > > > > >                  case 'd': > > > > >                          dump_sig = 1; > > > > > @@ -767,26 +1061,46 @@ int main(int argc, char **argv) > > > > > > > > > >          /* check necessary parameters */ > > > > >          if ((capsule_type == CAPSULE_NORMAL_BLOB && > > > > > -           ((argc != optind + 2) || !guid || > > > > > -            ((privkey_file && !cert_file) || > > > > > -             (!privkey_file && cert_file)))) || > > > > > +            (!((argc != optind + 2) ^ > > > > > !(blob_paths && argc == optind + 1)) || !guids || > > > > > +             ((privkey_file && !cert_file) || > > > > > +              (!privkey_file && cert_file)))) || > > > > >              (capsule_type != CAPSULE_NORMAL_BLOB && > > > > > -           ((argc != optind + 1) || > > > > > -            ((capsule_type == CAPSULE_ACCEPT) && !guid) || > > > > > -            ((capsule_type == CAPSULE_REVERT) && guid)))) { > > > > > +            ((argc != optind + 1) || > > > > > +             ((capsule_type == CAPSULE_ACCEPT) && !guids) || > > > > > +             ((capsule_type == CAPSULE_ACCEPT) && listcount != 1) || > > > > > +             ((capsule_type == CAPSULE_REVERT) && guids)))) { > > > > >                  print_usage(); > > > > >                  exit(EXIT_FAILURE); > > > > >          } > > > > > > > > > > +       /* populate blob_paths if image blob was > > > > > provided as positional argument */ > > > > > +       if (capsule_type == CAPSULE_NORMAL_BLOB && !blob_paths) { > > > > > +               blob_paths = malloc(sizeof(char *)); > > > > > +               if (!blob_paths) { > > > > > +                       > > > > > fprintf(stderr, "Could not allocate memory for blob > > > > > paths\n"); > > > > > +                       exit(EXIT_FAILURE); > > > > > +               } > > > > > +               *blob_paths = argv[argc - 2]; > > > > > +       } > > > > > + > > > > > +       /* populate arrays with zeros if they are not provided */ > > > > > +       if (!indices) > > > > > +               indices = calloc(listcount, sizeof(unsigned long)); > > > > > +       if (!instances) > > > > > +               instances = calloc(listcount, sizeof(unsigned long)); > > > > > +       if (!mcounts) > > > > > +               mcounts = calloc(listcount, sizeof(uint64_t)); > > > > > + > > > > >          if (capsule_type != CAPSULE_NORMAL_BLOB) { > > > > > -               if (create_empty_capsule(argv[argc - 1], guid, > > > > > +               if (create_empty_capsule(argv[argc - 1], guids, > > > > >                                           > > > > > capsule_type == CAPSULE_ACCEPT) < 0) { > > > > >                          > > > > > fprintf(stderr, "Creating empty capsule failed\n"); > > > > >                          exit(EXIT_FAILURE); > > > > >                  } > > > > > -       } else  if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, > > > > > -                                > > > > > index, instance, &fmp_ph_params, mcount, privkey_file, > > > > > -                                cert_file, (uint16_t)oemflags) < 0) { > > > > > +       } else if (create_fwbin(argv[argc - 1], blob_paths, guids, > > > > > +                               indices, instances, fw_versions, > > > > > +                               mcounts, listcount, privkey_file, > > > > > +                               cert_file, (uint16_t)oemflags) < 0) { > > > > >                  fprintf(stderr, "Creating > > > > > firmware capsule failed\n"); > > > > >                  exit(EXIT_FAILURE); > > > > >          } > > > > > -- > > > > > 2.30.2 > > > > > > > >