librpm - How to verify the signature key of an installed package - c

I would like to programmatically check if a RPM package is (1) signed (has a signature) and (2) the key used to sign is trusted.
[root]$ rpm -qi setup
Name : setup
Signature : RSA/SHA1, Wed 02 Oct 2013 05:15:22 AM MDT, Key ID 0946
[root]$ rpm -qi testing
Name : testing
Signature : (none)
I'm browsing the librpm API but I don't see any public methods allowing signature verification on already installed packages.
# This requires a file descriptor
rpmcli.h:rpmVerifySignatures
# This also requires a file descriptor
rpmlib.h:rpmReadPackageFile
Digging further I see:
# This uses a callback `qva_showPackage` which gives (QVA_t, rpmts, Header)
rpmcli.h:rpmcliVerify
But I cannot seem to get RPM tags (RPMTAG_SHA1HEADER) from the Header passed in by the callback. If I could get these tags then it would make sense to call into rpmpgp.h:pgpVerifySig to verify the signature.
Edit:
I see the bulk of the signature verification work is done in a static method rpmchecksig.c:rpmpkgVerifySigs which is only available through rpmcli.h:rpmVerifySignatures. But this method requires a file descriptor. Is there a way to get a FD from an already installed package to be able to use this method?

RPM will verify header-only signatures when retrieving from an rpmdb if enabled through various mode-specific %_vsflags* settings. See /usr/lib/rpm/macros for values.
You will see the verification if you do, say, "rpm -Vvv bash". You can also enable the header-only signature verification on --query (or other) rpm modes by changing specific macros.
There is a means (but not a specific call) to retrieve the header plaintext, the header-only signature, and the pubkey if you wish to verify external to rpm.

Related

LoadLibraryExW Fails to Load User32.dll

When trying to load C:\Windows\System32\user32.dll via LoadLibraryExW, it fails with the last error of ERROR_INVALID_IMAGE_HASH.
Here is how it is loaded:
HMODULE User32Lib = LoadLibraryExW(L"C:\\Windows\\System32\\user32.dll", NULL, LOAD_LIBRARY_REQUIRE_SIGNED_TARGET);
I looked at the DLL itself, and it was signed (for the version on my machine) on 8 April 2020 so it should still be valid.
Am I doing something incorrectly?
Apparently LOAD_LIBRARY_REQUIRE_SIGNED_TARGET requires the PE image to be linked with IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY (0x0080) in its DLL characteristics. This is a flag that forces the memory manager in the kernel to check for a digital signature when loading the image. Refer to the linker option /INTEGRITYCHECK.
Most of the system DLLs do not have this characteristic. "user32.dll" doesn't have it, but "bcrypt.dll" does:
PS C:\> $user32_hdr = get-peheader C:\Windows\System32\user32.dll
PS C:\> $bcrypt_hdr = get-peheader C:\Windows\System32\bcrypt.dll
PS C:\> '{0:x}' -f $user32_hdr.DllCharacteristics
4160
PS C:\> '{0:x}' -f $bcrypt_hdr.DllCharacteristics
41E0
I don't know much in particular about the subject of code signing and the implementation details in the loader and memory manager. I just used a debugger to discover that the load was failing with STATUS_INVALID_IMAGE_HASH in LdrpCompleteMapModule, after it checked for 0x80 in the DLL characteristics. From there I searched for discussions on this value and the /integritycheck option in relation to LOAD_LIBRARY_REQUIRE_SIGNED_TARGET. I found a few unofficial references that claimed the latter requires the former. So I wrote a script to dump the DLL characteristics of system DLLs in order to find one that has the IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY flag. Having found "bcrypt.dll" and checked that it wasn't already loaded, I confirmed that loading it with LOAD_LIBRARY_REQUIRE_SIGNED_TARGET does work.

what does gitolite setup fix?

