1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package token
18
19 import (
20 "crypto"
21 "crypto/ecdsa"
22 "crypto/rsa"
23 "encoding/hex"
24 "errors"
25 "fmt"
26 "os"
27 "strings"
28 "time"
29
30 "github.com/sassoftware/relic/cmdline/shared"
31 "github.com/sassoftware/relic/token"
32 "github.com/spf13/cobra"
33 "golang.org/x/crypto/openpgp"
34 "golang.org/x/crypto/openpgp/armor"
35 "golang.org/x/crypto/openpgp/packet"
36 )
37
38 var NewPgpKeyCmd = &cobra.Command{
39 Use: "pgp-generate",
40 Short: "Generate a new PGP key from token",
41 RunE: newPgpKeyCmd,
42 }
43
44 var (
45 argUserName string
46 argUserComment string
47 argUserEmail string
48 )
49
50 func init() {
51 shared.RootCmd.AddCommand(NewPgpKeyCmd)
52 NewPgpKeyCmd.Flags().StringVarP(&argUserName, "name", "n", "", "Name of user identity")
53 NewPgpKeyCmd.Flags().StringVarP(&argUserComment, "comment", "C", "", "Comment of user identity")
54 NewPgpKeyCmd.Flags().StringVarP(&argUserEmail, "email", "E", "", "Email of user identity")
55 addSelectOrGenerateFlags(NewPgpKeyCmd)
56 }
57
58 func makeKey(key token.Key, uids []*packet.UserId) (*openpgp.Entity, error) {
59 creationTime := time.Now()
60 var pubKey *packet.PublicKey
61 switch pub := key.Public().(type) {
62 case *rsa.PublicKey:
63 pubKey = packet.NewRSAPublicKey(creationTime, pub)
64 case *ecdsa.PublicKey:
65 pubKey = packet.NewECDSAPublicKey(creationTime, pub)
66 default:
67 return nil, errors.New("Unsupported key type")
68 }
69 entity := &openpgp.Entity{
70 PrimaryKey: pubKey,
71 PrivateKey: &packet.PrivateKey{
72 PublicKey: *pubKey,
73 Encrypted: false,
74 PrivateKey: key,
75 },
76 Identities: make(map[string]*openpgp.Identity),
77 }
78 isPrimaryID := true
79 for _, uid := range uids {
80 sig := &packet.Signature{
81 SigType: packet.SigTypePositiveCert,
82 CreationTime: creationTime,
83 PubKeyAlgo: pubKey.PubKeyAlgo,
84 Hash: crypto.SHA512,
85 IsPrimaryId: &isPrimaryID,
86 FlagsValid: true,
87 FlagSign: true,
88 FlagCertify: true,
89 IssuerKeyId: &pubKey.KeyId,
90 }
91 err := sig.SignUserId(uid.Id, entity.PrimaryKey, entity.PrivateKey, nil)
92 if err != nil {
93 return nil, err
94 }
95 entity.Identities[uid.Id] = &openpgp.Identity{
96 Name: uid.Name,
97 UserId: uid,
98 SelfSignature: sig,
99 }
100 }
101 return entity, nil
102 }
103
104 func newPgpKeyCmd(cmd *cobra.Command, args []string) error {
105 if argUserName == "" {
106 return errors.New("--name is required")
107 }
108 uid := packet.NewUserId(argUserName, argUserComment, argUserEmail)
109 if uid == nil {
110 return errors.New("Invalid user ID")
111 }
112 key, err := selectOrGenerate()
113 if err != nil {
114 return err
115 }
116 entity, err := makeKey(key, []*packet.UserId{uid})
117 if err != nil {
118 return err
119 }
120 fingerprint := hex.EncodeToString(entity.PrimaryKey.Fingerprint[:])
121 fmt.Fprintln(os.Stderr, "Token CKA_ID: ", formatKeyID(key.GetID()))
122 fmt.Fprintln(os.Stderr, "PGP ID: ", strings.ToUpper(fingerprint))
123 writer, err := armor.Encode(os.Stdout, openpgp.PublicKeyType, nil)
124 if err != nil {
125 return err
126 }
127 err = entity.Serialize(writer)
128 if err != nil {
129 return err
130 }
131 writer.Close()
132 fmt.Println()
133 return nil
134 }
135
View as plain text