Hi everyone
I'm following the discussion of using Sequoia PGP for rpm.
Recently, I submitted a patch set for the kernel to support new keys and signature formats transparently. Parsing those formats is offloaded to user space. The kernel gets from user space only minimal information: the public key or signature, the algorithm, the key fingerprint, etc.
This is the link of the patch set:
https://lore.kernel.org/bpf/20230425173557.724688-1-roberto.sassu@huaweiclou...
I was wondering if Sequoia PGP can be used on user space side. It gets the key or signature blob, parses them, and replies to the kernel with the information the latter needs.
I had a brief look at the documentation of the openpgp crate, and maybe it could be done, but I don't have a precise idea.
Just wanted to ask your opinion on this, as the part of Sequoia PGP I would need is very minimal (the parsing part). Also the binary itself should be statically linked (I aim to execute it early in the boot to load the GPG keys of the Linux distribution to the kernel).
Another point would be to avoid external dependencies, like a crypto library, and to use the kernel Crypto API instead (through socket(AF_ALG) in user space). Not the highest priority (as it would require to rewrite some parts of your library), but nice to have.
What do you think? Thanks
Roberto
I don’t know much but is this what you needed.
https://sequoia-pgp.org/blog/2023/04/27/rpm-sequoia/
https://fedoraproject.org/wiki/Changes/RpmSequoia
Paul
On Fri, 2023-04-28 at 14:48 +0000, me@paulapplegate.com wrote:
I don’t know much but is this what you needed.
Thanks, using Sequoia PGP in Fedora was just to say how I was aware of the library.
More or less, what I was asking is if there is a function or a group of functions that, given a blob of PGP packets, returns the public key, the algorithm, ...
Also, I would like to have a self-contained binary, without shared libraries, and stripping everything that it is not needed.
Thanks
Roberto
Roberto Sassu wrote:
On Fri, 2023-04-28 at 14:48 +0000, me@paulapplegate.com wrote:
I don’t know much but is this what you needed. https://sequoia-pgp.org/blog/2023/04/27/rpm-sequoia/ https://fedoraproject.org/wiki/Changes/RpmSequoia Thanks, using Sequoia PGP in Fedora was just to say how I was aware of
the library. More or less, what I was asking is if there is a function or a group of functions that, given a blob of PGP packets, returns the public key, the algorithm, ... Also, I would like to have a self-contained binary, without shared libraries, and stripping everything that it is not needed. Thanks Roberto
I’m sorry to say I don’t understand all that 😊 but I’m confident others will be able to help.
I can use the software that’s about it. Oh and I can Google and at least ask for help. Best of luck. Paul
Hi Roberto,
On 28.04.2023 16:16, Roberto Sassu wrote:
Just wanted to ask your opinion on this, as the part of Sequoia PGP I would need is very minimal (the parsing part). Also the binary itself should be statically linked (I aim to execute it early in the boot to load the GPG keys of the Linux distribution to the kernel).
This is definitely what Sequoia can be used for. Actually the parsing part is a large part of the codebase. Take a look here:
https://docs.rs/sequoia-openpgp/latest/sequoia_openpgp/parse/trait.Parse.htm...
Things can be parsed into their respective data types, e.g. for example this one for public keys:
https://docs.rs/sequoia-openpgp/latest/sequoia_openpgp/crypto/mpi/enum.Publi...
It'd be good if you had a concrete "input/expected-output" examples then we can assist you in writing small proof of concepts that do exactly that. (The other route is exploring Sequoia's extensive test suite).
Another point would be to avoid external dependencies, like a crypto library, and to use the kernel Crypto API instead (through socket(AF_ALG) in user space). Not the highest priority (as it would require to rewrite some parts of your library), but nice to have.
Currently Sequoia supports a number of cryptographic backends (for full list see: https://gitlab.com/sequoia-pgp/sequoia/-/tree/main/openpgp#crypto-backends ). Adding Kernel Crypto API would be yet another backend. This is doable in practice, it's never brought into question (related: https://gitlab.com/sequoia-pgp/sequoia/-/issues/333).
Not sure if there's a Rust crate that already exposes some kind of API or whether that would be part of the task. (For time-complexity estimation note that adding OpenSSL backend took me ~3 months).
What do you think?
For me it looks like a very nice idea. Do you have any further resources we could read to get familiar with Kernel Crypto API and the user-space parsing part?
Have a nice day!
Kind regards, Wiktor
On Fri, 2023-04-28 at 19:21 +0200, Wiktor Kwapisiewicz wrote:
Hi Roberto,
On 28.04.2023 16:16, Roberto Sassu wrote:
Just wanted to ask your opinion on this, as the part of Sequoia PGP I would need is very minimal (the parsing part). Also the binary itself should be statically linked (I aim to execute it early in the boot to load the GPG keys of the Linux distribution to the kernel).
This is definitely what Sequoia can be used for. Actually the parsing part is a large part of the codebase. Take a look here:
https://docs.rs/sequoia-openpgp/latest/sequoia_openpgp/parse/trait.Parse.htm...
Things can be parsed into their respective data types, e.g. for example this one for public keys:
https://docs.rs/sequoia-openpgp/latest/sequoia_openpgp/crypto/mpi/enum.Publi...
Hi Wiktor
ok, parsing PGP packets into Sequoia-specific structures would be the first part of the job. I also see that there are methods to get the value of the MPI, which definitely get us closer to the result.
The kernel in some cases expects the key to be in ASN.1 format, like this for RSA keys:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/cryp...
I'm currently using an encoder already in the kernel:
https://github.com/robertosassu/linux/blob/pgp-signatures-umd-v1-devel-v24/l...
This is the function to convert from MPI to ASN.1 (we can reuse it maybe).
https://github.com/robertosassu/linux/commit/e665a579d9b105caa1a95e8ea400ddb...
It'd be good if you had a concrete "input/expected-output" examples then we can assist you in writing small proof of concepts that do exactly that. (The other route is exploring Sequoia's extensive test suite).
The input and output are defined in this header file:
https://github.com/robertosassu/linux/blob/pgp-signatures-umd-v1-devel-v24/c...
I guess you can already parse the untouched PGP packets.
For the output, we need to fill the relevant structures. Also this seems sufficiently easy.
For now, for testing, I reused an existing PGP implementation in C:
https://github.com/robertosassu/linux/blob/pgp-signatures-umd-v1-devel-v24/c...
Line 206: set the key fingerprint as key ID Line 267: set the public key algorithm Line 321/322: set the public key (ECDSA) Line 326/333: set the public key (RSA)
For signatures, it is similar:
https://github.com/robertosassu/linux/blob/pgp-signatures-umd-v1-devel-v24/c...
Another point would be to avoid external dependencies, like a crypto library, and to use the kernel Crypto API instead (through socket(AF_ALG) in user space). Not the highest priority (as it would require to rewrite some parts of your library), but nice to have.
Currently Sequoia supports a number of cryptographic backends (for full list see: https://gitlab.com/sequoia-pgp/sequoia/-/tree/main/openpgp#crypto-backends ). Adding Kernel Crypto API would be yet another backend. This is doable in practice, it's never brought into question (related: https://gitlab.com/sequoia-pgp/sequoia/-/issues/333).
Not sure if there's a Rust crate that already exposes some kind of API or whether that would be part of the task. (For time-complexity estimation note that adding OpenSSL backend took me ~3 months).
Ok. Maybe this would have less priority. The first priority would be just reuse Sequoia PGP possibly untouched.
The second priority would be to make a minimal binary to be embedded to a kernel module.
For security reasons, Sequoia PGP will run in an isolated environment (will only receive/send data to the kernel).
At the very beginning of the program, I plan to also request the file descriptors for the Crypto API. After initialization, the program can only use a very limited set of system calls (read, write, recv, send, exit). This would be after everything is working, just to mention the long-term plan.
What do you think?
For me it looks like a very nice idea. Do you have any further resources we could read to get familiar with Kernel Crypto API and the user-space parsing part?
Yes:
https://github.com/robertosassu/linux/blob/pgp-signatures-umd-v1-devel-v24/D...
https://github.com/robertosassu/linux/blob/pgp-signatures-umd-v1-devel-v24/c...
In the latter, you see how to obtain file descriptors to communicate with the Crypto API.
The digest, or digest update operations, are performed with a send(). Getting the result is achieved with a recv().
The pgp_public_key.c file shows a possible usage.
The entire PGP implementation is available here:
https://github.com/robertosassu/linux/tree/pgp-signatures-umd-v1-devel-v24/c...
Thanks a lot for the help!
Roberto
Hi Roberto,
Wow, what a comprehensive reference! Thanks a lot for that and even though I still haven't parsed everything it gave me a high level overview of the scope.
On 2.05.2023 11:47, Roberto Sassu wrote:
Ok. Maybe this would have less priority. The first priority would be just reuse Sequoia PGP possibly untouched.
Yep, I agree. Even though you sent some really impressive code fragments my C is a little bit rusty (hehe) and it would take me quite a bit of time to write bindings to all these structs.
If you would be working on that part I'd be happy to fill in any "Sequoia-specific" parts in your Rust code including parsing MPIs and verifying signatures [0].
Thank you for your time!
Kind regards, Wiktor
[0]: https://docs.sequoia-pgp.org/sequoia_guide/chapter_01/index.html
Hi Roberto,
Not sure if you're following but I've been slowly working towards Kernel Crypto Sequoia backend:
https://gitlab.com/sequoia-pgp/sequoia/-/issues/1030 https://gitlab.com/sequoia-pgp/sequoia/-/tree/wiktor/add-kernel-crypto
And all was fine but we hit a major roadblock: it seems asymmetric operations are not available in user-space due to some patches not being upstreamed even though most of them look rather benign: https://github.com/smuellerDD/libkcapi/tree/master/kernel-patches/4.15-rc3/a...
Source: https://github.com/smuellerDD/libkcapi/issues/164#issuecomment-1633783571
Is this something you could help us / kcapi author with? The author says their patches were vetoed "because it was considered that it is not needed" and I think we've got a solid case here.
I'd do it myself but I think you're already deeply immersed in kernel development and it could go faster with you. If not, please do tell.
Thanks for help in advance!
Kind regards, Wiktor
On 28.04.2023 16:16, Roberto Sassu wrote:
Another point would be to avoid external dependencies, like a crypto library, and to use the kernel Crypto API instead (through socket(AF_ALG) in user space). Not the highest priority (as it would require to rewrite some parts of your library), but nice to have.
On Thu, 2023-07-13 at 10:31 +0200, Wiktor Kwapisiewicz wrote:
Hi Roberto,
Not sure if you're following but I've been slowly working towards Kernel Crypto Sequoia backend:
https://gitlab.com/sequoia-pgp/sequoia/-/issues/1030 https://gitlab.com/sequoia-pgp/sequoia/-/tree/wiktor/add-kernel-crypto
Hi Wiktor
thanks for taking care of this! I should have checked the Sequoia PGP development more closely.
Just an update on my side.
The kernel maintainers are not sure yet we would be able to get a fully isolated process in user space handling kernel workloads (in this case to convert the PGP keys and signatures into a format undestood by the kernel).
Without this guarantee, I kind of moved a bit the target, i.e. assuming that the conversion from PGP to kernel format is happening in a trusted environment, such as the vendor premises when the Linux kernel is built.
That is sufficient to achieve the goal of adding the PGP keys of the distribution as a new trust anchor to the kernel.
For signatures, the digest is calculated in the kernel. Altering a PGP signature at run-time has the only consequence of rejecting the data to verify. Thus, the signature conversion can happen in an untrusted environment.
Ok, so now the conversion part.
I changed a bit the kernel format to be more generic. It is Type- Length-Value (TLV). The purpose of the format and the defined fields is to fill the kernel structures public_key and public_key_signature. But there are additional fields, like the additional PGP data required to verify the signature. I added a field for that (SIG_DATA_END).
The original PGP implementation in the kernel was calculating again the fingerprint. However, maybe after all that is not even necessary, we can use the last 8 bytes extracted from the packet as key index.
The closest tool that can be used for converting PGP keys and signatures seems to be sequoia-sq. I was trying to modify this file:
https://gitlab.com/sequoia-pgp/sequoia-sq/-/blob/main/src/commands/dump.rs
but my Rust expertise is very limited..
So, I decided to modify gpg (in C) instead. I was much faster. Please have a look at the last two patches of this patch set:
https://lore.kernel.org/linux-integrity/20230706144225.1046544-1-roberto.sas...
They are basically filling a header:
struct uasym_hdr { __u8 data_type; __u8 _reserved0; __u16 num_fields; __u32 _reserved1; __u64 total_len; } __packed;
and an entry for each field we need to send to the kernel:
struct uasym_entry { __u16 field; __u32 length; __u8 data[]; } __packed;
For keys, we are sending these fields:
KEY_ALGO KEY_KID0 (the last 8 bytes of the fingerprint) KEY_DESC (can be anything, I chosen PGP: <last 4 bytes of fingerprint) KEY_PUB
Unfortunately, there is the additional complexity of converting the RSA key to the ASN.1 format (sequence of INTEGERS). I added a stripped down version of the code to encode the key with mpis_to_asn1_sequence() and asn1_encode_length().
For signatures, we are sending these fields:
SIG_KEY_ALGO SIG_HASH_ALGO SIG_ENC SIG_KID0 SIG_DATA_END SIG_S
So, to summarize, everything that I would need in the latest iteration of the kernel patches is a new option of the sequoia-sq command to convert PGP keys and signatures to the new kernel format.
And all was fine but we hit a major roadblock: it seems asymmetric operations are not available in user-space due to some patches not being upstreamed even though most of them look rather benign: https://github.com/smuellerDD/libkcapi/tree/master/kernel-patches/4.15-rc3/a...
Source: https://github.com/smuellerDD/libkcapi/issues/164#issuecomment-1633783571
Is this something you could help us / kcapi author with? The author says their patches were vetoed "because it was considered that it is not needed" and I think we've got a solid case here.
I understand kernel maintainers might not want new functionality, unless it is really needed. There would have been a concrete case with my trustworthy User Mode Driver solution, as it would have avoided to link other complex crypto libraries.
Without the trustworthy User Mode Driver, and doing everything in user space in a trusted environment, maybe the kernel extension would not be needed (sorry, I should have updated you while implementing the new solution).
Let me know what you think about the new developments.
Thanks!
Roberto
I'd do it myself but I think you're already deeply immersed in kernel development and it could go faster with you. If not, please do tell.
Thanks for help in advance!
Kind regards, Wiktor
On 28.04.2023 16:16, Roberto Sassu wrote:
Another point would be to avoid external dependencies, like a crypto library, and to use the kernel Crypto API instead (through socket(AF_ALG) in user space). Not the highest priority (as it would require to rewrite some parts of your library), but nice to have.
Devel mailing list -- devel@lists.sequoia-pgp.org To unsubscribe send an email to devel-leave@lists.sequoia-pgp.org
Hi Roberto,
On 13.07.2023 11:02, Roberto Sassu wrote:
I understand kernel maintainers might not want new functionality, unless it is really needed. There would have been a concrete case with my trustworthy User Mode Driver solution, as it would have avoided to link other complex crypto libraries.
Yep, it seems you were right, the new functionality is unlikely to make it to the upstream kernel.
We've decided to drop the "kernel crypto" ticket for the time being. Just in case you want a more detailed outline I've written it here: https://gitlab.com/sequoia-pgp/sequoia/-/issues/1030#note_1507831830
Thanks for help and have a nice day!
Kind regards, Wiktor