未验证 提交 410d10d3 编写于 作者: D Download-Fritz 提交者: GitHub

OcCryptoLib: Import new RSA stack

Import a new RSA stack and test utilities to support IMG4 image verification.
上级 70fe07f8
......@@ -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
);
/**
......
/** @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);
......
/** @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 <Base.h>
#include <Library/OcAppleKeysLib.h>
#include <Library/OcMiscLib.h>
CONST APPLE_PK_ENTRY PkDataBase[NUM_OF_PK] = {
#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
);
}
......
/**
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
/**
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
/**
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;
}
此差异已折叠。
/** @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
......
/** @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;
}
/** @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
);
}
/** @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;
......
#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
#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.
......
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 $@
......
#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
//
// 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
......@@ -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
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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册