Tuesday, March 15, 2022

What is: Linux keyring, gnome-keyring, Secret Service, and D-Bus (2019)

It’s a really long-read post and I wast sure if it’s better to split it into three parts or put them together. On the one side, there are keyrings, from another – D-Bus, and finally, there is a Secret Service.

Eventually, I decided to keep them here together as I googled all it in the same scope and the are related to each other.

So, in this post we will speak about the next:

  • what is the keyring at all
  • what is the difference between the Linux keyring and GNOME keyring, and do they relate to each other
  • what keyring implementations are
  • what is the org.freedesktop Secret Service and how it relates to the GNOME keyring
  • what is D-Bus, and how we can use it to see how a keyring service is working
  • and a couple of examples with Linux Keyring, GNOME Keyring, KWallet, and KeePass as a keyring backend

This post is absolutely not kind of “tutorial” with “HowTo Configure it” but instead – just an overview of the components mentioned above to try to understand what they are and how they can be used.

See also:

This post was written by a long-long googling, so here will be a lot of links to documents and other materials that were used.

I may confuse something or even understood in a wrong way, so please welcome to the comments, if you’ll see any errors.

The post’s writing process was like this:

What is the Keyring?

To start what the “keyring” word means at all?

Let’s start with Wikipedia – https://en.wikipedia.org/wiki/Keyring_(cryptography):

In cryptography, a keyring stores known encryption keys (and, in some cases, passwords).

Then, let’s proceed with the GNOME project documentation – https://help.gnome.org/users/seahorse/stable/keyring.html.en:

Much like a keyring in real life allows you to keep certain sets of keys together, a keyring in Passwords and Keys allows you to keep passwords and keys in separate groups.

And even let’s take a look at the MySQL documentation – https://dev.mysql.com/doc/refman/5.7/en/keyring-service.html:

a keyring service that enables internal server components and plugins to securely store sensitive information for later retrieval

Finally, take a look at the keyrings(7) man-page – http://man7.org/linux/man-pages/man7/keyrings.7.html:

The Linux key-management facility is primarily a way for various kernel components to retain or cache security data, authentication keys, encryption keys, and other data in the kernel.

So, the keyring concept – it is some mechanism, or facility, or a concrete application, intended to store some confidential data.

Good, let’s go deeper.

Linux keyring vs gnome-keyring

Useful links used:

Now, let’s speak about the difference between the Linux kernel keyring and the GNOME Keyring: at first, I was confused as I suggested that GNOME Keyring somehow uses kernel’s keyrings facility, but now – it’s just different things.

Let’s go back to the man 7 Linux keyrings:

keyrings – in-kernel key management and retention facility

I.e. Linux keyrings – it’s is kernel’s mechanism providing the ability to store secret information.

Now, let’s read the gnome-keyring documentation:

GNOME Keyring is a collection of components in GNOME that store secrets, passwords, keys, certificates and make them available to applications.

So, GNOME Keyring – is a collection of utilities (gnome-keyring-daemon, libraries, the seahorse package, etc) to store confidential data. See also GNOME Keyring architecture.

Good documents also can be found here – Tower Floor — Encryption, in particular, see the Caching Passwords document.

Summary

Let’s summarize the key differences between Linux keyrings and GNOME Keyring:

  • main():
    • Linux kernel – is a kernel’s facility for “passwords caching” – it stores them in a computer’s memory during an active user’s/system session
    • gnome-keyring –  is persistent storage with keeping data on a hard disk
  •  storing:
    • Linux keyring – store in RAM, thus passwords are available only during a session, there is no need to store them always
    • gnome-keyring – creates a file on a disk, usually, in the ~/.local/share/keyrings/
  • accessing:
    • Linux keyring – via syscalls from the user space into the kernel space
    • gnome-keyring – via DBus
  • applications to access:

Keyrings implementations

Beside that, python-keyring mention:

And this list is not full.

