I want to walk the certificate chain of a authenticode signed PE binary using the Windows API.
To get the certificate store I followed the example from Microsoft:
https://support.microsoft.com/en-us/help/323809/how-to-get-information-from-authenticode-signed-executables
With that I get the leaf certificate and the intermediate certificate, but not the root certificate. Tested with different Windows binaries (eg. explorer.exe)
I tried the following loops to walk the store:
while (pCertContext = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_ANY, NULL, pCertContext));
while (pCertContext = CertEnumCertificatesInStore(hStore, pCertContext));
Is the root certificate not included in the authenticode signature?
Do I miss some option?
Thanks #RbMm for your suggestion with CertGetCertificateChain, that does solve my question.
To get the whole chain, you need to start at the leaf certificate (store seams to start top-down).
Adapted from https://learn.microsoft.com/de-de/windows/desktop/SecCrypto/example-c-program-creating-a-certificate-chain:
CERT_INFO CertInfo;
CertInfo.Issuer = pSignerInfo->Issuer;
CertInfo.SerialNumber = pSignerInfo->SerialNumber;
pCertContext = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&CertInfo, NULL);
if (!pCertContext) {
_tprintf(_T("CertFindCertificateInStore failed with %x\n"), GetLastError());
__leave;
}
CERT_ENHKEY_USAGE EnhkeyUsage;
CERT_USAGE_MATCH CertUsage;
CERT_CHAIN_PARA ChainPara;
EnhkeyUsage.cUsageIdentifier = 0;
EnhkeyUsage.rgpszUsageIdentifier = NULL;
CertUsage.dwType = USAGE_MATCH_TYPE_AND;
CertUsage.Usage = EnhkeyUsage;
ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
ChainPara.RequestedUsage = CertUsage;
if (!CertGetCertificateChain(
NULL, // use the default chain engine
pCertContext, // pointer to the end certificate
NULL, // use the default time
NULL, // search no additional stores
&ChainPara, // use AND logic and enhanced key usage
// as indicated in the ChainPara
// data structure
dwFlags,
NULL, // currently reserved
&pChainContext)) {
cerr << "Error on CertGetCertificateChain" << endl;
__leave;
}
PCERT_SIMPLE_CHAIN rgpChain = NULL;
PCERT_CHAIN_ELEMENT rgpElement = NULL;
rgpChain = pChainContext->rgpChain[0];
for (int j = 0; j < rgpChain->cElement; j++) {
rgpElement = rgpChain->rgpElement[j];
PrintCertificateInfo(rgpElement->pCertContext);
cout << endl;
}
Related
i'm fairly new to OpenSSL and my current task at work is updating the code of a project from OpenSSL 1.1.1 to OpenSSL 3.0 and I'm stuck on a really weird problem.
I'm trying to create an RSA key from given raw data, precisely binary modulus and exponent that are converted to BIGNUM. I've tried to make it as it is described in the manual and the key creation works, but the problem is whatever I try to do with that key (or CTX based on it) fails, whether it's signature decryption or verification.
Here's the code where I create the key:
/* function set up above */
ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
if ( ctx == NULL) {
ERROR("Error: failed to initialize CTX from name.\n");
goto OPENSSL_ERROR;
}
modulus = BN_bin2bn(pubkey->data, pubkey->size, NULL);
exponent = BN_bin2bn(exp_arr, 3, NULL);
if ( modulus == NULL || exponent == NULL ) {
goto OPENSSL_ERROR;
}
OSSL_PARAM params[] = {
OSSL_PARAM_BN("n", &modulus, BN_num_bytes(modulus)*8),
OSSL_PARAM_BN("e", &exponent, BN_num_bytes(exponent)*8),
OSSL_PARAM_BN("d", NULL, 0),
OSSL_PARAM_END
};
status = EVP_PKEY_fromdata_init(ctx);
if ( status <= 0 ) {
ERROR("Error: failed to initialize key creation.\n");
goto OPENSSL_ERROR;
}
status = EVP_PKEY_fromdata(ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params);
if ( status <= 0 || evp_key == NULL ) {
ERROR("Error: failed to create key.\n");
goto OPENSSL_ERROR;
}
/* goes on to decrypt signature and later verify it against data - both fail */
It goes through swiftly, but trying to do whatever with that key or CTX based on that key fails miserably.
I tried creating CTX with EVP_PKEY_CTX_new_id(), but it changed nothing.
I tried omitting the parameter "d", but it changed nothing.
If anyone knows what I'm doing wrong and what should be changed - all help will be greatly appreciated.
P.S.
pubkey is passed to the function as argument, data is a binary array, size is obviously it's size (size_t)
the params given to the key are the same as in the previous version of the code which used the RSA_set0_key() function
unsigned char exp_arr[] = {0x01, 0x00, 0x01};
It is not obvious in the manual (nothing new with OpenSSL).
The problem is that the OSSL_PARAM params array cannot be initialized the way it is in the code above. It needs to be built using OSSL_PARAM_BLD, like this:
OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new();
if ( params_build == NULL ) {
goto OPENSSL_ERROR;
}
if ( !OSSL_PARAM_BLD_push_BN(params_build, "n", modulus) ) {
ERROR("Error: failed to push modulus into param build.\n");
goto OPENSSL_ERROR;
}
if ( !OSSL_PARAM_BLD_push_BN(params_build, "e", exponent) ) {
ERROR("Error: failed to push exponent into param build.\n");
goto OPENSSL_ERROR;
}
if ( !OSSL_PARAM_BLD_push_BN(params_build, "d", NULL) ) {
ERROR("Error: failed to push NULL into param build.\n");
goto OPENSSL_ERROR;
}
OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(params_build);
if ( params == NULL ) {
ERROR("Error: failed to construct params from build.\n");
goto OPENSSL_ERROR;
}
It'll probably work the same with all other types of keys created with EVP_PKEY_fromdata() function.
[IMPORTANT!]
Remember to check what are settable parameters for the key you're trying to create, otherwise you might get stuck on that part for a long time not knowing what's wrong with your code ;)
The GetExplicitEntriesFromAcl Win32 API function allows to retrieve the explicit entries of a file ACL. But when I change some entries, convert the result into a new ACL using SetEntriesInAcl and finally apply the ACL back to the file with SetSecurityInfo all inherited entries seem to be lost and only the (changed) explicit entries are left.
Is there a counterpart function "SetExplicitEntriesInAcl" that only replaces the explicit entries within an ACL structure and keeps the inherited entries intact?
Edit1: Code Sample
I'm using code similar to the following lines for ACL update:
int RemoveAclAccessRights( HANDLE hFile, PSID SidPtr,
DWORD AccessRights, ACCESS_MODE AccessMode )
{
PACL OldAcl = NULL, NewAcl = NULL;
PSECURITY_DESCRIPTOR SecDesc = NULL;
PEXPLICIT_ACCESS EntryList = NULL, EntryItem;
ULONG EntryCount, EntryIndex;
int r;
// Get a pointer to the existing DACL
r = GetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, &OldAcl, NULL, &SecDesc);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
r = GetExplicitEntriesFromAcl(OldAcl, &EntryCount, &EntryItem);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
EntryList = EntryItem;
EntryIndex = 0;
while ( EntryIndex < EntryCount ) {
// ... update access entry ...
EntryIndex++;
EntryItem++;
}
// Create a new ACL from the explicit entries of the existing DACL
r = SetEntriesInAcl(EntryCount, EntryList, NULL, &NewAcl);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
// Attach the new ACL as the object's DACL
r = SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, NewAcl, NULL);
_CleanUp:
LocalFree(NewAcl);
LocalFree(EntryList);
LocalFree(SecDesc);
return r;
}
Edit2: ACLs of the file and parent directory
Output of icacls on the file:
> icacls TestAcl01.txt
TestAcl01.txt VORDEFINIERT\Gäste:(R)
VORDEFINIERT\Administratoren:(I)(F)
NT-AUTORITÄT\SYSTEM:(I)(F)
NT-AUTORITÄT\Authentifizierte Benutzer:(I)(M)
VORDEFINIERT\Benutzer:(I)(RX)
Output of icacls on the parent directory:
> icacls .
. VORDEFINIERT\Administratoren:(I)(F)
VORDEFINIERT\Administratoren:(I)(OI)(CI)(IO)(F)
NT-AUTORITÄT\SYSTEM:(I)(F)
NT-AUTORITÄT\SYSTEM:(I)(OI)(CI)(IO)(F)
NT-AUTORITÄT\Authentifizierte Benutzer:(I)(M)
NT-AUTORITÄT\Authentifizierte Benutzer:(I)(OI)(CI)(IO)(M)
VORDEFINIERT\Benutzer:(I)(RX)
VORDEFINIERT\Benutzer:(I)(OI)(CI)(IO)(GR,GE)
The file has one explicit entry which is "VORDEFINIERT\Gäste:(R)" (SID "S-1-5-32-546"). The other entries are inherited from the parent directory.
In the while loop above I am trying to delete the explicit entry if it matches the SID using code like
if ( (EntryItem->Trustee.TrusteeForm == TRUSTEE_IS_SID) && EqualSid(EntryItem->Trustee.ptstrName, SidPtr) ) {
if ( EntryIndex < (EntryCount-1) )
MoveMemory(&EntryList[EntryIndex], &EntryList[EntryIndex+1], (EntryCount-EntryIndex-1)*sizeof(EntryList[0]));
EntryCount--;
continue;
}
Given the information in the latest edit, I can now replicate your problem. It only occurs in the case when you are removing all of the explicit entries from the DACL.
It turns out there's a nasty (and undocumented, so far as I can see) catch in SetEntriesInAcl: if you pass it a zero-length array, it silently returns NULL as the new ACL rather than returning an empty ACL as you might reasonably expect.
The documentation for SetSecurityInfo explains what happens in this case:
If the value of the SecurityInfo parameter includes the DACL_SECURITY_INFORMATION flag and the value of this parameter is set to NULL, full access to the object is granted to everyone.
That implicitly removes the inherited permissions (which are redundant anyway).
One way to fix the problem:
ACL empty_acl;
if (!InitializeAcl(&empty_acl, sizeof(empty_acl), ACL_REVISION))
goto _CleanUp;
// Create a new ACL from the explicit entries of the existing DACL
r = SetEntriesInAcl(EntryCount, EntryList, &empty_acl, &NewAcl);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
The following code seems to work but uses GetAclInformation and GetAce instead of GetExplicitEntriesFromAcl which requires pointer type checking and is thus somehow less convenient:
int UpdateAclAccessRights( HANDLE hFile, PSID SidPtr,
DWORD AccessRights, ACCESS_MODE AccessMode )
{
PACL DiscAcl = NULL;
PSECURITY_DESCRIPTOR SecDesc = NULL;
ACL_SIZE_INFORMATION AclSizeInfo;
PACCESS_ALLOWED_ACE AceItem;
int AceIndex;
int r;
// Get a pointer to the existing DACL
r = GetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, &DiscAcl, NULL, &SecDesc);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
ZeroMemory(&AclSizeInfo, sizeof(AclSizeInfo));
if (!GetAclInformation(DiscAcl, &AclSizeInfo, sizeof(AclSizeInfo), AclSizeInformation))
goto _CleanUp;
for (AceIndex = AclSizeInfo.AceCount-1; AceIndex >= 0; AceIndex--) {
if (!GetAce(DiscAcl, AceIndex, &((void*)AceItem)))
continue;
if ( (AceItem->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) &&
(AceItem->Header.AceType != ACCESS_DENIED_ACE_TYPE) )
continue; // entry pointer structure does not match AceItem
if ( (AceItem->Header.AceFlags && INHERITED_ACE) > 0 )
continue; // not an explicit entry
// ... update/delete access entry in case it matches SidPtr ...
}
// Attach updated ACL to the file object
r = SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, DiscAcl, NULL);
_CleanUp:
LocalFree(SecDesc);
return r;
}
I was working on writing a screenshot thing, and found this excellent topic for Mac: How can I get screenshot from all displays on MAC?
I was wondering if anyone has the equivalent for x11 library? To get all the monitors and then screenshot them all?
I had found this topic: https://stackoverflow.com/a/5293559/1828637
But the code linked from there is not as easy to follow for a novice like me.
Will RootWindow(3) get the area of all the monitors combined? Then I can go through and get the monitors dimensions then XGetImage those sections on the return of RootWindow?
I had come across this topic: How do take a screenshot correctly with xlib? But I'm not sure if it has multi-monitor support. I do this in ctypes so I cant test that code easily without going through the grueling task of writing it first. So I was wondering if this is correct or how would I modify it to handle multi mon please?
Edit
The poster there shared his code, it is seen here: https://github.com/Lalaland/ScreenCap/blob/master/src/screenCapturerImpl.cpp#L96 but it's complicated and I don't understand it. It uses functions like XFixesGetCursorImage which I can't find in the documentation, and I don't see how the multi monitors work there. Author of that topic warned he doesn't remember the code and it may not work with modern Linux.
This is not a perfect answer to the question, but the following code could be modified to get a very fast version of your desired end result:
https://github.com/Clodo76/vr-desktop-mirror/blob/master/DesktopCapture/main.cpp
The DesktopCapturePlugin_Initialize method converts all the displays into objects:
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API DesktopCapturePlugin_Initialize()
{
DesksClean();
g_needReinit = 0;
IDXGIFactory1* factory;
CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));
IDXGIAdapter1* adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{
IDXGIOutput* output;
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); j++)
{
DXGI_OUTPUT_DESC outputDesc;
output->GetDesc(&outputDesc);
MONITORINFOEX monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(outputDesc.Monitor, &monitorInfo);
// Maybe in future add a function to identify the primary monitor.
//if (monitorInfo.dwFlags == MONITORINFOF_PRIMARY)
{
int iDesk = DeskAdd();
g_desks[iDesk].g_width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
g_desks[iDesk].g_height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
IDXGIOutput1* output1;
output1 = reinterpret_cast<IDXGIOutput1*>(output);
output1->DuplicateOutput(device, &g_desks[iDesk].g_deskDupl);
}
output->Release();
}
adapter->Release();
}
factory->Release();
}
Then the OnRenderEvent method copies a frame from the display into a texture (provided by unity in this case):
void UNITY_INTERFACE_API OnRenderEvent(int eventId)
{
for (int iDesk = 0; iDesk < g_nDesks; iDesk++)
{
if (g_desks[iDesk].g_deskDupl == nullptr || g_desks[iDesk].g_texture == nullptr)
{
g_needReinit++;
return;
}
IDXGIResource* resource = nullptr;
const UINT timeout = 0; // ms
HRESULT resultAcquire = g_desks[iDesk].g_deskDupl->AcquireNextFrame(timeout, &g_desks[iDesk].g_frameInfo, &resource);
if (resultAcquire != S_OK)
{
g_needReinit++;
return;
}
g_desks[iDesk].g_isPointerVisible = (g_desks[iDesk].g_frameInfo.PointerPosition.Visible == TRUE);
g_desks[iDesk].g_pointerX = g_desks[iDesk].g_frameInfo.PointerPosition.Position.x;
g_desks[iDesk].g_pointerY = g_desks[iDesk].g_frameInfo.PointerPosition.Position.y;
ID3D11Texture2D* texture;
HRESULT resultQuery = resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
resource->Release();
if (resultQuery != S_OK)
{
g_needReinit++;
return;
}
ID3D11DeviceContext* context;
auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
device->GetImmediateContext(&context);
context->CopyResource(g_desks[iDesk].g_texture, texture);
g_desks[iDesk].g_deskDupl->ReleaseFrame();
}
g_needReinit = 0;
}
I am learning to use the Media Foundation API from sample code shown in Microsoft website using C instead of C++. The sample code is shown below.
HRESULT CreateVideoCaptureDevice(IMFMediaSource **ppSource)
{
*ppSource = NULL;
UINT32 count = 0;
IMFAttributes *pConfig = NULL;
IMFActivate **ppDevices = NULL;
// Create an attribute store to hold the search criteria.
HRESULT hr = MFCreateAttributes(&pConfig, 1);
// Request video capture devices.
if (SUCCEEDED(hr))
{
hr = pConfig->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
);
}
// Enumerate the devices,
if (SUCCEEDED(hr))
{
hr = MFEnumDeviceSources(pConfig, &ppDevices, &count);
}
// Create a media source for the first device in the list.
if (SUCCEEDED(hr))
{
if (count > 0)
{
hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(ppSource));
}
else
{
hr = MF_E_NOT_FOUND;
}
}
for (DWORD i = 0; i < count; i++)
{
ppDevices[i]->Release();
}
CoTaskMemFree(ppDevices);
return hr;
}
When I tried to build the sample code, I always get the following error:
error C2039: 'ActivateObject': is not a member of 'IMFActivate'
error C2039: 'Release': is not a member of 'IMFActivate'
error C2039: 'SetGUID': is not a member of 'IMFAttributes'
I explored the definition of IMFActivate and IMFAttributes (in mfidl.h) and I notice it have a C style interface.
May I know if anyone can show an example of how to use the interface ?
You should be using COM interfaces defined "C style", using virtual method table pointer:
IMFActivate* pMfActivate = ...
IMFMediaSource* pMfMediaSource;
pMfActivate->lpVtbl->ActivateObject(
pMfActivate, &IID_IMFMediaSource, (IUnknown**) &pMfMediaSource);
where C++ style is
IMFActivate* pMfActivate = ...
IMFMediaSource* pMfMediaSource;
pMfActivate->ActivateObject(
__uuidof(IMFMediaSource), (IUnknown**) &pMfMediaSource);
I have written some C code to connect to a Kerberized LDAP server. This all works fine, but at present, it currently generates a new TGT every time it connects, rather than using the one (assuming it already exists) in the default credentials cache.
I have looked into using the likes of krb5_cc_resolve and krb5_initialize to get a reference to the cache, but this seems to destroy the cache if it already exists, along with any tickets it holds.
Basically, what I want to know is: is there any way of checking the default credentials cache for existing TGTs without destroying it?
krb5_cc_initialize clears the cache, as the documentation says. Just don't do that if you want to access an existing cache
From the docs:
Any existing credentials are discarded and the principal name for the cache is set to the value specified
Look in the code for kstart where it implements the -H option.
http://git.eyrie.org/?p=kerberos/kstart.git;a=blob;f=framework.c;h=66e851413a9b4d71fa4d61ded2f3c0d71cd03b0c;hb=HEAD
Basically, you need to check the expire time for the principal in the ticket.
/* Obtain the ticket. */
memset(&increds, 0, sizeof(increds));
code = krb5_cc_resolve(ctx, config->cache, &ccache);
if (code != 0)
goto done;
increds.client = config->client;
else {
code = krb5_cc_get_principal(ctx, ccache, &increds.client);
if (code != 0)
goto done;
}
code = get_krbtgt_princ(ctx, increds.client, &increds.server);
if (code != 0)
goto done;
code = krb5_get_credentials(ctx, 0, ccache, &increds, &outcreds);
if (code != 0)
goto done;
increds_valid = true;
/* Check the expiration time and renewal limit. */
if (code == 0) {
now = time(NULL);
then = outcreds->times.endtime;
if (config->happy_ticket > 0)
offset = 60 * config->happy_ticket;
else
offset = 60 * config->keep_ticket + EXPIRE_FUDGE;
if (then < now + offset)
code = KRB5KRB_AP_ERR_TKT_EXPIRED;