The Signing Requirement
Recently, when I was trying to publish an Android library to Maven Central. One of the requirements is that all the files need to be signed with a GPG key.
Technically, I was able to generate the
.asc files containing the signature and passed the verification process when publishing to Maven Central. But how does the verification work? Let’s see.
First of all, we need to install GPG and then generate the key by following this tutorial.
Distribute Public Key
Now, we simulate the process of signing the file on a local computer and then sending the file included with the signature to the server emulator.
You can check your generated key id by using the command.
List all public keys:
gpg --list-keys --keyid-format LONG
List all private keys:
gpg --list-secret-keys --keyid-format LONG
Both works, because you have a pair of public and private keys. The public key is used for verification or encrypting data and the private key is used for signing or decrypting data.
Here on my machine, the key id is 2E7FF7EDBF52BC1C, the one after the slash character.
sec rsa4096/2E7FF7EDBF52BC1C 2021-03-07 [SC] 9C10BCB24C32F58DD911BAF42E7FF7EDBF52BC1C uid [ultimate] Justin Nguyen <email@example.com> ssb rsa4096/99C6D46AAD3145E4 2021-03-07 [E]
Let’s distribute the public key to the server. There are several ways to share it, export ASCII format or sending to the keyserver. In this topic, I make it simple by sending it to a keyserver.
gpg --keyserver hkp://keyserver.ubuntu.com --send-keys 2E7FF7EDBF52BC1C
Now, anyone can receive your public key from keyserver.ubuntu.com. Assume that the server emulator is a Maven Central and it knows the configuration of our public key id 2E7FF7EDBF52BC1C.
We can run the command to receive the key on the server emulator to get the shared public key.
gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 2E7FF7EDBF52BC1C
When the import is completed.
gpg: key 2E7FF7EDBF52BC1C: public key "Justin Nguyen <firstname.lastname@example.org>" imported gpg: Total number processed: 1 gpg: imported: 1
We can check the public key by using the command
--list-keys. Note that
--list-secret-keys does not work, because the server does not own your private key.
Now, let’s sign a helloworld.txt for example.
gpg --armor --detach-sig -u 2E7FF7EDBF52BC1C helloworld.txt
It will generate a helloworld.txt.asc file, this is the signature file from helloworld.txt. We need to send both to the server. Note that signing is not encrypting data.
Then, to simulate the git push or maven publish process, we copy these files and paste them to the server.
On the server to verify whether helloworld.txt comes from a trusted source. We can run the verify command to check it.
gpg --verify helloworld.txt.asc
As a result, it’s a good signature. If you try to modify the helloworld.txt and run the verify command again, it prompts a bad signature message, indicating that the helloworld.txt is not original.
There is a warning “This key is not certified with a trusted signature!”. It indicates that you have not trusted the key. More information in the GNU Handbook
If you want to trust the key, on the server you can edit it.
gpg --edit-key 2E7FF7EDBF52BC1C gpg> trust 1 = I don't know or won't say 2 = I do NOT trust 3 = I trust marginally 4 = I trust fully 5 = I trust ultimately m = back to the main menu Your decision? 5 gpg> save
Now, if you run the
--verify command again. The warning will disappear.
To recap, the person who holds the public key can verify whether it was signed by a private key. Only the person, who owns the private key can sign a file. That’s how the verification works.
This has nothing to do with encryption and decryption, you can check the GNU Handbook if you want to see how to implement it.