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