* [edk2-devel] [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature @ 2024-01-30 5:44 Nhi Pham via groups.io 2024-01-30 9:46 ` Wenxing Hou 0 siblings, 1 reply; 5+ messages in thread From: Nhi Pham via groups.io @ 2024-01-30 5:44 UTC (permalink / raw) To: devel; +Cc: Tam Chi Nguyen, Jiewen Yao, Wenxing Hou, Yi Li, Nhi Pham From: Tam Chi Nguyen <tamnguyenchi@os.amperecomputing.com> This patch adds a new Pkcs7GetSignature() API to support extracting the signature data from PKCS7 certificate. Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Wenxing Hou <wenxing.hou@intel.com> Cc: Yi Li <yi1.li@intel.com> Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com> --- CryptoPkg/Include/Library/BaseCryptLib.h | 29 +++++ CryptoPkg/Private/Protocol/Crypto.h | 29 +++++ CryptoPkg/Driver/Crypto.c | 33 ++++++ CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c | 120 ++++++++++++++++++++ CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c | 33 ++++++ CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c | 32 ++++++ 6 files changed, 276 insertions(+) diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h b/CryptoPkg/Include/Library/BaseCryptLib.h index a52bd91ad664..d52a91244482 100644 --- a/CryptoPkg/Include/Library/BaseCryptLib.h +++ b/CryptoPkg/Include/Library/BaseCryptLib.h @@ -5,6 +5,7 @@ functionality enabling. Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -2471,6 +2472,34 @@ ImageTimestampVerify ( OUT EFI_TIME *SigningTime ); +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ); + /** Retrieve the version from one X.509 certificate. diff --git a/CryptoPkg/Private/Protocol/Crypto.h b/CryptoPkg/Private/Protocol/Crypto.h index 0e0b1d94018d..d228cea0453b 100644 --- a/CryptoPkg/Private/Protocol/Crypto.h +++ b/CryptoPkg/Private/Protocol/Crypto.h @@ -3,6 +3,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -1036,6 +1037,34 @@ BOOLEAN OUT EFI_TIME *SigningTime ); +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +typedef +BOOLEAN +(EFIAPI *EDKII_CRYPTO_PKCS7_GET_SIGNATURE) ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ); + // ===================================================================================== // DH Key Exchange Primitive // ===================================================================================== diff --git a/CryptoPkg/Driver/Crypto.c b/CryptoPkg/Driver/Crypto.c index bdbb4863a97e..83094e73c33a 100644 --- a/CryptoPkg/Driver/Crypto.c +++ b/CryptoPkg/Driver/Crypto.c @@ -4,6 +4,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -3910,6 +3911,37 @@ CryptoServiceImageTimestampVerify ( return CALL_BASECRYPTLIB (Pkcs.Services.ImageTimestampVerify, ImageTimestampVerify, (AuthData, DataSize, TsaCert, CertSize, SigningTime), FALSE); } +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +CryptoServicePkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ) +{ + return CALL_BASECRYPTLIB (Pkcs.Services.Pkcs7GetSignature, Pkcs7GetSignature, (P7Data, P7Length, Signature, SignatureLength), FALSE); +} + // ===================================================================================== // DH Key Exchange Primitive // ===================================================================================== @@ -6748,6 +6780,7 @@ const EDKII_CRYPTO_PROTOCOL mEdkiiCrypto = { CryptoServicePkcs7GetCertificatesList, CryptoServiceAuthenticodeVerify, CryptoServiceImageTimestampVerify, + CryptoServicePkcs7GetSignature, /// DH CryptoServiceDhNew, CryptoServiceDhFree, diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c index 4e5a14e35210..9e3fccf1bb4e 100644 --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c @@ -11,6 +11,7 @@ Variable and will do basic check for data structure. Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -926,3 +927,122 @@ _Exit: return Status; } + +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ) +{ + PKCS7 *Pkcs7; + BOOLEAN Wrapped; + BOOLEAN Status; + UINT8 *SignedData; + UINT8 *Temp; + UINTN SignedDataSize; + STACK_OF (PKCS7_SIGNER_INFO) *SignerInfos; + PKCS7_SIGNER_INFO *SignInfo; + ASN1_OCTET_STRING *EncDigest; + + if ((P7Data == NULL) || (P7Length > INT_MAX) || + (Signature == NULL && SignatureLength == NULL)) { + return FALSE; + } + + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize); + if (!Status) { + return Status; + } + + Status = FALSE; + Pkcs7 = NULL; + // + // Retrieve PKCS#7 Data (DER encoding) + // + if (SignedDataSize > INT_MAX) { + goto _Exit; + } + + Temp = SignedData; + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize); + if (Pkcs7 == NULL) { + goto _Exit; + } + + // + // Check if it's PKCS#7 Signed Data (for Authenticode Scenario) + // + if (!PKCS7_type_is_signed (Pkcs7)) { + goto _Exit; + } + + // + // Check if there is one and only one signer. + // + SignerInfos = PKCS7_get_signer_info (Pkcs7); + if (!SignerInfos || (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) { + goto _Exit; + } + + // + // Locate the TimeStamp CounterSignature. + // + SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0); + if (SignInfo == NULL) { + goto _Exit; + } + + // + // Locate Message Digest which will be the data to be time-stamped. + // + EncDigest = SignInfo->enc_digest; + if (EncDigest == NULL) { + goto _Exit; + } + + *SignatureLength = EncDigest->length; + if (Signature != NULL) + { + if (*Signature == NULL) { + Status = FALSE; + goto _Exit; + } + CopyMem ((VOID *)*Signature, EncDigest->data, EncDigest->length); + Status = TRUE; + } + +_Exit: + // + // Release Resources + // + if (!Wrapped) { + free (SignedData); + } + if (Pkcs7 != NULL) { + PKCS7_free (Pkcs7); + } + + return Status; +} diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c index b9b7960126de..a080bbfc4237 100644 --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c @@ -3,6 +3,7 @@ real capabilities. Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -161,3 +162,35 @@ Pkcs7GetAttachedContent ( ASSERT (FALSE); return FALSE; } + +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c index 4e31bc278e0f..55d7b17688a0 100644 --- a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c +++ b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c @@ -4,6 +4,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -3146,6 +3147,37 @@ ImageTimestampVerify ( CALL_CRYPTO_SERVICE (ImageTimestampVerify, (AuthData, DataSize, TsaCert, CertSize, SigningTime), FALSE); } +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ) +{ + CALL_CRYPTO_SERVICE (Pkcs7GetSignature, (P7Data, P7Length, Signature, SignatureLength), FALSE); +} + // ===================================================================================== // DH Key Exchange Primitive // ===================================================================================== -- 2.25.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114759): https://edk2.groups.io/g/devel/message/114759 Mute This Topic: https://groups.io/mt/104048629/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [edk2-devel] [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature 2024-01-30 5:44 [edk2-devel] [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature Nhi Pham via groups.io @ 2024-01-30 9:46 ` Wenxing Hou 2024-01-30 9:48 ` Nhi Pham via groups.io 0 siblings, 1 reply; 5+ messages in thread From: Wenxing Hou @ 2024-01-30 9:46 UTC (permalink / raw) To: Nhi Pham, devel@edk2.groups.io; +Cc: Tam Chi Nguyen, Yao, Jiewen, Li, Yi1 Hi Pham, Thanks for your contribution. I think there are two works you need to do: Firstly, submit an EDKII PR to ensure the patch can pass the CI. Secondly, add unit-test to test the new API(such as: get signature then compare). Thanks Wenxing -----Original Message----- From: Nhi Pham <nhi@os.amperecomputing.com> Sent: Tuesday, January 30, 2024 1:44 PM To: devel@edk2.groups.io Cc: Tam Chi Nguyen <tamnguyenchi@os.amperecomputing.com>; Yao, Jiewen <jiewen.yao@intel.com>; Hou, Wenxing <wenxing.hou@intel.com>; Li, Yi1 <yi1.li@intel.com>; Nhi Pham <nhi@os.amperecomputing.com> Subject: [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature From: Tam Chi Nguyen <tamnguyenchi@os.amperecomputing.com> This patch adds a new Pkcs7GetSignature() API to support extracting the signature data from PKCS7 certificate. Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Wenxing Hou <wenxing.hou@intel.com> Cc: Yi Li <yi1.li@intel.com> Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com> --- CryptoPkg/Include/Library/BaseCryptLib.h | 29 +++++ CryptoPkg/Private/Protocol/Crypto.h | 29 +++++ CryptoPkg/Driver/Crypto.c | 33 ++++++ CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c | 120 ++++++++++++++++++++ CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c | 33 ++++++ CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c | 32 ++++++ 6 files changed, 276 insertions(+) diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h b/CryptoPkg/Include/Library/BaseCryptLib.h index a52bd91ad664..d52a91244482 100644 --- a/CryptoPkg/Include/Library/BaseCryptLib.h +++ b/CryptoPkg/Include/Library/BaseCryptLib.h @@ -5,6 +5,7 @@ functionality enabling. Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -2471,6 +2472,34 @@ ImageTimestampVerify ( OUT EFI_TIME *SigningTime ); +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could +be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ); + /** Retrieve the version from one X.509 certificate. diff --git a/CryptoPkg/Private/Protocol/Crypto.h b/CryptoPkg/Private/Protocol/Crypto.h index 0e0b1d94018d..d228cea0453b 100644 --- a/CryptoPkg/Private/Protocol/Crypto.h +++ b/CryptoPkg/Private/Protocol/Crypto.h @@ -3,6 +3,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -1036,6 +1037,34 @@ BOOLEAN OUT EFI_TIME *SigningTime ); +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could +be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +typedef +BOOLEAN +(EFIAPI *EDKII_CRYPTO_PKCS7_GET_SIGNATURE) ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ); + // ===================================================================================== // DH Key Exchange Primitive // ===================================================================================== diff --git a/CryptoPkg/Driver/Crypto.c b/CryptoPkg/Driver/Crypto.c index bdbb4863a97e..83094e73c33a 100644 --- a/CryptoPkg/Driver/Crypto.c +++ b/CryptoPkg/Driver/Crypto.c @@ -4,6 +4,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -3910,6 +3911,37 @@ CryptoServiceImageTimestampVerify ( return CALL_BASECRYPTLIB (Pkcs.Services.ImageTimestampVerify, ImageTimestampVerify, (AuthData, DataSize, TsaCert, CertSize, SigningTime), FALSE); } +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could +be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +CryptoServicePkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ) +{ + return CALL_BASECRYPTLIB (Pkcs.Services.Pkcs7GetSignature, +Pkcs7GetSignature, (P7Data, P7Length, Signature, SignatureLength), +FALSE); } + // ===================================================================================== // DH Key Exchange Primitive // ===================================================================================== @@ -6748,6 +6780,7 @@ const EDKII_CRYPTO_PROTOCOL mEdkiiCrypto = { CryptoServicePkcs7GetCertificatesList, CryptoServiceAuthenticodeVerify, CryptoServiceImageTimestampVerify, + CryptoServicePkcs7GetSignature, /// DH CryptoServiceDhNew, CryptoServiceDhFree, diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c index 4e5a14e35210..9e3fccf1bb4e 100644 --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c @@ -11,6 +11,7 @@ Variable and will do basic check for data structure. Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -926,3 +927,122 @@ _Exit: return Status; } + +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could +be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ) +{ + PKCS7 *Pkcs7; + BOOLEAN Wrapped; + BOOLEAN Status; + UINT8 *SignedData; + UINT8 *Temp; + UINTN SignedDataSize; + STACK_OF (PKCS7_SIGNER_INFO) *SignerInfos; + PKCS7_SIGNER_INFO *SignInfo; + ASN1_OCTET_STRING *EncDigest; + + if ((P7Data == NULL) || (P7Length > INT_MAX) || + (Signature == NULL && SignatureLength == NULL)) { + return FALSE; + } + + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, + &SignedDataSize); if (!Status) { + return Status; + } + + Status = FALSE; + Pkcs7 = NULL; + // + // Retrieve PKCS#7 Data (DER encoding) // if (SignedDataSize > + INT_MAX) { + goto _Exit; + } + + Temp = SignedData; + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) + SignedDataSize); if (Pkcs7 == NULL) { + goto _Exit; + } + + // + // Check if it's PKCS#7 Signed Data (for Authenticode Scenario) // + if (!PKCS7_type_is_signed (Pkcs7)) { + goto _Exit; + } + + // + // Check if there is one and only one signer. + // + SignerInfos = PKCS7_get_signer_info (Pkcs7); if (!SignerInfos || + (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) { + goto _Exit; + } + + // + // Locate the TimeStamp CounterSignature. + // + SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0); if (SignInfo + == NULL) { + goto _Exit; + } + + // + // Locate Message Digest which will be the data to be time-stamped. + // + EncDigest = SignInfo->enc_digest; + if (EncDigest == NULL) { + goto _Exit; + } + + *SignatureLength = EncDigest->length; if (Signature != NULL) { + if (*Signature == NULL) { + Status = FALSE; + goto _Exit; + } + CopyMem ((VOID *)*Signature, EncDigest->data, EncDigest->length); + Status = TRUE; + } + +_Exit: + // + // Release Resources + // + if (!Wrapped) { + free (SignedData); + } + if (Pkcs7 != NULL) { + PKCS7_free (Pkcs7); + } + + return Status; +} diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c index b9b7960126de..a080bbfc4237 100644 --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c @@ -3,6 +3,7 @@ real capabilities. Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -161,3 +162,35 @@ Pkcs7GetAttachedContent ( ASSERT (FALSE); return FALSE; } + +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could +be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c index 4e31bc278e0f..55d7b17688a0 100644 --- a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c +++ b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c @@ -4,6 +4,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -3146,6 +3147,37 @@ ImageTimestampVerify ( CALL_CRYPTO_SERVICE (ImageTimestampVerify, (AuthData, DataSize, TsaCert, CertSize, SigningTime), FALSE); } +/** + Get the data signature from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could +be wrapped + in a ContentInfo structure. + + If P7Data, Signature, SignatureLength is NULL, then return FALSE. + If P7Length overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] Signature Pointer to Signature data + @param[out] SignatureLength Length of signature in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSignature ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **Signature, + OUT UINTN *SignatureLength + ) +{ + CALL_CRYPTO_SERVICE (Pkcs7GetSignature, (P7Data, P7Length, Signature, +SignatureLength), FALSE); } + // ===================================================================================== // DH Key Exchange Primitive // ===================================================================================== -- 2.25.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114768): https://edk2.groups.io/g/devel/message/114768 Mute This Topic: https://groups.io/mt/104048629/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [edk2-devel] [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature 2024-01-30 9:46 ` Wenxing Hou @ 2024-01-30 9:48 ` Nhi Pham via groups.io 2024-02-01 2:09 ` Yao, Jiewen 0 siblings, 1 reply; 5+ messages in thread From: Nhi Pham via groups.io @ 2024-01-30 9:48 UTC (permalink / raw) To: Hou, Wenxing, devel@edk2.groups.io; +Cc: Tam Chi Nguyen, Yao, Jiewen, Li, Yi1 Thanks Wenxing. I'll do that. Regards, Nhi On 1/30/2024 4:46 PM, Hou, Wenxing wrote: > Hi Pham, > > Thanks for your contribution. > > I think there are two works you need to do: > Firstly, submit an EDKII PR to ensure the patch can pass the CI. > Secondly, add unit-test to test the new API(such as: get signature then compare). > > > Thanks > Wenxing > > > -----Original Message----- > From: Nhi Pham <nhi@os.amperecomputing.com> > Sent: Tuesday, January 30, 2024 1:44 PM > To: devel@edk2.groups.io > Cc: Tam Chi Nguyen <tamnguyenchi@os.amperecomputing.com>; Yao, Jiewen <jiewen.yao@intel.com>; Hou, Wenxing <wenxing.hou@intel.com>; Li, Yi1 <yi1.li@intel.com>; Nhi Pham <nhi@os.amperecomputing.com> > Subject: [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature > > From: Tam Chi Nguyen <tamnguyenchi@os.amperecomputing.com> > > This patch adds a new Pkcs7GetSignature() API to support extracting the signature data from PKCS7 certificate. > > Cc: Jiewen Yao <jiewen.yao@intel.com> > Cc: Wenxing Hou <wenxing.hou@intel.com> > Cc: Yi Li <yi1.li@intel.com> > Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com> > --- > CryptoPkg/Include/Library/BaseCryptLib.h | 29 +++++ > CryptoPkg/Private/Protocol/Crypto.h | 29 +++++ > CryptoPkg/Driver/Crypto.c | 33 ++++++ > CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c | 120 ++++++++++++++++++++ > CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c | 33 ++++++ > CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c | 32 ++++++ > 6 files changed, 276 insertions(+) > > diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h b/CryptoPkg/Include/Library/BaseCryptLib.h > index a52bd91ad664..d52a91244482 100644 > --- a/CryptoPkg/Include/Library/BaseCryptLib.h > +++ b/CryptoPkg/Include/Library/BaseCryptLib.h > @@ -5,6 +5,7 @@ > functionality enabling. > > Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR> > +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > SPDX-License-Identifier: BSD-2-Clause-Patent > > **/ > @@ -2471,6 +2472,34 @@ ImageTimestampVerify ( > OUT EFI_TIME *SigningTime > ); > > +/** > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > + Cryptographic Message Syntax Standard". The input signed data could > +be wrapped > + in a ContentInfo structure. > + > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > + If P7Length overflow, then return FALSE. > + If this interface is not supported, then return FALSE. > + > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > + @param[in] P7Length Length of the PKCS#7 message in bytes. > + @param[out] Signature Pointer to Signature data > + @param[out] SignatureLength Length of signature in bytes. > + > + @retval TRUE The operation is finished successfully. > + @retval FALSE Error occurs during the operation. > + @retval FALSE This interface is not supported. > + > +**/ > +BOOLEAN > +EFIAPI > +Pkcs7GetSignature ( > + IN CONST UINT8 *P7Data, > + IN UINTN P7Length, > + OUT UINT8 **Signature, > + OUT UINTN *SignatureLength > + ); > + > /** > Retrieve the version from one X.509 certificate. > > diff --git a/CryptoPkg/Private/Protocol/Crypto.h b/CryptoPkg/Private/Protocol/Crypto.h > index 0e0b1d94018d..d228cea0453b 100644 > --- a/CryptoPkg/Private/Protocol/Crypto.h > +++ b/CryptoPkg/Private/Protocol/Crypto.h > @@ -3,6 +3,7 @@ > > Copyright (C) Microsoft Corporation. All rights reserved. > Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR> > + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > SPDX-License-Identifier: BSD-2-Clause-Patent > > **/ > @@ -1036,6 +1037,34 @@ BOOLEAN > OUT EFI_TIME *SigningTime > ); > > +/** > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > + Cryptographic Message Syntax Standard". The input signed data could > +be wrapped > + in a ContentInfo structure. > + > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > + If P7Length overflow, then return FALSE. > + If this interface is not supported, then return FALSE. > + > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > + @param[in] P7Length Length of the PKCS#7 message in bytes. > + @param[out] Signature Pointer to Signature data > + @param[out] SignatureLength Length of signature in bytes. > + > + @retval TRUE The operation is finished successfully. > + @retval FALSE Error occurs during the operation. > + @retval FALSE This interface is not supported. > + > +**/ > +typedef > +BOOLEAN > +(EFIAPI *EDKII_CRYPTO_PKCS7_GET_SIGNATURE) ( > + IN CONST UINT8 *P7Data, > + IN UINTN P7Length, > + OUT UINT8 **Signature, > + OUT UINTN *SignatureLength > + ); > + > // ===================================================================================== > // DH Key Exchange Primitive > // ===================================================================================== > diff --git a/CryptoPkg/Driver/Crypto.c b/CryptoPkg/Driver/Crypto.c index bdbb4863a97e..83094e73c33a 100644 > --- a/CryptoPkg/Driver/Crypto.c > +++ b/CryptoPkg/Driver/Crypto.c > @@ -4,6 +4,7 @@ > > Copyright (C) Microsoft Corporation. All rights reserved. > Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR> > + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > SPDX-License-Identifier: BSD-2-Clause-Patent > > **/ > @@ -3910,6 +3911,37 @@ CryptoServiceImageTimestampVerify ( > return CALL_BASECRYPTLIB (Pkcs.Services.ImageTimestampVerify, ImageTimestampVerify, (AuthData, DataSize, TsaCert, CertSize, SigningTime), FALSE); } > > +/** > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > + Cryptographic Message Syntax Standard". The input signed data could > +be wrapped > + in a ContentInfo structure. > + > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > + If P7Length overflow, then return FALSE. > + If this interface is not supported, then return FALSE. > + > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > + @param[in] P7Length Length of the PKCS#7 message in bytes. > + @param[out] Signature Pointer to Signature data > + @param[out] SignatureLength Length of signature in bytes. > + > + @retval TRUE The operation is finished successfully. > + @retval FALSE Error occurs during the operation. > + @retval FALSE This interface is not supported. > + > +**/ > +BOOLEAN > +EFIAPI > +CryptoServicePkcs7GetSignature ( > + IN CONST UINT8 *P7Data, > + IN UINTN P7Length, > + OUT UINT8 **Signature, > + OUT UINTN *SignatureLength > + ) > +{ > + return CALL_BASECRYPTLIB (Pkcs.Services.Pkcs7GetSignature, > +Pkcs7GetSignature, (P7Data, P7Length, Signature, SignatureLength), > +FALSE); } > + > // ===================================================================================== > // DH Key Exchange Primitive > // ===================================================================================== > @@ -6748,6 +6780,7 @@ const EDKII_CRYPTO_PROTOCOL mEdkiiCrypto = { > CryptoServicePkcs7GetCertificatesList, > CryptoServiceAuthenticodeVerify, > CryptoServiceImageTimestampVerify, > + CryptoServicePkcs7GetSignature, > /// DH > CryptoServiceDhNew, > CryptoServiceDhFree, > diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c > index 4e5a14e35210..9e3fccf1bb4e 100644 > --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c > +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c > @@ -11,6 +11,7 @@ > Variable and will do basic check for data structure. > > Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> > +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > SPDX-License-Identifier: BSD-2-Clause-Patent > > **/ > @@ -926,3 +927,122 @@ _Exit: > > return Status; > } > + > +/** > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > + Cryptographic Message Syntax Standard". The input signed data could > +be wrapped > + in a ContentInfo structure. > + > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > + If P7Length overflow, then return FALSE. > + If this interface is not supported, then return FALSE. > + > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > + @param[in] P7Length Length of the PKCS#7 message in bytes. > + @param[out] Signature Pointer to Signature data > + @param[out] SignatureLength Length of signature in bytes. > + > + @retval TRUE The operation is finished successfully. > + @retval FALSE Error occurs during the operation. > + @retval FALSE This interface is not supported. > + > +**/ > +BOOLEAN > +EFIAPI > +Pkcs7GetSignature ( > + IN CONST UINT8 *P7Data, > + IN UINTN P7Length, > + OUT UINT8 **Signature, > + OUT UINTN *SignatureLength > + ) > +{ > + PKCS7 *Pkcs7; > + BOOLEAN Wrapped; > + BOOLEAN Status; > + UINT8 *SignedData; > + UINT8 *Temp; > + UINTN SignedDataSize; > + STACK_OF (PKCS7_SIGNER_INFO) *SignerInfos; > + PKCS7_SIGNER_INFO *SignInfo; > + ASN1_OCTET_STRING *EncDigest; > + > + if ((P7Data == NULL) || (P7Length > INT_MAX) || > + (Signature == NULL && SignatureLength == NULL)) { > + return FALSE; > + } > + > + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, > + &SignedDataSize); if (!Status) { > + return Status; > + } > + > + Status = FALSE; > + Pkcs7 = NULL; > + // > + // Retrieve PKCS#7 Data (DER encoding) // if (SignedDataSize > > + INT_MAX) { > + goto _Exit; > + } > + > + Temp = SignedData; > + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) > + SignedDataSize); if (Pkcs7 == NULL) { > + goto _Exit; > + } > + > + // > + // Check if it's PKCS#7 Signed Data (for Authenticode Scenario) // > + if (!PKCS7_type_is_signed (Pkcs7)) { > + goto _Exit; > + } > + > + // > + // Check if there is one and only one signer. > + // > + SignerInfos = PKCS7_get_signer_info (Pkcs7); if (!SignerInfos || > + (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) { > + goto _Exit; > + } > + > + // > + // Locate the TimeStamp CounterSignature. > + // > + SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0); if (SignInfo > + == NULL) { > + goto _Exit; > + } > + > + // > + // Locate Message Digest which will be the data to be time-stamped. > + // > + EncDigest = SignInfo->enc_digest; > + if (EncDigest == NULL) { > + goto _Exit; > + } > + > + *SignatureLength = EncDigest->length; if (Signature != NULL) { > + if (*Signature == NULL) { > + Status = FALSE; > + goto _Exit; > + } > + CopyMem ((VOID *)*Signature, EncDigest->data, EncDigest->length); > + Status = TRUE; > + } > + > +_Exit: > + // > + // Release Resources > + // > + if (!Wrapped) { > + free (SignedData); > + } > + if (Pkcs7 != NULL) { > + PKCS7_free (Pkcs7); > + } > + > + return Status; > +} > diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c > index b9b7960126de..a080bbfc4237 100644 > --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c > +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c > @@ -3,6 +3,7 @@ > real capabilities. > > Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR> > +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > SPDX-License-Identifier: BSD-2-Clause-Patent > > **/ > @@ -161,3 +162,35 @@ Pkcs7GetAttachedContent ( > ASSERT (FALSE); > return FALSE; > } > + > +/** > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > + Cryptographic Message Syntax Standard". The input signed data could > +be wrapped > + in a ContentInfo structure. > + > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > + If P7Length overflow, then return FALSE. > + If this interface is not supported, then return FALSE. > + > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > + @param[in] P7Length Length of the PKCS#7 message in bytes. > + @param[out] Signature Pointer to Signature data > + @param[out] SignatureLength Length of signature in bytes. > + > + @retval TRUE The operation is finished successfully. > + @retval FALSE Error occurs during the operation. > + @retval FALSE This interface is not supported. > + > +**/ > +BOOLEAN > +EFIAPI > +Pkcs7GetSignature ( > + IN CONST UINT8 *P7Data, > + IN UINTN P7Length, > + OUT UINT8 **Signature, > + OUT UINTN *SignatureLength > + ) > +{ > + ASSERT (FALSE); > + return FALSE; > +} > diff --git a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c > index 4e31bc278e0f..55d7b17688a0 100644 > --- a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c > +++ b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c > @@ -4,6 +4,7 @@ > > Copyright (C) Microsoft Corporation. All rights reserved. > Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR> > + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > SPDX-License-Identifier: BSD-2-Clause-Patent > > **/ > @@ -3146,6 +3147,37 @@ ImageTimestampVerify ( > CALL_CRYPTO_SERVICE (ImageTimestampVerify, (AuthData, DataSize, TsaCert, CertSize, SigningTime), FALSE); } > > +/** > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > + Cryptographic Message Syntax Standard". The input signed data could > +be wrapped > + in a ContentInfo structure. > + > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > + If P7Length overflow, then return FALSE. > + If this interface is not supported, then return FALSE. > + > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > + @param[in] P7Length Length of the PKCS#7 message in bytes. > + @param[out] Signature Pointer to Signature data > + @param[out] SignatureLength Length of signature in bytes. > + > + @retval TRUE The operation is finished successfully. > + @retval FALSE Error occurs during the operation. > + @retval FALSE This interface is not supported. > + > +**/ > +BOOLEAN > +EFIAPI > +Pkcs7GetSignature ( > + IN CONST UINT8 *P7Data, > + IN UINTN P7Length, > + OUT UINT8 **Signature, > + OUT UINTN *SignatureLength > + ) > +{ > + CALL_CRYPTO_SERVICE (Pkcs7GetSignature, (P7Data, P7Length, Signature, > +SignatureLength), FALSE); } > + > // ===================================================================================== > // DH Key Exchange Primitive > // ===================================================================================== > -- > 2.25.1 > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114769): https://edk2.groups.io/g/devel/message/114769 Mute This Topic: https://groups.io/mt/104048629/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [edk2-devel] [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature 2024-01-30 9:48 ` Nhi Pham via groups.io @ 2024-02-01 2:09 ` Yao, Jiewen 2024-02-19 3:31 ` Nhi Pham via groups.io 0 siblings, 1 reply; 5+ messages in thread From: Yao, Jiewen @ 2024-02-01 2:09 UTC (permalink / raw) To: Nhi Pham, Hou, Wenxing, devel@edk2.groups.io; +Cc: Tam Chi Nguyen, Li, Yi1 Hi Nhi Would you please: 1) File an issue in Bugzilla - https://bugzilla.tianocore.org/ 2) Share with us the usage of this new API. We are trying to understand why it is needed. Thank you Yao, Jiewen > -----Original Message----- > From: Nhi Pham <nhi@os.amperecomputing.com> > Sent: Tuesday, January 30, 2024 5:49 PM > To: Hou, Wenxing <wenxing.hou@intel.com>; devel@edk2.groups.io > Cc: Tam Chi Nguyen <tamnguyenchi@os.amperecomputing.com>; Yao, Jiewen > <jiewen.yao@intel.com>; Li, Yi1 <yi1.li@intel.com> > Subject: Re: [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature > > Thanks Wenxing. I'll do that. > > Regards, > Nhi > > On 1/30/2024 4:46 PM, Hou, Wenxing wrote: > > Hi Pham, > > > > Thanks for your contribution. > > > > I think there are two works you need to do: > > Firstly, submit an EDKII PR to ensure the patch can pass the CI. > > Secondly, add unit-test to test the new API(such as: get signature then > compare). > > > > > > Thanks > > Wenxing > > > > > > -----Original Message----- > > From: Nhi Pham <nhi@os.amperecomputing.com> > > Sent: Tuesday, January 30, 2024 1:44 PM > > To: devel@edk2.groups.io > > Cc: Tam Chi Nguyen <tamnguyenchi@os.amperecomputing.com>; Yao, Jiewen > <jiewen.yao@intel.com>; Hou, Wenxing <wenxing.hou@intel.com>; Li, Yi1 > <yi1.li@intel.com>; Nhi Pham <nhi@os.amperecomputing.com> > > Subject: [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature > > > > From: Tam Chi Nguyen <tamnguyenchi@os.amperecomputing.com> > > > > This patch adds a new Pkcs7GetSignature() API to support extracting the > signature data from PKCS7 certificate. > > > > Cc: Jiewen Yao <jiewen.yao@intel.com> > > Cc: Wenxing Hou <wenxing.hou@intel.com> > > Cc: Yi Li <yi1.li@intel.com> > > Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com> > > --- > > CryptoPkg/Include/Library/BaseCryptLib.h | 29 +++++ > > CryptoPkg/Private/Protocol/Crypto.h | 29 +++++ > > CryptoPkg/Driver/Crypto.c | 33 ++++++ > > CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c | 120 > ++++++++++++++++++++ > > CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c | 33 ++++++ > > CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c | 32 ++++++ > > 6 files changed, 276 insertions(+) > > > > diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h > b/CryptoPkg/Include/Library/BaseCryptLib.h > > index a52bd91ad664..d52a91244482 100644 > > --- a/CryptoPkg/Include/Library/BaseCryptLib.h > > +++ b/CryptoPkg/Include/Library/BaseCryptLib.h > > @@ -5,6 +5,7 @@ > > functionality enabling. > > > > Copyright (c) 2009 - 2022, Intel Corporation. All rights reserved.<BR> > > +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > > SPDX-License-Identifier: BSD-2-Clause-Patent > > > > **/ > > @@ -2471,6 +2472,34 @@ ImageTimestampVerify ( > > OUT EFI_TIME *SigningTime > > ); > > > > +/** > > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > > + Cryptographic Message Syntax Standard". The input signed data could > > +be wrapped > > + in a ContentInfo structure. > > + > > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > > + If P7Length overflow, then return FALSE. > > + If this interface is not supported, then return FALSE. > > + > > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > > + @param[in] P7Length Length of the PKCS#7 message in bytes. > > + @param[out] Signature Pointer to Signature data > > + @param[out] SignatureLength Length of signature in bytes. > > + > > + @retval TRUE The operation is finished successfully. > > + @retval FALSE Error occurs during the operation. > > + @retval FALSE This interface is not supported. > > + > > +**/ > > +BOOLEAN > > +EFIAPI > > +Pkcs7GetSignature ( > > + IN CONST UINT8 *P7Data, > > + IN UINTN P7Length, > > + OUT UINT8 **Signature, > > + OUT UINTN *SignatureLength > > + ); > > + > > /** > > Retrieve the version from one X.509 certificate. > > > > diff --git a/CryptoPkg/Private/Protocol/Crypto.h > b/CryptoPkg/Private/Protocol/Crypto.h > > index 0e0b1d94018d..d228cea0453b 100644 > > --- a/CryptoPkg/Private/Protocol/Crypto.h > > +++ b/CryptoPkg/Private/Protocol/Crypto.h > > @@ -3,6 +3,7 @@ > > > > Copyright (C) Microsoft Corporation. All rights reserved. > > Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR> > > + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > > SPDX-License-Identifier: BSD-2-Clause-Patent > > > > **/ > > @@ -1036,6 +1037,34 @@ BOOLEAN > > OUT EFI_TIME *SigningTime > > ); > > > > +/** > > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > > + Cryptographic Message Syntax Standard". The input signed data could > > +be wrapped > > + in a ContentInfo structure. > > + > > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > > + If P7Length overflow, then return FALSE. > > + If this interface is not supported, then return FALSE. > > + > > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > > + @param[in] P7Length Length of the PKCS#7 message in bytes. > > + @param[out] Signature Pointer to Signature data > > + @param[out] SignatureLength Length of signature in bytes. > > + > > + @retval TRUE The operation is finished successfully. > > + @retval FALSE Error occurs during the operation. > > + @retval FALSE This interface is not supported. > > + > > +**/ > > +typedef > > +BOOLEAN > > +(EFIAPI *EDKII_CRYPTO_PKCS7_GET_SIGNATURE) ( > > + IN CONST UINT8 *P7Data, > > + IN UINTN P7Length, > > + OUT UINT8 **Signature, > > + OUT UINTN *SignatureLength > > + ); > > + > > // > ================================================================= > ==================== > > // DH Key Exchange Primitive > > // > ================================================================= > ==================== > > diff --git a/CryptoPkg/Driver/Crypto.c b/CryptoPkg/Driver/Crypto.c index > bdbb4863a97e..83094e73c33a 100644 > > --- a/CryptoPkg/Driver/Crypto.c > > +++ b/CryptoPkg/Driver/Crypto.c > > @@ -4,6 +4,7 @@ > > > > Copyright (C) Microsoft Corporation. All rights reserved. > > Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR> > > + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > > SPDX-License-Identifier: BSD-2-Clause-Patent > > > > **/ > > @@ -3910,6 +3911,37 @@ CryptoServiceImageTimestampVerify ( > > return CALL_BASECRYPTLIB (Pkcs.Services.ImageTimestampVerify, > ImageTimestampVerify, (AuthData, DataSize, TsaCert, CertSize, SigningTime), > FALSE); } > > > > +/** > > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > > + Cryptographic Message Syntax Standard". The input signed data could > > +be wrapped > > + in a ContentInfo structure. > > + > > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > > + If P7Length overflow, then return FALSE. > > + If this interface is not supported, then return FALSE. > > + > > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > > + @param[in] P7Length Length of the PKCS#7 message in bytes. > > + @param[out] Signature Pointer to Signature data > > + @param[out] SignatureLength Length of signature in bytes. > > + > > + @retval TRUE The operation is finished successfully. > > + @retval FALSE Error occurs during the operation. > > + @retval FALSE This interface is not supported. > > + > > +**/ > > +BOOLEAN > > +EFIAPI > > +CryptoServicePkcs7GetSignature ( > > + IN CONST UINT8 *P7Data, > > + IN UINTN P7Length, > > + OUT UINT8 **Signature, > > + OUT UINTN *SignatureLength > > + ) > > +{ > > + return CALL_BASECRYPTLIB (Pkcs.Services.Pkcs7GetSignature, > > +Pkcs7GetSignature, (P7Data, P7Length, Signature, SignatureLength), > > +FALSE); } > > + > > // > ================================================================= > ==================== > > // DH Key Exchange Primitive > > // > ================================================================= > ==================== > > @@ -6748,6 +6780,7 @@ const EDKII_CRYPTO_PROTOCOL mEdkiiCrypto = { > > CryptoServicePkcs7GetCertificatesList, > > CryptoServiceAuthenticodeVerify, > > CryptoServiceImageTimestampVerify, > > + CryptoServicePkcs7GetSignature, > > /// DH > > CryptoServiceDhNew, > > CryptoServiceDhFree, > > diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c > b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c > > index 4e5a14e35210..9e3fccf1bb4e 100644 > > --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c > > +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c > > @@ -11,6 +11,7 @@ > > Variable and will do basic check for data structure. > > > > Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> > > +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > > SPDX-License-Identifier: BSD-2-Clause-Patent > > > > **/ > > @@ -926,3 +927,122 @@ _Exit: > > > > return Status; > > } > > + > > +/** > > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > > + Cryptographic Message Syntax Standard". The input signed data could > > +be wrapped > > + in a ContentInfo structure. > > + > > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > > + If P7Length overflow, then return FALSE. > > + If this interface is not supported, then return FALSE. > > + > > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > > + @param[in] P7Length Length of the PKCS#7 message in bytes. > > + @param[out] Signature Pointer to Signature data > > + @param[out] SignatureLength Length of signature in bytes. > > + > > + @retval TRUE The operation is finished successfully. > > + @retval FALSE Error occurs during the operation. > > + @retval FALSE This interface is not supported. > > + > > +**/ > > +BOOLEAN > > +EFIAPI > > +Pkcs7GetSignature ( > > + IN CONST UINT8 *P7Data, > > + IN UINTN P7Length, > > + OUT UINT8 **Signature, > > + OUT UINTN *SignatureLength > > + ) > > +{ > > + PKCS7 *Pkcs7; > > + BOOLEAN Wrapped; > > + BOOLEAN Status; > > + UINT8 *SignedData; > > + UINT8 *Temp; > > + UINTN SignedDataSize; > > + STACK_OF (PKCS7_SIGNER_INFO) *SignerInfos; > > + PKCS7_SIGNER_INFO *SignInfo; > > + ASN1_OCTET_STRING *EncDigest; > > + > > + if ((P7Data == NULL) || (P7Length > INT_MAX) || > > + (Signature == NULL && SignatureLength == NULL)) { > > + return FALSE; > > + } > > + > > + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, > > + &SignedDataSize); if (!Status) { > > + return Status; > > + } > > + > > + Status = FALSE; > > + Pkcs7 = NULL; > > + // > > + // Retrieve PKCS#7 Data (DER encoding) // if (SignedDataSize > > > + INT_MAX) { > > + goto _Exit; > > + } > > + > > + Temp = SignedData; > > + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) > > + SignedDataSize); if (Pkcs7 == NULL) { > > + goto _Exit; > > + } > > + > > + // > > + // Check if it's PKCS#7 Signed Data (for Authenticode Scenario) // > > + if (!PKCS7_type_is_signed (Pkcs7)) { > > + goto _Exit; > > + } > > + > > + // > > + // Check if there is one and only one signer. > > + // > > + SignerInfos = PKCS7_get_signer_info (Pkcs7); if (!SignerInfos || > > + (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) { > > + goto _Exit; > > + } > > + > > + // > > + // Locate the TimeStamp CounterSignature. > > + // > > + SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0); if (SignInfo > > + == NULL) { > > + goto _Exit; > > + } > > + > > + // > > + // Locate Message Digest which will be the data to be time-stamped. > > + // > > + EncDigest = SignInfo->enc_digest; > > + if (EncDigest == NULL) { > > + goto _Exit; > > + } > > + > > + *SignatureLength = EncDigest->length; if (Signature != NULL) { > > + if (*Signature == NULL) { > > + Status = FALSE; > > + goto _Exit; > > + } > > + CopyMem ((VOID *)*Signature, EncDigest->data, EncDigest->length); > > + Status = TRUE; > > + } > > + > > +_Exit: > > + // > > + // Release Resources > > + // > > + if (!Wrapped) { > > + free (SignedData); > > + } > > + if (Pkcs7 != NULL) { > > + PKCS7_free (Pkcs7); > > + } > > + > > + return Status; > > +} > > diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c > b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c > > index b9b7960126de..a080bbfc4237 100644 > > --- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c > > +++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c > > @@ -3,6 +3,7 @@ > > real capabilities. > > > > Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR> > > +Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > > SPDX-License-Identifier: BSD-2-Clause-Patent > > > > **/ > > @@ -161,3 +162,35 @@ Pkcs7GetAttachedContent ( > > ASSERT (FALSE); > > return FALSE; > > } > > + > > +/** > > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > > + Cryptographic Message Syntax Standard". The input signed data could > > +be wrapped > > + in a ContentInfo structure. > > + > > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > > + If P7Length overflow, then return FALSE. > > + If this interface is not supported, then return FALSE. > > + > > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > > + @param[in] P7Length Length of the PKCS#7 message in bytes. > > + @param[out] Signature Pointer to Signature data > > + @param[out] SignatureLength Length of signature in bytes. > > + > > + @retval TRUE The operation is finished successfully. > > + @retval FALSE Error occurs during the operation. > > + @retval FALSE This interface is not supported. > > + > > +**/ > > +BOOLEAN > > +EFIAPI > > +Pkcs7GetSignature ( > > + IN CONST UINT8 *P7Data, > > + IN UINTN P7Length, > > + OUT UINT8 **Signature, > > + OUT UINTN *SignatureLength > > + ) > > +{ > > + ASSERT (FALSE); > > + return FALSE; > > +} > > diff --git a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c > b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c > > index 4e31bc278e0f..55d7b17688a0 100644 > > --- a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c > > +++ b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c > > @@ -4,6 +4,7 @@ > > > > Copyright (C) Microsoft Corporation. All rights reserved. > > Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR> > > + Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> > > SPDX-License-Identifier: BSD-2-Clause-Patent > > > > **/ > > @@ -3146,6 +3147,37 @@ ImageTimestampVerify ( > > CALL_CRYPTO_SERVICE (ImageTimestampVerify, (AuthData, DataSize, > TsaCert, CertSize, SigningTime), FALSE); } > > > > +/** > > + Get the data signature from PKCS#7 signed data as described in "PKCS #7: > > + Cryptographic Message Syntax Standard". The input signed data could > > +be wrapped > > + in a ContentInfo structure. > > + > > + If P7Data, Signature, SignatureLength is NULL, then return FALSE. > > + If P7Length overflow, then return FALSE. > > + If this interface is not supported, then return FALSE. > > + > > + @param[in] P7Data Pointer to the PKCS#7 message to verify. > > + @param[in] P7Length Length of the PKCS#7 message in bytes. > > + @param[out] Signature Pointer to Signature data > > + @param[out] SignatureLength Length of signature in bytes. > > + > > + @retval TRUE The operation is finished successfully. > > + @retval FALSE Error occurs during the operation. > > + @retval FALSE This interface is not supported. > > + > > +**/ > > +BOOLEAN > > +EFIAPI > > +Pkcs7GetSignature ( > > + IN CONST UINT8 *P7Data, > > + IN UINTN P7Length, > > + OUT UINT8 **Signature, > > + OUT UINTN *SignatureLength > > + ) > > +{ > > + CALL_CRYPTO_SERVICE (Pkcs7GetSignature, (P7Data, P7Length, Signature, > > +SignatureLength), FALSE); } > > + > > // > ================================================================= > ==================== > > // DH Key Exchange Primitive > > // > ================================================================= > ==================== > > -- > > 2.25.1 > > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114927): https://edk2.groups.io/g/devel/message/114927 Mute This Topic: https://groups.io/mt/104048629/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [edk2-devel] [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature 2024-02-01 2:09 ` Yao, Jiewen @ 2024-02-19 3:31 ` Nhi Pham via groups.io 0 siblings, 0 replies; 5+ messages in thread From: Nhi Pham via groups.io @ 2024-02-19 3:31 UTC (permalink / raw) To: devel, jiewen.yao, Hou, Wenxing; +Cc: Tam Chi Nguyen, Li, Yi1 On 2/1/2024 9:09 AM, Yao, Jiewen via groups.io wrote: > Hi Nhi > Would you please: > 1) File an issue in Bugzilla - https://bugzilla.tianocore.org/ > 2) Share with us the usage of this new API. > > We are trying to understand why it is needed. Hi Jiewen, Sorry for late response. I've just been back from vacation. Happy Lunar New Year! Let me try to explain the demand. This new API is consumed by Ampere Altra EDK2 [1] for enrolling platform UEFI boot/update keys managed by secure storage service in secure world. That is Ampere Trusted Firmware Secure Boot/Update Design [2] which provides platform firmware owners a way to generate the pair of keys, sign their UEFI firmware, and enroll their public key under the UEFI Secure Variable Format. Any update (modify/append/delete) must be authenticated in secure world. Hence, that is the reason we have to extract the key and pass the signature to secure storage service. I wonder whether it would be possible to have this API in the CryptLib before opening the Bugzilla ticket? [1] https://github.com/AmpereComputing/edk2-platforms/blob/ampere/Silicon/Ampere/AmpereAltraPkg/Library/SecVarLib/SecVarLib.c#L613 [2] https://blog.cloudflare.com/armed-to-boot Thanks, Nhi -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#115583): https://edk2.groups.io/g/devel/message/115583 Mute This Topic: https://groups.io/mt/104048629/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-02-19 3:31 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-01-30 5:44 [edk2-devel] [PATCH 1/1] CryptoPkg: Add new API to get PKCS7 Signature Nhi Pham via groups.io 2024-01-30 9:46 ` Wenxing Hou 2024-01-30 9:48 ` Nhi Pham via groups.io 2024-02-01 2:09 ` Yao, Jiewen 2024-02-19 3:31 ` Nhi Pham via groups.io
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox