Skip to content
Newer
Older
100644 629 lines (568 sloc) 17.5 KB
470549d @rsc go.crypto: initial code
rsc authored
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package openpgp
6
7 import (
8 "crypto/rsa"
326f0c5 crypto/openpgp: select newest valid encryption subkey
Keith Ball authored
9 "io"
10 "time"
11
a73c6bb @adg go.crypto: use golang.org/x/... import paths
adg authored
12 "golang.org/x/crypto/openpgp/armor"
13 "golang.org/x/crypto/openpgp/errors"
14 "golang.org/x/crypto/openpgp/packet"
470549d @rsc go.crypto: initial code
rsc authored
15 )
16
17 // PublicKeyType is the armor type for a PGP public key.
18 var PublicKeyType = "PGP PUBLIC KEY BLOCK"
19
20 // PrivateKeyType is the armor type for a PGP private key.
21 var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
22
23 // An Entity represents the components of an OpenPGP key: a primary public key
24 // (which must be a signing key), one or more identities claimed by that key,
25 // and zero or more subkeys, which may be encryption keys.
26 type Entity struct {
aa3adaf @agl go.crypto/openpgp: check for revoked keys.
agl authored
27 PrimaryKey *packet.PublicKey
28 PrivateKey *packet.PrivateKey
29 Identities map[string]*Identity // indexed by Identity.Name
30 Revocations []*packet.Signature
31 Subkeys []Subkey
470549d @rsc go.crypto: initial code
rsc authored
32 }
33
34 // An Identity represents an identity claimed by an Entity and zero or more
35 // assertions by other entities about that claim.
36 type Identity struct {
37 Name string // by convention, has the form "Full Name (comment) <email@example.com>"
38 UserId *packet.UserId
39 SelfSignature *packet.Signature
40 Signatures []*packet.Signature
41 }
42
43 // A Subkey is an additional public key in an Entity. Subkeys can be used for
44 // encryption.
45 type Subkey struct {
46 PublicKey *packet.PublicKey
47 PrivateKey *packet.PrivateKey
48 Sig *packet.Signature
49 }
50
51 // A Key identifies a specific public key in an Entity. This is either the
52 // Entity's primary key or a subkey.
53 type Key struct {
54 Entity *Entity
55 PublicKey *packet.PublicKey
56 PrivateKey *packet.PrivateKey
57 SelfSignature *packet.Signature
58 }
59
60 // A KeyRing provides access to public and private keys.
61 type KeyRing interface {
62 // KeysById returns the set of keys that have the given key id.
63 KeysById(id uint64) []Key
aa3adaf @agl go.crypto/openpgp: check for revoked keys.
agl authored
64 // KeysByIdAndUsage returns the set of keys with the given id
65 // that also meet the key usage given by requiredUsage.
66 // The requiredUsage is expressed as the bitwise-OR of
67 // packet.KeyFlag* values.
68 KeysByIdUsage(id uint64, requiredUsage byte) []Key
470549d @rsc go.crypto: initial code
rsc authored
69 // DecryptionKeys returns all private keys that are valid for
70 // decryption.
71 DecryptionKeys() []Key
72 }
73
74 // primaryIdentity returns the Identity marked as primary or the first identity
75 // if none are so marked.
76 func (e *Entity) primaryIdentity() *Identity {
77 var firstIdentity *Identity
78 for _, ident := range e.Identities {
79 if firstIdentity == nil {
80 firstIdentity = ident
81 }
82 if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
83 return ident
84 }
85 }
86 return firstIdentity
87 }
88
89 // encryptionKey returns the best candidate Key for encrypting a message to the
90 // given Entity.
eb19e22 @agl go.crypto/openpgp: don't select expired keys.
agl authored
91 func (e *Entity) encryptionKey(now time.Time) (Key, bool) {
470549d @rsc go.crypto: initial code
rsc authored
92 candidateSubkey := -1
93
326f0c5 crypto/openpgp: select newest valid encryption subkey
Keith Ball authored
94 // Iterate the keys to find the newest key
95 var maxTime time.Time
470549d @rsc go.crypto: initial code
rsc authored
96 for i, subkey := range e.Subkeys {
eb19e22 @agl go.crypto/openpgp: don't select expired keys.
agl authored
97 if subkey.Sig.FlagsValid &&
98 subkey.Sig.FlagEncryptCommunications &&
99 subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
326f0c5 crypto/openpgp: select newest valid encryption subkey
Keith Ball authored
100 !subkey.Sig.KeyExpired(now) &&
101 (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
470549d @rsc go.crypto: initial code
rsc authored
102 candidateSubkey = i
326f0c5 crypto/openpgp: select newest valid encryption subkey
Keith Ball authored
103 maxTime = subkey.Sig.CreationTime
470549d @rsc go.crypto: initial code
rsc authored
104 }
105 }
106
107 if candidateSubkey != -1 {
108 subkey := e.Subkeys[candidateSubkey]
eb19e22 @agl go.crypto/openpgp: don't select expired keys.
agl authored
109 return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true
110 }
111
112 // If we don't have any candidate subkeys for encryption and
113 // the primary key doesn't have any usage metadata then we
114 // assume that the primary key is ok. Or, if the primary key is
115 // marked as ok to encrypt to, then we can obviously use it.
116 i := e.primaryIdentity()
117 if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications &&
118 e.PrimaryKey.PubKeyAlgo.CanEncrypt() &&
119 !i.SelfSignature.KeyExpired(now) {
120 return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true
470549d @rsc go.crypto: initial code
rsc authored
121 }
122
123 // This Entity appears to be signing only.
eb19e22 @agl go.crypto/openpgp: don't select expired keys.
agl authored
124 return Key{}, false
470549d @rsc go.crypto: initial code
rsc authored
125 }
126
127 // signingKey return the best candidate Key for signing a message with this
128 // Entity.
eb19e22 @agl go.crypto/openpgp: don't select expired keys.
agl authored
129 func (e *Entity) signingKey(now time.Time) (Key, bool) {
470549d @rsc go.crypto: initial code
rsc authored
130 candidateSubkey := -1
131
132 for i, subkey := range e.Subkeys {
eb19e22 @agl go.crypto/openpgp: don't select expired keys.
agl authored
133 if subkey.Sig.FlagsValid &&
134 subkey.Sig.FlagSign &&
135 subkey.PublicKey.PubKeyAlgo.CanSign() &&
136 !subkey.Sig.KeyExpired(now) {
470549d @rsc go.crypto: initial code
rsc authored
137 candidateSubkey = i
138 break
139 }
140 }
141
eb19e22 @agl go.crypto/openpgp: don't select expired keys.
agl authored
142 if candidateSubkey != -1 {
143 subkey := e.Subkeys[candidateSubkey]
144 return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true
145 }
470549d @rsc go.crypto: initial code
rsc authored
146
147 // If we have no candidate subkey then we assume that it's ok to sign
148 // with the primary key.
eb19e22 @agl go.crypto/openpgp: don't select expired keys.
agl authored
149 i := e.primaryIdentity()
150 if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign &&
151 !i.SelfSignature.KeyExpired(now) {
152 return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true
470549d @rsc go.crypto: initial code
rsc authored
153 }
154
eb19e22 @agl go.crypto/openpgp: don't select expired keys.
agl authored
155 return Key{}, false
470549d @rsc go.crypto: initial code
rsc authored
156 }
157
158 // An EntityList contains one or more Entities.
159 type EntityList []*Entity
160
161 // KeysById returns the set of keys that have the given key id.
162 func (el EntityList) KeysById(id uint64) (keys []Key) {
163 for _, e := range el {
164 if e.PrimaryKey.KeyId == id {
165 var selfSig *packet.Signature
166 for _, ident := range e.Identities {
167 if selfSig == nil {
168 selfSig = ident.SelfSignature
169 } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
170 selfSig = ident.SelfSignature
171 break
172 }
173 }
174 keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig})
175 }
176
177 for _, subKey := range e.Subkeys {
178 if subKey.PublicKey.KeyId == id {
179 keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
180 }
181 }
182 }
183 return
184 }
185
aa3adaf @agl go.crypto/openpgp: check for revoked keys.
agl authored
186 // KeysByIdAndUsage returns the set of keys with the given id that also meet
187 // the key usage given by requiredUsage. The requiredUsage is expressed as
188 // the bitwise-OR of packet.KeyFlag* values.
189 func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) {
190 for _, key := range el.KeysById(id) {
191 if len(key.Entity.Revocations) > 0 {
192 continue
193 }
194
195 if key.SelfSignature.RevocationReason != nil {
196 continue
197 }
198
199 if key.SelfSignature.FlagsValid && requiredUsage != 0 {
200 var usage byte
201 if key.SelfSignature.FlagCertify {
202 usage |= packet.KeyFlagCertify
203 }
204 if key.SelfSignature.FlagSign {
205 usage |= packet.KeyFlagSign
206 }
207 if key.SelfSignature.FlagEncryptCommunications {
208 usage |= packet.KeyFlagEncryptCommunications
209 }
210 if key.SelfSignature.FlagEncryptStorage {
211 usage |= packet.KeyFlagEncryptStorage
212 }
213 if usage&requiredUsage != requiredUsage {
214 continue
215 }
216 }
217
218 keys = append(keys, key)
219 }
220 return
221 }
222
470549d @rsc go.crypto: initial code
rsc authored
223 // DecryptionKeys returns all private keys that are valid for decryption.
224 func (el EntityList) DecryptionKeys() (keys []Key) {
225 for _, e := range el {
226 for _, subKey := range e.Subkeys {
227 if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
228 keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
229 }
230 }
231 }
232 return
233 }
234
235 // ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
236 func ReadArmoredKeyRing(r io.Reader) (EntityList, error) {
237 block, err := armor.Decode(r)
238 if err == io.EOF {
239 return nil, errors.InvalidArgumentError("no armored data found")
240 }
241 if err != nil {
242 return nil, err
243 }
244 if block.Type != PublicKeyType && block.Type != PrivateKeyType {
245 return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type)
246 }
247
248 return ReadKeyRing(block.Body)
249 }
250
251 // ReadKeyRing reads one or more public/private keys. Unsupported keys are
252 // ignored as long as at least a single valid key is found.
253 func ReadKeyRing(r io.Reader) (el EntityList, err error) {
254 packets := packet.NewReader(r)
255 var lastUnsupportedError error
256
257 for {
258 var e *Entity
2da167f @cmars openpgp: improve parser resilience & flexibility, add PublicKey.BitLe…
cmars authored
259 e, err = ReadEntity(packets)
470549d @rsc go.crypto: initial code
rsc authored
260 if err != nil {
2da167f @cmars openpgp: improve parser resilience & flexibility, add PublicKey.BitLe…
cmars authored
261 // TODO: warn about skipped unsupported/unreadable keys
470549d @rsc go.crypto: initial code
rsc authored
262 if _, ok := err.(errors.UnsupportedError); ok {
263 lastUnsupportedError = err
264 err = readToNextPublicKey(packets)
2da167f @cmars openpgp: improve parser resilience & flexibility, add PublicKey.BitLe…
cmars authored
265 } else if _, ok := err.(errors.StructuralError); ok {
266 // Skip unreadable, badly-formatted keys
267 lastUnsupportedError = err
268 err = readToNextPublicKey(packets)
470549d @rsc go.crypto: initial code
rsc authored
269 }
270 if err == io.EOF {
271 err = nil
272 break
273 }
274 if err != nil {
275 el = nil
276 break
277 }
278 } else {
279 el = append(el, e)
280 }
281 }
282
283 if len(el) == 0 && err == nil {
284 err = lastUnsupportedError
285 }
286 return
287 }
288
289 // readToNextPublicKey reads packets until the start of the entity and leaves
290 // the first packet of the new entity in the Reader.
291 func readToNextPublicKey(packets *packet.Reader) (err error) {
292 var p packet.Packet
293 for {
294 p, err = packets.Next()
295 if err == io.EOF {
296 return
297 } else if err != nil {
298 if _, ok := err.(errors.UnsupportedError); ok {
299 err = nil
300 continue
301 }
302 return
303 }
304
305 if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey {
306 packets.Unread(p)
307 return
308 }
309 }
aa0f5b4 @agl go.crypto: revert 7f5a59ff6b43.
agl authored
310
311 panic("unreachable")
470549d @rsc go.crypto: initial code
rsc authored
312 }
313
2da167f @cmars openpgp: improve parser resilience & flexibility, add PublicKey.BitLe…
cmars authored
314 // ReadEntity reads an entity (public key, identities, subkeys etc) from the
470549d @rsc go.crypto: initial code
rsc authored
315 // given Reader.
2da167f @cmars openpgp: improve parser resilience & flexibility, add PublicKey.BitLe…
cmars authored
316 func ReadEntity(packets *packet.Reader) (*Entity, error) {
470549d @rsc go.crypto: initial code
rsc authored
317 e := new(Entity)
318 e.Identities = make(map[string]*Identity)
319
320 p, err := packets.Next()
321 if err != nil {
322 return nil, err
323 }
324
325 var ok bool
326 if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok {
327 if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok {
328 packets.Unread(p)
329 return nil, errors.StructuralError("first packet was not a public/private key")
330 } else {
331 e.PrimaryKey = &e.PrivateKey.PublicKey
332 }
333 }
334
335 if !e.PrimaryKey.PubKeyAlgo.CanSign() {
336 return nil, errors.StructuralError("primary key cannot be used for signatures")
337 }
338
339 var current *Identity
aa3adaf @agl go.crypto/openpgp: check for revoked keys.
agl authored
340 var revocations []*packet.Signature
470549d @rsc go.crypto: initial code
rsc authored
341 EachPacket:
342 for {
343 p, err := packets.Next()
344 if err == io.EOF {
345 break
346 } else if err != nil {
347 return nil, err
348 }
349
350 switch pkt := p.(type) {
351 case *packet.UserId:
352 current = new(Identity)
353 current.Name = pkt.Id
354 current.UserId = pkt
355 e.Identities[pkt.Id] = current
356
357 for {
358 p, err = packets.Next()
359 if err == io.EOF {
360 return nil, io.ErrUnexpectedEOF
361 } else if err != nil {
362 return nil, err
363 }
364
365 sig, ok := p.(*packet.Signature)
366 if !ok {
367 return nil, errors.StructuralError("user ID packet not followed by self-signature")
368 }
369
370 if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
84ca184 @agl go.crypto/openpgp: fix user id signing.
agl authored
371 if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil {
470549d @rsc go.crypto: initial code
rsc authored
372 return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error())
373 }
374 current.SelfSignature = sig
375 break
376 }
377 current.Signatures = append(current.Signatures, sig)
378 }
379 case *packet.Signature:
aa3adaf @agl go.crypto/openpgp: check for revoked keys.
agl authored
380 if pkt.SigType == packet.SigTypeKeyRevocation {
381 revocations = append(revocations, pkt)
382 } else if pkt.SigType == packet.SigTypeDirectSignature {
383 // TODO: RFC4880 5.2.1 permits signatures
384 // directly on keys (eg. to bind additional
385 // revocation keys).
386 } else if current == nil {
470549d @rsc go.crypto: initial code
rsc authored
387 return nil, errors.StructuralError("signature packet found before user id packet")
aa3adaf @agl go.crypto/openpgp: check for revoked keys.
agl authored
388 } else {
389 current.Signatures = append(current.Signatures, pkt)
470549d @rsc go.crypto: initial code
rsc authored
390 }
391 case *packet.PrivateKey:
392 if pkt.IsSubkey == false {
393 packets.Unread(p)
394 break EachPacket
395 }
396 err = addSubkey(e, packets, &pkt.PublicKey, pkt)
397 if err != nil {
398 return nil, err
399 }
400 case *packet.PublicKey:
401 if pkt.IsSubkey == false {
402 packets.Unread(p)
403 break EachPacket
404 }
405 err = addSubkey(e, packets, pkt, nil)
406 if err != nil {
407 return nil, err
408 }
409 default:
410 // we ignore unknown packets
411 }
412 }
413
414 if len(e.Identities) == 0 {
415 return nil, errors.StructuralError("entity without any identities")
416 }
417
aa3adaf @agl go.crypto/openpgp: check for revoked keys.
agl authored
418 for _, revocation := range revocations {
419 err = e.PrimaryKey.VerifyRevocationSignature(revocation)
420 if err == nil {
421 e.Revocations = append(e.Revocations, revocation)
422 } else {
423 // TODO: RFC 4880 5.2.3.15 defines revocation keys.
424 return nil, errors.StructuralError("revocation signature signed by alternate key")
425 }
426 }
427
470549d @rsc go.crypto: initial code
rsc authored
428 return e, nil
429 }
430
431 func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error {
432 var subKey Subkey
433 subKey.PublicKey = pub
434 subKey.PrivateKey = priv
435 p, err := packets.Next()
436 if err == io.EOF {
437 return io.ErrUnexpectedEOF
438 }
439 if err != nil {
440 return errors.StructuralError("subkey signature invalid: " + err.Error())
441 }
442 var ok bool
443 subKey.Sig, ok = p.(*packet.Signature)
444 if !ok {
445 return errors.StructuralError("subkey packet not followed by signature")
446 }
aa3adaf @agl go.crypto/openpgp: check for revoked keys.
agl authored
447 if subKey.Sig.SigType != packet.SigTypeSubkeyBinding && subKey.Sig.SigType != packet.SigTypeSubkeyRevocation {
470549d @rsc go.crypto: initial code
rsc authored
448 return errors.StructuralError("subkey signature with wrong type")
449 }
450 err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig)
451 if err != nil {
452 return errors.StructuralError("subkey signature invalid: " + err.Error())
453 }
454 e.Subkeys = append(e.Subkeys, subKey)
455 return nil
456 }
457
458 const defaultRSAKeyBits = 2048
459
460 // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
461 // single identity composed of the given full name, comment and email, any of
462 // which may be empty but must not contain any of "()<>\x00".
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
463 // If config is nil, sensible defaults will be used.
464 func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
465 currentTime := config.Now()
466
470549d @rsc go.crypto: initial code
rsc authored
467 uid := packet.NewUserId(name, comment, email)
468 if uid == nil {
469 return nil, errors.InvalidArgumentError("user id field contained invalid characters")
470 }
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
471 signingPriv, err := rsa.GenerateKey(config.Random(), defaultRSAKeyBits)
470549d @rsc go.crypto: initial code
rsc authored
472 if err != nil {
473 return nil, err
474 }
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
475 encryptingPriv, err := rsa.GenerateKey(config.Random(), defaultRSAKeyBits)
470549d @rsc go.crypto: initial code
rsc authored
476 if err != nil {
477 return nil, err
478 }
479
480 e := &Entity{
481 PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey),
482 PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv),
483 Identities: make(map[string]*Identity),
484 }
485 isPrimaryId := true
486 e.Identities[uid.Id] = &Identity{
487 Name: uid.Name,
488 UserId: uid,
489 SelfSignature: &packet.Signature{
490 CreationTime: currentTime,
491 SigType: packet.SigTypePositiveCert,
492 PubKeyAlgo: packet.PubKeyAlgoRSA,
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
493 Hash: config.Hash(),
470549d @rsc go.crypto: initial code
rsc authored
494 IsPrimaryId: &isPrimaryId,
495 FlagsValid: true,
496 FlagSign: true,
497 FlagCertify: true,
498 IssuerKeyId: &e.PrimaryKey.KeyId,
499 },
500 }
501
502 e.Subkeys = make([]Subkey, 1)
503 e.Subkeys[0] = Subkey{
504 PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey),
505 PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv),
506 Sig: &packet.Signature{
507 CreationTime: currentTime,
508 SigType: packet.SigTypeSubkeyBinding,
509 PubKeyAlgo: packet.PubKeyAlgoRSA,
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
510 Hash: config.Hash(),
470549d @rsc go.crypto: initial code
rsc authored
511 FlagsValid: true,
512 FlagEncryptStorage: true,
513 FlagEncryptCommunications: true,
514 IssuerKeyId: &e.PrimaryKey.KeyId,
515 },
516 }
517 e.Subkeys[0].PublicKey.IsSubkey = true
518 e.Subkeys[0].PrivateKey.IsSubkey = true
519
520 return e, nil
521 }
522
523 // SerializePrivate serializes an Entity, including private key material, to
524 // the given Writer. For now, it must only be used on an Entity returned from
525 // NewEntity.
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
526 // If config is nil, sensible defaults will be used.
527 func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) {
470549d @rsc go.crypto: initial code
rsc authored
528 err = e.PrivateKey.Serialize(w)
529 if err != nil {
530 return
531 }
532 for _, ident := range e.Identities {
533 err = ident.UserId.Serialize(w)
534 if err != nil {
535 return
536 }
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
537 err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config)
470549d @rsc go.crypto: initial code
rsc authored
538 if err != nil {
539 return
540 }
541 err = ident.SelfSignature.Serialize(w)
542 if err != nil {
543 return
544 }
545 }
546 for _, subkey := range e.Subkeys {
547 err = subkey.PrivateKey.Serialize(w)
548 if err != nil {
549 return
550 }
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
551 err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
470549d @rsc go.crypto: initial code
rsc authored
552 if err != nil {
553 return
554 }
555 err = subkey.Sig.Serialize(w)
556 if err != nil {
557 return
558 }
559 }
560 return nil
561 }
562
563 // Serialize writes the public part of the given Entity to w. (No private
564 // key material will be output).
565 func (e *Entity) Serialize(w io.Writer) error {
566 err := e.PrimaryKey.Serialize(w)
567 if err != nil {
568 return err
569 }
570 for _, ident := range e.Identities {
571 err = ident.UserId.Serialize(w)
572 if err != nil {
573 return err
574 }
575 err = ident.SelfSignature.Serialize(w)
576 if err != nil {
577 return err
578 }
579 for _, sig := range ident.Signatures {
580 err = sig.Serialize(w)
581 if err != nil {
582 return err
583 }
584 }
585 }
586 for _, subkey := range e.Subkeys {
587 err = subkey.PublicKey.Serialize(w)
588 if err != nil {
589 return err
590 }
591 err = subkey.Sig.Serialize(w)
592 if err != nil {
593 return err
594 }
595 }
596 return nil
597 }
598
599 // SignIdentity adds a signature to e, from signer, attesting that identity is
600 // associated with e. The provided identity must already be an element of
601 // e.Identities and the private key of signer must have been decrypted if
602 // necessary.
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
603 // If config is nil, sensible defaults will be used.
604 func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error {
470549d @rsc go.crypto: initial code
rsc authored
605 if signer.PrivateKey == nil {
606 return errors.InvalidArgumentError("signing Entity must have a private key")
607 }
608 if signer.PrivateKey.Encrypted {
609 return errors.InvalidArgumentError("signing Entity's private key must be decrypted")
610 }
611 ident, ok := e.Identities[identity]
612 if !ok {
613 return errors.InvalidArgumentError("given identity string not found in Entity")
614 }
615
616 sig := &packet.Signature{
617 SigType: packet.SigTypeGenericCert,
618 PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
54eafe1 @agl openpgp: eliminate implicit rand.Reader and time.Now
agl authored
619 Hash: config.Hash(),
620 CreationTime: config.Now(),
470549d @rsc go.crypto: initial code
rsc authored
621 IssuerKeyId: &signer.PrivateKey.KeyId,
622 }
84ca184 @agl go.crypto/openpgp: fix user id signing.
agl authored
623 if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil {
470549d @rsc go.crypto: initial code
rsc authored
624 return err
625 }
626 ident.Signatures = append(ident.Signatures, sig)
627 return nil
628 }
Something went wrong with that request. Please try again.