public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Yao, Jiewen" <jiewen.yao@intel.com>
To: Laszlo Ersek <lersek@redhat.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>,
	"Zurcher, Christopher J" <christopher.j.zurcher@intel.com>
Cc: "Wang, Jian J" <jian.j.wang@intel.com>,
	"Lu, XiaoyuX" <xiaoyux.lu@intel.com>
Subject: Re: [edk2-devel] [PATCH 1/1] CryptoPkg/BaseCryptLib: Add EVP (Envelope) Digest interface
Date: Thu, 13 Aug 2020 14:38:04 +0000	[thread overview]
Message-ID: <CY4PR11MB128851D0F5103CD0EDABFE888C430@CY4PR11MB1288.namprd11.prod.outlook.com> (raw)
In-Reply-To: <15d6f379-9dd2-e6d7-5901-4b23e78c7794@redhat.com>

1) Agree with Laszlo.
We need extend internal protocol/ppi for this new API.

2) Do you have any data on the size difference between old SHA implementation or new MD implementation?

Thank you
Yao Jiewen

> -----Original Message-----
> From: Laszlo Ersek <lersek@redhat.com>
> Sent: Thursday, August 13, 2020 5:47 PM
> To: devel@edk2.groups.io; Zurcher, Christopher J
> <christopher.j.zurcher@intel.com>
> Cc: Yao, Jiewen <jiewen.yao@intel.com>; Wang, Jian J <jian.j.wang@intel.com>;
> Lu, XiaoyuX <xiaoyux.lu@intel.com>
> Subject: Re: [edk2-devel] [PATCH 1/1] CryptoPkg/BaseCryptLib: Add EVP
> (Envelope) Digest interface
> 
> Hi Christopher,
> 
> (+Mike,
> 
> On 08/13/20 03:20, Zurcher, Christopher J wrote:
> > BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2545
> >
> > The EVP interface should be used in place of discrete digest function
> > calls.
> >
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > Cc: Jian J Wang <jian.j.wang@intel.com>
> > Cc: Xiaoyu Lu <xiaoyux.lu@intel.com>
> > Signed-off-by: Christopher J Zurcher <christopher.j.zurcher@intel.com>
> > ---
> >  CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf    |   1 +
> >  CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf     |   1 +
> >  CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf |   1 +
> >  CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf     |   1 +
> >  CryptoPkg/Include/Library/BaseCryptLib.h           | 122 +++++++++++
> >  CryptoPkg/Library/BaseCryptLib/Evp/CryptEvpMd.c    | 228
> ++++++++++++++++++++
> >  6 files changed, 354 insertions(+)
> 
> (1) This patch extends the library class header, but updates only one
> *set* of the three library instance *sets*. The other two instance
> *sets* are:
> 
> - BaseCryptLibNull (just one instance), for which it should not be hard
> to provide Null implementations of the new functions;
> 
> - BaseCryptLibOnProtocolPpi (three instances -- Pei, Dxe, Smm).
> 
> 
> BaseCryptLibOnProtocolPpi is a tough nut, because it seems to require
> extending:
> 
> - the crypto service driver at CryptoPkg/Driver/,
> 
> - the interface to that driver (CryptoPkg/Private/Protocol/Crypto.h --
> reused by both "CryptoPkg/Private/Ppi/Crypto.h" and
> "CryptoPkg/Private/Protocol/SmmCrypto.h"),
> 
> - the PCD_CRYPTO_SERVICE_FAMILY_ENABLE structure at
> "CryptoPkg/Include/Pcd/PcdCryptoServiceFamilyEnable.h", for configuring
> the driver,
> 
> - the various PcdCryptoServiceFamilyEnable settings / build profiles in
> CryptoPkg/CryptoPkg.dsc.
> 
> 
> >
> > diff --git a/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
> b/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
> > index 4aae2aba95..3968f29412 100644
> > --- a/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
> > +++ b/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
> > @@ -50,6 +50,7 @@
> >    Pk/CryptAuthenticode.c
> >    Pk/CryptTs.c
> >    Pem/CryptPem.c
> > +  Evp/CryptEvpMd.c
> >
> >    SysCall/CrtWrapper.c
> >    SysCall/TimerWrapper.c
> > diff --git a/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf
> b/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf
> > index dc28e3a11d..d0b91716d0 100644
> > --- a/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf
> > +++ b/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf
> > @@ -57,6 +57,7 @@
> >    Pk/CryptTsNull.c
> >    Pem/CryptPemNull.c
> >    Rand/CryptRandNull.c
> > +  Evp/CryptEvpMd.c
> >
> >    SysCall/CrtWrapper.c
> >    SysCall/ConstantTimeClock.c
> > diff --git a/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
> b/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
> > index 5005beed02..9f3accd35b 100644
> > --- a/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
> > +++ b/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
> > @@ -56,6 +56,7 @@
> >    Pk/CryptAuthenticodeNull.c
> >    Pk/CryptTsNull.c
> >    Pem/CryptPem.c
> > +  Evp/CryptEvpMd.c
> >
> >    SysCall/CrtWrapper.c
> >    SysCall/TimerWrapper.c
> > diff --git a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
> b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
> > index 91ec3e03bf..420623cdc6 100644
> > --- a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
> > +++ b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
> > @@ -54,6 +54,7 @@
> >    Pk/CryptAuthenticodeNull.c
> >    Pk/CryptTsNull.c
> >    Pem/CryptPem.c
> > +  Evp/CryptEvpMd.c
> >
> >    SysCall/CrtWrapper.c
> >    SysCall/ConstantTimeClock.c
> > diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h
> b/CryptoPkg/Include/Library/BaseCryptLib.h
> > index ae9bde9e37..f3bf8aac0c 100644
> > --- a/CryptoPkg/Include/Library/BaseCryptLib.h
> > +++ b/CryptoPkg/Include/Library/BaseCryptLib.h
> > @@ -1012,6 +1012,128 @@ HmacSha256Final (
> >    OUT     UINT8  *HmacValue
> >    );
> >
> >
> +//==============================================================
> =======================
> > +//    EVP (Envelope) Primitive
> >
> +//==============================================================
> =======================
> > +
> > +/**
> > +  Allocates and initializes one EVP_MD_CTX context for subsequent EVP_MD
> use.
> > +
> > +  @return  Pointer to the EVP_MD_CTX context that has been initialized.
> > +           If the allocations fails, EvpMdNew() returns NULL.
> > +
> > +**/
> > +VOID *
> > +EFIAPI
> > +EvpMdNew (
> > +  VOID
> > +  );
> > +
> > +/**
> > +  Release the specified EVP_MD_CTX context.
> > +
> > +  @param[in]  EvpMdContext  Pointer to the EVP_MD_CTX context to be
> released.
> > +
> > +**/
> > +VOID
> > +EFIAPI
> > +EvpMdFree (
> > +  IN  VOID  *EvpMdContext
> > +  );
> > +
> > +/**
> > +  Initializes user-supplied memory pointed to by EvpMdContext as
> EVP_MD_CTX
> > +  context for subsequent use.
> > +
> > +  If EvpMdContext is NULL, then return FALSE.
> > +  If DigestName is NULL, then return FALSE.
> > +
> > +  @param[out]   EvpMdContext  Pointer to EVP_MD_CTX context being
> initialized.
> > +  @param[in]    DigestName    Pointer to the digest name.
> > +
> > +  @retval TRUE   EVP_MD_CTX context initialization succeeded.
> > +  @retval FALSE  EVP_MD_CTX context initialization failed.
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +EvpMdInit (
> > +  OUT VOID          *EvpMdContext,
> > +  IN  CONST CHAR8   *DigestName
> > +  );
> 
> (2) I suggest merging the New() and Init() functions into one -- we
> should only have a New() function:
> 
> VOID *
> EFIAPI
> EvpMdNew (
>   IN  CONST CHAR8 *DigestName
>   );
> 
> And this function would collect the actions from both the current New()
> and Init() functions.
> 
> I'm proposing this because:
> 
> (2a) Init() is not really useful. In theory we might be able to call
> Init() right after Final(), but that seems like a very obscure use case.
> 
> (2b) New() is useless without Init(); it makes no sense for a context to
> exist, somewhere in the edk2 codebase, *between* New() and Init().
> 
> (2c) Init() used to encourage a usage pattern (at least with HMACs)
> where the caller would allocate its own context storage first. This
> usage was fraught with a memory leak
> <https://bugzilla.tianocore.org/show_bug.cgi?id=2095#c7>. This isn't a
> practical problem in this case, because we're -- correctly -- not
> offering a GetContextSize() in this patch, but Init() is still a vestige
> of a bad pattern.
> 
> Basically a caller should go through New -> Update[n] -> Final -> Free,
> possibly calling Duplicate before or after Update.
> 
> ... I could even entertain merging "Final" into "Free", as there seems
> to be no point for a context to exist, in edk2, between Final and Free.
> That would make for New -> Update[n] -> Free.
> 
> I understand that this would diverge from the current model of the
> "digest function family", but I see it as an improvement.
> 
> 
> > +
> > +/**
> > +  Makes a copy of an existing EVP_MD context.
> > +
> > +  If EvpMdContext is NULL, then return FALSE.
> > +  If NewEvpMdContext is NULL, then return FALSE.
> > +
> > +  @param[in]  EvpMdContext     Pointer to EVP_MD context being copied.
> > +  @param[out] NewEvpMdContext  Pointer to new EVP_MD context.
> > +
> > +  @retval TRUE   EVP_MD context copy succeeded.
> > +  @retval FALSE  EVP_MD context copy failed.
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +EvpMdDuplicate (
> > +  IN  CONST VOID    *EvpMdContext,
> > +  OUT VOID          *NewEvpMdContext
> > +  );
> > +
> > +/**
> > +  Digests the input data and updates EVP_MD context.
> > +
> > +  This function performs EVP digest on a data buffer of the specified size.
> > +  It can be called multiple times to compute the digest of long or
> discontinuous data streams.
> > +  EVP_MD context should be already correctly initialized by EvpMdInit(), and
> should not
> > +  be finalized by EvpMdFinal(). Behavior with invalid context is undefined.
> > +
> > +  If EvpMdContext is NULL, then return FALSE.
> > +
> > +  @param[in, out]  EvpMdContext       Pointer to the EVP_MD context.
> > +  @param[in]       Data               Pointer to the buffer containing the data to be
> digested.
> > +  @param[in]       DataSize           Size of Data buffer in bytes.
> > +
> > +  @retval TRUE   EVP data digest succeeded.
> > +  @retval FALSE  EVP data digest failed.
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +EvpMdUpdate (
> > +  IN OUT  VOID        *EvpMdContext,
> > +  IN      CONST VOID  *Data,
> > +  IN      UINTN       DataSize
> > +  );
> > +
> > +/**
> > +  Completes computation of the EVP digest value.
> > +
> > +  This function completes EVP hash computation and retrieves the digest
> value into
> > +  the specified memory. After this function has been called, the EVP context
> cannot
> > +  be used again.
> > +  EVP context should be already correctly initialized by EvpMdInit(), and
> should
> > +  not be finalized by EvpMdFinal(). Behavior with invalid EVP context is
> undefined.
> > +
> > +  If EvpMdContext is NULL, then return FALSE.
> > +  If Digest is NULL, then return FALSE.
> > +
> > +  @param[in, out]  EvpMdContext   Pointer to the EVP context.
> > +  @param[out]      Digest         Pointer to a buffer that receives the EVP digest
> value.
> > +
> > +  @retval TRUE   EVP digest computation succeeded.
> > +  @retval FALSE  EVP digest computation failed.
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +EvpMdFinal (
> > +  IN OUT  VOID   *EvpMdContext,
> > +  OUT     UINT8  *DigestValue
> > +  );
> > +
> >
> //===============================================================
> ======================
> >  //    Symmetric Cryptography Primitive
> >
> //===============================================================
> ======================
> > diff --git a/CryptoPkg/Library/BaseCryptLib/Evp/CryptEvpMd.c
> b/CryptoPkg/Library/BaseCryptLib/Evp/CryptEvpMd.c
> > new file mode 100644
> > index 0000000000..a38c300eb8
> > --- /dev/null
> > +++ b/CryptoPkg/Library/BaseCryptLib/Evp/CryptEvpMd.c
> > @@ -0,0 +1,228 @@
> > +/** @file
> > +  EVP MD Wrapper Implementation for OpenSSL.
> > +
> > +Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> > +SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "InternalCryptLib.h"
> > +#include <openssl/evp.h>
> > +
> > +/**
> > +  Allocates and initializes one EVP_MD_CTX context for subsequent EVP_MD
> use.
> > +
> > +  @return  Pointer to the EVP_MD_CTX context that has been initialized.
> > +           If the allocations fails, EvpMdNew() returns NULL.
> > +
> > +**/
> > +VOID *
> > +EFIAPI
> > +EvpMdNew (
> > +  VOID
> > +  )
> > +{
> > +  //
> > +  // Allocates & Initializes EVP_MD_CTX Context by OpenSSL
> EVP_MD_CTX_new()
> > +  //
> > +  return (VOID *) EVP_MD_CTX_new ();
> > +}
> 
> (3) This (VOID*) cast is not needed, and makes the code harder to read,
> in my opinion.
> 
> 
> > +
> > +/**
> > +  Release the specified EVP_MD_CTX context.
> > +
> > +  @param[in]  EvpMdContext  Pointer to the EVP_MD_CTX context to be
> released.
> > +
> > +**/
> > +VOID
> > +EFIAPI
> > +EvpMdFree (
> > +  IN  VOID  *EvpMdContext
> > +  )
> > +{
> > +  //
> > +  // Free OpenSSL EVP_MD_CTX Context
> > +  //
> > +  EVP_MD_CTX_free ((EVP_MD_CTX *)EvpMdContext);
> > +}
> 
> (4) Same as (3), just in the reverse direction -- I suggest dropping the
> (EVP_MD_CTX *) cast.
> 
> (Points (3) and (4) apply to some more locations in this patch; if you
> agree with my comments, please review the rest for these superfluous casts.)
> 
> 
> (5) If possible, I'd suggest appending at least one other patch to this
> series, for putting the new interfaces to use at once. We should pick a
> library or driver in edk2 that currently consumes Sha256Init() and its
> friends, and convert those calls to EvpMd*().
> 
> Thanks,
> Laszlo
> 
> > +
> > +/**
> > +  Initializes user-supplied memory pointed to by EvpMdContext as
> EVP_MD_CTX
> > +  context for subsequent use.
> > +
> > +  If EvpMdContext is NULL, then return FALSE.
> > +  If DigestName is NULL, then return FALSE.
> > +
> > +  @param[out]   EvpMdContext  Pointer to EVP_MD_CTX context being
> initialized.
> > +  @param[in]    DigestName    Pointer to the digest name.
> > +
> > +  @retval TRUE   EVP_MD_CTX context initialization succeeded.
> > +  @retval FALSE  EVP_MD_CTX context initialization failed.
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +EvpMdInit (
> > +  OUT VOID          *EvpMdContext,
> > +  IN  CONST CHAR8   *DigestName
> > +  )
> > +{
> > +  CONST EVP_MD    *Digest;
> > +
> > +  //
> > +  // Check input parameters.
> > +  //
> > +  if (EvpMdContext == NULL || DigestName == NULL) {
> > +    return FALSE;
> > +  }
> > +
> > +  //
> > +  // OpenSSL EVP_MD Context Initialization
> > +  //
> > +  if (EVP_MD_CTX_reset ((EVP_MD_CTX *)EvpMdContext) != 1) {
> > +    return FALSE;
> > +  }
> > +
> > +  Digest = EVP_get_digestbyname (DigestName);
> > +  if (Digest == NULL) {
> > +    return FALSE;
> > +  }
> > +
> > +  if (EVP_DigestInit_ex ((EVP_MD_CTX *)EvpMdContext, Digest, NULL) != 1) {
> > +    return FALSE;
> > +  }
> > +
> > +  return TRUE;
> > +}
> > +
> > +/**
> > +  Makes a copy of an existing EVP_MD context.
> > +
> > +  If EvpMdContext is NULL, then return FALSE.
> > +  If NewEvpMdContext is NULL, then return FALSE.
> > +
> > +  @param[in]  EvpMdContext     Pointer to EVP_MD context being copied.
> > +  @param[out] NewEvpMdContext  Pointer to new EVP_MD context.
> > +
> > +  @retval TRUE   EVP_MD context copy succeeded.
> > +  @retval FALSE  EVP_MD context copy failed.
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +EvpMdDuplicate (
> > +  IN  CONST VOID    *EvpMdContext,
> > +  OUT VOID          *NewEvpMdContext
> > +  )
> > +{
> > +  //
> > +  // Check input parameters.
> > +  //
> > +  if (EvpMdContext == NULL || NewEvpMdContext == NULL) {
> > +    return FALSE;
> > +  }
> > +
> > +  if (EVP_MD_CTX_copy ((EVP_MD_CTX *)NewEvpMdContext, (EVP_MD_CTX
> *)EvpMdContext) != 1) {
> > +    return FALSE;
> > +  }
> > +
> > +  return TRUE;
> > +}
> > +
> > +/**
> > +  Digests the input data and updates EVP_MD context.
> > +
> > +  This function performs EVP digest on a data buffer of the specified size.
> > +  It can be called multiple times to compute the digest of long or
> discontinuous data streams.
> > +  EVP_MD context should be already correctly initialized by EvpMdInit(), and
> should not
> > +  be finalized by EvpMdFinal(). Behavior with invalid context is undefined.
> > +
> > +  If EvpMdContext is NULL, then return FALSE.
> > +
> > +  @param[in, out]  EvpMdContext       Pointer to the EVP_MD context.
> > +  @param[in]       Data               Pointer to the buffer containing the data to be
> digested.
> > +  @param[in]       DataSize           Size of Data buffer in bytes.
> > +
> > +  @retval TRUE   EVP data digest succeeded.
> > +  @retval FALSE  EVP data digest failed.
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +EvpMdUpdate (
> > +  IN OUT  VOID        *EvpMdContext,
> > +  IN      CONST VOID  *Data,
> > +  IN      UINTN       DataSize
> > +  )
> > +{
> > +  //
> > +  // Check input parameters.
> > +  //
> > +  if (EvpMdContext == NULL) {
> > +    return FALSE;
> > +  }
> > +
> > +  //
> > +  // Check invalid parameters, in case only DataLength was checked in
> OpenSSL
> > +  //
> > +  if (Data == NULL && DataSize != 0) {
> > +    return FALSE;
> > +  }
> > +
> > +  //
> > +  // OpenSSL EVP digest update
> > +  //
> > +  if (EVP_DigestUpdate ((EVP_MD_CTX *)EvpMdContext, Data, DataSize) != 1)
> {
> > +    return FALSE;
> > +  }
> > +
> > +  return TRUE;
> > +}
> > +
> > +/**
> > +  Completes computation of the EVP digest value.
> > +
> > +  This function completes EVP hash computation and retrieves the digest
> value into
> > +  the specified memory. After this function has been called, the EVP context
> cannot
> > +  be used again.
> > +  EVP context should be already correctly initialized by EvpMdInit(), and
> should
> > +  not be finalized by EvpMdFinal(). Behavior with invalid EVP context is
> undefined.
> > +
> > +  If EvpMdContext is NULL, then return FALSE.
> > +  If Digest is NULL, then return FALSE.
> > +
> > +  @param[in, out]  EvpMdContext   Pointer to the EVP context.
> > +  @param[out]      Digest         Pointer to a buffer that receives the EVP digest
> value.
> > +
> > +  @retval TRUE   EVP digest computation succeeded.
> > +  @retval FALSE  EVP digest computation failed.
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +EvpMdFinal (
> > +  IN OUT  VOID   *EvpMdContext,
> > +  OUT     UINT8  *DigestValue
> > +  )
> > +{
> > +  UINT32  Length;
> > +
> > +  //
> > +  // Check input parameters.
> > +  //
> > +  if (EvpMdContext == NULL || DigestValue == NULL) {
> > +    return FALSE;
> > +  }
> > +
> > +  //
> > +  // OpenSSL EVP digest finalization
> > +  //
> > +  if (EVP_DigestFinal_ex ((EVP_MD_CTX *)EvpMdContext, DigestValue,
> &Length) != 1) {
> > +    return FALSE;
> > +  }
> > +  if (EVP_MD_CTX_reset ((EVP_MD_CTX *)EvpMdContext) != 1) {
> > +    return FALSE;
> > +  }
> > +
> > +  return TRUE;
> > +}
> >


  parent reply	other threads:[~2020-08-13 14:38 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-13  1:20 [PATCH 0/1] CryptoPkg/BaseCryptLib: Add EVP (Envelope) Digest interface Zurcher, Christopher J
2020-08-13  1:20 ` [PATCH 1/1] " Zurcher, Christopher J
2020-08-13  9:46   ` [edk2-devel] " Laszlo Ersek
2020-08-13  9:47     ` Laszlo Ersek
2020-08-13 14:38     ` Yao, Jiewen [this message]
2020-08-14 21:33       ` Zurcher, Christopher J

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CY4PR11MB128851D0F5103CD0EDABFE888C430@CY4PR11MB1288.namprd11.prod.outlook.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox