Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add parsing and serializing interfaces for keyrings #275

Merged
merged 2 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading