Skip to content

x/crypto/openpgp: silently fail to read keyring when smartcard stub is present #9312

@jvehent

Description

@jvehent

When a GPG secring contains a smartcard stub, the openpgp package fails to read the keyring correctly and does not return an error. A call to openpgp.ReadKeyRing() will returns the entities that precedes the stub, excluding the entity located right before the stub.

For example, if a secring contains 3 entities and the smartcard stub is in position 3, then openpgp.ReadKeyRing() will only return the first entity. The second entity and the stub are ignored. No error is returned.

Steps to reproduce:

1. Create a keyring with two regular 1024 bits RSA keys

$ mkdir /tmp/testgolangopenpgp
$ gpg --batch --no-default-keyring --keyring /tmp/testgolangopenpgp/pubring.gpg --secret-keyring /tmp/testgolangopenpgp/secring.gpg --gen-key << EOF
> Key-Type: 1
> Key-Length: 1024
> Subkey-Type: 1
> Subkey-Length: 1024
> Name-Real: test key 1
> Name-Email: testkey1@example.net
> Expire-Date: 12m
> EOF
gpg: keyring `/tmp/testgolangopenpgp/secring.gpg' created
gpg: keyring `/tmp/testgolangopenpgp/pubring.gpg' created
..+++++
...+++++
.....+++++
..+++++
gpg: key 4BACAA9F marked as ultimately trusted
$ gpg --batch --no-default-keyring --keyring /tmp/testgolangopenpgp/pubring.gpg --secret-keyring /tmp/testgolangopenpgp/secring.gpg --gen-key << EOF
> Key-Type: 1
> Key-Length: 1024
> Subkey-Type: 1
> Subkey-Length: 1024
> Name-Real: test key 2
> Name-Email: testkey2@example.net
> Expire-Date: 12m
> EOF
.+++++
.+++++
+++++
+++++
gpg: key 56CE5F62 marked as ultimately trusted

2. Import a smartcard stub from a yubikey into the keyring

$ gpg --no-default-keyring --keyring /tmp/testgolangopenpgp/pubring.gpg --secret-keyring /tmp/testgolangopenpgp/secring.gpg --allow-secret-key-import --import yubikeystub yubikeytest1_stub.asc 
gpg: key 4FB5544F: already in secret keyring
gpg: key 59BEDBFC: already in secret keyring
gpg: Total number processed: 2
gpg:       secret keys read: 2
gpg:  secret keys unchanged: 2

/tmp/testgolangopenpgp/secring.gpg
----------------------------------
sec   1024R/4BACAA9F 2014-12-14 [expires: 2015-12-09]
uid                  test key 1 <testkey1@example.net>
ssb   1024R/AEC9CD3A 2014-12-14

sec   1024R/56CE5F62 2014-12-14 [expires: 2015-12-09]
uid                  test key 2 <testkey2@example.net>
ssb   1024R/A1E03C73 2014-12-14

sec>  2048R/59BEDBFC 2014-12-14 [expires: 2015-12-09]
      Card serial no. = 0000 00000001
uid                  Yubikey Smartcard test1 <yubikeytest1@example.net>
ssb>  2048R/9B633300 2014-12-14
ssb>  2048R/A8DE1BB7 2014-12-14

3. Attempt to read the entities in the keyring. Only the first entity is returned.

$ go run readkeyring.go 
found 1 entities in keyring
reading entity with fingerprint 2FA49C2800342153CA439C90ADC366D34BACAA9F

source code:

package main

import (
    "code.google.com/p/go.crypto/openpgp"
    "encoding/hex"
    "fmt"
    "os"
    "strings"
)

func main() {
    secringFile, err := os.Open("/tmp/testgolangopenpgp/secring.gpg")
    if err != nil {
        panic(err)
    }
    defer secringFile.Close()
    keyring, err := openpgp.ReadKeyRing(secringFile)
    if err != nil {
        err = fmt.Errorf("Keyring access failed: '%v'", err)
        panic(err)
    }
    fmt.Printf("found %d entities in keyring\n", len(keyring))
    for _, entity := range keyring {
        fingerprint := strings.ToUpper(hex.EncodeToString(entity.PrimaryKey.Fingerprint[:]))
        fmt.Println("reading entity with fingerprint", fingerprint)
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions