Skip to content

Commit 0d1ce13

Browse files
authored
Add parsing and serializing interfaces for keyrings (#275)
* Add parsing and serializing interfaces for keyrings * Make error check more compact
1 parent 453e819 commit 0d1ce13

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## Unreleased
8+
9+
### Added
10+
- API to serialize KeyRings to binary data:
11+
```go
12+
func (keyRing *KeyRing) Serialize() ([]byte, error)
13+
```
14+
- API to parse KeyRings from binary data:
15+
```go
16+
func NewKeyRingFromBinary(binKeys []byte) (*KeyRing, error)
17+
```
18+
719
## [2.7.5] 2023-31-01
820

921
### Added

crypto/keyring.go

+42
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,29 @@ func (keyRing *KeyRing) AddKey(key *Key) error {
4949
return nil
5050
}
5151

52+
// NewKeyRingFromBinary creates a new keyring with all the keys contained in the unarmored binary data.
53+
// Note that it accepts only unlocked or public keys, as KeyRing cannot contain locked keys.
54+
func NewKeyRingFromBinary(binKeys []byte) (*KeyRing, error) {
55+
entities, err := openpgp.ReadKeyRing(bytes.NewReader(binKeys))
56+
if err != nil {
57+
return nil, errors.Wrap(err, "gopenpgp: error in reading keyring")
58+
}
59+
60+
keyring := &KeyRing{}
61+
for _, entity := range entities {
62+
key, err := NewKeyFromEntity(entity)
63+
if err != nil {
64+
return nil, errors.Wrap(err, "gopenpgp: error in reading keyring")
65+
}
66+
67+
if err = keyring.AddKey(key); err != nil {
68+
return nil, errors.Wrap(err, "gopenpgp: error in reading keyring")
69+
}
70+
}
71+
72+
return keyring, nil
73+
}
74+
5275
// --- Extract keys from keyring
5376

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

114+
// Serialize serializes a KeyRing to binary data.
115+
func (keyRing *KeyRing) Serialize() ([]byte, error) {
116+
var buffer bytes.Buffer
117+
118+
for _, entity := range keyRing.entities {
119+
var err error
120+
if entity.PrivateKey == nil {
121+
err = entity.Serialize(&buffer)
122+
} else {
123+
err = entity.SerializePrivateWithoutSigning(&buffer, nil)
124+
}
125+
if err != nil {
126+
return nil, errors.Wrap(err, "gopenpgp: error in serializing keyring")
127+
}
128+
}
129+
130+
return buffer.Bytes(), nil
131+
}
132+
91133
// --- Extract info from key
92134

93135
// CountEntities returns the number of entities in the keyring.

crypto/keyring_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,21 @@ func TestMultipleKeyRing(t *testing.T) {
148148
assert.Exactly(t, 1, singleKeyRing.CountDecryptionEntities())
149149
}
150150

151+
func TestSerializeParse(t *testing.T) {
152+
serialized, err := keyRingTestMultiple.Serialize()
153+
assert.Nil(t, err)
154+
155+
parsed, err := NewKeyRingFromBinary(serialized)
156+
assert.Nil(t, err)
157+
158+
assert.Exactly(t, 3, len(parsed.GetKeys()))
159+
for i, parsedKey := range parsed.GetKeys() {
160+
expectedKey, err := keyRingTestMultiple.GetKey(i)
161+
assert.Nil(t, err)
162+
assert.Exactly(t, parsedKey.GetFingerprint(), expectedKey.GetFingerprint())
163+
}
164+
}
165+
151166
func TestClearPrivateKey(t *testing.T) {
152167
keyRingCopy, err := keyRingTestMultiple.Copy()
153168
if err != nil {

0 commit comments

Comments
 (0)