Also, there a bunch of client applications to be used with those keyrings, again the list is not full:

Passwords interception from the gnome-keyting

During googling, found an interesting bug discussion here – https://bugs.launchpad.net/ubuntu/+source/gnome-keyring/+bug/1780365

In short:

  1. a client and a service communicates via D-Bus
  2. a client ask for some data from the Secret Service (gnome-keyring in this case)
  3. the service via D-Bus send a confidential data
  4. another, “bad”, process listens dbus-messages and intercepts a password

What is the Secret Service?

Another one concept I had to google about: what is the “Secret Service”? How it relates to the GNOME Keyring and to the KWallet?

What is it doing in the Linux and how can I touch it?

Well, let’s go to the documentation again – https://specifications.freedesktop.org/secret-service/latest/ch01.html:

The Secret Service API allows client applications to store secrets securely in a service running in the user’s login session.

Aha, i.e. Secret Service – it’s not some particular service or an application, but it’s a specification, kind of an RFC created by the GNOME and KDE projects to determine how this API must be realized for a client which wants to use GNOME Keyring or KWallet to store their secrets.

Also, the Secret Service API supported not only by the GNOME Keyring and KWallet but also for example by the KeePass and other applications.

IMHO, a bit confusing is the Secret Service name itself – “a hidden service”. If it would be called Secrets Service, i.e. “service of a secrets data” – it would be much more clear.

The Secret Service glossary

In short terms:

  • secret:  a password itself, or any other secret data
  • item: each such a secret plus its set of attributes makes up an item
  • collection: a set of such items makes a collection (similar to the keyring or wallet concepts)
  • collections and items represented by D-Bus objects, each with its unique path
  • default collection: client applications without special conditions have to save items to the default collection which has to be accessible via the  /org/freedesktop/secrets/aliases/default D-Bus path

D-Bus

Oookay…

Not its time to try to recall with is the D-Bus so often mentioned in the previous parts, and how to deal with it.

So, the D-Bus on of the Linux kernel IPC – Inter-Process Communication – mechanisms, allowing for separate processes inside of an operating system to communicate with each other.

Useful links:

And in short about main concepts and terms in D-Bus:

  • D-Bus in general: it’s a “bus” for IPC, i.e. if in the previous SSH examples (see the SSH: RSA keys, and ssh-agent for SSH keys and their passwords management post) a UNIX socket was used, this time we are using the bus mechanism, see the https://www.kernel.org/doc/html/latest/driver-api/driver-model/bus.html. In its turn, those buses can be
    • a session bus
    • a system bus
    • private buses
  • messages: a base communication unit, data transfer similar to the TCP/IP, just in the D-Bus all data of a message is included to the message and not split over TCP-packets
    • when a message is sent usually it leads to some method to be called to execute some actions by an application providing this method
    • a message can be sent by an application to itself
  • namespaces and addresses:
    • as various applications can be placed on the same bus (or “listen to the same bus”) and during that the same application can provide various objects which can accept messages, then need to have some way to address those messages. In D-Bus, such an address consists of an interface name + service + an object name
    • a namespace example – org.freedesktop.dbus
    • an address example – unix:tmpdir=/tmp/my-app-name
  • interface: a set of methods and signals on a particular bus f a particular object. You can think of interfaces as named methods and signals group.
    • most of the interfaces will lead to the concrete construction of a language used for an application, for example, it can be a Java interface or a virtual class in С++
    • an interface example – org.freedesktop.Introspectable
  • service: represents a concrete connection of a particular application to a bus
    • under the service here means a bus name (in the origin – “well-known” Bus names), but keep in mind that the “bus name” here implies a particular connection name but not the bus name
    • if an application has more then one connection to a bus, or if the application is running in multitype instances – expanded by a PID number, for example, to make it unique
    • a service example – org.kde.screensaver
  • objects: the same application can provide access to its multiple objects using paths to separate those objects. Each such a path associated with a service represents a dedicated object, for example /MainInterface or /Documents/Doc1. Objects allow access to interfaces and the same object can provide such access to multiple interfaces at the same time
  • methods: each object has members of the two types – methods and signals
    • methods – ate messages sent to an object to trigger some action in an application, who created this object
    • methods can pass data to an application’s input and can return an output with some values from the application
    • methods always have a sender and receiver addresses
  • signals:
    • are similar to the methods, but are not tied to any specific destination and can be accepted by any application on the same bus
    • are generated by an application which exported an interface