gitolite info didn't work, adding keys turned them into a no access key and did NOT create a corresponding entry in auth-keys file.
To fix this run gitolite setup on gitolite server
Question: what could have landed me in that mess?
And what does gitolite setup do when invoked for the n-th time (it's no longer setting things up, according to the docs it fixes hooks, but I wonder what the use case would be and which was mine)?
More details on gitolite info
gitolite info command is invoked like so:
> ssh git-user#ser-git
PTY allocation request failed on channel 0
hello git-admin, this is ...#... running gitolite3 3.6.7-2 (Debian) on git 2.17.1
R W some-repository
R W gitolite-admin
R W testing
Connection to ser-git closed.
Bad output is: FATAL: unknown git/gitolite command: 'info'
More details: keys without access.
gitolite sshkeys-lint was showing keys with (no access), now those keys have access as I set them (now meaning after gitolite setup).
ssh-keygen -lf /home/repo/.ssh/authorized_keys | wc -l (or without piped part, regardless) number of keys and their names indicated I didn't have the newest one added.
Similar question that did not work for me: keydir entries not propagating to authorized_keys
Docs pretty much had the answer once I dug deeper, I guess. Which is fairly nice of #sitaramc.
Without options, 'gitolite setup' is a general "fix up everything" command
(for example, if you brought in repos from outside, or someone messed
around with the hooks, or you made an rc file change that affects access
rules, etc.)
Symptoms keys stopped propagating and error FATAL: unknown git/gitolite command: 'info' on ssh git-user#ser-git. Fix was to run gitolite setup. So onto first question, the title one:
what does gitolite setup fix?
gitolite setup is implemented here
my Perl is rather weak, but there's a setup function in line 56. It calls args (which parses options, so here it had nothing to parse), then unless h_only (hooks only arg for setup), which wasn't used, so we skip compile and POST_COMPILE trigger and go for the hooks.
sub setup {
my ( $admin, $pubkey, $h_only, $message ) = args();
unless ($h_only) {
setup_glrc();
setup_gladmin( $admin, $pubkey, $message );
_system("gitolite compile");
_system("gitolite trigger POST_COMPILE");
}
hook_repos(); # all of them, just to be sure
}
package Gitolite::conf::store has hook_repos(), line 228: we change the dir to repo base dir (as per config file), and for each phy_repo we do hook_1(phy_repo). What is a phy_repo? a physical one.
same package, different method and line: hook_1($repo) in line 354.
Method hook_1($repo)
It's quite literally about fixing all the hooks.
Recreates dirs for common and admin hooks.
Rewrites update_hook (common) and post_update_hook (admin).
Sets 755 permissions for both common and admin hooks.
Then using ln_sf it symlinks the folders for common/admin hooks.
ln_sf is in common module, in line 162

What is the difference between kobject, device_create and my code?

I am currently reading a book entitled "Linux device drivers" from O'Reilly.
Thing is that this book imo isn't really a guide on how to write drivers but it instead explains all the apis and their prinicples.
So I tried writing a small driver -which doesn't do anything interesting -with what I read so far.
Thing is:
I don't know which file I can execute cat on or echo to in order to invoke my callback functions
it looks nothing like all the other code snippets I found online
The different pieces of code:
my code (https://paste.ubuntu.com/p/8tVyTJTPBQ/)
creates:
$ls /sys/module/main/
oresize holders initsize initstate notes refcnt sections srcversion taint uevent
no new entry in /dev
code snippet using device_create: https://paste.ubuntu.com/p/cJxjdyXjhX/ source
creates:
$ ls /sys/module/main/
coresize holders initsize initstate notes refcnt sections srcversion taint uevent
$ ls -l /dev/ebbchar
crw------- 1 root root 238, 0 Mai 28 07:52 /dev/ebbchar
code using kobjects: https://paste.ubuntu.com/p/nt3XvZs7vF/ source
creates:
$ls -l /sys/kernel/
drwxr-xr-x 2 root root 0 Dec 17 16:29 etx_sysfs
I can see that my code successfully created a bunch of files under /sys/kernel. Now what is the difference in endgoal between my code and the two other snippets? Should I use device_create/kobjects or maybe none of those? The book I am reading doesn't mention anywhere the functions used by the 2 other pieces of code. So not sure which way I am supposed to follow...
Thanks_xe
device_create() creates a device and registers it with sysfs, and create necessary kobjects.
To create necessary kobjects, kobject-related functions(kobject_init(), kobject_add(), ...) are called in device_create().
If you need to create a device, you should call one of device creation functions like device_create().
Answering your question of how to keep up with latest api- Most api if renamed or updated retain similar name and reside mostly in the same header file so a quick grep on the source or easier is http://elixir.bootlin.com/ and search the source doc for a particular function in the Linux release you are working on. if you cant find the API in that release then go through the header to find the new API as the name will almost be the same for example when you will read the Timer chapter , you will find that setup_timer() has been changed to timer_setup(). and few other changes here and there.
If you feel like you can keep up with the latest discussion by subscribing to the kernel maillist or reading the documentation.

Upper filter device driver for a mouse

I've just started diving into driver related stuffs as what I want to do (cf. here) seems undoable with a "regular" application. For now, I'm just trying to install a Kernel Mode Driver (KMDF) as an upper filter for the mouse I want to modify the behaviour. The source files are not empty as they are filled in according to the Visual Studio KMDF template. The only modification I did so far in those source files was adding those two lines of code in the CreateDevice routine :
WdfFdoInitSetFilter(DeviceInit);
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_MOUSE);
to specify that the driver is a mouse filter driver.
However, I'm having trouble to install it as I would like on my virtual machine. Here is the INF file (don't pay too much attention to the comments, I just added them to better understand what's going on as it's the first time I'm confronted to such a file):
;
; EGMC_filter.inf
;
[Version]
Signature="$WINDOWS NT$" ;Operating system for which the INF file is valid
Class=Mouse ; The class is mouse
ClassGuid={4d36e96f-e325-11ce-bfc1-08002be10318} ; Mouse class GUID
Provider=%ManufacturerName% ; is specified in the Strings section (bottom of this file)
CatalogFile=EGMC_filter.cat ; for signature
DriverVer= ; TODO: set DriverVer in stampinf property pages
; The DestinationDirs section specifies the target destination directory for all copy, delete and/or rename operations
; on files referenced by name elsewhere in the INF file
[DestinationDirs]
DefaultDestDir = 12 ; directory is \Drivers on WinNT platforms
EGMC_filter_Device_CoInstaller_CopyFiles = 11 ; Directory is \system32 on WinNt platforms
[SourceDisksNames]
1 = %DiskName%,,,""
[SourceDisksFiles]
EGMC_filter.sys = 1,,
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
;*****************************************
; Install Section
;*****************************************
[Manufacturer] ; This section is used to list all devices handled by the driver
%ManufacturerName%=Standard,NT$ARCH$ ;stands for architecture. Is modified depending on x64 or x86
[Standard.NT$ARCH$] ; This is a model section
%EGMC_filter.DeviceDesc%=EGMC_filter_Device, USB\VID_093A&PID_2510; Specifying the Hardware ID for which to install the driver. No revision nb specified
[EGMC_filter_Device.NT] ; This is a DDInstall section
CopyFiles=Drivers_Dir ; CopyFiles directive that specify a copyfiles section (Drivers_Dir)
AddReg=EGMC_filter.AddReg
[EGMC_filter.AddReg]
HKR,,"UpperFilters",0x0010008,"EGMC_filter" ; REG_MULTI_SZ value
[Drivers_Dir] ; This is a CopyFile section.
EGMC_filter.sys ; All the files in this section are copied to the specified directory in the DestinationDirs section.
;-------------- Service installation
[EGMC_filter_Device.NT.Services]
AddService = EGMC_filter,%SPSVCINST_ASSOCSERVICE%, EGMC_filter_Service_Inst ; create a service installation section
; -------------- EGMC_filter driver install sections
[EGMC_filter_Service_Inst]
DisplayName = %EGMC_filter.SVCDESC%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\EGMC_filter.sys ; create a value in the registry with the fully qualified path of the driver's file
;
;--- EGMC_filter_Device Coinstaller installation ------
;
[EGMC_filter_Device.NT.CoInstallers]
AddReg=EGMC_filter_Device_CoInstaller_AddReg ;Add a registry section
CopyFiles=EGMC_filter_Device_CoInstaller_CopyFiles
[EGMC_filter_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
[EGMC_filter_Device_CoInstaller_CopyFiles]
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
[EGMC_filter_Device.NT.Wdf]
KmdfService = EGMC_filter, EGMC_filter_wdfsect
[EGMC_filter_wdfsect]
KmdfLibraryVersion = $KMDFVERSION$
[Strings]
SPSVCINST_ASSOCSERVICE= 0x00000002
ManufacturerName="EGMC" ; My manufacturer name
ClassName="Mouse" ; ClassName of the device
DiskName = "EGMC_filter Installation Disk" ; the disk name. DON'T KNOW WHERE IT COMES FROM !!!
EGMC_filter.DeviceDesc = "EGMC Filter Device"
EGMC_filter.SVCDESC = "EGMC_filter Service"
I'm trying to install my driver in a virtual machine running Windows 10. The VM is configured to support USB 2.0 and I've added a USB device filter in order for the VM to detect my particular mouse (otherwise, the VM couldn't distinguish the different mice connected).
First I tried deploying it via Visual Studio using the "Install/Reinstall and Verify" option in the project properties (configuration properties -> Driver Install -> Deployment). Note that remove previous driver versions before deployment is selected.
It didn't work and I got the following error messages :
[17:32:01:625]: ERROR: Task "Default Driver Package Installation Task" failed to complete successfully. Look at the logs in the driver test group explorer for more details on the failure.
[17:32:02:348]: Driver Post Install Actions
[17:32:02:348]: Removing any existing files from test execution folder.
[17:32:02:375]: Copying required files for "Driver Post Install Actions".
[17:32:02:934]: [Driver Post Install Actions] Command Line:
$KitRoot$\Testing\Runtimes\TAEF\te.exe "%SystemDrive%\DriverTest\Run\DriverTestTasks.dll" /select:"#Name='DriverTestTasks::_DriverPostInstall'" /rebootStateFile:%SystemDrive%\DriverTest\Run\DriverTestReboot.xml /enableWttLogging /wttDeviceString:$LogFile:file="%SystemDrive%\DriverTest\Run\Driver_Post_Install_Actions_00011.wtl",writemode=append,encoding=unicode,nofscache=true,EnableLvl="WexStartTest|WexEndTest|WexXml|WexProperty|WexCreateContext|WexCloseContext|*" /runas:Elevated
[17:32:05:387]: Result Summary: Total=1, Passed=1, Failed=0, Blocked=0, Warned=0, Skipped=0
[17:32:05:388]: Task "Driver Post Install Actions" completed successfully
Driver Deployment Task Failed: Default Driver Package Installation Task
It may sound stupid but I was unable to locate the logs in the driver test group explorer to get more info about the error.
Secondly, I tried using the "Hardware ID Driver" option instead of the "Install/Reinstall and Verify" one with the following Hardware ID "USB\VID_093A&PID_2510" (same as the one specified in the INF). It worked this time. However, I'm not sure to understand exactly why. So now that you got a better picture of what I'm doing, here are my questions :
1) I did understand that the SourceDisksNames section is used to specify the name of a disk (CD-rom, DVD) containing the .sys file of the driver. However, I don't understand how to install a driver from such a disk practically. Imagine I buy a specific hardware and it comes with a CD with the corresponding driver files. Once the CD is in the player, what should I do ? Should I run the INF file in order to install it ? From what I remember the only time I had to install a driver from a disk it was a .exe file.
2) What if I want to release my driver package via Internet ? What's the point of this section then ?
3) By default when I created the project, VS filled the disk name with "EGMC_filter Installation Disk". What does it correspond to ? Should I modify it ?
4) I don't understand how the deployment process works. I guess that VS first transfers the driver package (containing the .INF, .cat and .sys) to the VM and then launches the .INF file in the VM. Is that right ? If yes, what does the DiskName correspond to in the VM ? Does VS create some kind of ISO containing the package ? Where can I find where the package is stored in the VM ?
5) Does the deployment process differ when using the "Hardware ID Driver Update" and the "Install/Reinstall […]" options ?
6) Any idea why I can't install my driver using the "Install/Reinstall and Verify" option ? What's wrong with the INF file ? Has it something to do with the Disk name ?
7) Despite having read this page, I'm confused about why I can deploy my driver with the "Hardware ID" option considering that I didn't respect the form Root\xxx (I saw this page afterwards). However, it seems clear that for what I want to do, I must install my driver using the other option. Any idea why it still seems to work (at least partially) ?
8) After the "incorrect" installation is completed, a "EGMC Filter Device" entry is added to the Device Manager under Mice and other pointer devices even when the mouse of interest is unplugged. Why is this ? When I plug it, another entry appears.
9) When my driver is installed, the mouse doesn't work anymore (it doesn't even light up !). However, as the upper filter doesn't do anything for now, the mouse should work normally. The only explanation I've found so far is that the driver is installed as a function driver and not as a filter one. Could it be the case ? In the registry of the VM, I'm unable to find the UpperFilters keys with the "EGMC_filter" value in the section "Ordinateur\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class{4d36e96f-e325-11ce-bfc1-08002be10318}". The only one I found is : "UpperFilters : VboxMouse mouclass". It comforts me in my idea that the driver is installed as a function one… Could the VM interferes with my driver ?
10) The driver details of the mouse of interest (left) and the regular one (right) also confuse me as the mouhid is missing from the former.
11) Lastly, what's the point of specifying in the driver code that it's a filter driver ? What does it change concretely ?
I know it's a long post and that I'm asking quite specific questions but I hope you won't mind and hopefully some experts right there will be able to answer them.
I'm looking forward to your replies.
Guillaume.

