1

I'm developing an API using Golang, and I have a JSON file keys.json as follows:

{
  "publicKeys": {
    "Flex": "<valid pgp public key>",
    "Flex2": "<valid pgp public key>"
  },
  "privateKey": "<valid pgp private key>"
}

To unmarshal this, I have the following model

type PGPKeys struct {
    PublicKeys map[string]string `json:"publicKeys"`
    PrivateKey string            `json:"privateKey"`
}

and I unmarshal the code using

keysJSONFile, err := os.Open(keysPath)
    if keysJSONFile != nil {
        defer keysJSONFile.Close()
    }
    if err != nil {
        return nil, err
    }

    keysJSONBytes, err := ioutil.ReadAll(keysJSONFile)
    if err != nil {
        return nil, err
    }

    var pgpKeys PGPKeys
    err = json.Unmarshal(keysJSONBytes, &pgpKeys)
    if err != nil {
        return nil, err
    }

Later, when I use openpgp to get the public key packet, I am met with EOF error which armor.Decode returns when it's unable to find any blocks -- but I'm not sure why it's happening

func GetPublicKeyPacket(publicKey []byte) (*packet.PublicKey, error) {
    publicKeyReader := bytes.NewReader(publicKey)
    block, err := armor.Decode(publicKeyReader)
    if err != nil {
        return nil, err
    }

    if block.Type != openpgp.PublicKeyType {
        return nil, errors.New("Invalid public key data")
    }

    packetReader := packet.NewReader(block.Body)
    pkt, err := packetReader.Next()
    if err != nil {
        return nil, err
    }

    key, ok := pkt.(*packet.PublicKey)
    if !ok {
        return nil, err
    }
    return key, nil
}

NOTE: When I call the function, I do type conversion using something like

publicKeyPacket, err := pgp.GetPublicKeyPacket([]byte(h.PGPKeys.PublicKeys[h.Config.PGPIdentifier]))

Finally, I have tried moving the keys into individual TXT files and that works but for some reason having them in JSON does not

Haardik
  • 187
  • 1
  • 13

1 Answers1

1

I found a solution to this while randomly trying stuff, and I am as surprised as you (future answer reader) are. If someone can provide an explanation, I'd be thankful.

I was storing the keys in JSON by replacing all newlines with "\n" so that I can store it in a single line. You know how PGP keys have an empty line right after -----BEGIN PGP PUBLIC KEY BLOCK-----? Well, in my file, I had something like

"publicKeys": {
    "Flex": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nQfdsf...."
}

Adding that extra empty line, i.e. changing it to

"publicKeys": {
    "Flex": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nQfdsf...."
}

EDIT: As @Adrian mentioned in the comments, this was because it's an invalid PGP key if the line isn't there anymore according to the RFC spec. This is how it should be.

Haardik
  • 187
  • 1
  • 13
  • The "somehow" would be: making the value you provide conform to the format expected for a key. – Adrian Mar 20 '19 at 13:29
  • But I do type conversion. Also when it reads from json it still reads as text. – Haardik Mar 20 '19 at 14:32
  • 1
    I'm not saying it's not the right variable type or that it isn't text. The format expected for a key includes two newlines after the header, you had one. Your answer says the change "fixed it somehow" as if it were a mystery, but in fact you've just corrected your input data to match the specified format for that data. You can find more information on the expected data format in [RFC4880, Section 7](https://tools.ietf.org/html/rfc4880#section-7). – Adrian Mar 20 '19 at 15:57
  • I see, thanks a lot for clearing that up. It never occurred to me that not having the extra line could invalidate the entire key. – Haardik Mar 20 '19 at 22:48