D-Bus tools

CLI:

  • qdbus– watch and send messages via D-Bus
  • dbus-monitor– view a bus activity
  • dbus-sendsend messages via D-Bus

GUI:

  • qdbusviewer – view objects and messages, is a part of the qt5-tools set
  • d-feet – D-Bus debugger
  • bustle – D-Bus message analyzer and profiler

For example d-feet, install it:

Run it:

Keyrings examples

And a few examples of how those backends can be used from a Python or CLI utilities.

Linux keyring

As already mentioned, the Linux keyring is a kind of “caching service” in the kernel.

You can use the keyctl utility from the keyutils, and systemd-ask-password.

To read about:

And from the documentation:

Each process subscribes to three keyrings: a thread-specific keyring, a process-specific keyring, and a session-specific keyring.

Let’s see which keyrings are available for my current session:

keyctl show @s

Session Keyring

185597501 --alswrv   1000  1000  keyring: _ses

182944921 --alswrv   1000 65534   \_ keyring: _uid.1000

Or for my user:

keyctl show @u

Keyring

182944921 --alswrv   1000 65534  keyring: _uid.1000

Also, in the /proc/key-users you can get information about all keyrings and their statistics by each user:

cat /proc/key-users

0:    43 42/42 34/1000000 768/25000000

971:     1 1/1 1/200 9/20000

1000:     4 4/4 4/200 46/20000

And keys available for reading by our process (thebash which called the cat):

cat /proc/keys

008f6a74 I--Q---     1 perm 1f3f0000  1000 65534 keyring   _uid_ses.1000: 1

0ae78499 I--Q---     4 perm 1f3f0000  1000 65534 keyring   _uid.1000: empty

0b0ffe3d I--Q---   225 perm 3f030000  1000  1000 keyring   _ses: 1

2a28e4fe I--Q---    33 perm 3f030000  1000  1000 keyring   _ses: 1

A user’s keyrings in the current session:

keyctl describe @us

      -5: -lswrvalswrv------------  1000 65534 keyring: _uid_ses.1000

Keys in the current keyring:

keyctl list @us

1 key in keyring:

182944921: --alswrv  1000 65534 keyring: _uid.1000

Add a key:

keyctl add user example-key example-data @u

546850615

Find it:

keyctl request user example-key

546850615

Got its ID and now can read its content using this ID:

keyctl print 546850615

example-data

keyctl() syscall

Actually, the keyctl utility just executes the keyctl(2) system call:

strace -e keyctl keyctl print 546850615

keyctl(KEYCTL_READ, 546850615, NULL, 0) = 12

keyctl(KEYCTL_READ, 546850615, "example-data", 12) = 12

example-data

+++ exited with 0 +++

In the first call here – keyctl(KEYCTL_READ, 546850615, NULL, 0) = 12   – we performed the keyctl() syscall with passing the KEYCTL_READ operation and a key ID.

Okay – more or less clear here.

Materials used here:

Let’s go to the keyring storages.

gnome-keyring

Really problematic package, as for me, but still it is most widely used.

Install if not present yet:

sudo pacman -S gnome-keyring

Check D-Bus services – look for the org.freedesktop.secrets:

dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ListNames

...

string "org.freedesktop.secrets"

...

“Aha, here we are” (c)

Now we can get the service description by using the org.freedesktop.DBus.Introspectable.Introspect method:

dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/secrets org.freedesktop.DBus.Introspectable.Introspect

...

<node>

<interface name="org.freedesktop.DBus">

<method name="Hello">

<arg direction="out" type="s"/>

</method>

<method name="RequestName">

<arg direction="in" type="s"/>

<arg direction="in" type="u"/>

<arg direction="out" type="u"/>

</method>

<method name="ReleaseName">

<arg direction="in" type="s"/>

<arg direction="out" type="u"/>

</method>

...

Or with the qdbus, fid the service first:

qdbus | grep 'secrets\|keyring'

org.freedesktop.secrets

org.gnome.keyring

Read the qdbus help:

qdbus --help

...

With 0 arguments, qdbus will list the services available on the bus

With just the servicename, qdbus will list the object paths available on the service

With service name and object path, qdbus will list the methods, signals and properties available on the object

And get the full service’s description:

qdbus org.freedesktop.secrets /org/freedesktop/secrets

signal void org.freedesktop.DBus.Properties.PropertiesChanged(QString interface_name, QVariantMap changed_properties, QStringList invalidated_properties)

method QDBusVariant org.freedesktop.DBus.Properties.Get(QString interface_name, QString property_name)

method QVariantMap org.freedesktop.DBus.Properties.GetAll(QString interface_name)

method void org.freedesktop.DBus.Properties.Set(QString interface_name, QString property_name, QDBusVariant value)

method QString org.freedesktop.DBus.Introspectable.Introspect()

method QString org.freedesktop.DBus.Peer.GetMachineId()

method void org.freedesktop.DBus.Peer.Ping()

...

D-Bus GetConnectionUnixProcessID

Actually, I want to see who is listening on the another side of the bus. Let’s use the GetConnectionUnixProcessID method for this:

qdbus --session org.freedesktop.DBus / org.freedesktop.DBus.GetConnectionUnixProcessID org.freedesktop.secrets

1278791

Here we did:

  • a call to the org.freedesktop.DBus service
  • passing the / path
  • called the org.freedesktop.DBus.GetConnectionUnixProcessID method
  • and passing the service org.freedesktop.secrets name to the method to get its PID

Check what is the 1278791 PID:

ps xu | grep 1278791

setevoy  1278791  0.0  0.0 383876  8092 ?        SLl  Dec03   0:00 /usr/bin/gnome-keyring-daemon --start --foreground --components=secrets

Nice.

So, now we are knowing that the Secret Service role is played by the gnome-keyring application. Let’s try to add and remove some data using thepython-keyring and secret-tool.

python-keyring

Start with the python-keyring.

Install it:

sudo pacman -S python-keyring

Check:

>>> import keyring

>>> keyring.set_password("system", "username", "password")

>>> keyring.get_password("system", "username")

'password'

In case of errors like (can happen on the first run after installation on Arch Linux, for example):

>>> keyring.set_password("system", "username", "password")

Traceback (most recent call last):

...

jeepney.wrappers.DBusErrorResponse: [org.freedesktop.DBus.Error.UnknownMethod] ('No such interface “org.freedesktop.DBus.Properties” on object at path /org/freedesktop/secrets/collection/login',)

Or:

Traceback (most recent call last):

...

  raise PromptDismissedException('Prompt dismissed.')

secretstorage.exceptions.PromptDismissedException: Prompt dismissed.

You need to execute the /etc/X11/xinit/xinitrc.d/50-systemd-user.sh script:

. /etc/X11/xinit/xinitrc.d/50-systemd-user.sh

And create a new keyring and set a password for it:

Let’s check the dbus-monitor, to see what’s is going on in the D-Bus:

...

method call time=1575542111.465749 sender=:1.576 -> destination=org.freedesktop.secrets serial=7 path=/org/freedesktop/secrets/aliases/default; interface=org.freedesktop.Secret.Collection; member=CreateItem

