Skip to content

Commit

Permalink
Add parsing and serializing interfaces for keyrings (#275)
Browse files Browse the repository at this point in the history
* Add parsing and serializing interfaces for keyrings

* Make error check more compact
  • Loading branch information
wussler committed Apr 8, 2024
1 parent 453e819 commit 0d1ce13
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 0 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added
- API to serialize KeyRings to binary data:
```go
func (keyRing *KeyRing) Serialize() ([]byte, error)
```
- API to parse KeyRings from binary data:
```go
func NewKeyRingFromBinary(binKeys []byte) (*KeyRing, error)
```

## [2.7.5] 2023-31-01

### Added
Expand Down
42 changes: 42 additions & 0 deletions crypto/keyring.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,29 @@ func (keyRing *KeyRing) AddKey(key *Key) error {
return nil
}

// NewKeyRingFromBinary creates a new keyring with all the keys contained in the unarmored binary data.
// Note that it accepts only unlocked or public keys, as KeyRing cannot contain locked keys.
func NewKeyRingFromBinary(binKeys []byte) (*KeyRing, error) {
entities, err := openpgp.ReadKeyRing(bytes.NewReader(binKeys))
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in reading keyring")
}

keyring := &KeyRing{}
for _, entity := range entities {
key, err := NewKeyFromEntity(entity)
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in reading keyring")
}

if err = keyring.AddKey(key); err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in reading keyring")
}
}

return keyring, nil
}

// --- Extract keys from keyring

// GetKeys returns openpgp keys contained in this KeyRing.
Expand Down Expand Up @@ -88,6 +111,25 @@ func (keyRing *KeyRing) getSigningEntity() (*openpgp.Entity, error) {
return signEntity, nil
}

// Serialize serializes a KeyRing to binary data.
func (keyRing *KeyRing) Serialize() ([]byte, error) {
var buffer bytes.Buffer

for _, entity := range keyRing.entities {
var err error
if entity.PrivateKey == nil {
err = entity.Serialize(&buffer)
} else {
err = entity.SerializePrivateWithoutSigning(&buffer, nil)
}
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in serializing keyring")
}
}

return buffer.Bytes(), nil
}

// --- Extract info from key

// CountEntities returns the number of entities in the keyring.
Expand Down
15 changes: 15 additions & 0 deletions crypto/keyring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,21 @@ func TestMultipleKeyRing(t *testing.T) {
assert.Exactly(t, 1, singleKeyRing.CountDecryptionEntities())
}

func TestSerializeParse(t *testing.T) {
serialized, err := keyRingTestMultiple.Serialize()
assert.Nil(t, err)

parsed, err := NewKeyRingFromBinary(serialized)
assert.Nil(t, err)

assert.Exactly(t, 3, len(parsed.GetKeys()))
for i, parsedKey := range parsed.GetKeys() {
expectedKey, err := keyRingTestMultiple.GetKey(i)
assert.Nil(t, err)
assert.Exactly(t, parsedKey.GetFingerprint(), expectedKey.GetFingerprint())
}
}

func TestClearPrivateKey(t *testing.T) {
keyRingCopy, err := keyRingTestMultiple.Copy()
if err != nil {
Expand Down

0 comments on commit 0d1ce13

Please sign in to comment.