/** @file | |
RFC3161 Timestamp Countersignature Verification Wrapper Implementation which does | |
not provide real capabilities. | |
Copyright (c) 2024, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "InternalCryptLib.h" | |
#include <mbedtls/asn1.h> | |
// | |
// OID ASN.1 Value for SPC_RFC3161_OBJID ("1.3.6.1.4.1.311.3.3.1") | |
// | |
GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 mSpcRFC3161OidValue[] = { | |
0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x03, 0x03, 0x01 | |
}; | |
/** | |
Convert ASN.1 GeneralizedTime to EFI Time. | |
@param[in] Ptr Pointer to the ASN.1 GeneralizedTime to be converted. | |
@param[out] EfiTime Return the corresponding EFI Time. | |
@retval TRUE The time conversion succeeds. | |
@retval FALSE Invalid parameters. | |
**/ | |
STATIC | |
BOOLEAN | |
ConvertAsn1TimeToEfiTime ( | |
IN UINT8 *Ptr, | |
OUT EFI_TIME *EfiTime | |
) | |
{ | |
CONST CHAR8 *Str; | |
UINTN Index; | |
if ((Ptr == NULL) || (EfiTime == NULL)) { | |
return FALSE; | |
} | |
Str = (CONST CHAR8 *)Ptr; | |
SetMem (EfiTime, sizeof (EFI_TIME), 0); | |
Index = 0; | |
/* four digit year */ | |
EfiTime->Year = (Str[Index++] - '0') * 1000; | |
EfiTime->Year += (Str[Index++] - '0') * 100; | |
EfiTime->Year += (Str[Index++] - '0') * 10; | |
EfiTime->Year += (Str[Index++] - '0'); | |
if ((EfiTime->Year < 1900) || (EfiTime->Year > 9999)) { | |
return FALSE; | |
} | |
EfiTime->Month = (Str[Index++] - '0') * 10; | |
EfiTime->Month += (Str[Index++] - '0'); | |
if ((EfiTime->Month < 1) || (EfiTime->Month > 12)) { | |
return FALSE; | |
} | |
EfiTime->Day = (Str[Index++] - '0') * 10; | |
EfiTime->Day += (Str[Index++] - '0'); | |
if ((EfiTime->Day < 1) || (EfiTime->Day > 31)) { | |
return FALSE; | |
} | |
EfiTime->Hour = (Str[Index++] - '0') * 10; | |
EfiTime->Hour += (Str[Index++] - '0'); | |
if (EfiTime->Hour > 23) { | |
return FALSE; | |
} | |
EfiTime->Minute = (Str[Index++] - '0') * 10; | |
EfiTime->Minute += (Str[Index++] - '0'); | |
if (EfiTime->Minute > 59) { | |
return FALSE; | |
} | |
EfiTime->Second = (Str[Index++] - '0') * 10; | |
EfiTime->Second += (Str[Index++] - '0'); | |
if (EfiTime->Second > 59) { | |
return FALSE; | |
} | |
/* Note: we did not adjust the time based on time zone information */ | |
return TRUE; | |
} | |
/** | |
Verifies the validity of a RFC3161 Timestamp CounterSignature embedded in PE/COFF Authenticode | |
signature. | |
Return FALSE to indicate this interface is not supported. | |
@param[in] AuthData Pointer to the Authenticode Signature retrieved from signed | |
PE/COFF image to be verified. | |
@param[in] DataSize Size of the Authenticode Signature in bytes. | |
@param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER, which | |
is used for TSA certificate chain verification. | |
@param[in] CertSize Size of the trusted certificate in bytes. | |
@param[out] SigningTime Return the time of timestamp generation time if the timestamp | |
signature is valid. | |
@retval FALSE This interface is not supported. | |
**/ | |
BOOLEAN | |
EFIAPI | |
ImageTimestampVerify ( | |
IN CONST UINT8 *AuthData, | |
IN UINTN DataSize, | |
IN CONST UINT8 *TsaCert, | |
IN UINTN CertSize, | |
OUT EFI_TIME *SigningTime | |
) | |
{ | |
BOOLEAN Status; | |
UINT8 *Ptr; | |
UINT8 *End; | |
INT32 Len; | |
UINTN ObjLen; | |
UINT8 *TempPtr; | |
// | |
// Initializations | |
// | |
if (SigningTime != NULL) { | |
SetMem (SigningTime, sizeof (EFI_TIME), 0); | |
} | |
// | |
// Input Parameters Checking. | |
// | |
if ((AuthData == NULL) || (TsaCert == NULL)) { | |
return FALSE; | |
} | |
if ((DataSize > INT_MAX) || (CertSize > INT_MAX)) { | |
return FALSE; | |
} | |
Ptr = (UINT8 *)(UINTN)AuthData; | |
Len = (UINT32)DataSize; | |
End = Ptr + Len; | |
// ContentInfo | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
// ContentType | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// content | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) { | |
return FALSE; | |
} | |
End = Ptr + ObjLen; | |
// signedData | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
// version | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// digestAlgo | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// encapContentInfo | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// cert | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
TempPtr = Ptr; | |
// OPTIONAL CRLs | |
if (mbedtls_asn1_get_tag (&TempPtr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) == 0) { | |
Ptr = TempPtr + ObjLen; | |
} | |
// signerInfo | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) { | |
return FALSE; | |
} | |
// sub parse | |
// signerInfo | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
End = Ptr + ObjLen; | |
// version | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// sid | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// digestalgo | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// OPTIONAL AuthenticatedAttributes | |
TempPtr = Ptr; | |
if (mbedtls_asn1_get_tag (&TempPtr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) == 0) { | |
Ptr = TempPtr + ObjLen; | |
} | |
// signaturealgo | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// signature | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OCTET_STRING) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// OPTIONAL UnauthenticatedAttributes | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, 0xA1) != 0) { | |
return FALSE; | |
} | |
// Attribute | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
// type | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) { | |
return FALSE; | |
} | |
if (CompareMem (Ptr, mSpcRFC3161OidValue, sizeof (mSpcRFC3161OidValue)) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// values | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) { | |
return FALSE; | |
} | |
// values | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
// signedData OID | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// [0] | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) { | |
return FALSE; | |
} | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
// integer | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// SET | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
// tST OID | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) { | |
return FALSE; | |
} | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OCTET_STRING) != 0) { | |
return FALSE; | |
} | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
// Integer | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// policy OID | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// sequence | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// Integer | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) { | |
return FALSE; | |
} | |
Ptr += ObjLen; | |
// GeneralizedTime | |
if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_GENERALIZED_TIME) != 0) { | |
return FALSE; | |
} | |
// | |
// Retrieve the signing time from TS_TST_INFO structure. | |
// | |
if (SigningTime != NULL) { | |
SetMem (SigningTime, sizeof (EFI_TIME), 0); | |
Status = ConvertAsn1TimeToEfiTime (Ptr, SigningTime); | |
} | |
return Status; | |
} |