Serving multiple domains in one box with SNI

I'm using OpenSSL 0.9.8q in FreeBSD-8.2. I have 3 virtual hosts on my system and want to implement SNI to serve for all 3 of them in one server.
I have 3 separate certificates one for each, and in my ssl-server code I have to somehow find out what is the domain-name of client's request, and use the appropriate certificate file based on that. For this I wrote a function named get_ssl_servername_cb and passed it as callback function to SSL_CTX_set_tlsext_servername_callback. This way, in callback function I can get the the domain-name of the client's request.
But my problem is, this callback function is being executed after execution of SSL_accept function, but I have to choose and use the appropriate certificate before using SSL_new command, which is way before execution of SSL_accept.
So my question is, how can I use SSL_CTX_set_tlsext_servername_callback function for SNI?
but my problem is, this callback function is being executed after execution of "SSL_accept" function, but I have to choose and use the appropriate certificate before using "SSL_new" command, which is way before execution of SSL_accept.
When you start your server, you provide a default SSL_CTX. This is used for non-SNI clients, like SSLv3 clients and TLS clients that don't utilize SNI (like Windows XP). This is needed because the callback is not invoked in this situation.
Here are some examples to tickle the behavior using OpenSSL's s_client. To simulate a non-SNI client so that your get_ssl_servername_cb is not called, issue:
openssl s_client -connect localhost:8443 -ssl3 # SNI added at TLSv1
openssl s_client -connect localhost:8443 -tls1 # Windows XP client
To simulate a SNI client so that your get_ssl_servername_cb is called, issue:
openssl s_client -connect localhost:8443 -tls1 -servername localhost
You can also avoid the certificate verification errors by adding -CAfile. This is from one of my test scripts (for testing DSS/DSA certificates on localhost):
printf "GET / HTTP/1.1\r\n\r\n" | /usr/local/ssl/bin/openssl s_client \
-connect localhost:8443 -tls1 -servername localhost \
-CAfile pki/signing-dss-cert.pem
so my question is, how can I use "SSL_CTX_set_tlsext_servername_callback" function for SNI?
See the OpenSSL source code at <openssl dir>/apps/s_server.c; or see How to implement Server Name Indication(SNI) on OpenSSL in C or C++?.
In your get_ssl_servername_cb (set with SSL_CTX_set_tlsext_servername_callback), you examine the server name. One of two situations occur: you already have a SSL_CTX for the server's name, or you need to create a SSL_CTX for server's name.
Once you fetch the SSL_CTX from cache or create a new SSL_CTX, you then use SSL_set_SSL_CTX to swap in the context. There's an example of swapping in the new context in the OpenSSL source files. See the code for s_server.c (in <openssl dir>/apps/s_server.c). Follow the trail of ctx2,
Here's what it looks like in one of my projects. IsDomainInDefaultCert determines if the requested server name is provided by the default server certificate. If not, GetServerContext fetches the needed SSL_CTX. GetServerContext pulls the needed certificate out of an app-level cache; or creates it and puts it in the app-level cache (GetServerContext also asserts one reference count on the SSL_CTX so the OpenSSL library does not delete it from under the app).
static int ServerNameCallback(SSL *ssl, int *ad, void *arg)
{
UNUSED(ad);
UNUSED(arg);
ASSERT(ssl);
if (ssl == NULL)
return SSL_TLSEXT_ERR_NOACK;
const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
ASSERT(servername && servername[0]);
if (!servername || servername[0] == '\0')
return SSL_TLSEXT_ERR_NOACK;
/* Does the default cert already handle this domain? */
if (IsDomainInDefCert(servername))
return SSL_TLSEXT_ERR_OK;
/* Need a new certificate for this domain */
SSL_CTX* ctx = GetServerContext(servername);
ASSERT(ctx != NULL);
if (ctx == NULL)
return SSL_TLSEXT_ERR_NOACK;
/* Useless return value */
SSL_CTX* v = SSL_set_SSL_CTX(ssl, ctx);
ASSERT(v == ctx);
if (v != ctx)
return SSL_TLSEXT_ERR_NOACK;
return SSL_TLSEXT_ERR_OK;
}
In the code above, ad and arg are unused parameters. I don't know what ad does because I don't use it. arg can be used to pass in a context to the callback. I don't use arg either, but s_server.c uses it to print some debug information (the arg is a pointer to a BIOs tied to stderr (and a few others), IIRC).
For completeness, SSL_CTX are reference counted and they can be re-used. A newly created SSL_CTX has a count of 1, which is delegated to the OpenSSL internal caching mechanism. When you hand the SSL_CTX to a SSL object, the count increments to 2. When the SSL object calls SSL_CTX_free on the SSL_CTX, the function will decrement the reference count. If the context is expired and the reference count is 1, then the OpenSSL library will delete it from its internal cache.

Resources