main
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
5package openpgp
6
7import (
8 "crypto"
9 "crypto/rand"
10 "crypto/rsa"
11 goerrors "errors"
12 "io"
13 "math/big"
14 "time"
15
16 "github.com/ProtonMail/go-crypto/openpgp/ecdh"
17 "github.com/ProtonMail/go-crypto/openpgp/ecdsa"
18 "github.com/ProtonMail/go-crypto/openpgp/ed25519"
19 "github.com/ProtonMail/go-crypto/openpgp/ed448"
20 "github.com/ProtonMail/go-crypto/openpgp/eddsa"
21 "github.com/ProtonMail/go-crypto/openpgp/errors"
22 "github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
23 "github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
24 "github.com/ProtonMail/go-crypto/openpgp/packet"
25 "github.com/ProtonMail/go-crypto/openpgp/x25519"
26 "github.com/ProtonMail/go-crypto/openpgp/x448"
27)
28
29// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
30// single identity composed of the given full name, comment and email, any of
31// which may be empty but must not contain any of "()<>\x00".
32// If config is nil, sensible defaults will be used.
33func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
34 creationTime := config.Now()
35 keyLifetimeSecs := config.KeyLifetime()
36
37 // Generate a primary signing key
38 primaryPrivRaw, err := newSigner(config)
39 if err != nil {
40 return nil, err
41 }
42 primary := packet.NewSignerPrivateKey(creationTime, primaryPrivRaw)
43 if config.V6() {
44 if err := primary.UpgradeToV6(); err != nil {
45 return nil, err
46 }
47 }
48
49 e := &Entity{
50 PrimaryKey: &primary.PublicKey,
51 PrivateKey: primary,
52 Identities: make(map[string]*Identity),
53 Subkeys: []Subkey{},
54 Signatures: []*packet.Signature{},
55 }
56
57 if config.V6() {
58 // In v6 keys algorithm preferences should be stored in direct key signatures
59 selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypeDirectSignature, config)
60 err = writeKeyProperties(selfSignature, creationTime, keyLifetimeSecs, config)
61 if err != nil {
62 return nil, err
63 }
64 err = selfSignature.SignDirectKeyBinding(&primary.PublicKey, primary, config)
65 if err != nil {
66 return nil, err
67 }
68 e.Signatures = append(e.Signatures, selfSignature)
69 e.SelfSignature = selfSignature
70 }
71
72 err = e.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs, !config.V6())
73 if err != nil {
74 return nil, err
75 }
76
77 // NOTE: No key expiry here, but we will not return this subkey in EncryptionKey()
78 // if the primary/master key has expired.
79 err = e.addEncryptionSubkey(config, creationTime, 0)
80 if err != nil {
81 return nil, err
82 }
83
84 return e, nil
85}
86
87func (t *Entity) AddUserId(name, comment, email string, config *packet.Config) error {
88 creationTime := config.Now()
89 keyLifetimeSecs := config.KeyLifetime()
90 return t.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs, !config.V6())
91}
92
93func writeKeyProperties(selfSignature *packet.Signature, creationTime time.Time, keyLifetimeSecs uint32, config *packet.Config) error {
94 advertiseAead := config.AEAD() != nil
95
96 selfSignature.CreationTime = creationTime
97 selfSignature.KeyLifetimeSecs = &keyLifetimeSecs
98 selfSignature.FlagsValid = true
99 selfSignature.FlagSign = true
100 selfSignature.FlagCertify = true
101 selfSignature.SEIPDv1 = true // true by default, see 5.8 vs. 5.14
102 selfSignature.SEIPDv2 = advertiseAead
103
104 // Set the PreferredHash for the SelfSignature from the packet.Config.
105 // If it is not the must-implement algorithm from rfc4880bis, append that.
106 hash, ok := algorithm.HashToHashId(config.Hash())
107 if !ok {
108 return errors.UnsupportedError("unsupported preferred hash function")
109 }
110
111 selfSignature.PreferredHash = []uint8{hash}
112 if config.Hash() != crypto.SHA256 {
113 selfSignature.PreferredHash = append(selfSignature.PreferredHash, hashToHashId(crypto.SHA256))
114 }
115
116 // Likewise for DefaultCipher.
117 selfSignature.PreferredSymmetric = []uint8{uint8(config.Cipher())}
118 if config.Cipher() != packet.CipherAES128 {
119 selfSignature.PreferredSymmetric = append(selfSignature.PreferredSymmetric, uint8(packet.CipherAES128))
120 }
121
122 // We set CompressionNone as the preferred compression algorithm because
123 // of compression side channel attacks, then append the configured
124 // DefaultCompressionAlgo if any is set (to signal support for cases
125 // where the application knows that using compression is safe).
126 selfSignature.PreferredCompression = []uint8{uint8(packet.CompressionNone)}
127 if config.Compression() != packet.CompressionNone {
128 selfSignature.PreferredCompression = append(selfSignature.PreferredCompression, uint8(config.Compression()))
129 }
130
131 if advertiseAead {
132 // Get the preferred AEAD mode from the packet.Config.
133 // If it is not the must-implement algorithm from rfc9580, append that.
134 modes := []uint8{uint8(config.AEAD().Mode())}
135 if config.AEAD().Mode() != packet.AEADModeOCB {
136 modes = append(modes, uint8(packet.AEADModeOCB))
137 }
138
139 // For preferred (AES256, GCM), we'll generate (AES256, GCM), (AES256, OCB), (AES128, GCM), (AES128, OCB)
140 for _, cipher := range selfSignature.PreferredSymmetric {
141 for _, mode := range modes {
142 selfSignature.PreferredCipherSuites = append(selfSignature.PreferredCipherSuites, [2]uint8{cipher, mode})
143 }
144 }
145 }
146 return nil
147}
148
149func (t *Entity) addUserId(name, comment, email string, config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32, writeProperties bool) error {
150 uid := packet.NewUserId(name, comment, email)
151 if uid == nil {
152 return errors.InvalidArgumentError("user id field contained invalid characters")
153 }
154
155 if _, ok := t.Identities[uid.Id]; ok {
156 return errors.InvalidArgumentError("user id exist")
157 }
158
159 primary := t.PrivateKey
160 isPrimaryId := len(t.Identities) == 0
161 selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypePositiveCert, config)
162 if writeProperties {
163 err := writeKeyProperties(selfSignature, creationTime, keyLifetimeSecs, config)
164 if err != nil {
165 return err
166 }
167 }
168 selfSignature.IsPrimaryId = &isPrimaryId
169
170 // User ID binding signature
171 err := selfSignature.SignUserId(uid.Id, &primary.PublicKey, primary, config)
172 if err != nil {
173 return err
174 }
175 t.Identities[uid.Id] = &Identity{
176 Name: uid.Id,
177 UserId: uid,
178 SelfSignature: selfSignature,
179 Signatures: []*packet.Signature{selfSignature},
180 }
181 return nil
182}
183
184// AddSigningSubkey adds a signing keypair as a subkey to the Entity.
185// If config is nil, sensible defaults will be used.
186func (e *Entity) AddSigningSubkey(config *packet.Config) error {
187 creationTime := config.Now()
188 keyLifetimeSecs := config.KeyLifetime()
189
190 subPrivRaw, err := newSigner(config)
191 if err != nil {
192 return err
193 }
194 sub := packet.NewSignerPrivateKey(creationTime, subPrivRaw)
195 sub.IsSubkey = true
196 if config.V6() {
197 if err := sub.UpgradeToV6(); err != nil {
198 return err
199 }
200 }
201
202 subkey := Subkey{
203 PublicKey: &sub.PublicKey,
204 PrivateKey: sub,
205 }
206 subkey.Sig = createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyBinding, config)
207 subkey.Sig.CreationTime = creationTime
208 subkey.Sig.KeyLifetimeSecs = &keyLifetimeSecs
209 subkey.Sig.FlagsValid = true
210 subkey.Sig.FlagSign = true
211 subkey.Sig.EmbeddedSignature = createSignaturePacket(subkey.PublicKey, packet.SigTypePrimaryKeyBinding, config)
212 subkey.Sig.EmbeddedSignature.CreationTime = creationTime
213
214 err = subkey.Sig.EmbeddedSignature.CrossSignKey(subkey.PublicKey, e.PrimaryKey, subkey.PrivateKey, config)
215 if err != nil {
216 return err
217 }
218
219 err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
220 if err != nil {
221 return err
222 }
223
224 e.Subkeys = append(e.Subkeys, subkey)
225 return nil
226}
227
228// AddEncryptionSubkey adds an encryption keypair as a subkey to the Entity.
229// If config is nil, sensible defaults will be used.
230func (e *Entity) AddEncryptionSubkey(config *packet.Config) error {
231 creationTime := config.Now()
232 keyLifetimeSecs := config.KeyLifetime()
233 return e.addEncryptionSubkey(config, creationTime, keyLifetimeSecs)
234}
235
236func (e *Entity) addEncryptionSubkey(config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32) error {
237 subPrivRaw, err := newDecrypter(config)
238 if err != nil {
239 return err
240 }
241 sub := packet.NewDecrypterPrivateKey(creationTime, subPrivRaw)
242 sub.IsSubkey = true
243 if config.V6() {
244 if err := sub.UpgradeToV6(); err != nil {
245 return err
246 }
247 }
248
249 subkey := Subkey{
250 PublicKey: &sub.PublicKey,
251 PrivateKey: sub,
252 }
253 subkey.Sig = createSignaturePacket(e.PrimaryKey, packet.SigTypeSubkeyBinding, config)
254 subkey.Sig.CreationTime = creationTime
255 subkey.Sig.KeyLifetimeSecs = &keyLifetimeSecs
256 subkey.Sig.FlagsValid = true
257 subkey.Sig.FlagEncryptStorage = true
258 subkey.Sig.FlagEncryptCommunications = true
259
260 err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
261 if err != nil {
262 return err
263 }
264
265 e.Subkeys = append(e.Subkeys, subkey)
266 return nil
267}
268
269// Generates a signing key
270func newSigner(config *packet.Config) (signer interface{}, err error) {
271 switch config.PublicKeyAlgorithm() {
272 case packet.PubKeyAlgoRSA:
273 bits := config.RSAModulusBits()
274 if bits < 1024 {
275 return nil, errors.InvalidArgumentError("bits must be >= 1024")
276 }
277 if config != nil && len(config.RSAPrimes) >= 2 {
278 primes := config.RSAPrimes[0:2]
279 config.RSAPrimes = config.RSAPrimes[2:]
280 return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes)
281 }
282 return rsa.GenerateKey(config.Random(), bits)
283 case packet.PubKeyAlgoEdDSA:
284 if config.V6() {
285 // Implementations MUST NOT accept or generate v6 key material
286 // using the deprecated OIDs.
287 return nil, errors.InvalidArgumentError("EdDSALegacy cannot be used for v6 keys")
288 }
289 curve := ecc.FindEdDSAByGenName(string(config.CurveName()))
290 if curve == nil {
291 return nil, errors.InvalidArgumentError("unsupported curve")
292 }
293
294 priv, err := eddsa.GenerateKey(config.Random(), curve)
295 if err != nil {
296 return nil, err
297 }
298 return priv, nil
299 case packet.PubKeyAlgoECDSA:
300 curve := ecc.FindECDSAByGenName(string(config.CurveName()))
301 if curve == nil {
302 return nil, errors.InvalidArgumentError("unsupported curve")
303 }
304
305 priv, err := ecdsa.GenerateKey(config.Random(), curve)
306 if err != nil {
307 return nil, err
308 }
309 return priv, nil
310 case packet.PubKeyAlgoEd25519:
311 priv, err := ed25519.GenerateKey(config.Random())
312 if err != nil {
313 return nil, err
314 }
315 return priv, nil
316 case packet.PubKeyAlgoEd448:
317 priv, err := ed448.GenerateKey(config.Random())
318 if err != nil {
319 return nil, err
320 }
321 return priv, nil
322 default:
323 return nil, errors.InvalidArgumentError("unsupported public key algorithm")
324 }
325}
326
327// Generates an encryption/decryption key
328func newDecrypter(config *packet.Config) (decrypter interface{}, err error) {
329 switch config.PublicKeyAlgorithm() {
330 case packet.PubKeyAlgoRSA:
331 bits := config.RSAModulusBits()
332 if bits < 1024 {
333 return nil, errors.InvalidArgumentError("bits must be >= 1024")
334 }
335 if config != nil && len(config.RSAPrimes) >= 2 {
336 primes := config.RSAPrimes[0:2]
337 config.RSAPrimes = config.RSAPrimes[2:]
338 return generateRSAKeyWithPrimes(config.Random(), 2, bits, primes)
339 }
340 return rsa.GenerateKey(config.Random(), bits)
341 case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA:
342 fallthrough // When passing EdDSA or ECDSA, we generate an ECDH subkey
343 case packet.PubKeyAlgoECDH:
344 if config.V6() &&
345 (config.CurveName() == packet.Curve25519 ||
346 config.CurveName() == packet.Curve448) {
347 // Implementations MUST NOT accept or generate v6 key material
348 // using the deprecated OIDs.
349 return nil, errors.InvalidArgumentError("ECDH with Curve25519/448 legacy cannot be used for v6 keys")
350 }
351 var kdf = ecdh.KDF{
352 Hash: algorithm.SHA512,
353 Cipher: algorithm.AES256,
354 }
355 curve := ecc.FindECDHByGenName(string(config.CurveName()))
356 if curve == nil {
357 return nil, errors.InvalidArgumentError("unsupported curve")
358 }
359 return ecdh.GenerateKey(config.Random(), curve, kdf)
360 case packet.PubKeyAlgoEd25519, packet.PubKeyAlgoX25519: // When passing Ed25519, we generate an x25519 subkey
361 return x25519.GenerateKey(config.Random())
362 case packet.PubKeyAlgoEd448, packet.PubKeyAlgoX448: // When passing Ed448, we generate an x448 subkey
363 return x448.GenerateKey(config.Random())
364 default:
365 return nil, errors.InvalidArgumentError("unsupported public key algorithm")
366 }
367}
368
369var bigOne = big.NewInt(1)
370
371// generateRSAKeyWithPrimes generates a multi-prime RSA keypair of the
372// given bit size, using the given random source and pre-populated primes.
373func generateRSAKeyWithPrimes(random io.Reader, nprimes int, bits int, prepopulatedPrimes []*big.Int) (*rsa.PrivateKey, error) {
374 priv := new(rsa.PrivateKey)
375 priv.E = 65537
376
377 if nprimes < 2 {
378 return nil, goerrors.New("generateRSAKeyWithPrimes: nprimes must be >= 2")
379 }
380
381 if bits < 1024 {
382 return nil, goerrors.New("generateRSAKeyWithPrimes: bits must be >= 1024")
383 }
384
385 primes := make([]*big.Int, nprimes)
386
387NextSetOfPrimes:
388 for {
389 todo := bits
390 // crypto/rand should set the top two bits in each prime.
391 // Thus each prime has the form
392 // p_i = 2^bitlen(p_i) × 0.11... (in base 2).
393 // And the product is:
394 // P = 2^todo × α
395 // where α is the product of nprimes numbers of the form 0.11...
396 //
397 // If α < 1/2 (which can happen for nprimes > 2), we need to
398 // shift todo to compensate for lost bits: the mean value of 0.11...
399 // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
400 // will give good results.
401 if nprimes >= 7 {
402 todo += (nprimes - 2) / 5
403 }
404 for i := 0; i < nprimes; i++ {
405 var err error
406 if len(prepopulatedPrimes) == 0 {
407 primes[i], err = rand.Prime(random, todo/(nprimes-i))
408 if err != nil {
409 return nil, err
410 }
411 } else {
412 primes[i] = prepopulatedPrimes[0]
413 prepopulatedPrimes = prepopulatedPrimes[1:]
414 }
415
416 todo -= primes[i].BitLen()
417 }
418
419 // Make sure that primes is pairwise unequal.
420 for i, prime := range primes {
421 for j := 0; j < i; j++ {
422 if prime.Cmp(primes[j]) == 0 {
423 continue NextSetOfPrimes
424 }
425 }
426 }
427
428 n := new(big.Int).Set(bigOne)
429 totient := new(big.Int).Set(bigOne)
430 pminus1 := new(big.Int)
431 for _, prime := range primes {
432 n.Mul(n, prime)
433 pminus1.Sub(prime, bigOne)
434 totient.Mul(totient, pminus1)
435 }
436 if n.BitLen() != bits {
437 // This should never happen for nprimes == 2 because
438 // crypto/rand should set the top two bits in each prime.
439 // For nprimes > 2 we hope it does not happen often.
440 continue NextSetOfPrimes
441 }
442
443 priv.D = new(big.Int)
444 e := big.NewInt(int64(priv.E))
445 ok := priv.D.ModInverse(e, totient)
446
447 if ok != nil {
448 priv.Primes = primes
449 priv.N = n
450 break
451 }
452 }
453
454 priv.Precompute()
455 return priv, nil
456}