array [

dict entry(

string "org.freedesktop.Secret.Item.Attributes"

variant             array [

dict entry(

string "application"

string "Python keyring library"

)

dict entry(

string "service"

string "system"

)

dict entry(

string "username"

string "username"

)

]

)

dict entry(

string "org.freedesktop.Secret.Item.Label"

variant             string "Password for 'username' on 'system'"

)

]

...

struct {

object path "/org/freedesktop/secrets/session/s14"

}

...

signal time=1575542111.476006 sender=:1.220 -> destination=(null destination) serial=689 path=/org/freedesktop/secrets/collection/example_2dkeyring; interface=org.freedesktop.Secret.Collection; member=ItemCreated

object path "/org/freedesktop/secrets/collection/example_2dkeyring/5"

...

Here:

  1. sender=:1.576 – find the 1.576 in the D-Bus services list – it’s our Python (cmd: python):
  2. destination=org.freedesktop.secrets
    our /usr/bin/gnome-keyring-daemon, already seen in the org.freedesktop.DBus.GetConnectionUnixProcessIDoutput

Check the gnome-keyring storage with the seahorse utility for example:

Okay, “It works!” (c).

secret-tools

Another way can be to use secret-tools utility.

Add a new secret:

secret-tool store --label=SecretToolExample username username service secret

Password:

Retrieve it:

secret-tool lookup username username service secret

password

Check with the Seahorse in the storage:

KWallet

Install:

Check the D-Bus:

qdbus --session org.freedesktop.DBus / org.freedesktop.DBus.GetConnectionUnixProcessID org.freedesktop.secrets

1278791

ps aux | grep 1278791

setevoy  1278791  0.0  0.0 384008  8048 ?        SLl  Dec03   0:00 /usr/bin/gnome-keyring-daemon --start --foreground --components=secrets

Er…

Why not the kwallet, why still the gnome-keyring?

Try to kill it:

And the service-file is still old:

cat /usr/share/dbus-1/services/org.freedesktop.secrets.service

[D-BUS Service]

Name=org.freedesktop.secrets

Exec=/usr/bin/gnome-keyring-daemon --start --foreground --components=secrets

Okay, fully delete the gnome-keyring:

sudo pacman -Rsn seahorse

sudo pacman -Rsn gnome-keyring

And no service file now:

cat /usr/share/dbus-1/services/org.freedesktop.secrets.service

2019/12/05 13:15:03 open /usr/share/dbus-1/services/org.freedesktop.secrets.service: no such file or directory

Reinstall kwallet:

sudo pacman -S kwallet

warning: kwallet-5.64.0-1 is up to date -- reinstalling

...

No new service file:

qdbus --session org.freedesktop.DBus / org.freedesktop.DBus.GetConnectionUnixProcessID org.freedesktop.secrets

Error: org.freedesktop.DBus.Error.NameHasNoOwner

Could not get PID of name 'org.freedesktop.secrets': no such name

That’s weird…

Does D-Bus and Secret Service are supported by the KWallet at all?

Reddit says it’s not:

In brief, there is no longer a secret service implementation for KDE that I am aware of

And the ksecretsservice documentation is just full of  ToDo’s…

It’s a pity. I do like Qt-based KDE applications.

And the more strange is the fact that the Secret Service specification was written by both GNOME and KDE projects together, but it’s supported by the GNOME Keyring only…

Still, we can use KWallet without the Secret Service integration.

Run the KDE’s wallets manager:

Create a wallet:

Set its password:

Obviously, now our Python lib will stop working as no Secret Service now is available:

>>> keyring.set_password("system", "username", "password")

Traceback (most recent call last):

...

raise value

jeepney.wrappers.DBusErrorResponse: [org.freedesktop.DBus.Error.ServiceUnknown] ('The name org.freedesktop.secrets was not provided by any .service files',)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):

...

raise SecretServiceNotAvailableException(data) from resp

secretstorage.exceptions.SecretServiceNotAvailableException: The name org.freedesktop.secrets was not provided by any .service files

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

...

