[tech] Geminipg: using Gnupg to sign Gemini pages and directories

Christophe HENRY <listes (a) sbgodin.fr>

Hi all!

This is a proposal to add signature capability to any page or
directory. Indeed, this could also be applicable to an HTML service.
The point is, with Gemini, that the page you get on Gemini is just like
it appears to be.

You may need to publish and be sure that like people can check the
pages. People may want to be sure that the text was signed by its
alleged author.

## For a file:

gpg --detach-sign --armor --output index.gmi.sig index.gmi

The file "index.gmi" is signed using the current certificate. The
signature is a binary file.

gpg --verify index.gmi.sig index.gmi

The command checks the signature and returns the date and the key used.

## For a directoy:

sha256sum directory/* | gpg --clear-sign --output directory.sig

All the file of "directory" are sha256-sumed. The results go in a file that is signed.


# On the server side

## One signature for one file

./chapter_1.gmi
./chapter_1.sig
./chapter_2.gmi
./chapter_2.sig

## Several signatures for one file

./page.gmi
./page.gmi.sig/
./page.gmi.sig/{sha256 of the signed file}-{fingerprint of the signing key #1}.sig
./page.gmi.sig/{sha256 of the signed file}-{fingerprint of the signing key #2}.sig

## One signature for one directory

./mybook/chapter_1.gmi
./mybook/chapter_2.gmi
./mybook.sig

## Several signatures for one directory

./mybook/chapter_1.gmi
./mybook/chapter_2.gmi
./mybook.sig/ : {sha256 of the signed file list}-{fingerprint of the
signing key #1}.sig /mybook.sig/ : {sha256 of the signed file
list}-{fingerprint of the signing key #2}.sig


# On the client side:

Signatures discovery for ./directory/page.gmi :

1. ./directory/page.gmi.sig # one signature
2. ./directory/page.gmi.sig/ # several signatures for one page
3. ./directory.sig # all the files of the directory for one signature
4. ./directory.sig/ # all the files of the directory for several signatures

In such a case, the server must return a directory index or a
"index.gmi" containing all the links for the signatures.

# Publishing

The writer signs the files before publishing them. The server may also
generate the signature on the fly ; it regenerates the signature if the
file is newer than the signature.

# General requirements:


  page, the signatures and verify each signature.

Thanks in advance for all point of view and remarks!

-- 
Christophe HENRY
FR EO EN - https://sbgodin.fr

Link to individual message.

nervuri <nervuri (a) disroot.org>

I really like what you're trying to achieve, but maybe we can find a
solution than doesn't involve all those extra files / network requests.

Why not use a single SHA256SUMS file for all files on the capsule?  We
could put it in .well-known and sign it.  To generate it, we only need
a simple script that runs sha256sum recursively.  We end up with:

.well-known/key.pub
.well-known/SHA256SUMS
.well-known/SHA256SUMS.sign

A proof-of-concept client can also be a relatively simple shell script:

./verify.sh gemini://capsule.org/~user/file

It would first download the 3 well-known files, check the signature of
SHA256SUMS and keep it locally, along with the key.  Then it can verify
any file on gemini://capsule.org/~user/ without making additional
network requests.  On hash mismatch, it would check if SHA256SUMS
changed on the server.  It would apply TOFU on key.pub.  It could output
gemtext to stdout, to be piped into a client that renders it nicely.

Note that in this example, .well-known is under ~user, not directly
under capsule.org.  This is to account for multi-user systems
(pubnixes/tilde communities).

The 3 files can be merged into one, because why not?  So this system
involves one extra network request every once in a while, which makes
the client stand out fingerprinting-wise.  This slight privacy trade-off
is something to keep in mind when you use this feature - maybe only use
it sparingly, when you need the extra security.

That's it, in short.  It would work the same way on gemini, gopher and
the web.  I'll probably code this if nobody does it before me.

I also want to explore the idea of a signed "key-sources" file
containing links to the public key from multiple sources, for
cross-checking in case the key changes.  Not sure how this would work
exactly, I need to give it more thought.

Instead of GPG, I recommend OpenBSD's signify [1], which gives us nice
and short Ed25519 keys and signatures.  It's also available on GNU/Linux
(in Debian, `apt install signify-openbsd`).

There is already a good solution for page signing on the web [2], made
by the developer of EteSync (great guy).  The problem of included files
is solved by subresource integrity [3].

[1] https://man.openbsd.org/signify
[2] https://stosb.com/blog/signed-web-pages/
[3] https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity


> Several signatures for one file

I don't think multiple signatures are worth the added complexity.  But
I'm curious if you have arguments to the contrary.

Link to individual message.

nervuri <nervuri (a) disroot.org>

On Thu, Feb 25, 2021, Christophe HENRY wrote:
>Nice to meet you :-)

Likewise.

>> Why not use a single SHA256SUMS file for all files on the capsule?  We
>
>Depending on the number of pages, it would become a huge file to
>locally update if one file happens to be modified.

It would be about 1 MB per 10,000 files and it would be updated
selectively by the script.  I think that's generally good enough.
"Premature optimization is the root of all evil." :)

>Indeed, if it was only for me, I would sign the files inline
>(--clear-sign). Or even would add dedicated headers? But, wait, it's
>been discussed ;-)

Inline signatures would work well in some cases.  They are ugly, but
they're otherwise the perfect solution: no extra network requests, clear
indication of which file is signed...

>> I also want to explore the idea of a signed "key-sources" file
>> containing links to the public key from multiple sources, for
>> cross-checking in case the key changes.  Not sure how this would work
>> exactly, I need to give it more thought.
>
>Yes, I totally agree. The good news is that it's already part of the
>Gnupg ecosystem.

You mean keyservers?  They weren't doing so well, last I checked:
https://gist.github.com/rjhansen/67ab921ffb4084c865b3618d6955275f

But it looks like keys.openpgp.org has remedied those issues:
https://keys.openpgp.org/about/news#2019-06-12-launch

Still, it's only a single source.  Are there any other such modern
keyservers?

>> Instead of GPG, I recommend OpenBSD's signify [1], which gives us nice
>> and short Ed25519 keys and signatures.  It's also available on
>> GNU/Linux (in Debian, `apt install signify-openbsd`).
>> (?)
>
>This way, we would lose the web of trust. Wouldn't we?

We would lose the PGP version of it, although there's nothing stopping
you from signing someone else's signify key, to show that you trust it
(and send that person your signature, to publish on his/her site).  This
gives us an ad-hoc web of trust.

I never had the chance to use the PGP web of trust.  It sounds good in
theory, but in practice the UI seriously hinders its adoption.  It might
work within projects like Debian, but if I want to verify a file on the
net made by someone I don't know (and whose PGP-friends I don't know),
the only way for me to check if I have the right key is to get it from
multiple sources and/or network perspectives.  This is what I've always
done, the web of trust never entered the picture.

>> I don't think multiple signatures are worth the added complexity.  But
>> I'm curious if you have arguments to the contrary.
>
>It's a major piece of my thoughts. It's why I would like to keep
>signatures on one file (or even in a header?). Say one famous person
>publishes something great and signed it. On his capsule, there would be
>"page.gmi" and "page.gmi.sig". If I want to keep this by my side or
>want to reuse the page, I can also re-publish the two files.

Ah, ok.  In this case, I would explain in a separate page: "this is the
author's text and this is his signature" (links to both).  Again, an
ad-hoc solution for a rare use case, no technical burden.  This would be
my preference, at least.

Link to individual message.

Francesco Camuffo <f (a) fmac.xyz>

Hi.

I made a very basic proof-of-concept program [1] to check the signify
signature of a resource.

[1] https://git.sr.ht/~fmac/gemisign

Link to individual message.

nervuri <nervuri (a) disroot.org>

On Sun, Mar 07, 2021, Francesco Camuffo wrote:
>Hi.
>
>I made a very basic proof-of-concept program [1] to check the signify
>signature of a resource.
>
>[1] https://git.sr.ht/~fmac/gemisign

Hi!

This made my day when you posted it.  I finally got around to trying it
out (compiling gmni+BearSSL was a pain), tested it and found that it
works well, once all the pieces are in place.  Thanks for taking the
initial steps!  And sorry for replying so late.

My recommendation is to merge key.pub, SHA256SUMS and SHA256SUMS.sig
into a single file, to reduce the number of network requests.  I
considered concatenating them within a plaintext file (using a separator
like "~~~"), but then I discovered signify's -z option, which signs a
gzip archive and embeds the signature in the gzip header.  GPG can do
something similar - see `gpgtar`.

Using an archive in this way has several benefits:


with long, repeating paths)

could add `key-sources` later on


I suggest `.well-known/signature-bundle` as the standard location for
the signed archive.  It's important for this file *not* to have an
extension, because the archive format might change later on, as software
evolves.

I wrote an implementation in POSIX Shell:

https://tildegit.org/nervuri/NetSigil

I'm using it to sign gemini://rawtext.club/~nervuri/ and
https://nervuri.net/.  Remember, none of this is strictly
Gemini-specific.

Verification is not yet implemented, but can be done manually - see the
README.

I intend to put all of this in a spec, after finishing the
implementation.

If you sign your capsules, please let me know.  I'd like to make a
public list of signed capsules/websites/gopherholes and their keys.


P.S.  I learned recently that there are established ways to publish PGP
keys, both under .well-known and as DNS records, see:

https://slxh.nl/blog/2016/pgp-and-dns/
https://datatracker.ietf.org/doc/draft-koch-openpgp-webkey-service/?include_text=1

Link to individual message.

ew.gemini <ew.gemini (a) nassur.net>

Hello,


nervuri <nervuri at disroot.org> writes:

> On Sun, Mar 07, 2021, Francesco Camuffo wrote:
>>Hi.
>>
>>I made a very basic proof-of-concept program [1] to check the signify
>>signature of a resource.
>>
>>[1] https://git.sr.ht/~fmac/gemisign
>
>snip
> My recommendation is to merge key.pub, SHA256SUMS and SHA256SUMS.sig
> into a single file, to reduce the number of network requests.  I
> considered concatenating them within a plaintext file (using a separator
> like "~~~"), but then I discovered signify's -z option, which signs a
> gzip archive and embeds the signature in the gzip header.  GPG can do
> something similar - see `gpgtar`.
>
> Using an archive in this way has several benefits:
>
> * compression (which actually matters if you have a big SHA256SUMS file
> with long, repeating paths)
> * an elegant way to bundle as many files as we need; for instance, we
> could add `key-sources` later on
> * no separate signature file(s)
>
> I suggest `.well-known/signature-bundle` as the standard location for
> the signed archive.  It's important for this file *not* to have an
> extension, because the archive format might change later on, as software
> evolves.
>
> I wrote an implementation in POSIX Shell:
>
> https://tildegit.org/nervuri/NetSigil
>

I spent some time today to retrace what you have outlined. I was
able to create signature-bundle and extract the information from
it again.

Some time ago I wrote about my experiments here:
2020-12-17 Towards a proper FlightLog 4 -- Experiment with
gpg-Signatures
=> gemini://gemini.circumlunar.space/~ew/2020/20201217-towards-a-proper-flightlog-4.gmi

Apart from file names and such details both ways ware very
similar:
- create a list of checksums of all files in the tree
- sign this list with your secret key
- publish the corresponding public key.

The biggest difference is the use of tools.
- I use plain gpg
- you use signify-openbsd (which I did not know about)


signify-openbsd uses a different key generation mechanism.
Skimming the docs coming with the debian package did not say,
what algorithm is used. So to me this looks like "but why
another?" --- this might be my ignorance, however.

So what is the reason you choose signify-openbsd?
Is there a way to link such a signify pair of keys to my gpg
key?


Thanks for sharing this.
I especially like the fact that NetSigil is a modest shell script!

Cheers,
~ew



-- 
Keep it simple!

Link to individual message.

Alexis <flexibeast (a) gmail.com>


ew.gemini <ew.gemini at nassur.net> writes:

>
> signify-openbsd uses a different key generation mechanism.
> Skimming the docs coming with the debian package did not say,
> what algorithm is used. So to me this looks like "but why
> another?" --- this might be my ignorance, however.

Not sure if you're already aware of this intro, describing the 
reasons for signify's existence and design decisions:

    https://www.openbsd.org/papers/bsdcan-signify.html


Alexis.

Link to individual message.

nervuri <nervuri (a) disroot.org>

On Wed, 2021-04-07, ew.gemini wrote:
>I spent some time today to retrace what you have outlined. I was
>able to create signature-bundle and extract the information from
>it again.

Nice!  Let me know if you had any trouble understanding the code and/or
explanation.  I want it to be clear.

>=> gemini://gemini.circumlunar.space/~ew/2020/20201217-towards-a-proper-flightlog-4.gmi

You ask at the end:

>However: Is it useful?

I think it's always good to be able to check that files on the server
have not been tampered with.  Signing is a best practice which I'd love
to see widespred.

>So what is the reason you choose signify-openbsd?

- it produces small (ed25519) keys and signatures;
- the software is *way* less complex than GPG and closer to the Unix
  philosophy.  "Complexity is the worst enemy of security", the saying
  goes.

Also see the text that Alexis linked to.

I may add GPG support as well, because it's more popular and can also
produce archives with embedded signatures.  The downer is that gpgtar
archives are not standard, `tar -xf` doesn't work on them.

>Is there a way to link such a signify pair of keys to my gpg
>key?

Yes, you can cross-sign them.  This is what I did: the GPG signature of
my signify key is published alongside both keys:

gemini://rawtext.club/~nervuri/keys/

And the entire capsule (GPG key included) is signed with my signify key.

>I especially like the fact that NetSigil is a modest shell script!

I'd like to thank shellcheck for keeping me out of trouble:
https://www.shellcheck.net/

Link to individual message.

---

Previous Thread: Clients that auto-display inline images?

Next Thread: [tech] Announcing go-gemini v0.1.15