x/crypto/openpgp: How to get public key-id from signature?

166 views
Skip to first unread message

talala...@gmail.com

unread,
Jun 6, 2019, 6:37:58 AM6/6/19
to golang-openpgp
Hi all,

I am currently working on a Go program where I need to verify GPG signatures. I have the detached armored signature and the signed message but no respective public key nor the key's id.

I have used the following files in my examples below:

On command-line I would do the following:
$ gpg --verify Release.gpg Release
gpg
: Signature made Sat Jun 17 10:57:48 2017 CEST
gpg
:                using RSA key 8B48AD6246925553
gpg
: Can't check signature: No public key
gpg: Signature made Sat Jun 17 10:57:48 2017 CEST
gpg:                using RSA key 7638D0442B90D010
gpg: Can'
t check signature: No public key
gpg
: Signature made Sat Jun 17 11:15:12 2017 CEST
gpg
:                using RSA key 6FB2A1C265FFB764
gpg
: Can't check signature: No public key
$
$ gpg --keyserver pool.sks-keyservers.net --receive-keys 8B48AD6246925553 7638D0442B90D010 6FB2A1C265FFB764
...
gpg: no ultimately trusted keys found
gpg: Total number processed: 3
gpg:               imported: 2
gpg:              unchanged: 1
$
$ gpg --verify Release.gpg Release
gpg: Signature made Sat Jun 17 10:57:48 2017 CEST
gpg:                using RSA key 8B48AD6246925553
gpg: Good signature from "Debian Archive Automatic Signing Key (7.0/wheezy) <ftpm...@debian.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: A1BD 8E9D 78F7 FE5C 3E65  D8AF 8B48 AD62 4692 5553
gpg: Signature made Sat Jun 17 10:57:48 2017 CEST
gpg:                using RSA key 7638D0442B90D010
gpg: Good signature from "Debian Archive Automatic Signing Key (8/jessie) <ftpm...@debian.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 126C 0D24 BD8A 2942 CC7D  F8AC 7638 D044 2B90 D010
gpg: Signature made Sat Jun 17 11:15:12 2017 CEST
gpg:                using RSA key 6FB2A1C265FFB764
gpg: Good signature from "Wheezy Stable Release Key <debian-...@lists.debian.org>" [expired]
gpg: Note: This key has expired!
Primary key fingerprint: ED6D 6527 1AAC F0FF 15D1  2303 6FB2 A1C2 65FF B764

In Go, provided that I have the key-id(s), I can:
package main

import (
   
"bytes"
   
"fmt"
   
"io/ioutil"
   
"log"
   
"net/http"
   
"os"
   
"strings"

   
"golang.org/x/crypto/openpgp"
)

func main
() {
    keyIDs
:= []string{
       
"8B48AD6246925553",
       
"7638D0442B90D010",
       
"6FB2A1C265FFB764",
   
}

   
var keys []byte
   
for _, id := range keyIDs {
        k
, err := getPublicKey(id)
       
if err != nil {
            log
.Fatal(err)
       
}
        keys
= append(keys, k...)
   
}

    keyring
, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(keys))
   
if err != nil {
        log
.Fatal(err)
   
}

    sig
, err := os.Open("./Release.gpg")
   
if err != nil {
        log
.Fatal(err)
   
}
    target
, err := os.Open("./Release")
   
if err != nil {
        log
.Fatal(err)
   
}

    signer
, err := openpgp.CheckArmoredDetachedSignature(keyring, target, sig)
   
if err != nil {
        log
.Fatal(err)
   
}

    fmt
.Println("All good")
    fmt
.Println(signer)
}

func getPublicKey
(stub string) ([]byte, error) {
    uri
:= fmt.Sprintf("pool.sks-keyservers.net/pks/lookup?search=0x%s&options=mr&op=get", stub)

   
// try different mirrors in case of failure
    resp
, err := http.Get("http://" + "hkps." + uri)
   
if err != nil {
        resp
, err = http.Get("http://" + "eu." + uri)
       
if err != nil {
            resp
, err = http.Get("http://" + "na." + uri)
           
if err != nil {
                resp
, err = http.Get("http://" + uri)
           
}
       
}
   
}
   
if err != nil {
       
return nil, err
   
}
    defer resp
.Body.Close()

    b
, err := ioutil.ReadAll(resp.Body)
   
if err != nil {
       
return nil, err
   
}
   
if strings.Contains(strings.ToLower(string(b)), "no results found") {
       
return nil, fmt.Errorf("no public key found for %q", stub)
   
}

   
return b, nil
}

The problem arises when I don't have the key-id(s) to begin with. I could do a `os.Exec(...)` but I would like to do this entirely in Go (if possible) and not have to depend on GPG.

Now to my question: is there a way that I can get the public key-id from just the signature and signed message similar to how the `gpg --verify` command gives this info?

Axel Wagner

unread,
Jun 6, 2019, 6:56:26 AM6/6/19
to talala...@gmail.com, golang-openpgp
Hi,

I think you should be able to use a packet.Reader and extract either a packet.Signature or a packet.SignatureV3 - either of them can give you the IssuerKeyId.
Does that help?

Axel

--
You received this message because you are subscribed to the Google Groups "golang-openpgp" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-openpg...@googlegroups.com.
To post to this group, send email to golang-...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-openpgp/97e23722-f922-4ad5-aea9-feb87a3ed6be%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

talala...@gmail.com

unread,
Jun 6, 2019, 8:19:15 AM6/6/19
to golang-openpgp
Hi,

Thank you for the quick response.

For the following signature file: http://archive.ubuntu.com/ubuntu/ubuntu/dists/xenial/Release.gpg

I get IssuerKeyId = 4654310438941296053

However, at the command-line with GPG, I get 40976EAF437D05B5

Is there some hashing algorithm that is used on IssuerKeyId or am I doing something wrong?

Regards,
Talal
To unsubscribe from this group and stop receiving emails from it, send an email to golang-...@googlegroups.com.

Axel Wagner

unread,
Jun 6, 2019, 8:36:00 AM6/6/19
to talala...@gmail.com, golang-openpgp
No, it's just that you are printing it in decimal and gpg prints it in hex :) It's the same number.

To unsubscribe from this group and stop receiving emails from it, send an email to golang-openpg...@googlegroups.com.

To post to this group, send email to golang-...@googlegroups.com.

talala...@gmail.com

unread,
Jun 6, 2019, 12:46:20 PM6/6/19
to golang-openpgp
That solves it. Thank you for the help, it is much appreciated :)
Reply all
Reply to author
Forward
0 new messages