raise RuntimeError("Unable to initialize SecretService: %s" % e)

RuntimeError: Unable to initialize SecretService: The name org.freedesktop.secrets was not provided by any .service files

But you can configure a keyring backend and set the kwallet5 directly, googled it here>>>:

>>> kwallet5 = keyring.backends.kwallet.DBusKeyring()

>>> keyring.set_keyring(kwallet5)

>>> keyring.get_keyring()

<keyring.backends.kwallet.DBusKeyring object at 0x7f7efba66fa0>

Add a password:

>>> keyring.set_password("system", "username", "password")

Check the D-Bus messages:

method call time=1575545736.524015 sender=:1.318 -> destination=:1.269 serial=38 path=/modules/kwalletd5; interface=org.kde.KWallet; member=writePassword

int32 365838442

string "system"

string "username"

string "password"

string "Python keyring library"

And the KWallet:

KeePass

Also, KeePass can act as a keyring backend service using the Secret Storage specification.

If the gnome-keyring is still running – you’ll get the “Another secret service is running” error from the KeePass:

Remove the gnome-keyring, and activate Secret Service:

Check the D-Bus activity:

method call time=1575546064.021083 sender=:1.599 -> destination=org.freedesktop.DBus serial=26 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=RequestName

  string "org.freedesktop.secrets"

  uint32 4

signal time=1575546064.021157 sender=org.freedesktop.DBus -> destination=(null destination) serial=258 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged

  string "org.freedesktop.secrets"

  string ""

  string ":1.599"

signal time=1575546064.021212 sender=org.freedesktop.DBus -> destination=:1.599 serial=16 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired

  string "org.freedesktop.secrets"

method return time=1575546064.021245 sender=org.freedesktop.DBus -> destination=:1.599 serial=17 reply_serial=26

  uint32 1

Check, who is listening to the org.freedesktop.secrets:

qdbus --session org.freedesktop.DBus / org.freedesktop.DBus.GetConnectionUnixProcessID org.freedesktop.secrets

4006761

ps aux | grep 4006761

setevoy  4006761  2.0  0.5 475888 89656 tty1     SLl  13:40   0:02 keepassxc

Okay – this is our KeePass.

Add something to the database:

secret-tool store --label=SecretToolExample username username service secret

Password:

libsecret-Message: 13:45:13.448: Remote error from secret service: org.freedesktop.DBus.Error.UnknownObject: No such object path '/org/freedesktop/secrets/aliases/default'

secret-tool: No such object path '/org/freedesktop/secrets/aliases/default'

Er…

Aha, need to configure an internal path in the KeePass database, see this>>> comment.

Add a new group in the database:

Next, go to the Database > Database settings and specify local path to a directory which will be used to store data when acting as a Secret Service storage:

Restart KeePass and check the D-Bus – can see now how the collection was added now:

signal time=1575546948.831195 sender=:1.613 -> destination=(null destination) serial=22 path=/org/freedesktop/secrets; interface=org.freedesktop.Secret.Service; member=CollectionCreated

object path "/org/freedesktop/secrets/collection/Main"

Add a record:

secret-tool store --label=SecretToolExample username username service secret

Password:

Check the D-Bus:

...

method call time=1575547056.148892 sender=:1.616 -> destination=org.freedesktop.secrets serial=10 path=/org/freedesktop/secrets/aliases/default; interface=org.freedesktop.Secret.Collection; member=CreateItem

array [

dict entry(

string "org.freedesktop.Secret.Item.Attributes"

variant             array [

dict entry(

string "service"

string "secret"

)

dict entry(

string "username"

string "username"

)

]

)

dict entry(

string "org.freedesktop.Secret.Item.Label"

variant             string "SecretToolExample"

)

]

...

And the KeePass itself:

That’s all for now.

Useful links

keyrings, Secret Service, etc

D-Bus


Also published on Medium.



from Hacker News https://ift.tt/cgm8Gst

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.