mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
OcCryptoLib: Import new RSA stack
Import a new RSA stack and test utilities to support IMG4 image verification.
This commit is contained in:
parent
70fe07f83a
commit
410d10d3fc
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,6 +13,7 @@ TestsUser/Prelinked/Prelinked
|
||||
TestsUser/Prelinked/Result.xml
|
||||
TestsUser/Serialized/Serialized
|
||||
TestsUser/Smbios/Smbios
|
||||
Utilities/RsaTool/RsaTool
|
||||
Utilities/EfiResTool/EfiResTool
|
||||
Utilities/AppleEfiSignTool/AppleEfiSignTool
|
||||
Utilities/readlabel/readlabel
|
||||
|
||||
@ -53,7 +53,7 @@ OcAppleChunklistInitializeContext (
|
||||
BOOLEAN
|
||||
OcAppleChunklistVerifySignature (
|
||||
IN OUT OC_APPLE_CHUNKLIST_CONTEXT *Context,
|
||||
IN RSA_PUBLIC_KEY *PublicKey
|
||||
IN CONST OC_RSA_PUBLIC_KEY *PublicKey
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
50
Include/Library/OcAppleImg4Lib.h
Normal file
50
Include/Library/OcAppleImg4Lib.h
Normal file
@ -0,0 +1,50 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef OC_APPLE_IMG4_LIB_H
|
||||
#define OC_APPLE_IMG4_LIB_H
|
||||
|
||||
/**
|
||||
Verify the signature of ImageBuffer against Type of its IMG4 Manifest.
|
||||
|
||||
@param[in] This The pointer to the current protocol instance.
|
||||
@param[in] ObjType The IMG4 object type to validate against.
|
||||
@param[in] ImageBuffer The buffer to validate.
|
||||
@param[in] ImageSize The size, in bytes, of ImageBuffer.
|
||||
@param[in] SbMode The requested IMG4 Secure Boot mode.
|
||||
@param[in] ManifestBuffer The buffer of the IMG4 Manifest.
|
||||
@param[in] ManifestSize The size, in bytes, of ManifestBuffer.
|
||||
@param[out] HashDigest On output, a pointer to ImageBuffer's digest.
|
||||
@param[out] DigestSize On output, the size, in bytes, of *HashDigest.
|
||||
|
||||
@retval EFI_SUCCESS ImageBuffer is correctly signed.
|
||||
@retval EFI_INVALID_PARAMETER One or more required parameters are NULL.
|
||||
@retval EFI_OUT_OF_RESOURCES Not enough resources are available.
|
||||
@retval EFI_SECURITY_VIOLATION ImageBuffer's signature is invalid.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AppleImg4Verify (
|
||||
IN APPLE_IMG4_VERIFICATION_PROTOCOL *This,
|
||||
IN UINT32 ObjType,
|
||||
IN CONST VOID *ImageBuffer,
|
||||
IN UINTN ImageSize,
|
||||
IN UINT8 SbMode,
|
||||
IN CONST VOID *ManifestBuffer,
|
||||
IN UINTN ManifestSize,
|
||||
OUT UINT8 **HashDigest OPTIONAL,
|
||||
OUT UINTN *DigestSize OPTIONAL
|
||||
);
|
||||
|
||||
#endif // OC_APPLE_IMG4_LIB_H
|
||||
@ -20,14 +20,9 @@
|
||||
|
||||
#define NUM_OF_PK 2
|
||||
|
||||
OC_STATIC_ASSERT (
|
||||
sizeof (RSA_PUBLIC_KEY) == 520,
|
||||
"Incompatible configured RSA key size"
|
||||
);
|
||||
|
||||
typedef struct APPLE_PK_ENTRY_ {
|
||||
UINT8 Hash[SHA256_DIGEST_SIZE];
|
||||
UINT8 PublicKey[sizeof (RSA_PUBLIC_KEY)];
|
||||
UINT8 Hash[SHA256_DIGEST_SIZE];
|
||||
CONST OC_RSA_PUBLIC_KEY *PublicKey;
|
||||
} APPLE_PK_ENTRY;
|
||||
|
||||
extern CONST APPLE_PK_ENTRY PkDataBase[NUM_OF_PK];
|
||||
|
||||
@ -19,13 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#ifndef OC_CRYPTO_LIB_H
|
||||
#define OC_CRYPTO_LIB_H
|
||||
|
||||
//
|
||||
// Default to 2048-bit key length for RSA.
|
||||
//
|
||||
#ifndef CONFIG_RSA_KEY_BIT_SIZE
|
||||
#define CONFIG_RSA_KEY_BIT_SIZE 2048
|
||||
#define CONFIG_RSA_KEY_SIZE (CONFIG_RSA_KEY_BIT_SIZE / 8)
|
||||
#endif
|
||||
#include <Library/OcGuardLib.h>
|
||||
|
||||
//
|
||||
// Default to 128-bit key length for AES.
|
||||
@ -43,6 +37,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#define SHA384_DIGEST_SIZE 48
|
||||
#define SHA512_DIGEST_SIZE 64
|
||||
|
||||
#define OC_MAX_SHA_DIGEST_SIZE SHA512_DIGEST_SIZE
|
||||
|
||||
//
|
||||
// Block sizes.
|
||||
//
|
||||
@ -53,7 +49,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
//
|
||||
// Derived parameters.
|
||||
//
|
||||
#define RSANUMWORDS (CONFIG_RSA_KEY_SIZE / sizeof (UINT32))
|
||||
#define AES_BLOCK_SIZE 16
|
||||
|
||||
//
|
||||
@ -70,22 +65,16 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#endif
|
||||
|
||||
//
|
||||
// For now abort on anything but 2048, but we can support 1024 and 4096 at least.
|
||||
// Possible RSA algorithm types supported by OcCryptoLib
|
||||
// for RSA digital signature verification
|
||||
// PcdOcCryptoAllowedSigHashTypes MUST be kept in sync with changes!
|
||||
//
|
||||
#if CONFIG_RSA_KEY_BIT_SIZE != 2048 || CONFIG_RSA_KEY_SIZE != 256
|
||||
#error "Only RSA-2048 is supported"
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct RSA_PUBLIC_KEY_ {
|
||||
UINT32 Size;
|
||||
UINT32 N0Inv;
|
||||
UINT32 N[RSANUMWORDS];
|
||||
UINT32 Rr[RSANUMWORDS];
|
||||
} RSA_PUBLIC_KEY;
|
||||
|
||||
#pragma pack(pop)
|
||||
typedef enum OC_SIG_HASH_TYPE_ {
|
||||
OcSigHashTypeSha256,
|
||||
OcSigHashTypeSha384,
|
||||
OcSigHashTypeSha512,
|
||||
OcSigHashTypeMax
|
||||
} OC_SIG_HASH_TYPE;
|
||||
|
||||
typedef struct AES_CONTEXT_ {
|
||||
UINT8 RoundKey[AES_KEY_EXP_SIZE];
|
||||
@ -123,15 +112,43 @@ typedef struct SHA512_CONTEXT_ {
|
||||
|
||||
typedef SHA512_CONTEXT SHA384_CONTEXT;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
///
|
||||
/// The structure describing the RSA Public Key format.
|
||||
/// The exponent is always 65537.
|
||||
///
|
||||
typedef PACKED struct {
|
||||
///
|
||||
/// The number of 64-bit values of N and RSqrMod each.
|
||||
///
|
||||
UINT16 NumQwords;
|
||||
///
|
||||
/// Padding for 64-bit alignment. Must be 0 to allow future extensions.
|
||||
///
|
||||
UINT8 Reserved[6];
|
||||
///
|
||||
/// The Montgomery Inverse in 64-bit space: -1 / N[0] mod 2^64.
|
||||
///
|
||||
UINT64 N0Inv;
|
||||
} OC_RSA_PUBLIC_KEY_HDR;
|
||||
|
||||
typedef PACKED struct {
|
||||
///
|
||||
/// The RSA Public Key header structure.
|
||||
///
|
||||
OC_RSA_PUBLIC_KEY_HDR Hdr;
|
||||
///
|
||||
/// The Modulus and Montgomery's R^2 mod N in little endian byte order.
|
||||
///
|
||||
UINT64 Data[];
|
||||
} OC_RSA_PUBLIC_KEY;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
//
|
||||
// Functions prototypes
|
||||
//
|
||||
BOOLEAN
|
||||
RsaVerify (
|
||||
RSA_PUBLIC_KEY *Key,
|
||||
UINT8 *Signature,
|
||||
UINT8 *Sha256
|
||||
);
|
||||
|
||||
VOID
|
||||
AesInitCtxIv (
|
||||
@ -148,7 +165,7 @@ AesSetCtxIv (
|
||||
|
||||
//
|
||||
// Data size MUST be mutiple of AES_BLOCK_SIZE;
|
||||
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for Padding scheme
|
||||
// NOTES: you need to set Iv in Context via AesInitCtxIv() or AesSetCtxIv()
|
||||
// no Iv should ever be reused with the same key
|
||||
//
|
||||
@ -169,7 +186,7 @@ AesCbcDecryptBuffer (
|
||||
//
|
||||
// Same function for encrypting as for decrypting.
|
||||
// Iv is incremented for every block, and used after encryption as XOR-compliment for output
|
||||
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for Padding scheme
|
||||
// NOTES: you need to set Iv in Context via AesInitCtxIv() or AesSetCtxIv()
|
||||
// no Iv should ever be reused with the same key
|
||||
//
|
||||
@ -305,6 +322,107 @@ Sha384 (
|
||||
UINTN Len
|
||||
);
|
||||
|
||||
/**
|
||||
Verifies Data against Hash with the appropiate SHA2 algorithm for HashSize.
|
||||
|
||||
@param[in] Data The data to verify the hash of.
|
||||
@param[in] DataSize The, in bytes, of Data.
|
||||
@param[in] Hash The reference hash to verify against.
|
||||
@param[in] HashSize The size, in bytes, of Hash.
|
||||
|
||||
@return 0 All HashSize bytes of the two buffers are identical.
|
||||
@retval Non-zero If HashSize is not a valid SHA2 digest size, -1. Otherwise,
|
||||
the first mismatched byte in Data's hash subtracted from
|
||||
the first mismatched byte in Hash.
|
||||
|
||||
**/
|
||||
INTN
|
||||
SigVerifyShaHashBySize (
|
||||
IN CONST VOID *Data,
|
||||
IN UINTN DataSize,
|
||||
IN CONST UINT8 *Hash,
|
||||
IN UINTN HashSize
|
||||
);
|
||||
|
||||
/**
|
||||
Verify a RSA PKCS1.5 signature against an expected hash.
|
||||
The exponent is always 65537 as per the format specification.
|
||||
|
||||
@param[in] Key The RSA Public Key.
|
||||
@param[in] Signature The RSA signature to be verified.
|
||||
@param[in] SignatureSize Size, in bytes, of Signature.
|
||||
@param[in] Hash The Hash digest of the signed data.
|
||||
@param[in] HashSize Size, in bytes, of Hash.
|
||||
@param[in] Algorithm The RSA algorithm used.
|
||||
|
||||
@returns Whether the signature has been successfully verified as valid.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
RsaVerifySigHashFromKey (
|
||||
IN CONST OC_RSA_PUBLIC_KEY *Key,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SignatureSize,
|
||||
IN CONST UINT8 *Hash,
|
||||
IN UINTN HashSize,
|
||||
IN OC_SIG_HASH_TYPE Algorithm
|
||||
);
|
||||
|
||||
/**
|
||||
Verify RSA PKCS1.5 signed data against its signature.
|
||||
The modulus' size must be a multiple of the configured BIGNUM word size.
|
||||
This will be true for any conventional RSA, which use two's potencies.
|
||||
|
||||
@param[in] Modulus The RSA modulus byte array.
|
||||
@param[in] ModulusSize The size, in bytes, of Modulus.
|
||||
@param[in] Exponent The RSA exponent.
|
||||
@param[in] Signature The RSA signature to be verified.
|
||||
@param[in] SignatureSize Size, in bytes, of Signature.
|
||||
@param[in] Data The signed data to verify.
|
||||
@param[in] DataSize Size, in bytes, of Data.
|
||||
@param[in] Algorithm The RSA algorithm used.
|
||||
|
||||
@returns Whether the signature has been successfully verified as valid.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
RsaVerifySigDataFromData (
|
||||
IN CONST UINT8 *Modulus,
|
||||
IN UINTN ModulusSize,
|
||||
IN UINT32 Exponent,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SignatureSize,
|
||||
IN CONST UINT8 *Data,
|
||||
IN UINTN DataSize,
|
||||
IN OC_SIG_HASH_TYPE Algorithm
|
||||
);
|
||||
|
||||
/**
|
||||
Verify RSA PKCS1.5 signed data against its signature.
|
||||
The modulus' size must be a multiple of the configured BIGNUM word size.
|
||||
This will be true for any conventional RSA, which use two's potencies.
|
||||
The exponent is always 65537 as per the format specification.
|
||||
|
||||
@param[in] Key The RSA Public Key.
|
||||
@param[in] Signature The RSA signature to be verified.
|
||||
@param[in] SignatureSize Size, in bytes, of Signature.
|
||||
@param[in] Data The signed data to verify.
|
||||
@param[in] DataSize Size, in bytes, of Data.
|
||||
@param[in] Algorithm The RSA algorithm used.
|
||||
|
||||
@returns Whether the signature has been successfully verified as valid.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
RsaVerifySigDataFromKey (
|
||||
IN CONST OC_RSA_PUBLIC_KEY *Key,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SignatureSize,
|
||||
IN CONST UINT8 *Data,
|
||||
IN UINTN DataSize,
|
||||
IN OC_SIG_HASH_TYPE Algorithm
|
||||
);
|
||||
|
||||
/**
|
||||
Performs a cryptographically secure comparison of the contents of two
|
||||
buffers.
|
||||
|
||||
@ -18,6 +18,11 @@
|
||||
#include <Uefi.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
|
||||
/**
|
||||
The size, in Bits, of one Byte.
|
||||
**/
|
||||
#define OC_CHAR_BIT 8
|
||||
|
||||
/**
|
||||
Convert seconds to microseconds for use in e.g. gBS->Stall.
|
||||
**/
|
||||
|
||||
@ -20,14 +20,6 @@
|
||||
#include <Library/OcFileLib.h>
|
||||
#include <Library/OcSerializeLib.h>
|
||||
|
||||
/**
|
||||
Ensure that we actually use RSA 2048.
|
||||
**/
|
||||
OC_STATIC_ASSERT (
|
||||
CONFIG_RSA_KEY_BIT_SIZE == 2048 && CONFIG_RSA_KEY_SIZE == 256,
|
||||
"Unsupported RSA key size"
|
||||
);
|
||||
|
||||
/**
|
||||
Storage vault file containing a dictionary with SHA-256 hashes for all files.
|
||||
**/
|
||||
@ -104,7 +96,7 @@ OcStorageInitFromFs (
|
||||
OUT OC_STORAGE_CONTEXT *Context,
|
||||
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
|
||||
IN CONST CHAR16 *Path,
|
||||
IN RSA_PUBLIC_KEY *StorageKey OPTIONAL
|
||||
IN OC_RSA_PUBLIC_KEY *StorageKey OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@ -99,7 +99,7 @@ OcAppleChunklistInitializeContext (
|
||||
BOOLEAN
|
||||
OcAppleChunklistVerifySignature (
|
||||
IN OUT OC_APPLE_CHUNKLIST_CONTEXT *Context,
|
||||
IN RSA_PUBLIC_KEY *PublicKey
|
||||
IN CONST OC_RSA_PUBLIC_KEY *PublicKey
|
||||
)
|
||||
{
|
||||
BOOLEAN Result;
|
||||
@ -107,10 +107,13 @@ OcAppleChunklistVerifySignature (
|
||||
ASSERT (Context != NULL);
|
||||
ASSERT (Context->Signature != NULL);
|
||||
|
||||
Result = RsaVerify (
|
||||
Result = RsaVerifySigHashFromKey (
|
||||
PublicKey,
|
||||
Context->Signature->Signature,
|
||||
Context->Hash
|
||||
sizeof (Context->Signature->Signature),
|
||||
Context->Hash,
|
||||
sizeof (Context->Hash),
|
||||
OcSigHashTypeSha256
|
||||
);
|
||||
DEBUG_CODE (
|
||||
if (Result) {
|
||||
|
||||
@ -617,7 +617,7 @@ VerifyApplePeImageSignature (
|
||||
{
|
||||
UINTN Index = 0;
|
||||
APPLE_SIGNATURE_CONTEXT *SignatureContext = NULL;
|
||||
RSA_PUBLIC_KEY *Pk = NULL;
|
||||
OC_RSA_PUBLIC_KEY *Pk = NULL;
|
||||
|
||||
//
|
||||
// Build context if not present
|
||||
@ -680,7 +680,7 @@ VerifyApplePeImageSignature (
|
||||
//
|
||||
// PublicKey valid. Extract prepared publickey from database
|
||||
//
|
||||
Pk = (RSA_PUBLIC_KEY *) PkDataBase[Index].PublicKey;
|
||||
Pk = (OC_RSA_PUBLIC_KEY *) PkDataBase[Index].PublicKey;
|
||||
}
|
||||
}
|
||||
|
||||
@ -694,7 +694,7 @@ VerifyApplePeImageSignature (
|
||||
//
|
||||
// Verify signature
|
||||
//
|
||||
if (RsaVerify (Pk, SignatureContext->Signature, Context->PeImageHash) == 1 ) {
|
||||
if (RsaVerifySigHashFromKey (Pk, SignatureContext->Signature, sizeof (SignatureContext->Signature), Context->PeImageHash, sizeof (Context->PeImageHash), OcSigHashTypeSha256) == 1 ) {
|
||||
DEBUG ((DEBUG_INFO, "Signature verified!\n"));
|
||||
FreePool (SignatureContext);
|
||||
FreePool (Context);
|
||||
|
||||
322
Library/OcAppleImg4Lib/OcAppleImg4Lib.c
Normal file
322
Library/OcAppleImg4Lib/OcAppleImg4Lib.c
Normal file
@ -0,0 +1,322 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Guid/AppleVariable.h>
|
||||
|
||||
#include <Protocol/AppleImg4Verification.h>
|
||||
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcAppleKeysLib.h>
|
||||
#include <Library/OcCryptoLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
#include "libDER/oids.h"
|
||||
#include "libDERImg4/libDERImg4.h"
|
||||
#include "libDERImg4/Img4oids.h"
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED const uint8_t *DERImg4RootCertificate = gAppleX86SecureBootRootCaCert;
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED const size_t *DERImg4RootCertificateSize = &gAppleX86SecureBootRootCaCertSize;
|
||||
|
||||
bool
|
||||
DERImg4VerifySignature (
|
||||
DERByte *Modulus,
|
||||
DERSize ModulusSize,
|
||||
uint32_t Exponent,
|
||||
const uint8_t *Signature,
|
||||
size_t SignatureSize,
|
||||
uint8_t *Data,
|
||||
size_t DataSize,
|
||||
const DERItem *AlgoOid
|
||||
)
|
||||
{
|
||||
OC_SIG_HASH_TYPE AlgoType;
|
||||
|
||||
ASSERT (Modulus != NULL);
|
||||
ASSERT (ModulusSize > 0);
|
||||
ASSERT (Signature != NULL);
|
||||
ASSERT (SignatureSize > 0);
|
||||
ASSERT (Data != NULL);
|
||||
ASSERT (DataSize > 0);
|
||||
ASSERT (AlgoOid != NULL);
|
||||
|
||||
if (DEROidCompare (AlgoOid, &oidSha512Rsa)) {
|
||||
AlgoType = OcSigHashTypeSha512;
|
||||
} else if (DEROidCompare (AlgoOid, &oidSha384Rsa)) {
|
||||
AlgoType = OcSigHashTypeSha384;
|
||||
} else if (DEROidCompare (AlgoOid, &oidSha256Rsa)) {
|
||||
AlgoType = OcSigHashTypeSha256;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return RsaVerifySigDataFromData (
|
||||
Modulus,
|
||||
ModulusSize,
|
||||
Exponent,
|
||||
Signature,
|
||||
SignatureSize,
|
||||
Data,
|
||||
DataSize,
|
||||
AlgoType
|
||||
);
|
||||
}
|
||||
|
||||
VOID
|
||||
InternalRetrieveHwInfo (
|
||||
OUT DERImg4Environment *Environment
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN DataSize;
|
||||
//
|
||||
// FIXME: Retrieve these values from trusted storage and expose the variables.
|
||||
//
|
||||
ASSERT (Environment != NULL);
|
||||
|
||||
ZeroMem (Environment, sizeof (*Environment));
|
||||
|
||||
DataSize = sizeof (Environment->ecid);
|
||||
Status = gRT->GetVariable (
|
||||
L"ApECID",
|
||||
&gAppleSecureBootVariableGuid,
|
||||
NULL,
|
||||
&DataSize,
|
||||
&Environment->ecid
|
||||
);
|
||||
if (EFI_ERROR (Status) || DataSize != sizeof (Environment->ecid)) {
|
||||
Environment->ecid = 0;
|
||||
}
|
||||
|
||||
DataSize = sizeof (Environment->chipId);
|
||||
Status = gRT->GetVariable (
|
||||
L"ApChipID",
|
||||
&gAppleSecureBootVariableGuid,
|
||||
NULL,
|
||||
&DataSize,
|
||||
&Environment->chipId
|
||||
);
|
||||
if (EFI_ERROR (Status) || DataSize != sizeof (Environment->chipId)) {
|
||||
Environment->chipId = 0;
|
||||
}
|
||||
|
||||
DataSize = sizeof (Environment->boardId);
|
||||
Status = gRT->GetVariable (
|
||||
L"ApBoardID",
|
||||
&gAppleSecureBootVariableGuid,
|
||||
NULL,
|
||||
&DataSize,
|
||||
&Environment->boardId
|
||||
);
|
||||
if (EFI_ERROR (Status) || DataSize != sizeof (Environment->boardId)) {
|
||||
Environment->boardId = 0;
|
||||
}
|
||||
|
||||
Environment->certificateEpoch = 2;
|
||||
|
||||
DataSize = sizeof (Environment->securityDomain);
|
||||
Status = gRT->GetVariable (
|
||||
L"ApSecurityDomain",
|
||||
&gAppleSecureBootVariableGuid,
|
||||
NULL,
|
||||
&DataSize,
|
||||
&Environment->securityDomain
|
||||
);
|
||||
if (EFI_ERROR (Status) || DataSize != sizeof (Environment->securityDomain)) {
|
||||
Environment->securityDomain = 1;
|
||||
}
|
||||
|
||||
DataSize = sizeof (Environment->productionStatus);
|
||||
Status = gRT->GetVariable (
|
||||
L"ApProductionStatus",
|
||||
&gAppleSecureBootVariableGuid,
|
||||
NULL,
|
||||
&DataSize,
|
||||
&Environment->productionStatus
|
||||
);
|
||||
if (EFI_ERROR (Status)
|
||||
|| DataSize != sizeof (Environment->productionStatus)) {
|
||||
Environment->productionStatus = TRUE;
|
||||
}
|
||||
|
||||
DataSize = sizeof (Environment->securityMode);
|
||||
Status = gRT->GetVariable (
|
||||
L"ApSecurityMode",
|
||||
&gAppleSecureBootVariableGuid,
|
||||
NULL,
|
||||
&DataSize,
|
||||
&Environment->securityMode
|
||||
);
|
||||
if (EFI_ERROR (Status) || DataSize != sizeof (Environment->securityMode)) {
|
||||
Environment->securityMode = TRUE;
|
||||
}
|
||||
|
||||
DataSize = sizeof (Environment->effectiveProductionStatus);
|
||||
Status = gRT->GetVariable (
|
||||
L"EffectiveProductionStatus",
|
||||
&gAppleSecureBootVariableGuid,
|
||||
NULL,
|
||||
&DataSize,
|
||||
&Environment->effectiveProductionStatus
|
||||
);
|
||||
if (EFI_ERROR (Status)
|
||||
|| DataSize != sizeof (Environment->effectiveProductionStatus)) {
|
||||
Environment->effectiveProductionStatus = TRUE;
|
||||
}
|
||||
|
||||
DataSize = sizeof (Environment->effectiveSecurityMode);
|
||||
Status = gRT->GetVariable (
|
||||
L"EffectiveSecurityMode",
|
||||
&gAppleSecureBootVariableGuid,
|
||||
NULL,
|
||||
&DataSize,
|
||||
&Environment->effectiveSecurityMode
|
||||
);
|
||||
if (EFI_ERROR (Status)
|
||||
|| DataSize != sizeof (Environment->effectiveSecurityMode)) {
|
||||
Environment->effectiveSecurityMode = TRUE;
|
||||
}
|
||||
|
||||
DataSize = sizeof (Environment->internalUseOnlyUnit);
|
||||
Status = gRT->GetVariable (
|
||||
L"InternalUseOnlyUnit",
|
||||
&gAppleSecureBootVariableGuid,
|
||||
NULL,
|
||||
&DataSize,
|
||||
&Environment->internalUseOnlyUnit
|
||||
);
|
||||
if (EFI_ERROR (Status)
|
||||
|| DataSize != sizeof (Environment->internalUseOnlyUnit)) {
|
||||
Environment->internalUseOnlyUnit = FALSE;
|
||||
}
|
||||
|
||||
// CHANGE: HardwareModel is unused.
|
||||
}
|
||||
|
||||
/**
|
||||
Verify the signature of ImageBuffer against Type of its IMG4 Manifest.
|
||||
|
||||
@param[in] This The pointer to the current protocol instance.
|
||||
@param[in] ObjType The IMG4 object type to validate against.
|
||||
@param[in] ImageBuffer The buffer to validate.
|
||||
@param[in] ImageSize The size, in bytes, of ImageBuffer.
|
||||
@param[in] SbMode The requested IMG4 Secure Boot mode.
|
||||
@param[in] ManifestBuffer The buffer of the IMG4 Manifest.
|
||||
@param[in] ManifestSize The size, in bytes, of ManifestBuffer.
|
||||
@param[out] HashDigest On output, a pointer to ImageBuffer's digest.
|
||||
@param[out] DigestSize On output, the size, in bytes, of *HashDigest.
|
||||
|
||||
@retval EFI_SUCCESS ImageBuffer is correctly signed.
|
||||
@retval EFI_INVALID_PARAMETER One or more required parameters are NULL.
|
||||
@retval EFI_OUT_OF_RESOURCES Not enough resources are available.
|
||||
@retval EFI_SECURITY_VIOLATION ImageBuffer's signature is invalid.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AppleImg4Verify (
|
||||
IN APPLE_IMG4_VERIFICATION_PROTOCOL *This,
|
||||
IN UINT32 ObjType,
|
||||
IN CONST VOID *ImageBuffer,
|
||||
IN UINTN ImageSize,
|
||||
IN UINT8 SbMode,
|
||||
IN CONST VOID *ManifestBuffer,
|
||||
IN UINTN ManifestSize,
|
||||
OUT UINT8 **HashDigest OPTIONAL,
|
||||
OUT UINTN *DigestSize OPTIONAL
|
||||
)
|
||||
{
|
||||
DERReturn DerResult;
|
||||
INTN CmpResult;
|
||||
|
||||
DERImg4Environment EnvInfo;
|
||||
DERImg4ManifestInfo ManInfo;
|
||||
|
||||
if ((ImageBuffer == NULL || ImageSize == 0)
|
||||
|| (ManifestBuffer == NULL || ManifestSize == 0)
|
||||
|| (HashDigest == NULL && DigestSize != NULL)
|
||||
|| (HashDigest != NULL && DigestSize == NULL)
|
||||
|| (SbMode != AppleImg4SbModeMedium
|
||||
&& SbMode != AppleImg4SbModeFull)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
DerResult = DERImg4ParseManifest (
|
||||
&ManInfo,
|
||||
ManifestBuffer,
|
||||
ManifestSize,
|
||||
ObjType
|
||||
);
|
||||
if (DerResult != DR_Success) {
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
//
|
||||
// As ManInfo.imageDigest is a buffer of static size, the bounds check to
|
||||
// retrieve it acts as implicit sanitizing of ManInfo.imageDigestSize which
|
||||
// can be considered trusted at this point.
|
||||
//
|
||||
CmpResult = SigVerifyShaHashBySize (
|
||||
ImageBuffer,
|
||||
ImageSize,
|
||||
ManInfo.imageDigest,
|
||||
ManInfo.imageDigestSize
|
||||
);
|
||||
if (CmpResult != 0) {
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
|
||||
InternalRetrieveHwInfo (&EnvInfo);
|
||||
|
||||
if (SbMode == AppleImg4SbModeMedium) {
|
||||
if (ManInfo.hasEcid
|
||||
|| !ManInfo.hasXugs || ManInfo.environment.xugs != EnvInfo.xugs
|
||||
|| (ManInfo.environment.internalUseOnlyUnit
|
||||
&& ManInfo.environment.internalUseOnlyUnit != EnvInfo.internalUseOnlyUnit)) {
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
} else if (SbMode == AppleImg4SbModeFull) {
|
||||
if (!ManInfo.hasEcid || ManInfo.environment.ecid != EnvInfo.ecid
|
||||
|| ManInfo.hasXugs
|
||||
|| ManInfo.environment.internalUseOnlyUnit) {
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ManInfo.environment.boardId != EnvInfo.boardId)
|
||||
|| (ManInfo.environment.chipId != EnvInfo.chipId)
|
||||
|| (ManInfo.environment.certificateEpoch < EnvInfo.certificateEpoch)
|
||||
|| (ManInfo.environment.productionStatus != EnvInfo.productionStatus && !ManInfo.environment.productionStatus)
|
||||
|| (ManInfo.environment.securityMode != EnvInfo.securityMode && !ManInfo.environment.securityMode)
|
||||
|| (ManInfo.environment.securityDomain != EnvInfo.securityDomain)
|
||||
|| (ManInfo.hasEffectiveProductionStatus
|
||||
&& (ManInfo.environment.effectiveProductionStatus != EnvInfo.effectiveProductionStatus && !ManInfo.environment.effectiveProductionStatus))
|
||||
|| (ManInfo.hasEffectiveSecurityMode
|
||||
&& (ManInfo.environment.effectiveSecurityMode != EnvInfo.effectiveSecurityMode && !ManInfo.environment.effectiveSecurityMode))
|
||||
) {
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
|
||||
if (HashDigest != NULL) {
|
||||
*HashDigest = AllocateCopyPool (ManInfo.imageDigestSize, ManInfo.imageDigest);
|
||||
if (*HashDigest == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
*DigestSize = ManInfo.imageDigestSize;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
@ -55,3 +55,4 @@
|
||||
libDERImg4/Img4oids.h
|
||||
libDERImg4/libDERImg4.h
|
||||
libDERImg4/libDERImg4_config.h
|
||||
OcAppleImg4Lib.c
|
||||
|
||||
@ -1002,6 +1002,10 @@ DERImg4ManifestDecodeProperty (
|
||||
return DR_BufOverflow;
|
||||
}
|
||||
|
||||
if (Property.valueItem.length == 0) {
|
||||
return DR_DecodeError;
|
||||
}
|
||||
|
||||
DERMemmove (
|
||||
ManInfo->imageDigest,
|
||||
Property.valueItem.data,
|
||||
|
||||
@ -18,6 +18,23 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DER_IMG4_MAX_DIGEST_SIZE 64
|
||||
|
||||
extern const uint8_t *DERImg4RootCertificate;
|
||||
extern const size_t *DERImg4RootCertificateSize;
|
||||
|
||||
bool
|
||||
DERImg4VerifySignature (
|
||||
DERByte *Modulus,
|
||||
DERSize ModulusSize,
|
||||
uint32_t Exponent,
|
||||
const uint8_t *Signature,
|
||||
size_t SignatureSize,
|
||||
uint8_t *Data,
|
||||
size_t DataSize,
|
||||
const DERItem *AlgoOid
|
||||
);
|
||||
|
||||
/* ---------------------- Do not edit below this line ---------------------- */
|
||||
|
||||
#ifndef DER_IMG4_MAN_CERT_CHAIN_MAX
|
||||
|
||||
@ -12,39 +12,64 @@
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
**/
|
||||
|
||||
#include <Library/OcAppleKeysLib.h>
|
||||
#include <Base.h>
|
||||
|
||||
CONST APPLE_PK_ENTRY PkDataBase[NUM_OF_PK] = {
|
||||
#include <Library/OcAppleKeysLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
///
|
||||
/// The data size of a 2048 Bits RSA Public Key. Includes N and R^2 mod N.
|
||||
///
|
||||
#define OC_RSA_PK_2048_NUM_BYTES (2 * (2048 / OC_CHAR_BIT))
|
||||
|
||||
typedef PACKED struct {
|
||||
///
|
||||
/// RSA Public Key header structure.
|
||||
///
|
||||
OC_RSA_PUBLIC_KEY_HDR Hdr;
|
||||
///
|
||||
/// The Modulus and Montgomery's R^2 mod N in little endian byte order.
|
||||
///
|
||||
union {
|
||||
UINT8 Bytes[OC_RSA_PK_2048_NUM_BYTES];
|
||||
UINT64 Qwords[OC_RSA_PK_2048_NUM_BYTES / sizeof (UINT64)];
|
||||
} Data;
|
||||
} OC_RSA_PUBLIC_KEY_2048;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
//
|
||||
// Verify the structure size equals to the header plus two times the key size
|
||||
// (N and R^2 mod N).
|
||||
//
|
||||
OC_STATIC_ASSERT (
|
||||
sizeof (OC_RSA_PUBLIC_KEY_2048) == sizeof (OC_RSA_PUBLIC_KEY_HDR) + OC_RSA_PK_2048_NUM_BYTES,
|
||||
"The 2048-bit RSA PK struct is malformed."
|
||||
);
|
||||
|
||||
STATIC CONST OC_RSA_PUBLIC_KEY_2048 mPkDb1 = {
|
||||
{ ARRAY_SIZE (mPkDb1.Data.Qwords) / 2, { 0 }, 0xb9a584a4e7cd16d1 },
|
||||
/**
|
||||
CFFD3E6B FE66EC75 F44B7E2E 0ED26398 08A98D10 AC378E55
|
||||
1CAA0E1C 1D85EF6C D51C758C 751816BF 599FBEDA EF4D6B0C
|
||||
EBA31024 7357CDE1 05696D2E F6A36FE8 540A010E 96311C7E
|
||||
1F1971E8 34C3A237 EFF5FFCC 1262FDA4 B399EE9A 29CCCBFC
|
||||
1E767165 3F3F2F61 08DAACA3 372D465A C518D154 56A315FC
|
||||
555F417D F0095974 755F5150 E667EDA8 823162E0 8CF831F7
|
||||
AF5831CF 3F0D92CA BAD076C1 3F74ED92 4CC8A3DE CCD11863
|
||||
9120D1CB 2E85B06B DB155AE2 DA144006 44B63635 CD9AF896
|
||||
C172DF2B 4ED961FE 1F467BEA F0EB0BCE EDA1DF17 7D5112CA
|
||||
299E9EC8 6F5E85D4 79213FB1 F9DD5B93 8C57DE9A 52FF62A7
|
||||
E1431EA9 250EE129 4338CDD9 CA48E7C3
|
||||
**/
|
||||
{
|
||||
//
|
||||
// PublicKey hash
|
||||
//
|
||||
{
|
||||
0xc7, 0xa1, 0xb9, 0x36, 0x28, 0x80, 0xde, 0x69, 0x57, 0x62, 0xb7, 0xb6,
|
||||
0x5b, 0xec, 0x6b, 0xf1, 0x56, 0xa5, 0x5c, 0xf9, 0x24, 0x7f, 0x22, 0xef,
|
||||
0x78, 0x62, 0x35, 0x53, 0x7f, 0x95, 0x2b, 0x45
|
||||
},
|
||||
//
|
||||
// Original PublicKey
|
||||
//
|
||||
/**
|
||||
CFFD3E6B FE66EC75 F44B7E2E 0ED26398 08A98D10 AC378E55
|
||||
1CAA0E1C 1D85EF6C D51C758C 751816BF 599FBEDA EF4D6B0C
|
||||
EBA31024 7357CDE1 05696D2E F6A36FE8 540A010E 96311C7E
|
||||
1F1971E8 34C3A237 EFF5FFCC 1262FDA4 B399EE9A 29CCCBFC
|
||||
1E767165 3F3F2F61 08DAACA3 372D465A C518D154 56A315FC
|
||||
555F417D F0095974 755F5150 E667EDA8 823162E0 8CF831F7
|
||||
AF5831CF 3F0D92CA BAD076C1 3F74ED92 4CC8A3DE CCD11863
|
||||
9120D1CB 2E85B06B DB155AE2 DA144006 44B63635 CD9AF896
|
||||
C172DF2B 4ED961FE 1F467BEA F0EB0BCE EDA1DF17 7D5112CA
|
||||
299E9EC8 6F5E85D4 79213FB1 F9DD5B93 8C57DE9A 52FF62A7
|
||||
E1431EA9 250EE129 4338CDD9 CA48E7C3
|
||||
**/
|
||||
//
|
||||
// PublicKey in format specified by Chromium project implementation
|
||||
//
|
||||
{
|
||||
0x40, 0x00, 0x00, 0x00, 0xd1, 0x16, 0xcd, 0xe7, 0xcf, 0xfd, 0x3e, 0x6b,
|
||||
//
|
||||
// N
|
||||
//
|
||||
0xcf, 0xfd, 0x3e, 0x6b,
|
||||
0xfe, 0x66, 0xec, 0x75, 0xf4, 0x4b, 0x7e, 0x2e, 0x0e, 0xd2, 0x63, 0x98,
|
||||
0x08, 0xa9, 0x8d, 0x10, 0xac, 0x37, 0x8e, 0x55, 0x1c, 0xaa, 0x0e, 0x1c,
|
||||
0x1d, 0x85, 0xef, 0x6c, 0xd5, 0x1c, 0x75, 0x8c, 0x75, 0x18, 0x16, 0xbf,
|
||||
@ -66,6 +91,9 @@ CONST APPLE_PK_ENTRY PkDataBase[NUM_OF_PK] = {
|
||||
0x6f, 0x5e, 0x85, 0xd4, 0x79, 0x21, 0x3f, 0xb1, 0xf9, 0xdd, 0x5b, 0x93,
|
||||
0x8c, 0x57, 0xde, 0x9a, 0x52, 0xff, 0x62, 0xa7, 0xe1, 0x43, 0x1e, 0xa9,
|
||||
0x25, 0x0e, 0xe1, 0x29, 0x43, 0x38, 0xcd, 0xd9, 0xca, 0x48, 0xe7, 0xc3,
|
||||
//
|
||||
// R^2 mod N
|
||||
//
|
||||
0x4f, 0x4b, 0x25, 0x95, 0x56, 0xa1, 0xa9, 0x4f, 0x33, 0x4f, 0x0f, 0xdc,
|
||||
0xcd, 0x7c, 0xb6, 0xab, 0x41, 0xa8, 0xfe, 0x2c, 0x24, 0x94, 0xad, 0x39,
|
||||
0x7f, 0x5a, 0x6d, 0x82, 0x40, 0x42, 0x32, 0xf9, 0xbb, 0x27, 0xc1, 0x17,
|
||||
@ -89,37 +117,30 @@ CONST APPLE_PK_ENTRY PkDataBase[NUM_OF_PK] = {
|
||||
0xe1, 0x72, 0xc3, 0x6c, 0x5f, 0xe4, 0x66, 0x0d, 0x4e, 0x08, 0x65, 0x9c,
|
||||
0x46, 0xc5, 0x7b, 0x04
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
STATIC CONST OC_RSA_PUBLIC_KEY_2048 mPkDb2 = {
|
||||
{ ARRAY_SIZE (mPkDb2.Data.Qwords) / 2, { 0 }, 0x646a020e9ed45d13 },
|
||||
/**
|
||||
E50AC288 2D44B7E3 3B67C51D AC639329 DA0363BD EAB5179F
|
||||
F88E460E E703D6CE 30383B25 0DE0E2FF 39386811 512A1A3B
|
||||
7531294F 9C512D28 FF56E5CD EB989342 B3A1A866 B41382A6
|
||||
2FB17D5D 3E97454A E19EB3C8 FA42F103 1DA21EEC 8D33BCE7
|
||||
8C4E3C55 EFF8A596 3A3CDAB7 2F475061 30FC1978 03DB6CA5
|
||||
A0FDC594 82EC0A3F 408364E3 4FAE9FD6 D5EBF633 357E3E7A
|
||||
3BA491D3 34A62604 B9CBF382 63BFF475 5168DB6D FBBA8669
|
||||
B7DB7280 218C4EAC 561CBF2F 932EAD6B 41159573 D7FF75B1
|
||||
9D65195F 0A41DC32 ED6F6D55 51716B6F 744ACD2D 3EE64FDE
|
||||
29742594 5ED2FF45 2B8CC72B C5D4C987 D0D1DC0A FC543E28
|
||||
F7A49046 8F434122 58F91106 8253C0B6
|
||||
**/
|
||||
{
|
||||
//
|
||||
// PublicKey hash
|
||||
//
|
||||
{
|
||||
0x74, 0x61, 0x89, 0x8e, 0x6e, 0x62, 0x96, 0x2e, 0xdd, 0x64, 0x44, 0x71,
|
||||
0x45, 0xf0, 0xd9, 0xd0, 0x2b, 0xcc, 0x95, 0x19, 0x49, 0x20, 0x46, 0x67,
|
||||
0x1e, 0x1f, 0xcd, 0xdd, 0x18, 0xdc, 0x9b, 0x8b
|
||||
},
|
||||
//
|
||||
// Original PublicKey
|
||||
//
|
||||
/**
|
||||
E50AC288 2D44B7E3 3B67C51D AC639329 DA0363BD EAB5179F
|
||||
F88E460E E703D6CE 30383B25 0DE0E2FF 39386811 512A1A3B
|
||||
7531294F 9C512D28 FF56E5CD EB989342 B3A1A866 B41382A6
|
||||
2FB17D5D 3E97454A E19EB3C8 FA42F103 1DA21EEC 8D33BCE7
|
||||
8C4E3C55 EFF8A596 3A3CDAB7 2F475061 30FC1978 03DB6CA5
|
||||
A0FDC594 82EC0A3F 408364E3 4FAE9FD6 D5EBF633 357E3E7A
|
||||
3BA491D3 34A62604 B9CBF382 63BFF475 5168DB6D FBBA8669
|
||||
B7DB7280 218C4EAC 561CBF2F 932EAD6B 41159573 D7FF75B1
|
||||
9D65195F 0A41DC32 ED6F6D55 51716B6F 744ACD2D 3EE64FDE
|
||||
29742594 5ED2FF45 2B8CC72B C5D4C987 D0D1DC0A FC543E28
|
||||
F7A49046 8F434122 58F91106 8253C0B6
|
||||
**/
|
||||
//
|
||||
// PublicKey in format specified by Chromium project implementation
|
||||
//
|
||||
{
|
||||
0x40, 0x00, 0x00, 0x00, 0x13, 0x5d, 0xd4, 0x9e, 0xe5, 0x0a, 0xc2, 0x88,
|
||||
//
|
||||
// N
|
||||
//
|
||||
0xe5, 0x0a, 0xc2, 0x88,
|
||||
0x2d, 0x44, 0xb7, 0xe3, 0x3b, 0x67, 0xc5, 0x1d, 0xac, 0x63, 0x93, 0x29,
|
||||
0xda, 0x03, 0x63, 0xbd, 0xea, 0xb5, 0x17, 0x9f, 0xf8, 0x8e, 0x46, 0x0e,
|
||||
0xe7, 0x03, 0xd6, 0xce, 0x30, 0x38, 0x3b, 0x25, 0x0d, 0xe0, 0xe2, 0xff,
|
||||
@ -141,6 +162,9 @@ CONST APPLE_PK_ENTRY PkDataBase[NUM_OF_PK] = {
|
||||
0x5e, 0xd2, 0xff, 0x45, 0x2b, 0x8c, 0xc7, 0x2b, 0xc5, 0xd4, 0xc9, 0x87,
|
||||
0xd0, 0xd1, 0xdc, 0x0a, 0xfc, 0x54, 0x3e, 0x28, 0xf7, 0xa4, 0x90, 0x46,
|
||||
0x8f, 0x43, 0x41, 0x22, 0x58, 0xf9, 0x11, 0x06, 0x82, 0x53, 0xc0, 0xb6,
|
||||
//
|
||||
// R^2 mod N
|
||||
//
|
||||
0xa7, 0x3e, 0xe4, 0x73, 0x82, 0xbe, 0x69, 0xc7, 0x7c, 0x75, 0x84, 0xea,
|
||||
0xb2, 0x84, 0xaf, 0xff, 0x16, 0x2f, 0xe4, 0xce, 0x22, 0x68, 0xf6, 0x35,
|
||||
0x42, 0x90, 0xd7, 0x3a, 0x15, 0xee, 0x79, 0x8a, 0x54, 0x99, 0x93, 0x6e,
|
||||
@ -167,6 +191,34 @@ CONST APPLE_PK_ENTRY PkDataBase[NUM_OF_PK] = {
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// The pointer casts are safe because the structs are compatible.
|
||||
//
|
||||
CONST APPLE_PK_ENTRY PkDataBase[NUM_OF_PK] = {
|
||||
{
|
||||
//
|
||||
// PublicKey hash
|
||||
//
|
||||
{
|
||||
0xc7, 0xa1, 0xb9, 0x36, 0x28, 0x80, 0xde, 0x69, 0x57, 0x62, 0xb7, 0xb6,
|
||||
0x5b, 0xec, 0x6b, 0xf1, 0x56, 0xa5, 0x5c, 0xf9, 0x24, 0x7f, 0x22, 0xef,
|
||||
0x78, 0x62, 0x35, 0x53, 0x7f, 0x95, 0x2b, 0x45
|
||||
},
|
||||
(CONST OC_RSA_PUBLIC_KEY *)&mPkDb1
|
||||
},
|
||||
{
|
||||
//
|
||||
// PublicKey hash
|
||||
//
|
||||
{
|
||||
0x74, 0x61, 0x89, 0x8e, 0x6e, 0x62, 0x96, 0x2e, 0xdd, 0x64, 0x44, 0x71,
|
||||
0x45, 0xf0, 0xd9, 0xd0, 0x2b, 0xcc, 0x95, 0x19, 0x49, 0x20, 0x46, 0x67,
|
||||
0x1e, 0x1f, 0xcd, 0xdd, 0x18, 0xdc, 0x9b, 0x8b
|
||||
},
|
||||
(CONST OC_RSA_PUBLIC_KEY *)&mPkDb2
|
||||
}
|
||||
};
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 gAppleX86SecureBootRootCaCert[] = {
|
||||
0x30, 0x82, 0x05, 0x62, 0x30, 0x82, 0x03, 0x4A, 0xA0, 0x03, 0x02, 0x01, 0x02,
|
||||
0x02, 0x08, 0x25, 0x2D, 0x14, 0x97, 0x18, 0x5C, 0x6A, 0xA0, 0x30, 0x0D, 0x06,
|
||||
|
||||
@ -86,6 +86,9 @@ InternalGetHardwareModel (
|
||||
OUT CHAR8 Model[16]
|
||||
)
|
||||
{
|
||||
//
|
||||
// FIXME: Retrieve this value from trusted storage and expose the variable.
|
||||
//
|
||||
EFI_STATUS Status;
|
||||
UINTN DataSize;
|
||||
CHAR8 HwModel[16];
|
||||
@ -114,6 +117,9 @@ InternalGetApEcid (
|
||||
OUT UINT64 *Ecid
|
||||
)
|
||||
{
|
||||
//
|
||||
// FIXME: Retrieve this value from trusted storage and expose the variable.
|
||||
//
|
||||
EFI_STATUS Status;
|
||||
UINTN DataSize;
|
||||
UINT64 ApEcid;
|
||||
|
||||
@ -159,14 +159,14 @@ InternalGetDiskImageBootFile (
|
||||
if ((Policy & OC_LOAD_TRUST_APPLE_V1_KEY) != 0) {
|
||||
Result = OcAppleChunklistVerifySignature (
|
||||
&ChunklistContext,
|
||||
(RSA_PUBLIC_KEY *)&PkDataBase[0].PublicKey
|
||||
PkDataBase[0].PublicKey
|
||||
);
|
||||
}
|
||||
|
||||
if (!Result && ((Policy & OC_LOAD_TRUST_APPLE_V2_KEY) != 0)) {
|
||||
Result = OcAppleChunklistVerifySignature (
|
||||
&ChunklistContext,
|
||||
(RSA_PUBLIC_KEY *)&PkDataBase[1].PublicKey
|
||||
PkDataBase[1].PublicKey
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
134
Library/OcCryptoLib/BigNumLib.h
Normal file
134
Library/OcCryptoLib/BigNumLib.h
Normal file
@ -0,0 +1,134 @@
|
||||
/**
|
||||
This library performs arbitrary precision arithmetic operations.
|
||||
For more details, please refer to the source files and function headers.
|
||||
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef BIG_NUM_LIB_H
|
||||
#define BIG_NUM_LIB_H
|
||||
|
||||
#include <Library/OcMiscLib.h>
|
||||
|
||||
///
|
||||
/// A BIGNUM word. This is at best an integer of the platform's natural size
|
||||
/// to optimize memory accesses and arithmetic operation count.
|
||||
///
|
||||
typedef UINTN OC_BN_WORD;
|
||||
//
|
||||
// Declarations regarding the Word size.
|
||||
//
|
||||
#define OC_BN_WORD_SIZE (sizeof (OC_BN_WORD))
|
||||
#define OC_BN_WORD_NUM_BITS (OC_BN_WORD_SIZE * OC_CHAR_BIT)
|
||||
//
|
||||
// Declarations regarding the maximum size of OC_BN structures.
|
||||
//
|
||||
typedef UINT16 OC_BN_NUM_WORDS;
|
||||
typedef UINT32 OC_BN_NUM_BITS;
|
||||
#define OC_BN_MAX_SIZE MAX_UINT16
|
||||
#define OC_BN_MAX_LEN (OC_BN_MAX_SIZE / OC_BN_WORD_SIZE)
|
||||
|
||||
//
|
||||
// Primitives
|
||||
//
|
||||
|
||||
/**
|
||||
Assigns A the value 0.
|
||||
|
||||
@param[in,out] A The number to assign to.
|
||||
@param[in] NumWords The number of Words of A.
|
||||
|
||||
**/
|
||||
VOID
|
||||
BigNumAssign0 (
|
||||
IN OUT OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords
|
||||
);
|
||||
|
||||
/**
|
||||
Parses a data array into a number. The buffer size must be a multiple of the
|
||||
Word size. The length of Result must precisely fit the required size.
|
||||
|
||||
@param[in,out] Result The buffer to store the result in.
|
||||
@param[in] NumWords The number of Words of Result.
|
||||
@param[in] Buffer The buffer to parse.
|
||||
@param[in] BufferSize The size, in bytes, of Buffer.
|
||||
|
||||
**/
|
||||
VOID
|
||||
BigNumParseBuffer (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST UINT8 *Buffer,
|
||||
IN UINTN BufferSize
|
||||
);
|
||||
|
||||
/**
|
||||
Swaps the byte order of Word.
|
||||
|
||||
@param[in] Word The Word to swap.
|
||||
|
||||
@returns The byte-swapped value of Word.
|
||||
|
||||
**/
|
||||
OC_BN_WORD
|
||||
BigNumSwapWord (
|
||||
IN OC_BN_WORD Word
|
||||
);
|
||||
|
||||
//
|
||||
// Montgomery arithmetics
|
||||
//
|
||||
|
||||
/**
|
||||
Calculates the Montgomery Inverse and R² mod N.
|
||||
|
||||
@param[in,out] RSqrMod The buffer to return R^2 mod N into.
|
||||
@param[in] NumWords The number of Words of RSqrMod and N.
|
||||
@param[in] N The Montgomery Modulus.
|
||||
|
||||
@returns The Montgomery Inverse of N.
|
||||
|
||||
**/
|
||||
OC_BN_WORD
|
||||
BigNumCalculateMontParams (
|
||||
IN OUT OC_BN_WORD *RSqrMod,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *N
|
||||
);
|
||||
|
||||
/**
|
||||
Caulculates the exponentiation of A with B mod N.
|
||||
|
||||
@param[in,out] Result The buffer to return the result into.
|
||||
@param[in] NumWords The number of Words of Result, A, N and RSqrMod.
|
||||
@param[in] A The base.
|
||||
@param[in] B The exponent.
|
||||
@param[in] N The modulus.
|
||||
@param[in] N0Inv The Montgomery Inverse of N.
|
||||
@param[in] RSqrMod Montgomery's R^2 mod N.
|
||||
|
||||
@returns Whether the operation was completes successfully.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
BigNumPowMod (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN UINT32 B,
|
||||
IN CONST OC_BN_WORD *N,
|
||||
IN OC_BN_WORD N0Inv,
|
||||
IN CONST OC_BN_WORD *RSqrMod
|
||||
);
|
||||
|
||||
#endif // BIG_NUM_LIB_H
|
||||
129
Library/OcCryptoLib/BigNumLibInternal.h
Normal file
129
Library/OcCryptoLib/BigNumLibInternal.h
Normal file
@ -0,0 +1,129 @@
|
||||
/**
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef BIG_NUM_LIB_INTERNAL_H
|
||||
#define BIG_NUM_LIB_INTERNAL_H
|
||||
|
||||
#include "BigNumLib.h"
|
||||
|
||||
/**
|
||||
Calculates the product of A and B.
|
||||
|
||||
@param[out] Hi Buffer in which the high Word of the result is returned.
|
||||
@param[in] A The multiplicant.
|
||||
@param[in] B The multiplier.
|
||||
|
||||
@returns The low Word of the result.
|
||||
|
||||
**/
|
||||
OC_BN_WORD
|
||||
BigNumWordMul (
|
||||
OUT OC_BN_WORD *Hi,
|
||||
IN OC_BN_WORD A,
|
||||
IN OC_BN_WORD B
|
||||
);
|
||||
|
||||
/**
|
||||
Calulates the difference of A and B.
|
||||
A must have the same precision as B. Result must have a precision at most as
|
||||
bit as A and B.
|
||||
|
||||
@param[in,out] Result The buffer to return the result into.
|
||||
@param[in] NumWords The number of Words of Result, minimum number of
|
||||
Words of A and B.
|
||||
@param[in] A The minuend.
|
||||
@param[in] B The subtrahend.
|
||||
|
||||
**/
|
||||
VOID
|
||||
BigNumSub (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWordsResult,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN CONST OC_BN_WORD *B
|
||||
);
|
||||
|
||||
/**
|
||||
Calculates the binary union of A and (Value << Exponent).
|
||||
|
||||
@param[in,out] A The number to OR with and store the result into.
|
||||
@param[in] NumWords The number of Words of A.
|
||||
@param[in] Value The Word value to OR with.
|
||||
@param[in] Exponent The Word shift exponent.
|
||||
|
||||
**/
|
||||
VOID
|
||||
BigNumOrWord (
|
||||
IN OUT OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN OC_BN_WORD Value,
|
||||
IN UINTN Exponent
|
||||
);
|
||||
|
||||
/**
|
||||
Calculates the remainder of A and B.
|
||||
|
||||
@param[in,out] Result The buffer to return the result into.
|
||||
@param[in] NumWordsRest The number of Words of Result and B.
|
||||
@param[in] A The dividend.
|
||||
@param[in] NumWordsA The number of Words of A.
|
||||
@param[in] B The divisor.
|
||||
|
||||
@returns Whether the operation was completes successfully.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
BigNumMod (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWordsRest,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWordsA,
|
||||
IN CONST OC_BN_WORD *B
|
||||
);
|
||||
|
||||
/**
|
||||
Returns the relative order of A and B. A and B must have the same precision.
|
||||
|
||||
@param[in] A The first number to compare.
|
||||
@param[in] NumWords The number of Words to compare.
|
||||
@param[in] B The second number to compare.
|
||||
|
||||
@retval < 0 A is lower than B.
|
||||
@retval 0 A is as big as B.
|
||||
@retval > 0 A is greater than B.
|
||||
|
||||
**/
|
||||
INTN
|
||||
BigNumCmp (
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *B
|
||||
);
|
||||
|
||||
/**
|
||||
Returns the number of significant bits in a number.
|
||||
Logically matches OpenSSL's BN_num_bits.
|
||||
|
||||
@param[in] A The number to gather the number of significant bits of.
|
||||
@param[in] NumWords The number of Words of A.
|
||||
|
||||
@returns The number of significant bits in A.
|
||||
|
||||
**/
|
||||
OC_BN_NUM_BITS
|
||||
BigNumSignificantBits (
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN UINTN NumWords
|
||||
);
|
||||
|
||||
#endif // BIG_NUM_LIB_INTERNAL_H
|
||||
659
Library/OcCryptoLib/BigNumMontgomery.c
Normal file
659
Library/OcCryptoLib/BigNumMontgomery.c
Normal file
@ -0,0 +1,659 @@
|
||||
/**
|
||||
This library performs arbitrary precision Montgomery operations.
|
||||
All results are returned into caller-provided buffers. The caller is
|
||||
responsible to ensure the buffers can hold the full result of the operation.
|
||||
|
||||
https://chromium.googlesource.com/chromiumos/platform/ec/+/master/common/rsa.c
|
||||
has served as a template for several algorithmic ideas.
|
||||
|
||||
This code is not to be considered general-purpose but solely to support
|
||||
cryptographic operations such as RSA encryption. As such, there are arbitrary
|
||||
limitations, such as requirement of equal precision, to limit the complexity
|
||||
of the operations to the bare minimum required to support such use caes.
|
||||
|
||||
SECURITY: Currently, no security measures have been taken. This code is
|
||||
vulnerable to both timing and side channel attacks for value
|
||||
leakage. However, its current purpose is the verification of public
|
||||
binaries with public certificates, for which this is perfectly
|
||||
acceptable, especially in regards to performance.
|
||||
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcCryptoLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
|
||||
#include "BigNumLibInternal.h"
|
||||
|
||||
/**
|
||||
Calculates the Montgomery Inverse -1 / A mod 2^#Bits(Word).
|
||||
This algorithm is based on the Extended Euclidean Algorithm, which returns
|
||||
1 / A mod 2^#Bits(Word).
|
||||
|
||||
@param[in] A The number to calculate the Montgomery Inverse of.
|
||||
|
||||
@retval 0 The Montgomery Inverse of A could not be computed.
|
||||
@retval other The Montgomery Inverse of A.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
OC_BN_WORD
|
||||
BigNumMontInverse (
|
||||
IN CONST OC_BN_WORD *A
|
||||
)
|
||||
{
|
||||
OC_BN_WORD Dividend;
|
||||
OC_BN_WORD Divisor;
|
||||
OC_BN_WORD X;
|
||||
OC_BN_WORD Y;
|
||||
OC_BN_WORD Mod;
|
||||
OC_BN_WORD Div;
|
||||
OC_BN_WORD Tmp;
|
||||
|
||||
ASSERT (A != NULL);
|
||||
//
|
||||
// We cannot compute the Montgomery Inverse of 0.
|
||||
//
|
||||
if (A[0] == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// The initial divisor 2^Bits(Word) obviously cannot be represented as a
|
||||
// variable value. For this reason, the first two iterations of the loop are
|
||||
// unrolled. 2^Bits(Word) is represented as 0 as those two values are
|
||||
// congruent modulo 2^Bits(Word), which is the variable storage space.
|
||||
// The modulo operation is therefor implemented as a subtraction loop.
|
||||
//
|
||||
|
||||
//
|
||||
// === INITIALISATION ===
|
||||
//
|
||||
// Divisor = 1U << sizeof(A->Words[0]) * OC_CHAR_BIT;
|
||||
// Dividend = A->Words[0];
|
||||
//
|
||||
// Y = 1;
|
||||
// X = 0;
|
||||
//
|
||||
// === LOOP UNROLL 1) ===
|
||||
//
|
||||
// Div = Dividend / Divisor; // => 0
|
||||
// Mod = Dividend % Divisor; // => A->Words[0]
|
||||
//
|
||||
// Dividend = Divisor; // => 2^Bits(Word)
|
||||
// Divisor = Mod; // => A->Words[0]
|
||||
//
|
||||
Dividend = 0;
|
||||
Divisor = A[0];
|
||||
//
|
||||
// Tmp = Y - Div * X; // => 1
|
||||
// Y = X; // => 0
|
||||
// X = Tmp; // => 1
|
||||
//
|
||||
// === LOOP UNROLL 2) ===
|
||||
//
|
||||
// Div = Dividend / Divisor;
|
||||
// Mod = Dividend % Divisor;
|
||||
//
|
||||
Div = 0;
|
||||
do {
|
||||
Dividend -= Divisor;
|
||||
++Div;
|
||||
} while (Dividend >= Divisor);
|
||||
|
||||
Mod = Dividend;
|
||||
//
|
||||
// Dividend = Divisor;
|
||||
// Divisor = Mod;
|
||||
//
|
||||
Dividend = Divisor;
|
||||
Divisor = Mod;
|
||||
//
|
||||
// Tmp = Y - Div * X; // => -Div
|
||||
// Y = X; // => 1
|
||||
// X = Tmp; // => -Div
|
||||
//
|
||||
Y = 1;
|
||||
X = (OC_BN_WORD)0U - Div;
|
||||
|
||||
while (Divisor != 0) {
|
||||
//
|
||||
// FIXME: This needs a good source for an algorithm specification.
|
||||
//
|
||||
Div = Dividend / Divisor;
|
||||
Mod = Dividend % Divisor;
|
||||
|
||||
Dividend = Divisor;
|
||||
Divisor = Mod;
|
||||
|
||||
Tmp = Y - Div * X;
|
||||
Y = X;
|
||||
X = Tmp;
|
||||
}
|
||||
//
|
||||
// When the loop ends, Dividend contains the Greatest Common Divisor.
|
||||
// If it is not 1, we cannot compute the Montgomery Inverse.
|
||||
//
|
||||
if (Dividend != 1) {
|
||||
return 0;
|
||||
}
|
||||
//
|
||||
// As per above, Y is 1 / A mod 2^#Bits(Word), so invert the result to yield
|
||||
// -1 / A mod 2^#Bits(Word).
|
||||
//
|
||||
return (OC_BN_WORD)0U - Y;
|
||||
}
|
||||
|
||||
OC_BN_WORD
|
||||
BigNumCalculateMontParams (
|
||||
IN OUT OC_BN_WORD *RSqrMod,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *N
|
||||
)
|
||||
{
|
||||
OC_BN_WORD N0Inv;
|
||||
UINT32 NumBits;
|
||||
UINTN SizeRSqr;
|
||||
OC_BN_NUM_WORDS NumWordsRSqr;
|
||||
OC_BN_WORD *RSqr;
|
||||
|
||||
ASSERT (RSqrMod != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (N != NULL);
|
||||
//
|
||||
// Calculate the Montgomery Inverse.
|
||||
// This is a reduced approach of the algorithmic -1 / N mod 2^#Bits(N),
|
||||
// where the modulus is reduced from 2^#Bits(N) to 2^#Bits(Word). This
|
||||
// reduces N to N[0] and yields an inverse valid in the Word domain.
|
||||
//
|
||||
N0Inv = BigNumMontInverse (N);
|
||||
if (N0Inv == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NumBits = BigNumSignificantBits (N, NumWords);
|
||||
|
||||
OC_STATIC_ASSERT (
|
||||
OC_BN_MAX_SIZE * OC_CHAR_BIT <= ((MAX_UINTN - 1) / 2) - (OC_CHAR_BIT - 1),
|
||||
"An overflow verification must be added"
|
||||
);
|
||||
//
|
||||
// Considering NumBits can at most be MAX_UINT16 * OC_CHAR_BIT, this cannot
|
||||
// overflow. OC_CHAR_BIT-1 is added to achieve rounding towards the next Byte
|
||||
// boundary.
|
||||
//
|
||||
SizeRSqr = ALIGN_VALUE (
|
||||
((2 * (NumBits + 1) + (OC_CHAR_BIT - 1)) / OC_CHAR_BIT),
|
||||
OC_BN_WORD_SIZE
|
||||
);
|
||||
if (SizeRSqr > OC_BN_MAX_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
RSqr = AllocatePool (SizeRSqr);
|
||||
if (RSqr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
NumWordsRSqr = (OC_BN_NUM_WORDS)(SizeRSqr / OC_BN_WORD_SIZE);
|
||||
//
|
||||
// Calculate Montgomery's R^2 mod N.
|
||||
//
|
||||
BigNumAssign0 (RSqr, NumWordsRSqr);
|
||||
//
|
||||
// 2 * NumBits cannot overflow as per above.
|
||||
//
|
||||
BigNumOrWord (RSqr, NumWordsRSqr, 1, 2 * NumBits);
|
||||
BigNumMod (RSqrMod, NumWords, RSqr, NumWordsRSqr, N);
|
||||
|
||||
FreePool (RSqr);
|
||||
|
||||
return N0Inv;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the sum of C and the product of A and B.
|
||||
|
||||
@param[out] Hi Buffer in which the high Word of the result is returned.
|
||||
@param[in] C The addend.
|
||||
@param[in] A The multiplicant.
|
||||
@param[in] B The multiplier.
|
||||
|
||||
@returns The low Word of the result.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
OC_BN_WORD
|
||||
BigNumWordAddMul (
|
||||
OUT OC_BN_WORD *Hi,
|
||||
IN OC_BN_WORD C,
|
||||
IN OC_BN_WORD A,
|
||||
IN OC_BN_WORD B
|
||||
)
|
||||
{
|
||||
OC_BN_WORD ResHi;
|
||||
OC_BN_WORD ResLo;
|
||||
|
||||
ASSERT (Hi != NULL);
|
||||
|
||||
ResLo = BigNumWordMul (&ResHi, A, B) + C;
|
||||
if (ResLo < C) {
|
||||
++ResHi;
|
||||
}
|
||||
|
||||
*Hi = ResHi;
|
||||
return ResLo;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the sum of C, the product of A and B, and Carry.
|
||||
|
||||
@param[out] Hi Buffer in which the high Word of the result is returned.
|
||||
@param[in] C The addend.
|
||||
@param[in] A The multiplicant.
|
||||
@param[in] B The multiplier.
|
||||
@param[in] Carry The carry of the previous multiplication.
|
||||
|
||||
@returns The low Word of the result.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
OC_BN_WORD
|
||||
BigNumWordAddMulCarry (
|
||||
OUT OC_BN_WORD *Hi,
|
||||
IN OC_BN_WORD C,
|
||||
IN OC_BN_WORD A,
|
||||
IN OC_BN_WORD B,
|
||||
IN OC_BN_WORD Carry
|
||||
)
|
||||
{
|
||||
OC_BN_WORD MulResHi;
|
||||
OC_BN_WORD MulResLo;
|
||||
|
||||
ASSERT (Hi != NULL);
|
||||
|
||||
MulResLo = BigNumWordAddMul (&MulResHi, C, A, B);
|
||||
MulResLo += Carry;
|
||||
if (MulResLo < Carry) {
|
||||
++MulResHi;
|
||||
}
|
||||
|
||||
*Hi = MulResHi;
|
||||
return MulResLo;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates a row of the product of A and B mod N.
|
||||
|
||||
@param[in,out] Result The result buffer.
|
||||
@param[in] NumWords The number of Words of Result, B and N.
|
||||
@param[in] AWord The current row's Word of the multiplicant.
|
||||
@param[in] B The multiplier.
|
||||
@param[in] N The modulus.
|
||||
@param[in] N0Inv The Montgomery Inverse of N.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumMontMulRow (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN OC_BN_WORD AWord,
|
||||
IN CONST OC_BN_WORD *B,
|
||||
IN CONST OC_BN_WORD *N,
|
||||
IN OC_BN_WORD N0Inv
|
||||
)
|
||||
{
|
||||
UINTN CompIndex;
|
||||
|
||||
OC_BN_WORD CCurMulHi;
|
||||
OC_BN_WORD CCurMulLo;
|
||||
OC_BN_WORD CCurMontHi;
|
||||
OC_BN_WORD CCurMontLo;
|
||||
OC_BN_WORD TFirst;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (B != NULL);
|
||||
ASSERT (N != NULL);
|
||||
ASSERT (N0Inv != 0);
|
||||
//
|
||||
// Standard multiplication
|
||||
// C = C + A*B
|
||||
//
|
||||
CCurMulLo = BigNumWordAddMul (
|
||||
&CCurMulHi,
|
||||
Result[0],
|
||||
AWord,
|
||||
B[0]
|
||||
);
|
||||
//
|
||||
// Montgomery Reduction preparation
|
||||
// As N_first is reduced mod 2^#Bits (word), we're operating in this domain
|
||||
// and reduce both C and the result as well.
|
||||
// t_first = C * N_first
|
||||
//
|
||||
TFirst = CCurMulLo * N0Inv;
|
||||
//
|
||||
// Montgomery Reduction
|
||||
// 1. C = C + t_first * N
|
||||
// 2. In the first step, only the carries are actually used, which implies
|
||||
// division by R.
|
||||
//
|
||||
CCurMontLo = BigNumWordAddMul (&CCurMontHi, CCurMulLo, TFirst, N[0]);
|
||||
|
||||
for (CompIndex = 1; CompIndex < NumWords; ++CompIndex) {
|
||||
//
|
||||
// Standard multiplication
|
||||
// C = C + A*B + carry
|
||||
//
|
||||
CCurMulLo = BigNumWordAddMulCarry (
|
||||
&CCurMulHi,
|
||||
Result[CompIndex],
|
||||
AWord,
|
||||
B[CompIndex],
|
||||
CCurMulHi
|
||||
);
|
||||
//
|
||||
// Montgomery Reduction
|
||||
// 1. C = C + t_first * N + carry
|
||||
//
|
||||
CCurMontLo = BigNumWordAddMulCarry (
|
||||
&CCurMontHi,
|
||||
CCurMulLo,
|
||||
TFirst,
|
||||
N[CompIndex],
|
||||
CCurMontHi
|
||||
);
|
||||
//
|
||||
// 2. The index shift translates to a bitshift equivalent to the division
|
||||
// by R = 2^#Bits (word).
|
||||
// C = C / R
|
||||
//
|
||||
Result[CompIndex - 1] = CCurMontLo;
|
||||
}
|
||||
//
|
||||
// Assign the most significant byte the remaining carrys.
|
||||
//
|
||||
CCurMulLo = CCurMulHi + CCurMontHi;
|
||||
Result[CompIndex - 1] = CCurMulLo;
|
||||
//
|
||||
// If the result has wrapped around, C >= N is true and we reduce mod N.
|
||||
//
|
||||
if (CCurMulLo < CCurMulHi) {
|
||||
//
|
||||
// The discarded most significant word must be the last borrow of the
|
||||
// subtraction, as C_actual = (CCurMul >> WORD_BITS)||C.
|
||||
//
|
||||
BigNumSub (Result, NumWords, Result, N);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the Montgomery product of A and B mod N.
|
||||
|
||||
@param[in,out] Result The result buffer.
|
||||
@param[in] NumWords The number of Words of Result, A, B and N.
|
||||
@param[in] A The multiplicant.
|
||||
@param[in] B The multiplier.
|
||||
@param[in] N The modulus.
|
||||
@param[in] N0Inv The Montgomery Inverse of N.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumMontMul (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN CONST OC_BN_WORD *B,
|
||||
IN CONST OC_BN_WORD *N,
|
||||
IN OC_BN_WORD N0Inv
|
||||
)
|
||||
{
|
||||
UINTN RowIndex;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (B != NULL);
|
||||
ASSERT (N != NULL);
|
||||
ASSERT (N0Inv != 0);
|
||||
|
||||
ZeroMem (Result, (UINTN)NumWords * OC_BN_WORD_SIZE);
|
||||
//
|
||||
// RowIndex is used as an index into the words of A. Because this domain
|
||||
// operates in mod 2^#Bits (word), 'row results' do not require multiplication
|
||||
// as the positional factor is stripped by the word-size modulus.
|
||||
//
|
||||
for (RowIndex = 0; RowIndex < NumWords; ++RowIndex) {
|
||||
BigNumMontMulRow (Result, NumWords, A[RowIndex], B, N, N0Inv);
|
||||
}
|
||||
//
|
||||
// As this implementation only reduces mod N on overflow and not for every
|
||||
// yes-instance of C >= N, any sequence of Montgomery Multiplications must be
|
||||
// completed with a final reduction step.
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
This is an optimized version of the call
|
||||
BigNumMontMulRow (C, 0, A, N, N0Inv)
|
||||
|
||||
Calculates a row of the product of 0 and A mod N.
|
||||
|
||||
@param[in,out] Result The result buffer.
|
||||
@param[in] NumWords The number of Words of Result and N.
|
||||
@param[in] N The modulus.
|
||||
@param[in] N0Inv The Montgomery Inverse of N.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumMontMulRow0 (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *N,
|
||||
IN OC_BN_WORD N0Inv
|
||||
)
|
||||
{
|
||||
UINTN CompIndex;
|
||||
|
||||
OC_BN_WORD CCurMontHi;
|
||||
OC_BN_WORD CCurMontLo;
|
||||
OC_BN_WORD TFirst;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (N != NULL);
|
||||
ASSERT (N0Inv != 0);
|
||||
//
|
||||
// Montgomery Reduction preparation
|
||||
// As N_first is reduced mod 2^#Bits (word), we reduce C as well.
|
||||
// Due to the reduction, the high bits are discarded safely.
|
||||
// t_first = C * N_first
|
||||
//
|
||||
TFirst = Result[0] * N0Inv;
|
||||
//
|
||||
// Montgomery Reduction
|
||||
// 1. C = C + t_first * N
|
||||
// 2. In the first step, only the carries are actually used, so the
|
||||
// division by R can be omited.
|
||||
//
|
||||
CCurMontLo = BigNumWordAddMul (&CCurMontHi, Result[0], TFirst, N[0]);
|
||||
for (CompIndex = 1; CompIndex < NumWords; ++CompIndex) {
|
||||
//
|
||||
// Montgomery Reduction
|
||||
// 1. C = C + t_first * N + carry
|
||||
//
|
||||
CCurMontLo = BigNumWordAddMulCarry (
|
||||
&CCurMontHi,
|
||||
Result[CompIndex],
|
||||
TFirst,
|
||||
N[CompIndex],
|
||||
CCurMontHi
|
||||
);
|
||||
//
|
||||
// 2. The index shift translates to a bitshift equivalent to the division
|
||||
// by R = 2^#Bits (word).
|
||||
// C = C / R
|
||||
//
|
||||
Result[CompIndex - 1] = CCurMontLo;
|
||||
}
|
||||
//
|
||||
// Assign the most significant byte the remaining carry.
|
||||
//
|
||||
Result[CompIndex - 1] = CCurMontHi;
|
||||
}
|
||||
|
||||
/**
|
||||
This is an optimized version of the call
|
||||
BigNumMontMul (C, 1, A, N, N0Inv)
|
||||
|
||||
@param[in,out] Result The result buffer.
|
||||
@param[in] NumWords The number of Words of Result, A and N.
|
||||
@param[in] A The multiplicant.
|
||||
@param[in] N The modulus.
|
||||
@param[in] N0Inv The Montgomery Inverse of N.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumMontMul1 (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN CONST OC_BN_WORD *N,
|
||||
IN OC_BN_WORD N0Inv
|
||||
)
|
||||
{
|
||||
UINTN RowIndex;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (N != NULL);
|
||||
ASSERT (N0Inv != 0);
|
||||
|
||||
ZeroMem (Result, (UINTN)NumWords * OC_BN_WORD_SIZE);
|
||||
//
|
||||
// Perform the entire standard multiplication and one Montgomery Reduction.
|
||||
//
|
||||
BigNumMontMulRow (Result, NumWords, 1, A, N, N0Inv);
|
||||
//
|
||||
// Perform the remaining Montgomery Reductions.
|
||||
//
|
||||
for (RowIndex = 1; RowIndex < NumWords; ++RowIndex) {
|
||||
BigNumMontMulRow0 (Result, NumWords, N, N0Inv);
|
||||
}
|
||||
//
|
||||
// As this implementation only reduces mod N on overflow and not for every
|
||||
// yes-instance of C >= N, any sequence of Montgomery Multiplications must be
|
||||
// completed with a final reduction step.
|
||||
//
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BigNumPowMod (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN UINT32 B,
|
||||
IN CONST OC_BN_WORD *N,
|
||||
IN OC_BN_WORD N0Inv,
|
||||
IN CONST OC_BN_WORD *RSqrMod
|
||||
)
|
||||
{
|
||||
OC_BN_WORD *ATmp;
|
||||
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (N != NULL);
|
||||
ASSERT (N0Inv != 0);
|
||||
ASSERT (RSqrMod != NULL);
|
||||
//
|
||||
// Currently, only the most frequent exponents are supported.
|
||||
//
|
||||
if (B != 0x10001 && B != 3) {
|
||||
DEBUG ((DEBUG_INFO, "OCCR: Unsupported exponent: %x\n", B));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ATmp = AllocatePool ((UINTN)NumWords * OC_BN_WORD_SIZE);
|
||||
if (ATmp == NULL) {
|
||||
DEBUG ((DEBUG_INFO, "OCCR: Memory allocation failure in ModPow\n"));
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Convert A into the Montgomery Domain.
|
||||
// ATmp = MM (A, R^2 mod N)
|
||||
//
|
||||
BigNumMontMul (ATmp, NumWords, A, RSqrMod, N, N0Inv);
|
||||
|
||||
if (B == 0x10001) {
|
||||
//
|
||||
// Squaring the intermediate results 16 times yields A'^ (2^16).
|
||||
//
|
||||
for (Index = 0; Index < 16; Index += 2) {
|
||||
//
|
||||
// Result = MM (ATmp, ATmp)
|
||||
//
|
||||
BigNumMontMul (Result, NumWords, ATmp, ATmp, N, N0Inv);
|
||||
//
|
||||
// ATmp = MM (Result, Result)
|
||||
//
|
||||
BigNumMontMul (ATmp, NumWords, Result, Result, N, N0Inv);
|
||||
}
|
||||
//
|
||||
// Because A is not within the Montgomery Domain, this implies another
|
||||
// division by R, which takes the result out of the Montgomery Domain.
|
||||
// C = MM (ATmp, A)
|
||||
//
|
||||
BigNumMontMul (Result, NumWords, ATmp, A, N, N0Inv);
|
||||
} else {
|
||||
//
|
||||
// Result = MM (ATmp, ATmp)
|
||||
//
|
||||
BigNumMontMul (Result, NumWords, ATmp, ATmp, N, N0Inv);
|
||||
//
|
||||
// ATmp = MM (Result, ATmp)
|
||||
//
|
||||
BigNumMontMul (ATmp, NumWords, Result, ATmp, N, N0Inv);
|
||||
//
|
||||
// Perform a Montgomery Multiplication with 1, which effectively is a
|
||||
// division by R, taking the result out of the Montgomery Domain.
|
||||
// C = MM (ATmp, 1)
|
||||
// TODO: Is this needed or can we just multiply with A above?
|
||||
//
|
||||
BigNumMontMul1 (Result, NumWords, ATmp, N, N0Inv);
|
||||
}
|
||||
//
|
||||
// The Montgomery Multiplications above only ensure the result is mod N when
|
||||
// it does not fit within #Bits(N). For N != 0, which is an obvious
|
||||
// requirement, #Bits(N) can only ever fit values smaller than 2*N, so the
|
||||
// result is at most one modulus too large.
|
||||
// C = C mod N
|
||||
//
|
||||
if (BigNumCmp (Result, NumWords, N) >= 0){
|
||||
BigNumSub (Result, NumWords, Result, N);
|
||||
}
|
||||
|
||||
FreePool (ATmp);
|
||||
return TRUE;
|
||||
}
|
||||
903
Library/OcCryptoLib/BigNumPrimitives.c
Normal file
903
Library/OcCryptoLib/BigNumPrimitives.c
Normal file
@ -0,0 +1,903 @@
|
||||
/**
|
||||
This library performs unsigned arbitrary precision arithmetic operations.
|
||||
All results are returned into caller-provided buffers. The caller is
|
||||
responsible to ensure the buffers can hold a value of the precision it
|
||||
desires. Too large results will be truncated without further notification for
|
||||
public APIs.
|
||||
|
||||
https://github.com/kokke/tiny-bignum-c has served as a template for several
|
||||
algorithmic ideas.
|
||||
|
||||
This code is not to be considered general-purpose but solely to support
|
||||
cryptographic operations such as RSA encryption. As such, there are arbitrary
|
||||
limitations, such as requirement of equal precision, to limit the complexity
|
||||
of the operations to the bare minimum required to support such use caes.
|
||||
|
||||
SECURITY: Currently, no security measures have been taken. This code is
|
||||
vulnerable to both timing and side channel attacks for value
|
||||
leakage. However, its current purpose is the verification of public
|
||||
binaries with public certificates, for which this is perfectly
|
||||
acceptable, especially in regards to performance.
|
||||
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcCryptoLib.h>
|
||||
#include <Library/OcGuardLib.h>
|
||||
|
||||
#include "BigNumLibInternal.h"
|
||||
|
||||
#define OC_BN_MAX_VAL ((OC_BN_WORD)0U - 1U)
|
||||
|
||||
OC_STATIC_ASSERT (
|
||||
OC_BN_WORD_SIZE == sizeof (UINT32) || OC_BN_WORD_SIZE == sizeof (UINT64),
|
||||
"OC_BN_WORD_SIZE and OC_BN_WORD_NUM_BITS usages must be adapted."
|
||||
);
|
||||
|
||||
OC_BN_WORD
|
||||
BigNumSwapWord (
|
||||
IN OC_BN_WORD Word
|
||||
)
|
||||
{
|
||||
if (OC_BN_WORD_SIZE == sizeof (UINT32)) {
|
||||
return (OC_BN_WORD)SwapBytes32 ((UINT32)Word);
|
||||
}
|
||||
|
||||
if (OC_BN_WORD_SIZE == sizeof (UINT64)) {
|
||||
return (OC_BN_WORD)SwapBytes64 ((UINT64)Word);
|
||||
}
|
||||
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
Shifts A left by Exponent Words.
|
||||
|
||||
@param[in,out] Result The buffer to return the result into.
|
||||
@param[in] NumWordsResult The number of Words of Result.
|
||||
@param[in,out] A The number to be word-shifted.
|
||||
@param[in] NumWordsA The number of Words of A.
|
||||
@param[in] Exponent The Word shift exponent.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumLeftShiftWords (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWordsResult,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWordsA,
|
||||
IN UINTN Exponent
|
||||
)
|
||||
{
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWordsResult > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWordsA > 0);
|
||||
ASSERT (Exponent < NumWordsResult);
|
||||
ASSERT (NumWordsResult - Exponent >= NumWordsA);
|
||||
|
||||
CopyMem (&Result[Exponent], A, (NumWordsResult - Exponent) * OC_BN_WORD_SIZE);
|
||||
ZeroMem (Result, Exponent * OC_BN_WORD_SIZE);
|
||||
if (NumWordsResult - Exponent > NumWordsA) {
|
||||
ZeroMem (
|
||||
&Result[NumWordsA + Exponent],
|
||||
(NumWordsResult - Exponent - NumWordsA) * OC_BN_WORD_SIZE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Shifts A left by Exponent Bits for 0 < Exponent < #Bits(Word).
|
||||
|
||||
@param[in,out] Result The buffer to return the result into.
|
||||
@param[in] NumWordsResult The number of Words of Result.
|
||||
@param[in] A The base.
|
||||
@param[in] NumWordsA The number of Words of A.
|
||||
@param[in] NumWords The Word shift exponent.
|
||||
@param[in] NumBits The Bit shift exponent.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumLeftShiftWordsAndBits (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWordsResult,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWordsA,
|
||||
IN UINTN NumWords,
|
||||
IN UINT8 NumBits
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWordsResult > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWordsA > 0);
|
||||
ASSERT (NumWordsResult >= NumWords);
|
||||
//
|
||||
// NumBits must not be 0 because a shift of a Word by its Bit width or
|
||||
// larger is Undefined Behaviour.
|
||||
//
|
||||
ASSERT (NumBits > 0);
|
||||
ASSERT (NumBits < OC_BN_WORD_NUM_BITS);
|
||||
//
|
||||
// This, assuming below, is required to avoid overflows, which purely
|
||||
// internal calls should never produce.
|
||||
//
|
||||
ASSERT (NumWordsResult - NumWords > NumWordsA);
|
||||
//
|
||||
// This is not an algorithmic requirement, but BigNumLeftShiftWords shall be
|
||||
// called if TRUE.
|
||||
//
|
||||
ASSERT (NumWords > 0);
|
||||
|
||||
for (Index = (NumWordsA - 1); Index > 0; --Index) {
|
||||
Result[Index + NumWords] = (A[Index] << NumBits) | (A[Index - 1] >> (OC_BN_WORD_NUM_BITS - NumBits));
|
||||
}
|
||||
//
|
||||
// Handle the edge-cases at the beginning and the end of the value.
|
||||
//
|
||||
Result[NumWords] = A[0] << NumBits;
|
||||
Result[NumWordsA + NumWords] = A[NumWordsA - 1] >> (OC_BN_WORD_NUM_BITS - NumBits);
|
||||
//
|
||||
// Zero everything outside of the previously set ranges.
|
||||
//
|
||||
ZeroMem (&Result[NumWordsA + NumWords + 1], (NumWordsResult - NumWords - NumWordsA - 1) * OC_BN_WORD_SIZE);
|
||||
ZeroMem (Result, NumWords * OC_BN_WORD_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
Shifts A left by Exponent Bits for 0 < Exponent < #Bits(Word).
|
||||
|
||||
@param[in,out] A The base.
|
||||
@param[in] NumWords The number of Words of A.
|
||||
@param[in] Exponent The Bit shift exponent.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumLeftShiftBitsSmall (
|
||||
IN OUT OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN UINT8 Exponent
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
//
|
||||
// Exponent must not be 0 because a shift of a Word by its Bit width or
|
||||
// larger is Undefined Behaviour.
|
||||
//
|
||||
ASSERT (Exponent > 0);
|
||||
ASSERT (Exponent < OC_BN_WORD_NUM_BITS);
|
||||
|
||||
for (Index = (NumWords - 1); Index > 0; --Index) {
|
||||
A[Index] = (A[Index] << Exponent) | (A[Index - 1] >> (OC_BN_WORD_NUM_BITS - Exponent));
|
||||
}
|
||||
A[0] <<= Exponent;
|
||||
}
|
||||
|
||||
/**
|
||||
Shifts A right by Exponent Bits for 0 < Exponent < #Bits(Word).
|
||||
|
||||
@param[in,out] A The base.
|
||||
@param[in] NumWords The number of Words of A.
|
||||
@param[in] Exponent The Bit shift exponent.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumRightShiftBitsSmall (
|
||||
IN OUT OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN UINT8 Exponent
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
//
|
||||
// Exponent must not be 0 because a shift of a Word by its Bit width or
|
||||
// larger is Undefined Behaviour.
|
||||
//
|
||||
ASSERT (Exponent > 0);
|
||||
ASSERT (Exponent < OC_BN_WORD_NUM_BITS);
|
||||
|
||||
for (Index = 0; Index < (NumWords - 1U); ++Index) {
|
||||
A[Index] = (A[Index] >> Exponent) | (A[Index + 1] << (OC_BN_WORD_NUM_BITS - Exponent));
|
||||
}
|
||||
A[Index] >>= Exponent;
|
||||
}
|
||||
|
||||
OC_BN_WORD
|
||||
BigNumWordMul64 (
|
||||
OUT OC_BN_WORD *Hi,
|
||||
IN OC_BN_WORD A,
|
||||
IN OC_BN_WORD B
|
||||
);
|
||||
|
||||
/**
|
||||
Calculates the product of A and B.
|
||||
|
||||
@param[out] Hi Buffer in which the high Word of the result is returned.
|
||||
@param[in] A The multiplicant.
|
||||
@param[in] B The multiplier.
|
||||
|
||||
@returns The low Word of the result.
|
||||
|
||||
**/
|
||||
OC_BN_WORD
|
||||
BigNumWordMul (
|
||||
OUT OC_BN_WORD *Hi,
|
||||
IN OC_BN_WORD A,
|
||||
IN OC_BN_WORD B
|
||||
)
|
||||
{
|
||||
UINT64 Result64;
|
||||
|
||||
ASSERT (Hi != NULL);
|
||||
|
||||
if (OC_BN_WORD_SIZE == sizeof (UINT32)) {
|
||||
Result64 = (UINT64)A * B;
|
||||
//
|
||||
// FIXME: The subtraction in the shift is a dirty hack to shut up MSVC.
|
||||
//
|
||||
*Hi = (OC_BN_WORD)(RShiftU64 (Result64, OC_BN_WORD_NUM_BITS));
|
||||
return (OC_BN_WORD)Result64;
|
||||
}
|
||||
|
||||
if (OC_BN_WORD_SIZE == sizeof (UINT64)) {
|
||||
return BigNumWordMul64 (Hi, A, B);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Assigns A to Result.
|
||||
|
||||
@param[in,out] Result The buffer to store the result in.
|
||||
@param[in] NumWordsResult The number of Words of Result.
|
||||
@param[in] A The number to assign.
|
||||
@param[in] NumWordsA The number of Words of A.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumAssign (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWordsResult,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWordsA
|
||||
)
|
||||
{
|
||||
UINTN NumWordsCopy;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWordsResult > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWordsA > 0);
|
||||
|
||||
if (NumWordsResult > NumWordsA) {
|
||||
ZeroMem (
|
||||
&Result[NumWordsA],
|
||||
(NumWordsResult - NumWordsA) * OC_BN_WORD_SIZE
|
||||
);
|
||||
NumWordsCopy = NumWordsA;
|
||||
} else {
|
||||
NumWordsCopy = NumWordsResult;
|
||||
}
|
||||
|
||||
CopyMem (Result, A, NumWordsCopy * OC_BN_WORD_SIZE);
|
||||
}
|
||||
|
||||
VOID
|
||||
BigNumAssign0 (
|
||||
IN OUT OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords
|
||||
)
|
||||
{
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
|
||||
ZeroMem (A, NumWords * OC_BN_WORD_SIZE);
|
||||
}
|
||||
|
||||
VOID
|
||||
BigNumSub (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN CONST OC_BN_WORD *B
|
||||
)
|
||||
{
|
||||
OC_BN_WORD TmpResult;
|
||||
OC_BN_WORD Tmp1;
|
||||
OC_BN_WORD Tmp2;
|
||||
UINTN Index;
|
||||
UINT8 Borrow;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (B != NULL);
|
||||
//
|
||||
// As the same indices are ever accessed at a step, the index is always
|
||||
// increased per step, the preexisting values in c are unused and all are
|
||||
// are set, it is safe to call this function with c = a or c = b
|
||||
// ATTENTION: This might conflict with future "top" optimizations
|
||||
//
|
||||
Borrow = 0;
|
||||
for (Index = 0; Index < NumWords; ++Index) {
|
||||
Tmp1 = A[Index];
|
||||
Tmp2 = B[Index] + Borrow;
|
||||
TmpResult = (Tmp1 - Tmp2);
|
||||
//
|
||||
// When a subtraction wraps around, the result must be bigger than either
|
||||
// operand.
|
||||
//
|
||||
Borrow = (Tmp2 < Borrow) | (Tmp1 < TmpResult);
|
||||
Result[Index] = TmpResult;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Propagates multiplicative Carry from the result at Index - 1 within Result.
|
||||
|
||||
@param[in,out] A The number to propagate Carry in.
|
||||
@param[in] NumWords The number of Words of A.
|
||||
@param[in] Index The index from which on to add Carry.
|
||||
@param[in] Carry The carry from the multiplication of Index - 1.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumMulPropagateCarry (
|
||||
IN OUT OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN UINTN Index,
|
||||
IN OC_BN_WORD Carry
|
||||
)
|
||||
{
|
||||
OC_BN_WORD Tmp;
|
||||
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
|
||||
for (; Index < NumWords && Carry != 0; ++Index) {
|
||||
Tmp = A[Index] + Carry;
|
||||
//
|
||||
// When an addition wraps around, the result must be smaller than either
|
||||
// operand.
|
||||
//
|
||||
Carry = (Tmp < Carry);
|
||||
A[Index] = Tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of significant bits in a Word.
|
||||
|
||||
@param[in] Word The word to gather the number of significant bits of.
|
||||
|
||||
@returns The number of significant bits in Word.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
UINT8
|
||||
BigNumSignificantBitsWord (
|
||||
IN OC_BN_WORD Word
|
||||
)
|
||||
{
|
||||
UINT8 NumBits;
|
||||
OC_BN_WORD Mask;
|
||||
//
|
||||
// The values we are receiving are very likely large, thus this approach
|
||||
// should be reasonably fast.
|
||||
//
|
||||
NumBits = OC_BN_WORD_NUM_BITS;
|
||||
Mask = (OC_BN_WORD)1U << (OC_BN_WORD_NUM_BITS - 1);
|
||||
while ((Word & Mask) == 0) {
|
||||
--NumBits;
|
||||
Mask >>= 1U;
|
||||
}
|
||||
|
||||
return NumBits;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the most significant word index of A.
|
||||
|
||||
@param[in] A The number to gather the most significant Word index of.
|
||||
@param[in] NumWords The number of Words of A.
|
||||
|
||||
@returns The index of the most significant Word in A.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
OC_BN_NUM_WORDS
|
||||
BigNumMostSignificantWord (
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords
|
||||
)
|
||||
{
|
||||
OC_BN_NUM_WORDS Index;
|
||||
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
|
||||
Index = NumWords;
|
||||
do {
|
||||
--Index;
|
||||
if (A[Index] != 0) {
|
||||
return Index;
|
||||
}
|
||||
} while (Index != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OC_BN_NUM_BITS
|
||||
BigNumSignificantBits (
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN UINTN NumWords
|
||||
)
|
||||
{
|
||||
OC_BN_NUM_BITS Index;
|
||||
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
|
||||
Index = BigNumMostSignificantWord (A, NumWords);
|
||||
return ((Index * OC_BN_WORD_NUM_BITS) + BigNumSignificantBitsWord (A[Index]));
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the product of A and B.
|
||||
|
||||
@param[in,out] Result The buffer to store the result in.
|
||||
@param[in] NumWordsResult The number of Words of Result.
|
||||
@param[in] A The multiplicant.
|
||||
@param[in] NumWordsA The number of Words of A.
|
||||
@param[in] B The multiplier.
|
||||
@param[in] NumWordsB The number of Words of B.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumMul (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWordsResult,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWordsA,
|
||||
IN CONST OC_BN_WORD *B,
|
||||
IN OC_BN_NUM_WORDS NumWordsB
|
||||
)
|
||||
{
|
||||
//
|
||||
// Given a better modulo function, this is subject for removal.
|
||||
// This algorithm is based on a space-optimised version of the conventional
|
||||
// Long Multiplication.
|
||||
// https://en.wikipedia.org/wiki/Multiplication_algorithm#Optimizing_space_complexity
|
||||
//
|
||||
OC_BN_WORD CurWord;
|
||||
OC_BN_WORD MulHi;
|
||||
OC_BN_WORD MulLo;
|
||||
OC_BN_WORD CurCarry;
|
||||
|
||||
UINTN LengthA;
|
||||
UINTN LengthB;
|
||||
UINTN LengthTmp;
|
||||
|
||||
UINTN IndexRes;
|
||||
UINTN IndexA;
|
||||
UINTN IndexB;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWordsResult > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWordsA > 0);
|
||||
ASSERT (B != NULL);
|
||||
ASSERT (NumWordsB > 0);
|
||||
ASSERT (A != Result);
|
||||
ASSERT (B != Result);
|
||||
|
||||
BigNumAssign0 (Result, NumWordsResult);
|
||||
//
|
||||
// These additions cannot overflow because NumWords fits UINTN.
|
||||
//
|
||||
LengthA = BigNumMostSignificantWord (A, NumWordsA) + 1;
|
||||
LengthB = BigNumMostSignificantWord (B, NumWordsB) + 1;
|
||||
//
|
||||
// This cannot overflow for sane outputs due to the address space limitation.
|
||||
//
|
||||
ASSERT (LengthA + LengthB > LengthA);
|
||||
//
|
||||
// This is required to avoid overflows, which purely internal calls should
|
||||
// never produce.
|
||||
//
|
||||
ASSERT (LengthA + LengthB - 1 < NumWordsResult);
|
||||
|
||||
CurCarry = 0;
|
||||
for (IndexRes = 0; IndexRes < LengthA + LengthB - 1; ++IndexRes) {
|
||||
//
|
||||
// Add the carry from the last iteration.
|
||||
//
|
||||
CurWord = Result[IndexRes] + CurCarry;
|
||||
CurCarry = (CurWord < CurCarry);
|
||||
//
|
||||
// When IndexB is out of bounds for B, the value at the requested position
|
||||
// would be 0 and hence no calculation would be performed.
|
||||
//
|
||||
if (IndexRes < LengthB) {
|
||||
IndexA = 0;
|
||||
LengthTmp = IndexRes + 1;
|
||||
IndexB = IndexRes;
|
||||
} else {
|
||||
IndexA = IndexRes - LengthB + 1;
|
||||
LengthTmp = LengthA;
|
||||
IndexB = LengthB - 1;
|
||||
}
|
||||
|
||||
for (; IndexA < LengthTmp; ++IndexA, --IndexB) {
|
||||
//
|
||||
// No arithmetics need to be performed when both operands are 0.
|
||||
//
|
||||
if ((A[IndexA] | B[IndexB]) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MulLo = BigNumWordMul (&MulHi, A[IndexA], B[IndexB]);
|
||||
//
|
||||
// FIXME:
|
||||
// This is hard to read and probably not optimal, however during
|
||||
// simplification of various operations, it turned out multiplication
|
||||
// itself is only required as part of the current modulo implementation.
|
||||
// Instead of cleaning and tweaking this algorithm, an optimised modulo
|
||||
// algorithm that does not depend on this multiplication algorithm should
|
||||
// be found and imported, rendering this function subject for removal.
|
||||
//
|
||||
CurCarry += MulHi;
|
||||
if (CurCarry < MulHi) {
|
||||
//
|
||||
// If the current Carry overflows, propagate a carry of maximum value
|
||||
// upwards and start counting anew.
|
||||
//
|
||||
BigNumMulPropagateCarry (
|
||||
Result,
|
||||
NumWordsResult,
|
||||
IndexRes + 1,
|
||||
OC_BN_MAX_VAL
|
||||
);
|
||||
++CurCarry;
|
||||
}
|
||||
|
||||
CurWord += MulLo;
|
||||
if (CurWord < MulLo) {
|
||||
CurCarry += 1;
|
||||
if (CurCarry < 1) {
|
||||
//
|
||||
// If the current Carry overflows, propagate a carry of maximum value
|
||||
// upwards and start counting anew.
|
||||
//
|
||||
BigNumMulPropagateCarry (
|
||||
Result,
|
||||
NumWordsResult,
|
||||
IndexRes + 1,
|
||||
OC_BN_MAX_VAL
|
||||
);
|
||||
++CurCarry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result[IndexRes] = CurWord;
|
||||
}
|
||||
//
|
||||
// Set the MSB to the carry of the last iteration.
|
||||
//
|
||||
Result[IndexRes] = CurCarry;
|
||||
}
|
||||
|
||||
VOID
|
||||
BigNumOrWord (
|
||||
IN OUT OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN OC_BN_WORD Value,
|
||||
IN UINTN Exponent
|
||||
)
|
||||
{
|
||||
UINTN WordIndex;
|
||||
UINT8 NumBits;
|
||||
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (Exponent / OC_BN_WORD_NUM_BITS < NumWords);
|
||||
|
||||
WordIndex = Exponent / OC_BN_WORD_NUM_BITS;
|
||||
if (WordIndex < NumWords) {
|
||||
NumBits = Exponent % OC_BN_WORD_NUM_BITS;
|
||||
A[WordIndex] |= (Value << NumBits);
|
||||
}
|
||||
}
|
||||
|
||||
INTN
|
||||
BigNumCmp (
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST OC_BN_WORD *B
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (B != NULL);
|
||||
|
||||
Index = NumWords;
|
||||
do {
|
||||
--Index;
|
||||
if (A[Index] > B[Index]) {
|
||||
return 1;
|
||||
} else if (A[Index] < B[Index]) {
|
||||
return -1;
|
||||
}
|
||||
} while (Index != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the left-shift of A by Exponent Bits.
|
||||
|
||||
@param[in,out] Result The buffer to return the result into.
|
||||
@param[in] NumWordsResult The number of Words of Result.
|
||||
@param[in] A The number to shift.
|
||||
@param[in] NumWordsA The number of Words of A.
|
||||
@param[in] Exponent The amount of Bits to shift by.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumLeftShift (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWordsResult,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWordsA,
|
||||
IN UINTN Exponent
|
||||
)
|
||||
{
|
||||
UINTN NumWords;
|
||||
UINT8 NumBits;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWordsResult > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWordsA > 0);
|
||||
|
||||
NumWords = Exponent / OC_BN_WORD_NUM_BITS;
|
||||
NumBits = Exponent % OC_BN_WORD_NUM_BITS;
|
||||
|
||||
if (NumBits != 0) {
|
||||
BigNumLeftShiftWordsAndBits (
|
||||
Result,
|
||||
NumWordsResult,
|
||||
A,
|
||||
NumWordsA,
|
||||
NumWords,
|
||||
NumBits
|
||||
);
|
||||
} else {
|
||||
BigNumLeftShiftWords (Result, NumWordsResult, A, NumWordsA, NumWords);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the quotient of A and B.
|
||||
|
||||
@param[in,out] Result The buffer to return the result into.
|
||||
@param[in] NumWordsRest The number of Words of Result, A, DenonBuf and
|
||||
DividenBuf.
|
||||
@param[in] A The dividend.
|
||||
@param[in] B The divisor.
|
||||
@param[in] NumWordsB The number of Words of B.
|
||||
@param[in] DenomBuf A temporary denominator buffer.
|
||||
@param[in] DividendBuf A temporary dividend buffer.
|
||||
|
||||
@returns Whether the operation was completes successfully.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
BigNumDiv (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWordsRest,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN CONST OC_BN_WORD *B,
|
||||
IN OC_BN_NUM_WORDS NumWordsB,
|
||||
IN OC_BN_WORD *DenomBuf,
|
||||
IN OC_BN_WORD *DividendBuf
|
||||
)
|
||||
{
|
||||
//
|
||||
// As for multiplication, this is subject for removal.
|
||||
//
|
||||
UINTN CurBitIndex;
|
||||
BOOLEAN Overflow;
|
||||
|
||||
UINT32 NumBitsA;
|
||||
UINT32 NumBitsB;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWordsRest > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (B != NULL);
|
||||
ASSERT (NumWordsB > 0);
|
||||
ASSERT (DenomBuf != NULL);
|
||||
ASSERT (DividendBuf != NULL);
|
||||
//
|
||||
// Use an integer of natural size to store the current Bit index as 'current'
|
||||
// is always a 2's potency. While a BIGNUM can theoretically hold a
|
||||
// 2's potency eight times larger than what can represent as Bit index with a
|
||||
// natural integer (Bytes vs Bits), this cannot happen within this function
|
||||
// as 'a' aligned to the next 2's potency would need to be just as big for
|
||||
// this to be the case. This cannot happen due to the address space
|
||||
// limitation.
|
||||
//
|
||||
CurBitIndex = 0;
|
||||
Overflow = FALSE;
|
||||
//
|
||||
// Shift b to the left so it has the same amount of significant bits as a.
|
||||
// This would, without this speedup, be done on per-bit basis by the loop
|
||||
// below.
|
||||
//
|
||||
NumBitsA = BigNumSignificantBits (A, NumWordsRest);
|
||||
NumBitsB = BigNumSignificantBits (B, NumWordsB);
|
||||
if (NumBitsA > NumBitsB) {
|
||||
CurBitIndex = NumBitsA - NumBitsB; // int Current = 1 << (numBitsA - numBitsB);
|
||||
BigNumLeftShift (DenomBuf, NumWordsRest, B, NumWordsB, CurBitIndex); // Denom = B << CurBitIndex
|
||||
} else {
|
||||
CurBitIndex = 0; // int Current = 1;
|
||||
BigNumAssign (DenomBuf, NumWordsRest, B, NumWordsB); // Denom = B
|
||||
}
|
||||
|
||||
while (BigNumCmp (DenomBuf, NumWordsRest, A) <= 0) { // while (Denom <= a) {
|
||||
if (DenomBuf[NumWordsRest - 1] > (OC_BN_MAX_VAL / 2U)) {
|
||||
Overflow = TRUE;
|
||||
break;
|
||||
}
|
||||
++CurBitIndex; // Current <<= 1;
|
||||
BigNumLeftShiftBitsSmall (DenomBuf, NumWordsRest, 1); // Denom <<= 1;
|
||||
}
|
||||
if (!Overflow) {
|
||||
BigNumRightShiftBitsSmall (DenomBuf, NumWordsRest, 1); // Denom >>= 1;
|
||||
--CurBitIndex; // Current >>= 1;
|
||||
}
|
||||
BigNumAssign0 (Result, NumWordsRest); // int Result = 0;
|
||||
BigNumAssign (DividendBuf, NumWordsRest, A, NumWordsRest); // Dividend = A
|
||||
//
|
||||
// currentBitIndex cannot add-wraparound to reach this value as reasoned in
|
||||
// the comment before.
|
||||
//
|
||||
while (CurBitIndex != (0ULL - 1ULL)) { // while (Current != 0)
|
||||
if (BigNumCmp (DividendBuf, NumWordsRest, DenomBuf) >= 0) { // if (Dividend >= Denom)
|
||||
BigNumSub (DividendBuf, NumWordsRest, DividendBuf, DenomBuf); // Dividend -= denom;
|
||||
BigNumOrWord (Result, NumWordsRest, 1, CurBitIndex); // Result |= current;
|
||||
}
|
||||
--CurBitIndex; // Current >>= 1;
|
||||
BigNumRightShiftBitsSmall (DenomBuf, NumWordsRest, 1); // Denom >>= 1;
|
||||
} // return Result;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BigNumMod (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWordsRest,
|
||||
IN CONST OC_BN_WORD *A,
|
||||
IN OC_BN_NUM_WORDS NumWordsA,
|
||||
IN CONST OC_BN_WORD *B
|
||||
)
|
||||
{
|
||||
//
|
||||
// FIXME:
|
||||
// The algorithm is rather expensive and slow. It utilitises the current
|
||||
// suboptimal multiplication and division algorithms. An optimised algorithm
|
||||
// should be imported and formerly mentioned functions be removed as they'd
|
||||
// be dead code.
|
||||
//
|
||||
UINTN TempsBnSize;
|
||||
|
||||
VOID *Memory;
|
||||
OC_BN_WORD *TmpDiv;
|
||||
OC_BN_WORD *TmpMod;
|
||||
OC_BN_WORD *TmpDenom;
|
||||
OC_BN_WORD *TmpDividend;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWordsRest > 0);
|
||||
ASSERT (A != NULL);
|
||||
ASSERT (NumWordsA > 0);
|
||||
ASSERT (B != NULL);
|
||||
ASSERT (NumWordsA >= NumWordsRest);
|
||||
|
||||
OC_STATIC_ASSERT (
|
||||
OC_BN_MAX_SIZE <= MAX_UINTN / 4,
|
||||
"An overflow verification must be added"
|
||||
);
|
||||
|
||||
TempsBnSize = NumWordsA * OC_BN_WORD_SIZE;
|
||||
Memory = AllocatePool (4 * TempsBnSize);
|
||||
if (Memory == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TmpDiv = (OC_BN_WORD *)Memory;
|
||||
TmpMod = (OC_BN_WORD *)((UINTN)TmpDiv + TempsBnSize);
|
||||
TmpDenom = (OC_BN_WORD *)((UINTN)TmpMod + TempsBnSize);
|
||||
TmpDividend = (OC_BN_WORD *)((UINTN)TmpDenom + TempsBnSize);
|
||||
|
||||
BigNumDiv (TmpDiv, NumWordsA, A, B, NumWordsRest, TmpDenom, TmpDividend);
|
||||
BigNumMul (TmpMod, NumWordsA, TmpDiv, NumWordsA, B, NumWordsRest);
|
||||
BigNumSub (Result, NumWordsRest, A, TmpMod);
|
||||
|
||||
FreePool (Memory);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
BigNumParseBuffer (
|
||||
IN OUT OC_BN_WORD *Result,
|
||||
IN OC_BN_NUM_WORDS NumWords,
|
||||
IN CONST UINT8 *Buffer,
|
||||
IN UINTN BufferSize
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
OC_BN_WORD Tmp;
|
||||
|
||||
ASSERT (Result != NULL);
|
||||
ASSERT (NumWords * OC_BN_WORD_SIZE == BufferSize);
|
||||
ASSERT (Buffer != NULL);
|
||||
ASSERT (BufferSize > 0);
|
||||
ASSERT ((BufferSize % OC_BN_WORD_SIZE) == 0);
|
||||
|
||||
for (Index = OC_BN_WORD_SIZE; Index <= BufferSize; Index += OC_BN_WORD_SIZE) {
|
||||
if (OC_BN_WORD_SIZE == sizeof (UINT32)) {
|
||||
Tmp = (OC_BN_WORD)(
|
||||
((UINT32)Buffer[(BufferSize - Index) + 0] << 24U) |
|
||||
((UINT32)Buffer[(BufferSize - Index) + 1] << 16U) |
|
||||
((UINT32)Buffer[(BufferSize - Index) + 2] << 8U) |
|
||||
((UINT32)Buffer[(BufferSize - Index) + 3] << 0U));
|
||||
} else if (OC_BN_WORD_SIZE == sizeof (UINT64)) {
|
||||
Tmp = (OC_BN_WORD)(
|
||||
((UINT64)Buffer[(BufferSize - Index) + 0] << 56U) |
|
||||
((UINT64)Buffer[(BufferSize - Index) + 1] << 48U) |
|
||||
((UINT64)Buffer[(BufferSize - Index) + 2] << 40U) |
|
||||
((UINT64)Buffer[(BufferSize - Index) + 3] << 32U) |
|
||||
((UINT64)Buffer[(BufferSize - Index) + 4] << 24U) |
|
||||
((UINT64)Buffer[(BufferSize - Index) + 5] << 16U) |
|
||||
((UINT64)Buffer[(BufferSize - Index) + 6] << 8U) |
|
||||
((UINT64)Buffer[(BufferSize - Index) + 7] << 0U));
|
||||
}
|
||||
|
||||
Result[(Index / OC_BN_WORD_SIZE) - 1] = Tmp;
|
||||
}
|
||||
}
|
||||
64
Library/OcCryptoLib/IA32/BigNumWordMul64.c
Normal file
64
Library/OcCryptoLib/IA32/BigNumWordMul64.c
Normal file
@ -0,0 +1,64 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OcGuardLib.h>
|
||||
|
||||
#include "../BigNumLib.h"
|
||||
|
||||
OC_BN_WORD
|
||||
BigNumWordMul64 (
|
||||
OUT OC_BN_WORD *Hi,
|
||||
IN OC_BN_WORD A,
|
||||
IN OC_BN_WORD B
|
||||
)
|
||||
{
|
||||
ASSERT (OC_BN_WORD_SIZE == sizeof (UINT64));
|
||||
ASSERT (Hi != NULL);
|
||||
//
|
||||
// This is to be used when the used compiler lacks support for both the
|
||||
// __int128 type and a suiting intrinsic to perform the calculation.
|
||||
//
|
||||
// Source: https://stackoverflow.com/a/31662911
|
||||
//
|
||||
CONST OC_BN_WORD SubWordShift = OC_BN_WORD_NUM_BITS / 2;
|
||||
CONST OC_BN_WORD SubWordMask = ((OC_BN_WORD)1U << SubWordShift) - 1;
|
||||
|
||||
OC_BN_WORD ALo;
|
||||
OC_BN_WORD AHi;
|
||||
OC_BN_WORD BLo;
|
||||
OC_BN_WORD BHi;
|
||||
|
||||
OC_BN_WORD P0;
|
||||
OC_BN_WORD P1;
|
||||
OC_BN_WORD P2;
|
||||
OC_BN_WORD P3;
|
||||
|
||||
OC_BN_WORD Cy;
|
||||
|
||||
ALo = A & SubWordMask;
|
||||
AHi = A >> SubWordShift;
|
||||
BLo = B & SubWordMask;
|
||||
BHi = B >> SubWordShift;
|
||||
|
||||
P0 = ALo * BLo;
|
||||
P1 = ALo * BHi;
|
||||
P2 = AHi * BLo;
|
||||
P3 = AHi * BHi;
|
||||
|
||||
Cy = (((P0 >> SubWordShift) + (P1 & SubWordMask) + (P2 & SubWordMask)) >> SubWordShift) & SubWordMask;
|
||||
|
||||
*Hi = P3 + (P1 >> SubWordShift) + (P2 >> SubWordShift) + Cy;
|
||||
return P0 + (P1 << SubWordShift) + (P2 << SubWordShift);
|
||||
}
|
||||
@ -25,17 +25,31 @@
|
||||
|
||||
|
||||
#
|
||||
# VALID_ARCHITECTURES = X64
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
Aes.c
|
||||
Rsa2048Sha256.c
|
||||
RsaDigitalSign.c
|
||||
Md5.c
|
||||
Sha1.c
|
||||
Sha2.c
|
||||
SecureMem.c
|
||||
PasswordHash.c
|
||||
BigNumLib.h
|
||||
BigNumLibInternal.h
|
||||
BigNumPrimitives.c
|
||||
BigNumMontgomery.c
|
||||
|
||||
[Sources.IA32]
|
||||
IA32/BigNumWordMul64.c
|
||||
|
||||
[Sources.X64]
|
||||
IA32/BigNumWordMul64.c
|
||||
|
||||
[FixedPcd]
|
||||
gOcSupportPkgTokenSpaceGuid.PcdOcCryptoAllowedRsaModuli
|
||||
gOcSupportPkgTokenSpaceGuid.PcdOcCryptoAllowedSigHashTypes
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
|
||||
@ -1,332 +0,0 @@
|
||||
/** @file
|
||||
|
||||
OcCryptoLib
|
||||
|
||||
Copyright (c) 2018, savvas
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
/**
|
||||
Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
|
||||
Implementation of RSA signature verification which uses a pre-processed key
|
||||
for computation.
|
||||
**/
|
||||
|
||||
#ifdef EFIAPI
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#endif
|
||||
|
||||
#include <Library/OcCryptoLib.h>
|
||||
|
||||
/**
|
||||
PKCS#1 padding (from the RSA PKCS#1 v2.1 standard)
|
||||
|
||||
The DER-encoded padding is defined as follows :
|
||||
0x00 || 0x01 || PS || 0x00 || T
|
||||
|
||||
T: DER Encoded DigestInfo value which depends on the hash function used,
|
||||
for SHA-256:
|
||||
(0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H.
|
||||
|
||||
Length(T) = 51 octets for SHA-256
|
||||
|
||||
PS: octet string consisting of {Length(RSA Key) - Length(T) - 3} 0xFF
|
||||
**/
|
||||
#define PKCS_PAD_SIZE (CONFIG_RSA_KEY_SIZE - SHA256_DIGEST_SIZE)
|
||||
|
||||
STATIC UINT8 mSha256Tail[] = {
|
||||
0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
|
||||
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
|
||||
0x05, 0x00, 0x04, 0x20
|
||||
};
|
||||
|
||||
UINT64
|
||||
Mula32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 C
|
||||
)
|
||||
{
|
||||
UINT64 Ret = A;
|
||||
|
||||
Ret *= B;
|
||||
Ret += C;
|
||||
return Ret;
|
||||
}
|
||||
|
||||
UINT64
|
||||
Mulaa32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 C,
|
||||
UINT32 D
|
||||
)
|
||||
{
|
||||
UINT64 Ret = A;
|
||||
|
||||
Ret *= B;
|
||||
Ret += C;
|
||||
Ret += D;
|
||||
return Ret;
|
||||
}
|
||||
|
||||
//
|
||||
// A[] -= Mod
|
||||
//
|
||||
STATIC
|
||||
VOID
|
||||
SubMod (
|
||||
RSA_PUBLIC_KEY *Key,
|
||||
UINT32 *A
|
||||
)
|
||||
{
|
||||
INT64 B = 0;
|
||||
UINT32 Index = 0;
|
||||
for (Index = 0; Index < RSANUMWORDS; ++Index) {
|
||||
B += (UINT64) A[Index] - Key->N[Index];
|
||||
A[Index] = (UINT32) B;
|
||||
B >>= 32;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Return A[] >= Mod
|
||||
//
|
||||
STATIC
|
||||
INT32
|
||||
GeMod (
|
||||
RSA_PUBLIC_KEY *Key,
|
||||
CONST UINT32 *A
|
||||
)
|
||||
{
|
||||
UINT32 Index = 0;
|
||||
|
||||
for (Index = RSANUMWORDS; Index;) {
|
||||
--Index;
|
||||
if (A[Index] < Key->N[Index])
|
||||
return 0;
|
||||
if (A[Index] > Key->N[Index])
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Montgomery c[] += a * b[] / R % mod
|
||||
//
|
||||
STATIC
|
||||
VOID
|
||||
MontMulAdd (
|
||||
RSA_PUBLIC_KEY *Key,
|
||||
UINT32 *C,
|
||||
UINT32 Aa,
|
||||
UINT32 *Bb
|
||||
)
|
||||
{
|
||||
UINT64 A,B;
|
||||
UINT32 D0, Index;
|
||||
|
||||
A = Mula32 (Aa, Bb[0], C[0]);
|
||||
D0 = (UINT32) A * Key->N0Inv;
|
||||
B = Mula32 (D0, Key->N[0], (UINT32) A);
|
||||
|
||||
for (Index = 1; Index < RSANUMWORDS; ++Index) {
|
||||
A = Mulaa32 (Aa, Bb[Index], C[Index], (UINT32) (A >> 32));
|
||||
B = Mulaa32 (D0, Key->N[Index], (UINT32) A, (UINT32) (B >> 32));
|
||||
C[Index - 1] = (UINT32) B;
|
||||
}
|
||||
|
||||
A = (A >> 32) + (B >> 32);
|
||||
C[Index - 1] = (UINT32) A;
|
||||
|
||||
if (A >> 32) {
|
||||
SubMod (Key, C);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Montgomery c[] = a[] * b[] / R % mod
|
||||
//
|
||||
STATIC
|
||||
VOID
|
||||
MontMul (
|
||||
RSA_PUBLIC_KEY *Key,
|
||||
UINT32 *C,
|
||||
UINT32 *A,
|
||||
UINT32 *B
|
||||
)
|
||||
{
|
||||
UINT32 Index;
|
||||
|
||||
ZeroMem (C, CONFIG_RSA_KEY_SIZE);
|
||||
|
||||
for (Index = 0; Index < RSANUMWORDS; ++Index)
|
||||
MontMulAdd (Key, C, A[Index], B);
|
||||
}
|
||||
|
||||
/**
|
||||
In-place public exponentiation.
|
||||
Exponent depends on the configuration (65537 (default), or 3).
|
||||
|
||||
@param Key Key to use in signing
|
||||
@param InOut Input and output big-endian byte array
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
ModPow (
|
||||
RSA_PUBLIC_KEY *Key,
|
||||
UINT8 *InOut
|
||||
)
|
||||
{
|
||||
UINT32 *A = NULL;
|
||||
UINT32 *Ar = NULL;
|
||||
UINT32 *Aar = NULL;
|
||||
UINT32 *Aaa = NULL;
|
||||
INT32 Index = 0;
|
||||
UINT32 Tmp = 0;
|
||||
|
||||
UINT32 Workbuf32[RSANUMWORDS * 3];
|
||||
|
||||
A = Workbuf32;
|
||||
Ar = A + RSANUMWORDS;
|
||||
Aar = Ar + RSANUMWORDS;
|
||||
|
||||
//
|
||||
// Re-use location
|
||||
//
|
||||
Aaa = Aar;
|
||||
|
||||
//
|
||||
// Convert from big endian byte array to little endian word array
|
||||
//
|
||||
for (Index = 0; Index < (INT32) RSANUMWORDS; ++Index) {
|
||||
Tmp =
|
||||
((UINT32)InOut[((RSANUMWORDS - 1 - Index) * 4) + 0] << 24) |
|
||||
((UINT32)InOut[((RSANUMWORDS - 1 - Index) * 4) + 1] << 16) |
|
||||
((UINT32)InOut[((RSANUMWORDS - 1 - Index) * 4) + 2] << 8) |
|
||||
((UINT32)InOut[((RSANUMWORDS - 1 - Index) * 4) + 3] << 0);
|
||||
A[Index] = Tmp;
|
||||
}
|
||||
|
||||
MontMul (Key, Ar, A, Key->Rr);
|
||||
//
|
||||
// Exponent 65537
|
||||
//
|
||||
for (Index = 0; Index < 16; Index += 2) {
|
||||
MontMul (Key, Aar, Ar, Ar);
|
||||
MontMul (Key, Ar, Aar, Aar);
|
||||
}
|
||||
MontMul (Key, Aaa, Ar, A);
|
||||
|
||||
if (GeMod (Key, Aaa)){
|
||||
SubMod (Key, Aaa);
|
||||
}
|
||||
|
||||
//
|
||||
// Convert to bigendian byte array
|
||||
//
|
||||
for (Index = (INT32) RSANUMWORDS - 1; Index >= 0; --Index) {
|
||||
Tmp = Aaa[Index];
|
||||
|
||||
*InOut++ = (UINT8) (Tmp >> 24);
|
||||
*InOut++ = (UINT8) (Tmp >> 16);
|
||||
*InOut++ = (UINT8) (Tmp >> 8);
|
||||
*InOut++ = (UINT8) (Tmp >> 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check PKCS#1 padding bytes
|
||||
*
|
||||
* @param sig Signature to verify
|
||||
* @return 0 if the padding is correct.
|
||||
*/
|
||||
STATIC
|
||||
INT32
|
||||
CheckPadding (
|
||||
UINT8 *Sig
|
||||
)
|
||||
{
|
||||
UINT8 *Ptr = NULL;
|
||||
INT32 Result = 0;
|
||||
UINT32 Index = 0;
|
||||
|
||||
Ptr = Sig;
|
||||
//
|
||||
// First 2 bytes are always 0x00 0x01
|
||||
//
|
||||
Result |= *Ptr++ ^ 0x00;
|
||||
Result |= *Ptr++ ^ 0x01;
|
||||
//
|
||||
// Then 0xff bytes until the tail
|
||||
//
|
||||
for (Index = 0; Index < PKCS_PAD_SIZE - sizeof (mSha256Tail) - 2; Index++)
|
||||
Result |= *Ptr++ ^ 0xff;
|
||||
//
|
||||
// Check the tail
|
||||
//
|
||||
Result |= CompareMem (Ptr, mSha256Tail, sizeof (mSha256Tail));
|
||||
return Result != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Verify a SHA256WithRSA PKCS#1 v1.5 signature against an expected
|
||||
SHA256 hash.
|
||||
|
||||
@param Key RSA public key
|
||||
@param Signature RSA signature
|
||||
@param Sha256 SHA-256 digest of the content to verify
|
||||
|
||||
@return FALSE on failure, TRUE on success.
|
||||
**/
|
||||
BOOLEAN
|
||||
RsaVerify (
|
||||
RSA_PUBLIC_KEY *Key,
|
||||
UINT8 *Signature,
|
||||
UINT8 *Sha256
|
||||
)
|
||||
{
|
||||
UINT8 Buf[CONFIG_RSA_KEY_SIZE];
|
||||
|
||||
//
|
||||
// Copy input to local workspace
|
||||
//
|
||||
CopyMem (Buf, Signature, CONFIG_RSA_KEY_SIZE);
|
||||
|
||||
//
|
||||
// In-place exponentiation
|
||||
//
|
||||
ModPow (Key, Buf);
|
||||
|
||||
//
|
||||
// Check the PKCS#1 padding
|
||||
//
|
||||
if (CheckPadding (Buf) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Check the digest
|
||||
//
|
||||
if (CompareMem (Buf + PKCS_PAD_SIZE, Sha256, SHA256_DIGEST_SIZE) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// All checked out OK
|
||||
//
|
||||
return TRUE;
|
||||
}
|
||||
614
Library/OcCryptoLib/RsaDigitalSign.c
Normal file
614
Library/OcCryptoLib/RsaDigitalSign.c
Normal file
@ -0,0 +1,614 @@
|
||||
/** @file
|
||||
This library performs RSA-based cryptography operations.
|
||||
|
||||
SECURITY: Currently, no security measures have been taken. This code is
|
||||
vulnerable to both timing and side channel attacks for value
|
||||
leakage. However, its current purpose is the verification of public
|
||||
binaries with public certificates, for which this is perfectly
|
||||
acceptable, especially in regards to performance.
|
||||
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcCryptoLib.h>
|
||||
#include <Library/OcGuardLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
|
||||
#include "BigNumLib.h"
|
||||
|
||||
//
|
||||
// RFC 3447, 9.2 EMSA-PKCS1-v1_5, Notes 1.
|
||||
//
|
||||
STATIC CONST UINT8 mPkcsDigestEncodingPrefixSha256[] = {
|
||||
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x01, 0x05, 0x00, 0x04, 0x20
|
||||
};
|
||||
|
||||
STATIC CONST UINT8 mPkcsDigestEncodingPrefixSha384[] = {
|
||||
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x02, 0x05, 0x00, 0x04, 0x30
|
||||
};
|
||||
|
||||
STATIC CONST UINT8 mPkcsDigestEncodingPrefixSha512[] = {
|
||||
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x03, 0x05, 0x00, 0x04, 0x40
|
||||
};
|
||||
|
||||
/**
|
||||
Returns whether the RSA modulus size is allowed.
|
||||
|
||||
@param[in] ModulusSize The size, in bytes, of the RSA modulus.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
InternalRsaModulusSizeIsAllowed (
|
||||
IN UINT16 ModulusSize
|
||||
)
|
||||
{
|
||||
//
|
||||
// Verify ModulusSize is a two's potency.
|
||||
//
|
||||
if ((ModulusSize & (ModulusSize - 1U)) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (PcdGet16 (PcdOcCryptoAllowedRsaModuli) & ModulusSize) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns whether the signature hashing algorithm is allowed.
|
||||
|
||||
@param[in] Type The signature hashing algorithm type.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
InternalSigHashTypeIsAllowed (
|
||||
IN OC_SIG_HASH_TYPE Type
|
||||
)
|
||||
{
|
||||
return (PcdGet16 (PcdOcCryptoAllowedSigHashTypes) & (1U << Type)) != 0;
|
||||
}
|
||||
|
||||
INTN
|
||||
SigVerifyShaHashBySize (
|
||||
IN CONST VOID *Data,
|
||||
IN UINTN DataSize,
|
||||
IN CONST UINT8 *Hash,
|
||||
IN UINTN HashSize
|
||||
)
|
||||
{
|
||||
OC_SIG_HASH_TYPE Hashtype;
|
||||
UINT8 DataDigest[OC_MAX_SHA_DIGEST_SIZE];
|
||||
|
||||
ASSERT (Data != NULL);
|
||||
ASSERT (DataSize > 0);
|
||||
ASSERT (Hash != NULL);
|
||||
ASSERT (HashSize > 0);
|
||||
ASSERT (HashSize <= sizeof (DataDigest));
|
||||
|
||||
switch (HashSize) {
|
||||
case SHA512_DIGEST_SIZE:
|
||||
{
|
||||
Hashtype = OcSigHashTypeSha512;
|
||||
Sha512 (DataDigest, Data, DataSize);
|
||||
break;
|
||||
}
|
||||
|
||||
case SHA384_DIGEST_SIZE:
|
||||
{
|
||||
Hashtype = OcSigHashTypeSha384;
|
||||
Sha384 (DataDigest, Data, DataSize);
|
||||
break;
|
||||
}
|
||||
|
||||
case SHA256_DIGEST_SIZE:
|
||||
{
|
||||
Hashtype = OcSigHashTypeSha256;
|
||||
Sha256 (DataDigest, Data, DataSize);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!InternalSigHashTypeIsAllowed (Hashtype)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return CompareMem (DataDigest, Hash, HashSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Verify a RSA PKCS1.5 signature against an expected hash.
|
||||
|
||||
@param[in] N The RSA modulus.
|
||||
@param[in] N0Inv The Montgomery Inverse of N.
|
||||
@param[in] RSqrMod Montgomery's R^2 mod N.
|
||||
@param[in] NumWords The number of Words of N and RSqrMod.
|
||||
@param[in] Exponent The RSA exponent.
|
||||
@param[in] Signature The RSA signature to be verified.
|
||||
@param[in] SignatureSize Size, in bytes, of Signature.
|
||||
@param[in] Hash The Hash digest of the signed data.
|
||||
@param[in] HashSize Size, in bytes, of Hash.
|
||||
@param[in] Algorithm The RSA algorithm used.
|
||||
|
||||
@returns Whether the signature has been successfully verified as valid.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
RsaVerifySigHashFromProcessed (
|
||||
IN CONST OC_BN_WORD *N,
|
||||
IN UINTN NumWords,
|
||||
IN OC_BN_WORD N0Inv,
|
||||
IN CONST OC_BN_WORD *RSqrMod,
|
||||
IN UINT32 Exponent,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SignatureSize,
|
||||
IN CONST UINT8 *Hash,
|
||||
IN UINTN HashSize,
|
||||
IN OC_SIG_HASH_TYPE Algorithm
|
||||
)
|
||||
{
|
||||
BOOLEAN Result;
|
||||
INTN CmpResult;
|
||||
|
||||
UINTN ModulusSize;
|
||||
|
||||
VOID *Memory;
|
||||
OC_BN_WORD *EncryptedSigNum;
|
||||
OC_BN_WORD *DecryptedSigNum;
|
||||
|
||||
CONST UINT8 *Padding;
|
||||
UINTN PaddingSize;
|
||||
UINTN DigestSize;
|
||||
UINTN Index;
|
||||
|
||||
OC_BN_WORD Tmp;
|
||||
|
||||
ASSERT (N != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (RSqrMod != NULL);
|
||||
ASSERT (Signature != NULL);
|
||||
ASSERT (SignatureSize > 0);
|
||||
ASSERT (Hash != NULL);
|
||||
ASSERT (HashSize > 0);
|
||||
|
||||
OC_STATIC_ASSERT (
|
||||
OcSigHashTypeSha512 == OcSigHashTypeMax - 1,
|
||||
"New switch cases have to be added for every introduced algorithm."
|
||||
);
|
||||
|
||||
if (NumWords > OC_BN_MAX_LEN) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!InternalSigHashTypeIsAllowed (Algorithm)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (Algorithm) {
|
||||
case OcSigHashTypeSha256:
|
||||
{
|
||||
ASSERT (HashSize == SHA256_DIGEST_SIZE);
|
||||
|
||||
Padding = mPkcsDigestEncodingPrefixSha256;
|
||||
PaddingSize = sizeof (mPkcsDigestEncodingPrefixSha256);
|
||||
break;
|
||||
}
|
||||
|
||||
case OcSigHashTypeSha384:
|
||||
{
|
||||
ASSERT (HashSize == SHA384_DIGEST_SIZE);
|
||||
|
||||
Padding = mPkcsDigestEncodingPrefixSha384;
|
||||
PaddingSize = sizeof (mPkcsDigestEncodingPrefixSha384);
|
||||
break;
|
||||
}
|
||||
|
||||
case OcSigHashTypeSha512:
|
||||
{
|
||||
ASSERT (HashSize == SHA512_DIGEST_SIZE);
|
||||
|
||||
Padding = mPkcsDigestEncodingPrefixSha512;
|
||||
PaddingSize = sizeof (mPkcsDigestEncodingPrefixSha512);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
}
|
||||
//
|
||||
// Verify the Signature size matches the Modulus size.
|
||||
// This implicitly verifies it's a multiple of the Word size.
|
||||
//
|
||||
ModulusSize = NumWords * OC_BN_WORD_SIZE;
|
||||
if (!InternalRsaModulusSizeIsAllowed (ModulusSize)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (SignatureSize != ModulusSize) {
|
||||
DEBUG ((DEBUG_INFO, "OCCR: Signature length does not match key length"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Memory = AllocatePool (2 * ModulusSize);
|
||||
if (Memory == NULL) {
|
||||
DEBUG ((DEBUG_INFO, "OCCR: Memory allocation failure\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
EncryptedSigNum = Memory;
|
||||
DecryptedSigNum = (OC_BN_WORD *)((UINTN)EncryptedSigNum + ModulusSize);
|
||||
|
||||
BigNumParseBuffer (
|
||||
EncryptedSigNum,
|
||||
(OC_BN_NUM_WORDS)NumWords,
|
||||
Signature,
|
||||
SignatureSize
|
||||
);
|
||||
|
||||
Result = BigNumPowMod (
|
||||
DecryptedSigNum,
|
||||
(OC_BN_NUM_WORDS)NumWords,
|
||||
EncryptedSigNum,
|
||||
Exponent,
|
||||
N,
|
||||
N0Inv,
|
||||
RSqrMod
|
||||
);
|
||||
if (!Result) {
|
||||
FreePool (Memory);
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Convert the result to a big-endian byte array.
|
||||
// Re-use EncryptedSigNum as it is not required anymore.
|
||||
// FIXME: Doing this as part of the comparison could speed up the process
|
||||
// and clean up the code.
|
||||
//
|
||||
Index = NumWords;
|
||||
while (Index > 0) {
|
||||
--Index;
|
||||
Tmp = BigNumSwapWord (
|
||||
DecryptedSigNum[NumWords - 1 - Index]
|
||||
);
|
||||
EncryptedSigNum[Index] = Tmp;
|
||||
}
|
||||
Signature = (UINT8 *)EncryptedSigNum;
|
||||
|
||||
//
|
||||
// From RFC 3447, 9.2 EMSA-PKCS1-v1_5:
|
||||
//
|
||||
// 5. Concatenate PS, the DER encoding T, and other padding to form the
|
||||
// encoded message EM as
|
||||
//
|
||||
// EM = 0x00 || 0x01 || PS || 0x00 || T.
|
||||
//
|
||||
|
||||
//
|
||||
// 3. If emLen < tLen + 11, output "intended encoded message length too
|
||||
// short" and stop.
|
||||
//
|
||||
// The additions cannot overflow because both PaddingSize and HashSize are
|
||||
// sane at this point.
|
||||
//
|
||||
DigestSize = PaddingSize + HashSize;
|
||||
if (SignatureSize < DigestSize + 11) {
|
||||
FreePool (Memory);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Signature[0] != 0x00 || Signature[1] != 0x01) {
|
||||
FreePool (Memory);
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// 4. Generate an octet string PS consisting of emLen - tLen - 3 octets with
|
||||
// hexadecimal value 0xff. The length of PS will be at least 8 octets.
|
||||
//
|
||||
// The additions and subtractions cannot overflow as per 3.
|
||||
//
|
||||
for (Index = 2; Index < SignatureSize - DigestSize - 3 + 2; ++Index) {
|
||||
if (Signature[Index] != 0xFF) {
|
||||
FreePool (Memory);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (Signature[Index] != 0x00) {
|
||||
FreePool (Memory);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
++Index;
|
||||
|
||||
CmpResult = CompareMem (&Signature[Index], Padding, PaddingSize);
|
||||
if (CmpResult != 0) {
|
||||
FreePool (Memory);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Index += PaddingSize;
|
||||
|
||||
CmpResult = CompareMem (&Signature[Index], Hash, HashSize);
|
||||
if (CmpResult != 0) {
|
||||
FreePool (Memory);
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// The code above must have covered the entire Signature range.
|
||||
//
|
||||
ASSERT (Index + HashSize == SignatureSize);
|
||||
|
||||
FreePool (Memory);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Verify RSA PKCS1.5 signed data against its signature.
|
||||
The modulus' size must be a multiple of the configured BIGNUM word size.
|
||||
This will be true for any conventional RSA, which use two's potencies.
|
||||
|
||||
@param[in] N The RSA modulus.
|
||||
@param[in] NumWords The number of Words of N and RSqrMod.
|
||||
@param[in] N0Inv The Montgomery Inverse of N.
|
||||
@param[in] RSqrMod Montgomery's R^2 mod N.
|
||||
@param[in] Exponent The RSA exponent.
|
||||
@param[in] Signature The RSA signature to be verified.
|
||||
@param[in] SignatureSize Size, in bytes, of Signature.
|
||||
@param[in] Data The signed data to verify.
|
||||
@param[in] DataSize Size, in bytes, of Data.
|
||||
@param[in] Algorithm The RSA algorithm used.
|
||||
|
||||
@returns Whether the signature has been successfully verified as valid.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
RsaVerifySigDataFromProcessed (
|
||||
IN CONST OC_BN_WORD *N,
|
||||
IN UINTN NumWords,
|
||||
IN OC_BN_WORD N0Inv,
|
||||
IN CONST OC_BN_WORD *RSqrMod,
|
||||
IN UINT32 Exponent,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SignatureSize,
|
||||
IN CONST UINT8 *Data,
|
||||
IN UINTN DataSize,
|
||||
IN OC_SIG_HASH_TYPE Algorithm
|
||||
)
|
||||
{
|
||||
UINT8 Hash[OC_MAX_SHA_DIGEST_SIZE];
|
||||
UINTN HashSize;
|
||||
|
||||
ASSERT (N != NULL);
|
||||
ASSERT (NumWords > 0);
|
||||
ASSERT (RSqrMod != NULL);
|
||||
ASSERT (Exponent > 0);
|
||||
ASSERT (Signature != NULL);
|
||||
ASSERT (SignatureSize > 0);
|
||||
ASSERT (Data != NULL);
|
||||
ASSERT (DataSize > 0);
|
||||
|
||||
OC_STATIC_ASSERT (
|
||||
OcSigHashTypeSha512 == OcSigHashTypeMax - 1,
|
||||
"New switch cases have to be added for every introduced algorithm."
|
||||
);
|
||||
|
||||
switch (Algorithm) {
|
||||
case OcSigHashTypeSha256:
|
||||
{
|
||||
Sha256 (Hash, Data, DataSize);
|
||||
HashSize = SHA256_DIGEST_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
case OcSigHashTypeSha384:
|
||||
{
|
||||
Sha384 (Hash, Data, DataSize);
|
||||
HashSize = SHA384_DIGEST_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
case OcSigHashTypeSha512:
|
||||
{
|
||||
Sha512 (Hash, Data, DataSize);
|
||||
HashSize = SHA512_DIGEST_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
//
|
||||
// New switch cases have to be added for every introduced algorithm.
|
||||
//
|
||||
ASSERT (FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return RsaVerifySigHashFromProcessed (
|
||||
N,
|
||||
NumWords,
|
||||
N0Inv,
|
||||
RSqrMod,
|
||||
Exponent,
|
||||
Signature,
|
||||
SignatureSize,
|
||||
Hash,
|
||||
HashSize,
|
||||
Algorithm
|
||||
);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
RsaVerifySigDataFromData (
|
||||
IN CONST UINT8 *Modulus,
|
||||
IN UINTN ModulusSize,
|
||||
IN UINT32 Exponent,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SignatureSize,
|
||||
IN CONST UINT8 *Data,
|
||||
IN UINTN DataSize,
|
||||
IN OC_SIG_HASH_TYPE Algorithm
|
||||
)
|
||||
{
|
||||
UINTN ModulusNumWords;
|
||||
|
||||
VOID *Memory;
|
||||
OC_BN_WORD *N;
|
||||
OC_BN_WORD *RSqrMod;
|
||||
|
||||
OC_BN_WORD N0Inv;
|
||||
BOOLEAN Result;
|
||||
|
||||
ASSERT (Modulus != NULL);
|
||||
ASSERT (ModulusSize > 0);
|
||||
ASSERT (Exponent > 0);
|
||||
ASSERT (Signature != NULL);
|
||||
ASSERT (SignatureSize > 0);
|
||||
ASSERT (Data != NULL);
|
||||
ASSERT (DataSize > 0);
|
||||
|
||||
ModulusNumWords = ModulusSize / OC_BN_WORD_SIZE;
|
||||
if (ModulusNumWords > OC_BN_MAX_LEN
|
||||
|| (ModulusSize % OC_BN_WORD_SIZE) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
OC_STATIC_ASSERT (
|
||||
OC_BN_MAX_SIZE <= MAX_UINTN / 2,
|
||||
"An overflow verification must be added"
|
||||
);
|
||||
|
||||
Memory = AllocatePool (2 * ModulusSize);
|
||||
if (Memory == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
N = (OC_BN_WORD *)Memory;
|
||||
RSqrMod = (OC_BN_WORD *)((UINTN)N + ModulusSize);
|
||||
|
||||
BigNumParseBuffer (N, ModulusNumWords, Modulus, ModulusSize);
|
||||
|
||||
N0Inv = BigNumCalculateMontParams (RSqrMod, ModulusNumWords, N);
|
||||
if (N0Inv == 0) {
|
||||
FreePool (Memory);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Result = RsaVerifySigDataFromProcessed (
|
||||
N,
|
||||
ModulusNumWords,
|
||||
N0Inv,
|
||||
RSqrMod,
|
||||
Exponent,
|
||||
Signature,
|
||||
SignatureSize,
|
||||
Data,
|
||||
DataSize,
|
||||
Algorithm
|
||||
);
|
||||
|
||||
FreePool (Memory);
|
||||
return Result;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
RsaVerifySigHashFromKey (
|
||||
IN CONST OC_RSA_PUBLIC_KEY *Key,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SignatureSize,
|
||||
IN CONST UINT8 *Hash,
|
||||
IN UINTN HashSize,
|
||||
IN OC_SIG_HASH_TYPE Algorithm
|
||||
)
|
||||
{
|
||||
ASSERT (Key != NULL);
|
||||
ASSERT (Signature != NULL);
|
||||
ASSERT (SignatureSize > 0);
|
||||
ASSERT (Hash != NULL);
|
||||
ASSERT (HashSize > 0);
|
||||
|
||||
OC_STATIC_ASSERT (
|
||||
OC_BN_WORD_SIZE <= 8,
|
||||
"The parentheses need to be changed to avoid truncation."
|
||||
);
|
||||
//
|
||||
// When OC_BN_WORD is not UINT64, this violates the strict aliasing rule.
|
||||
// However, due to packed-ness and byte order, this is perfectly safe.
|
||||
//
|
||||
return RsaVerifySigHashFromProcessed (
|
||||
(OC_BN_WORD *)Key->Data,
|
||||
Key->Hdr.NumQwords * (8 / OC_BN_WORD_SIZE),
|
||||
(OC_BN_WORD)Key->Hdr.N0Inv,
|
||||
(OC_BN_WORD *)&Key->Data[Key->Hdr.NumQwords],
|
||||
0x10001,
|
||||
Signature,
|
||||
SignatureSize,
|
||||
Hash,
|
||||
HashSize,
|
||||
Algorithm
|
||||
);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
RsaVerifySigDataFromKey (
|
||||
IN CONST OC_RSA_PUBLIC_KEY *Key,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SignatureSize,
|
||||
IN CONST UINT8 *Data,
|
||||
IN UINTN DataSize,
|
||||
IN OC_SIG_HASH_TYPE Algorithm
|
||||
)
|
||||
{
|
||||
ASSERT (Key != NULL);
|
||||
ASSERT (Signature != NULL);
|
||||
ASSERT (SignatureSize > 0);
|
||||
ASSERT (Data != NULL);
|
||||
ASSERT (DataSize > 0);
|
||||
|
||||
OC_STATIC_ASSERT (
|
||||
OC_BN_WORD_SIZE <= 8,
|
||||
"The parentheses need to be changed to avoid truncation."
|
||||
);
|
||||
//
|
||||
// When OC_BN_WORD is not UINT64, this violates the strict aliasing rule.
|
||||
// However, due to packed-ness and byte order, this is perfectly safe.
|
||||
//
|
||||
return RsaVerifySigDataFromProcessed (
|
||||
(OC_BN_WORD *)Key->Data,
|
||||
Key->Hdr.NumQwords * (8 / OC_BN_WORD_SIZE),
|
||||
(OC_BN_WORD)Key->Hdr.N0Inv,
|
||||
(OC_BN_WORD *)&Key->Data[Key->Hdr.NumQwords],
|
||||
0x10001,
|
||||
Signature,
|
||||
SignatureSize,
|
||||
Data,
|
||||
DataSize,
|
||||
Algorithm
|
||||
);
|
||||
}
|
||||
49
Library/OcCryptoLib/X64/BigNumWordMul64.c
Normal file
49
Library/OcCryptoLib/X64/BigNumWordMul64.c
Normal file
@ -0,0 +1,49 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OcGuardLib.h>
|
||||
|
||||
#include "../BigNumLib.h"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
||||
OC_BN_WORD
|
||||
BigNumWordMul64 (
|
||||
OUT OC_BN_WORD *Hi,
|
||||
IN OC_BN_WORD A,
|
||||
IN OC_BN_WORD B
|
||||
)
|
||||
{
|
||||
ASSERT (OC_BN_WORD_SIZE == sizeof (UINT64));
|
||||
ASSERT (Hi != NULL);
|
||||
|
||||
#if !defined(_MSC_VER) || defined(__clang__)
|
||||
//
|
||||
// Clang and GCC support the __int128 type for edk2 builds.
|
||||
//
|
||||
unsigned __int128 Result = (unsigned __int128)A * B;
|
||||
*Hi = (OC_BN_WORD)(Result >> OC_BN_WORD_NUM_BITS);
|
||||
return (OC_BN_WORD)Result;
|
||||
#else
|
||||
//
|
||||
// MSVC does not support the __int128 type for edk2 builds, but a proprietary
|
||||
// intrinsic function declared above.
|
||||
//
|
||||
return _umul128 (A, B, Hi);
|
||||
#endif
|
||||
}
|
||||
@ -123,14 +123,13 @@ STATIC
|
||||
EFI_STATUS
|
||||
OcStorageInitializeVault (
|
||||
IN OUT OC_STORAGE_CONTEXT *Context,
|
||||
IN VOID *Vault OPTIONAL,
|
||||
IN VOID *Vault OPTIONAL,
|
||||
IN UINT32 VaultSize,
|
||||
IN RSA_PUBLIC_KEY *StorageKey OPTIONAL,
|
||||
IN VOID *Signature OPTIONAL
|
||||
IN OC_RSA_PUBLIC_KEY *StorageKey OPTIONAL,
|
||||
IN VOID *Signature OPTIONAL,
|
||||
IN UINT32 SignatureSize OPTIONAL
|
||||
)
|
||||
{
|
||||
UINT8 Digest[SHA256_DIGEST_SIZE];
|
||||
|
||||
if (Signature != NULL && Vault == NULL) {
|
||||
DEBUG ((DEBUG_ERROR, "OCS: Missing vault with signature\n"));
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
@ -144,9 +143,7 @@ OcStorageInitializeVault (
|
||||
if (Signature != NULL) {
|
||||
ASSERT (StorageKey != NULL);
|
||||
|
||||
Sha256 (Digest, Vault, VaultSize);
|
||||
|
||||
if (!RsaVerify (StorageKey, Signature, Digest)) {
|
||||
if (!RsaVerifySigDataFromKey (StorageKey, Signature, SignatureSize, Vault, VaultSize, OcSigHashTypeSha256)) {
|
||||
DEBUG ((DEBUG_ERROR, "OCS: Invalid vault signature\n"));
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
@ -219,7 +216,7 @@ OcStorageInitFromFs (
|
||||
OUT OC_STORAGE_CONTEXT *Context,
|
||||
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
|
||||
IN CONST CHAR16 *Path,
|
||||
IN RSA_PUBLIC_KEY *StorageKey OPTIONAL
|
||||
IN OC_RSA_PUBLIC_KEY *StorageKey OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
@ -227,6 +224,7 @@ OcStorageInitFromFs (
|
||||
VOID *Vault;
|
||||
VOID *Signature;
|
||||
UINT32 DataSize;
|
||||
UINT32 SignatureSize;
|
||||
|
||||
ZeroMem (Context, sizeof (*Context));
|
||||
|
||||
@ -253,11 +251,13 @@ OcStorageInitFromFs (
|
||||
return Status;
|
||||
}
|
||||
|
||||
SignatureSize = 0;
|
||||
|
||||
if (StorageKey) {
|
||||
Signature = OcStorageReadFileUnicode (
|
||||
Context,
|
||||
OC_STORAGE_VAULT_SIGNATURE_PATH,
|
||||
&DataSize
|
||||
&SignatureSize
|
||||
);
|
||||
|
||||
if (Signature == NULL) {
|
||||
@ -265,18 +265,6 @@ OcStorageInitFromFs (
|
||||
OcStorageFree (Context);
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
|
||||
if (DataSize != CONFIG_RSA_KEY_SIZE) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"OCS: Vault signature size mismatch: %u vs %u\n",
|
||||
DataSize,
|
||||
CONFIG_RSA_KEY_SIZE
|
||||
));
|
||||
FreePool (Signature);
|
||||
OcStorageFree (Context);
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
} else {
|
||||
Signature = NULL;
|
||||
}
|
||||
@ -288,7 +276,7 @@ OcStorageInitFromFs (
|
||||
&DataSize
|
||||
);
|
||||
|
||||
Status = OcStorageInitializeVault (Context, Vault, DataSize, StorageKey, Signature);
|
||||
Status = OcStorageInitializeVault (Context, Vault, DataSize, StorageKey, Signature, SignatureSize);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_INFO, "OCS: Vault init failure %p (%u) - %r\n", Vault, DataSize, Status));
|
||||
|
||||
@ -80,6 +80,18 @@
|
||||
# @Prompt Initialize the console to the specified mode on entry.
|
||||
gOcSupportPkgTokenSpaceGuid.PcdConsoleControlEntryMode|0|UINT8|0x00000100
|
||||
|
||||
## Defines the allowed OcCryptoLib RSA moduli by OR'ing the two's potencies in bytes.<BR><BR>
|
||||
# @Prompt Allow these RSA moduli for cryptographic usage.
|
||||
gOcSupportPkgTokenSpaceGuid.PcdOcCryptoAllowedRsaModuli|0x300|UINT16|0x00000500
|
||||
|
||||
## Defines the allowed OcCryptoLib signature hashing algorihtms by OR'ing the
|
||||
# types' Bit indices.<BR><BR>
|
||||
# Bit 0 - OcSigHashTypeSha256
|
||||
# Bit 1 - OcSigHashTypeSha384
|
||||
# Bit 2 - OcSigHashTypeSha512
|
||||
# @Prompt Allow these signature hashing algorithms for cryptographic usage.
|
||||
gOcSupportPkgTokenSpaceGuid.PcdOcCryptoAllowedSigHashTypes|0x07|UINT16|0x00000501
|
||||
|
||||
[LibraryClasses]
|
||||
## @libraryclass
|
||||
OcAcpiLib|Include/Library/OcAcpiLib.h
|
||||
@ -105,6 +117,9 @@
|
||||
## @libraryclass
|
||||
OcAppleImageVerificationLib|Include/Library/OcAppleImageVerificationLib.h
|
||||
|
||||
## @libraryclass
|
||||
OcAppleImg4Lib|Include/Library/OcAppleImg4Lib.h
|
||||
|
||||
## @libraryclass
|
||||
OcAppleKernelLib|Include/Library/OcAppleKernelLib.h
|
||||
|
||||
|
||||
@ -47,10 +47,13 @@ TestRsa2048Sha256Verify (
|
||||
SIGNED_DATA_LEN
|
||||
);
|
||||
|
||||
SignatureVerified = RsaVerify (
|
||||
(RSA_PUBLIC_KEY *) Rsa2048Sha256Sample.PublicKey,
|
||||
SignatureVerified = RsaVerifySigHashFromKey (
|
||||
(OC_RSA_PUBLIC_KEY *) Rsa2048Sha256Sample.PublicKey,
|
||||
Rsa2048Sha256Sample.Signature,
|
||||
DataSha256Hash
|
||||
sizeof (Rsa2048Sha256Sample.Signature),
|
||||
DataSha256Hash,
|
||||
sizeof (DataSha256Hash),
|
||||
OcSigHashTypeSha256
|
||||
);
|
||||
|
||||
if (SignatureVerified) {
|
||||
|
||||
@ -15,6 +15,8 @@ rm -rf DICT fuzz*.log ; mkdir DICT ; UBSAN_OPTIONS='halt_on_error=1' ./DiskImage
|
||||
|
||||
**/
|
||||
|
||||
EFI_GUID gOcVendorVariableGuid;
|
||||
|
||||
uint8_t *readFile(const char *str, long *size) {
|
||||
FILE *f = fopen(str, "rb");
|
||||
|
||||
@ -116,7 +118,7 @@ int main (int argc, char *argv[]) {
|
||||
goto ContinueDmgLoop;
|
||||
}
|
||||
|
||||
Result = OcAppleChunklistVerifySignature (&ChunklistContext, (RSA_PUBLIC_KEY *)PkDataBase[0].PublicKey);
|
||||
Result = OcAppleChunklistVerifySignature (&ChunklistContext, PkDataBase[0].PublicKey);
|
||||
if (!Result) {
|
||||
printf ("Chunklist signature verification error\n");
|
||||
goto ContinueDmgLoop;
|
||||
|
||||
172
TestsUser/Img4/Img4.c
Normal file
172
TestsUser/Img4/Img4.c
Normal file
@ -0,0 +1,172 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <Base.h>
|
||||
|
||||
#include <Protocol/AppleSecureBoot.h>
|
||||
#include <Library/OcCryptoLib.h>
|
||||
|
||||
#include "libDER/oids.h"
|
||||
#include "libDERImg4/Img4oids.h"
|
||||
#include "libDERImg4/libDERImg4.h"
|
||||
|
||||
#ifdef FUZZING_TEST
|
||||
#define main no_main
|
||||
#endif
|
||||
|
||||
EFI_GUID gAppleSecureBootVariableGuid;
|
||||
|
||||
void InternalDebugEnvInfo (
|
||||
const DERImg4Environment *Env
|
||||
)
|
||||
{
|
||||
printf (
|
||||
"\nEcid: %llx\n"
|
||||
"BoardId: %x\n"
|
||||
"ChipId: %x\n"
|
||||
"CertificateEpoch: %x\n"
|
||||
"SecurityDomain: %x\n"
|
||||
"ProductionStatus: %x\n"
|
||||
"SecurityMode: %x\n"
|
||||
"EffectiveProductionStatus: %x\n"
|
||||
"EffectiveSecurityMode:%x \n"
|
||||
"InternalUseOnlyUnit: %x\n"
|
||||
"Xugs: %x\n\n",
|
||||
(unsigned long long)Env->ecid,
|
||||
Env->boardId,
|
||||
Env->chipId,
|
||||
Env->certificateEpoch,
|
||||
Env->securityDomain,
|
||||
Env->productionStatus,
|
||||
Env->securityMode,
|
||||
Env->effectiveProductionStatus,
|
||||
Env->effectiveSecurityMode,
|
||||
Env->internalUseOnlyUnit,
|
||||
Env->xugs
|
||||
);
|
||||
}
|
||||
|
||||
uint8_t *readFile(const char *str, uint32_t *size) {
|
||||
FILE *f = fopen(str, "rb");
|
||||
|
||||
if (!f) return NULL;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
uint8_t *string = malloc(fsize);
|
||||
fread(string, fsize, 1, f);
|
||||
fclose(f);
|
||||
*size = fsize;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
int verifyImg4 (char *imageName, char *manifestName, char *type)
|
||||
{
|
||||
void *Manifest, *Image;
|
||||
uint32_t ManSize, ImgSize;
|
||||
DERImg4ManifestInfo ManInfo;
|
||||
|
||||
Manifest = readFile (manifestName, &ManSize);
|
||||
if (Manifest == NULL) {
|
||||
printf ("\n!!! read error !!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DERReturn r = DERImg4ParseManifest (
|
||||
&ManInfo,
|
||||
Manifest,
|
||||
ManSize,
|
||||
SIGNATURE_32 (type[3], type[2], type[1], type[0])
|
||||
);
|
||||
free (Manifest);
|
||||
if (r != DR_Success) {
|
||||
printf ("\n !!! DERImg4ParseManifest failed - %d !!!\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
InternalDebugEnvInfo (&ManInfo.environment);
|
||||
|
||||
Image = readFile (imageName, &ImgSize);
|
||||
if (Image == NULL) {
|
||||
printf ("\n!!! read error !!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
INTN CmpResult = SigVerifyShaHashBySize (
|
||||
Image,
|
||||
ImgSize,
|
||||
ManInfo.imageDigest,
|
||||
ManInfo.imageDigestSize
|
||||
);
|
||||
|
||||
free (Image);
|
||||
|
||||
if (CmpResult != 0) {
|
||||
printf ("\n!!! digest mismatch !!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2 || (argc % 3) != 1) {
|
||||
printf ("Img4 ([image path] [manifest path] [object type])*\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int r = 0;
|
||||
for (int i = 1; i < (argc - 1); i += 3) {
|
||||
if (strlen (argv[i + 2]) != 4) {
|
||||
printf ("Object types require exactly 4 characters.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = verifyImg4 (
|
||||
argv[i + 0],
|
||||
argv[i + 1],
|
||||
argv[i + 2]
|
||||
);
|
||||
if (r != 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
const uint32_t signatures[] = {
|
||||
APPLE_SB_OBJ_EFIBOOT,
|
||||
APPLE_SB_OBJ_EFIBOOT_DEBUG,
|
||||
APPLE_SB_OBJ_EFIBOOT_BASE,
|
||||
APPLE_SB_OBJ_MUPD,
|
||||
APPLE_SB_OBJ_HPMU,
|
||||
APPLE_SB_OBJ_THOU,
|
||||
APPLE_SB_OBJ_GPUU,
|
||||
APPLE_SB_OBJ_ETHU,
|
||||
APPLE_SB_OBJ_SDFU,
|
||||
APPLE_SB_OBJ_DTHU
|
||||
};
|
||||
|
||||
if (Data == NULL || Size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DERImg4ManifestInfo ManInfo;
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE (signatures); ++i) {
|
||||
DERImg4ParseManifest (
|
||||
&ManInfo,
|
||||
Data,
|
||||
Size,
|
||||
signatures[i]
|
||||
);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -65,8 +65,6 @@ typedef char CHAR8;
|
||||
typedef unsigned short CHAR16;
|
||||
typedef signed char INT8;
|
||||
typedef unsigned char UINT8;
|
||||
typedef ssize_t INTN;
|
||||
typedef size_t UINTN;
|
||||
typedef bool BOOLEAN;
|
||||
typedef int32_t INT32;
|
||||
typedef uint32_t UINT32;
|
||||
@ -74,6 +72,12 @@ typedef int64_t INT64;
|
||||
typedef uint64_t UINT64;
|
||||
typedef int16_t INT16;
|
||||
typedef uint16_t UINT16;
|
||||
#if SIZE_MAX == UINT64_MAX
|
||||
typedef INT64 INTN;
|
||||
#elif SIZE_MAX == UINT32_MAX
|
||||
typedef INT32 INTN;
|
||||
#endif
|
||||
typedef size_t UINTN;
|
||||
typedef size_t EFI_STATUS;
|
||||
typedef UINTN RETURN_STATUS;
|
||||
typedef UINT64 EFI_PHYSICAL_ADDRESS;
|
||||
@ -1884,4 +1888,7 @@ GetCurrentMemoryMap (
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define _PCD_GET_MODE_16_PcdOcCryptoAllowedSigHashTypes (1U | 2U | 4U) // SHA256, SHA384, SHA512
|
||||
#define _PCD_GET_MODE_16_PcdOcCryptoAllowedRsaModuli (512U | 256U)
|
||||
|
||||
#endif
|
||||
|
||||
79
TestsUser/RsaPreprocess/RsaPreprocess.c
Normal file
79
TestsUser/RsaPreprocess/RsaPreprocess.c
Normal file
@ -0,0 +1,79 @@
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/OcCryptoLib.h>
|
||||
#include <Library/OcAppleKeysLib.h>
|
||||
|
||||
#include <BigNumLib.h>
|
||||
|
||||
uint8_t *readFile(const char *str, uint32_t *size) {
|
||||
FILE *f = fopen(str, "rb");
|
||||
|
||||
if (!f) return NULL;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
uint8_t *string = malloc(fsize);
|
||||
fread(string, fsize, 1, f);
|
||||
fclose(f);
|
||||
|
||||
*size = fsize;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
int verifyRsa (CONST OC_RSA_PUBLIC_KEY *PublicKey, char *Name)
|
||||
{
|
||||
OC_BN_WORD N0Inv;
|
||||
UINTN ModulusSize = PublicKey->Hdr.NumQwords * sizeof (UINT64);
|
||||
|
||||
OC_BN_WORD *RSqrMod = malloc(ModulusSize);
|
||||
if (RSqrMod == NULL) {
|
||||
printf ("memory allocation error!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
N0Inv = BigNumCalculateMontParams (
|
||||
RSqrMod,
|
||||
ModulusSize / OC_BN_WORD_SIZE,
|
||||
PublicKey->Data
|
||||
);
|
||||
|
||||
printf (
|
||||
"%s: results: %d %d\n",
|
||||
Name,
|
||||
memcmp (
|
||||
RSqrMod,
|
||||
&PublicKey->Data[PublicKey->Hdr.NumQwords],
|
||||
ModulusSize
|
||||
),
|
||||
N0Inv != PublicKey->Hdr.N0Inv
|
||||
);
|
||||
|
||||
free(RSqrMod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned int Index;
|
||||
OC_RSA_PUBLIC_KEY *PublicKey;
|
||||
uint32_t PkSize;
|
||||
|
||||
for (Index = 1; Index < argc; ++Index) {
|
||||
PublicKey = (OC_RSA_PUBLIC_KEY *)readFile (argv[Index], &PkSize);
|
||||
if (PublicKey == NULL) {
|
||||
printf ("read error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
verifyRsa (PublicKey, argv[Index]);
|
||||
free (PublicKey);
|
||||
}
|
||||
|
||||
for (Index = 0; Index < ARRAY_SIZE (PkDataBase); ++Index) {
|
||||
verifyRsa (PkDataBase[Index].PublicKey, "inbuilt");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -18,9 +18,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
#include "AppleEfiPeImage.h"
|
||||
#include "AppleEfiFatBinary.h"
|
||||
#include <Library/OcCryptoLib.h>
|
||||
#include <Library/OcAppleKeysLib.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef NDEBUG
|
||||
# define DEBUG_PRINT(x) printf x
|
||||
#else
|
||||
# define DEBUG_PRINT(x) do {} while (0)
|
||||
@ -428,7 +429,7 @@ VerifyApplePeImageSignature (
|
||||
uint8_t SigBe[256];
|
||||
uint8_t CalcucatedHash[32];
|
||||
uint8_t PkHash[32];
|
||||
RSA_PUBLIC_KEY *Pk = NULL;
|
||||
const OC_RSA_PUBLIC_KEY *Pk = NULL;
|
||||
APPLE_PE_COFF_LOADER_IMAGE_CONTEXT *Context = NULL;
|
||||
|
||||
Context = malloc (sizeof (APPLE_PE_COFF_LOADER_IMAGE_CONTEXT));
|
||||
@ -479,7 +480,7 @@ VerifyApplePeImageSignature (
|
||||
//
|
||||
// PublicKey valid. Extract prepared publickey from database
|
||||
//
|
||||
Pk = (RSA_PUBLIC_KEY *) PkDataBase[Index].PublicKey;
|
||||
Pk = PkDataBase[Index].PublicKey;
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,7 +492,7 @@ VerifyApplePeImageSignature (
|
||||
//
|
||||
// Verify signature
|
||||
//
|
||||
if (RsaVerify (Pk, SigBe, CalcucatedHash) == 1 ) {
|
||||
if (RsaVerifySigHashFromKey (Pk, SigBe, sizeof (SigBe), CalcucatedHash, sizeof (CalcucatedHash), OcSigHashTypeSha256) == 1 ) {
|
||||
puts ("Signature verified!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -68,13 +68,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E')
|
||||
#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0')
|
||||
|
||||
typedef struct {
|
||||
uint32_t Data1;
|
||||
uint16_t Data2;
|
||||
uint16_t Data3;
|
||||
uint8_t Data4[8];
|
||||
} EFI_GUID;
|
||||
|
||||
///
|
||||
/// PE images can start with an optional DOS header, so if an image is run
|
||||
/// under DOS it can print an error message.
|
||||
|
||||
0
Utilities/AppleEfiSignTool/IncludeDummy/Base.h
Normal file
0
Utilities/AppleEfiSignTool/IncludeDummy/Base.h
Normal file
0
Utilities/AppleEfiSignTool/IncludeDummy/Uefi.h
Normal file
0
Utilities/AppleEfiSignTool/IncludeDummy/Uefi.h
Normal file
@ -1,6 +1,6 @@
|
||||
CC ?= gcc
|
||||
CFLAGS=-c -Wall -Wextra -pedantic -O3 -DDEBUG -I../../Include -include UefiCompat.h
|
||||
OBJS=AppleEfiBinary.o Sha2.o Rsa2048Sha256.o OcAppleKeysLib.o main.o
|
||||
CFLAGS=-c -Wall -Wextra -pedantic -O3 -I../../Include -IIncludeDummy -include UefiCompat.h
|
||||
OBJS=AppleEfiBinary.o Sha2.o BigNumWordMul64.o BigNumPrimitives.o BigNumMontgomery.o RsaDigitalSign.o OcAppleKeysLib.o main.o
|
||||
|
||||
all: AppleEfiSignTool
|
||||
|
||||
@ -10,8 +10,17 @@ AppleEfiSignTool: $(OBJS)
|
||||
Sha2.o:
|
||||
$(CC) $(CFLAGS) ../../Library/OcCryptoLib/Sha2.c -o $@
|
||||
|
||||
Rsa2048Sha256.o:
|
||||
$(CC) $(CFLAGS) ../../Library/OcCryptoLib/Rsa2048Sha256.c -o $@
|
||||
BigNumWordMul64.o:
|
||||
$(CC) $(CFLAGS) ../../Library/OcCryptoLib/IA32/BigNumWordMul64.c -o $@
|
||||
|
||||
BigNumPrimitives.o:
|
||||
$(CC) $(CFLAGS) ../../Library/OcCryptoLib/BigNumPrimitives.c -o $@
|
||||
|
||||
BigNumMontgomery.o:
|
||||
$(CC) $(CFLAGS) ../../Library/OcCryptoLib/BigNumMontgomery.c -o $@
|
||||
|
||||
RsaDigitalSign.o:
|
||||
$(CC) $(CFLAGS) -include OcCryptoConfig.h ../../Library/OcCryptoLib/RsaDigitalSign.c -o $@
|
||||
|
||||
OcAppleKeysLib.o:
|
||||
$(CC) $(CFLAGS) ../../Library/OcAppleKeysLib/OcAppleKeysLib.c -o $@
|
||||
|
||||
11
Utilities/AppleEfiSignTool/OcCryptoConfig.h
Normal file
11
Utilities/AppleEfiSignTool/OcCryptoConfig.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef OC_CRYPTO_CONFIG_H
|
||||
#define OC_CRYPTO_CONFIG_H
|
||||
|
||||
#include <Library/OcCryptoLib.h>
|
||||
|
||||
#define _PCD_GET_MODE_16_PcdOcCryptoAllowedSigHashTypes \
|
||||
(1U << OcSigHashTypeSha256) | (1U << OcSigHashTypeSha384) | (1U << OcSigHashTypeSha512)
|
||||
|
||||
#define _PCD_GET_MODE_16_PcdOcCryptoAllowedRsaModuli (512U | 256U)
|
||||
|
||||
#endif // OC_CRYPTO_CONFIG_H
|
||||
@ -1,12 +1,18 @@
|
||||
//
|
||||
// FIXME: Fix up TestsUser/Include/Base.h and unify.
|
||||
//
|
||||
#ifndef UEFI_COMPAT_H
|
||||
#define UEFI_COMPAT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef char CHAR8;
|
||||
typedef uint16_t CHAR16;
|
||||
typedef int8_t INT8;
|
||||
typedef int16_t INT16;
|
||||
typedef int32_t INT32;
|
||||
@ -20,14 +26,65 @@ typedef void VOID;
|
||||
typedef intptr_t INTN;
|
||||
typedef size_t UINTN;
|
||||
|
||||
typedef UINTN RETURN_STATUS;
|
||||
typedef RETURN_STATUS EFI_STATUS;
|
||||
|
||||
struct EFI_SYSTEM_TABLE_;
|
||||
typedef struct EFI_SYSTEM_TABLE_ EFI_SYSTEM_TABLE;
|
||||
|
||||
typedef struct {
|
||||
uint32_t Data1;
|
||||
uint16_t Data2;
|
||||
uint16_t Data3;
|
||||
uint8_t Data4[8];
|
||||
} EFI_GUID;
|
||||
|
||||
#define CONST const
|
||||
#define STATIC static
|
||||
#define TRUE true
|
||||
#define FALSE false
|
||||
#define GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
#define PACKED
|
||||
#define IN
|
||||
#define OUT
|
||||
#define OPTIONAL
|
||||
#define EFIAPI
|
||||
|
||||
#define MAX_INT8 INT8_MAX
|
||||
#define MAX_INT16 INT16_MAX
|
||||
#define MAX_INT32 INT32_MAX
|
||||
#define MAX_INT64 INT64_MAX
|
||||
#define MAX_INTN INT64_MAX
|
||||
#define MAX_UINT8 UINT8_MAX
|
||||
#define MAX_UINT16 UINT16_MAX
|
||||
#define MAX_UINT32 UINT32_MAX
|
||||
#define MAX_UINT64 UINT64_MAX
|
||||
#define MAX_UINTN SIZE_MAX
|
||||
|
||||
#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
|
||||
#define PcdGet16(TokenName) _PCD_GET_MODE_16_##TokenName
|
||||
|
||||
#define ASSERT assert
|
||||
#define DEBUG(...)
|
||||
|
||||
#if !defined(_MSC_VER) || defined (__clang__)
|
||||
#define SwapBytes16 __builtin_bswap16
|
||||
#define SwapBytes32 __builtin_bswap32
|
||||
#define SwapBytes64 __builtin_bswap64
|
||||
#else
|
||||
#define SwapBytes16 _byteswap_ushort
|
||||
#define SwapBytes32 _byteswap_ulong
|
||||
#define SwapBytes64 _byteswap_uint64
|
||||
#endif
|
||||
#define RShiftU64(A, B) ((UINT64)(A) >> (UINTN)(B))
|
||||
#define RShiftL64(A, B) ((UINT64)(A) << (UINTN)(B))
|
||||
|
||||
#define ZeroMem(Dst, Size) (memset)((Dst), 0, (Size))
|
||||
#define CopyMem(Dst, Src, Size) (memcpy)((Dst), (Src), (Size))
|
||||
#define CompareMem(One, Two, Size) (memcmp)((One),(Two),(Size))
|
||||
|
||||
#define AllocatePool(Size) (malloc)(Size)
|
||||
#define FreePool(Ptr) (free)(Ptr)
|
||||
|
||||
#endif // UEFI_COMPAT_H
|
||||
|
||||
Binary file not shown.
@ -11,7 +11,12 @@ fi
|
||||
|
||||
cd "$(/usr/bin/dirname "$0")" || abort "Failed to enter working directory!"
|
||||
|
||||
OCPath=../../EFI/OC
|
||||
OCPath="$1"
|
||||
|
||||
if [ "$OCPath" = "" ]; then
|
||||
OCPath=../../EFI/OC
|
||||
fi
|
||||
|
||||
KeyPath="${OCPath}/Keys"
|
||||
OCBin="${OCPath}/OpenCore.efi"
|
||||
RootCA="${KeyPath}/ca.pem"
|
||||
@ -70,7 +75,7 @@ if [ "${off}" -le 16 ]; then
|
||||
abort "${OCBin} is borked"
|
||||
fi
|
||||
|
||||
/bin/dd of="${OCBin}" if="${PubKey}" bs=1 seek="${off}" count=520 conv=notrunc || abort "Failed to bin-patch ${OCBin}"
|
||||
/bin/dd of="${OCBin}" if="${PubKey}" bs=1 seek="${off}" count=528 conv=notrunc || abort "Failed to bin-patch ${OCBin}"
|
||||
|
||||
echo "All done!"
|
||||
exit 0
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
CC ?= gcc
|
||||
CFLAGS=-Wall -Wextra -pedantic -O3 -I/usr/local/opt/openssl/include -I/opt/local/include
|
||||
LDFLAGS=-L/usr/local/opt/openssl/lib -lcrypto
|
||||
LDFLAGS=-L/usr/local/opt/openssl/lib -L/opt/local/lib -lcrypto
|
||||
|
||||
all: RsaTool
|
||||
|
||||
|
||||
@ -73,24 +73,25 @@ static void write_data(void* context, void* data, size_t size) {
|
||||
/* Pre-processes and outputs RSA public key to standard out.
|
||||
*/
|
||||
static void output(RSA* key, t_data_printer printer, void *printer_ctx) {
|
||||
int i, nwords;
|
||||
uint64_t i, nwords;
|
||||
const BIGNUM *key_n;
|
||||
BIGNUM *N = NULL;
|
||||
BIGNUM *Big1 = NULL, *Big2 = NULL, *Big32 = NULL, *BigMinus1 = NULL;
|
||||
BIGNUM *Big1 = NULL, *Big2 = NULL, *Big64 = NULL, *BigMinus1 = NULL;
|
||||
BIGNUM *B = NULL;
|
||||
BIGNUM *N0inv= NULL, *R = NULL, *RR = NULL, *RRTemp = NULL, *NnumBits = NULL;
|
||||
BIGNUM *n = NULL, *rr = NULL;
|
||||
BN_CTX *bn_ctx = BN_CTX_new();
|
||||
uint32_t n0invout;
|
||||
/* Output size of RSA key in 32-bit words */
|
||||
nwords = RSA_size(key) / 4;
|
||||
uint64_t n0invout;
|
||||
/* Output size of RSA key in 64-bit words */
|
||||
nwords = RSA_size(key) / 8;
|
||||
if (nwords > UINT16_MAX) return;
|
||||
printer(printer_ctx, &nwords, sizeof(nwords));
|
||||
/* Initialize BIGNUMs */
|
||||
RSA_get0_key(key, &key_n, NULL, NULL);
|
||||
N = BN_dup(key_n);
|
||||
Big1 = BN_new();
|
||||
Big2 = BN_new();
|
||||
Big32 = BN_new();
|
||||
Big64 = BN_new();
|
||||
BigMinus1 = BN_new();
|
||||
N0inv= BN_new();
|
||||
R = BN_new();
|
||||
@ -101,14 +102,16 @@ static void output(RSA* key, t_data_printer printer, void *printer_ctx) {
|
||||
rr = BN_new();
|
||||
BN_set_word(Big1, 1L);
|
||||
BN_set_word(Big2, 2L);
|
||||
BN_set_word(Big32, 32L);
|
||||
BN_set_word(Big64, 64L);
|
||||
BN_sub(BigMinus1, Big1, Big2);
|
||||
B = BN_new();
|
||||
BN_exp(B, Big2, Big32, bn_ctx); /* B = 2^32 */
|
||||
/* Calculate and output N0inv = -1 / N[0] mod 2^32 */
|
||||
BN_exp(B, Big2, Big64, bn_ctx); /* B = 2^64 */
|
||||
/* Calculate and output N0inv = -1 / N[0] mod 2^64 */
|
||||
BN_mod_inverse(N0inv, N, B, bn_ctx);
|
||||
BN_sub(N0inv, B, N0inv);
|
||||
n0invout = BN_get_word(N0inv);
|
||||
n0invout = (uint64_t) BN_get_word(N0inv);
|
||||
BN_rshift(N0inv, N0inv, 32);
|
||||
n0invout |= (uint64_t) BN_get_word(N0inv) << 32ULL;
|
||||
printer(printer_ctx, &n0invout, sizeof(n0invout));
|
||||
/* Calculate R = 2^(# of key bits) */
|
||||
BN_set_word(NnumBits, BN_num_bits(N));
|
||||
@ -118,20 +121,20 @@ static void output(RSA* key, t_data_printer printer, void *printer_ctx) {
|
||||
BN_mul(RRTemp, RR, R, bn_ctx);
|
||||
BN_mod(RR, RRTemp, N, bn_ctx);
|
||||
/* Write out modulus as little endian array of integers. */
|
||||
for (i = 0; i < nwords; ++i) {
|
||||
for (i = 0; i < nwords*2; ++i) {
|
||||
uint32_t nout;
|
||||
BN_mod(n, N, B, bn_ctx); /* n = N mod B */
|
||||
nout = BN_get_word(n);
|
||||
printer(printer_ctx, &nout, sizeof(nout));
|
||||
BN_rshift(N, N, 32); /* N = N/B */
|
||||
printer(printer_ctx, &nout, sizeof(nout));
|
||||
}
|
||||
/* Write R^2 as little endian array of integers. */
|
||||
for (i = 0; i < nwords; ++i) {
|
||||
for (i = 0; i < nwords*2; ++i) {
|
||||
uint32_t rrout;
|
||||
BN_mod(rr, RR, B, bn_ctx); /* rr = RR mod B */
|
||||
rrout = BN_get_word(rr);
|
||||
printer(printer_ctx, &rrout, sizeof(rrout));
|
||||
BN_rshift(RR, RR, 32); /* RR = RR/B */
|
||||
printer(printer_ctx, &rrout, sizeof(rrout));
|
||||
}
|
||||
/* print terminator */
|
||||
printer(printer_ctx, NULL, 0);
|
||||
@ -139,7 +142,7 @@ static void output(RSA* key, t_data_printer printer, void *printer_ctx) {
|
||||
BN_free(N);
|
||||
BN_free(Big1);
|
||||
BN_free(Big2);
|
||||
BN_free(Big32);
|
||||
BN_free(Big64);
|
||||
BN_free(BigMinus1);
|
||||
BN_free(N0inv);
|
||||
BN_free(R);
|
||||
|
||||
@ -21,6 +21,12 @@
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#if !defined(HAVE_RSA_GET0_KEY) && defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x1000100fL
|
||||
#define HAVE_RSA_GET0_KEY
|
||||
#define HAVE_RSA_SET0_KEY
|
||||
#define EVP_MD_CTX_cleanup EVP_MD_CTX_free
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_RSA_GET0_KEY
|
||||
/**
|
||||
* Get the RSA parameters
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user