@@ -11,66 +11,154 @@ import (
11
11
"github.com/ProtonMail/go-crypto/openpgp/packet"
12
12
)
13
13
14
- func (e * Entity ) NewForwardingEntity (name , comment , email string , config * packet.Config ) (forwardeeKey * Entity , proxyParam []byte , err error ) {
15
- encryptionSubKey , ok := e .EncryptionKey (config .Now ())
16
- if ! ok {
17
- return nil , nil , errors .InvalidArgumentError ("no valid encryption key found" )
18
- }
19
-
20
- if encryptionSubKey .PublicKey .Version != 4 {
21
- return nil , nil , errors .InvalidArgumentError ("unsupported encryption subkey version" )
22
- }
14
+ // ForwardingInstance represents a single forwarding instance (mapping IDs to a Proxy Param)
15
+ type ForwardingInstance struct {
16
+ ForwarderKeyId uint64
17
+ ForwardeeKeyId uint64
18
+ ProxyParameter []byte
19
+ }
23
20
24
- if encryptionSubKey .PrivateKey .PubKeyAlgo != packet .PubKeyAlgoECDH {
25
- return nil , nil , errors .InvalidArgumentError ("encryption subkey is not algorithm 18 (ECDH)" )
21
+ // NewForwardingEntity generates a new forwardee key and derives the proxy parameters from the entity e.
22
+ // If strict, it will return an error if encryption-capable non-revoked subkeys with a wrong algorithm are found,
23
+ // instead of ignoring them
24
+ func (e * Entity ) NewForwardingEntity (
25
+ name , comment , email string , config * packet.Config , strict bool ,
26
+ ) (
27
+ forwardeeKey * Entity , instances []ForwardingInstance , err error ,
28
+ ) {
29
+ if e .PrimaryKey .Version != 4 {
30
+ return nil , nil , errors .InvalidArgumentError ("unsupported key version" )
26
31
}
27
32
28
- ecdhKey , ok := encryptionSubKey .PrivateKey .PrivateKey .(* ecdh.PrivateKey )
29
- if ! ok {
30
- return nil , nil , errors .InvalidArgumentError ("encryption subkey is not type ECDH" )
33
+ now := config .Now ()
34
+ i := e .PrimaryIdentity ()
35
+ if e .PrimaryKey .KeyExpired (i .SelfSignature , now ) || // primary key has expired
36
+ i .SelfSignature == nil || // user ID has no self-signature
37
+ i .SelfSignature .SigExpired (now ) || // user ID self-signature has expired
38
+ e .Revoked (now ) || // primary key has been revoked
39
+ i .Revoked (now ) { // user ID has been revoked
40
+ return nil , nil , errors .InvalidArgumentError ("primary key is expired" )
31
41
}
32
42
43
+ // Generate a new Primary key for the forwardee
33
44
config .Algorithm = packet .PubKeyAlgoEdDSA
34
45
config .Curve = packet .Curve25519
46
+ keyLifetimeSecs := config .KeyLifetime ()
35
47
36
- forwardeeKey , err = NewEntity ( name , comment , email , config )
48
+ forwardeePrimaryPrivRaw , err := newSigner ( config )
37
49
if err != nil {
38
50
return nil , nil , err
39
51
}
40
52
41
- forwardeeEcdhKey , ok := forwardeeKey .Subkeys [0 ].PrivateKey .PrivateKey .(* ecdh.PrivateKey )
42
- if ! ok {
43
- return nil , nil , goerrors .New ("wrong forwarding sub key generation" )
53
+ primary := packet .NewSignerPrivateKey (now , forwardeePrimaryPrivRaw )
54
+
55
+ forwardeeKey = & Entity {
56
+ PrimaryKey : & primary .PublicKey ,
57
+ PrivateKey : primary ,
58
+ Identities : make (map [string ]* Identity ),
59
+ Subkeys : []Subkey {},
44
60
}
45
61
46
- proxyParam , err = ecdh . DeriveProxyParam ( ecdhKey , forwardeeEcdhKey )
62
+ err = forwardeeKey . addUserId ( name , comment , email , config , now , keyLifetimeSecs )
47
63
if err != nil {
48
64
return nil , nil , err
49
65
}
50
66
51
- kdf := ecdh.KDF {
52
- Version : ecdh .KDFVersionForwarding ,
53
- Hash : ecdhKey .KDF .Hash ,
54
- Cipher : ecdhKey .KDF .Cipher ,
55
- ReplacementFingerprint : encryptionSubKey .PublicKey .Fingerprint ,
67
+ // Init empty instances
68
+ instances = []ForwardingInstance {}
69
+
70
+ // Handle all forwarder subkeys
71
+ for _ , forwarderSubKey := range e .Subkeys {
72
+ // Filter flags
73
+ if ! forwarderSubKey .Sig .FlagsValid || forwarderSubKey .Sig .FlagCertify || forwarderSubKey .Sig .FlagSign ||
74
+ forwarderSubKey .Sig .FlagAuthenticate || forwarderSubKey .Sig .FlagGroupKey {
75
+ continue
76
+ }
77
+
78
+ // Filter expiration & revokal
79
+ if forwarderSubKey .PublicKey .KeyExpired (forwarderSubKey .Sig , now ) ||
80
+ forwarderSubKey .Sig .SigExpired (now ) ||
81
+ forwarderSubKey .Revoked (now ) {
82
+ continue
83
+ }
84
+
85
+ if forwarderSubKey .PublicKey .PubKeyAlgo != packet .PubKeyAlgoECDH {
86
+ if strict {
87
+ return nil , nil , errors .InvalidArgumentError ("encryption subkey is not algorithm 18 (ECDH)" )
88
+ } else {
89
+ continue
90
+ }
91
+ }
92
+
93
+ forwarderEcdhKey , ok := forwarderSubKey .PrivateKey .PrivateKey .(* ecdh.PrivateKey )
94
+ if ! ok {
95
+ return nil , nil , errors .InvalidArgumentError ("malformed key" )
96
+ }
97
+
98
+ err = forwardeeKey .addEncryptionSubkey (config , now , 0 )
99
+ if err != nil {
100
+ return nil , nil , err
101
+ }
102
+
103
+ forwardeeSubKey := forwardeeKey .Subkeys [len (forwardeeKey .Subkeys ) - 1 ]
104
+
105
+ forwardeeEcdhKey , ok := forwardeeSubKey .PrivateKey .PrivateKey .(* ecdh.PrivateKey )
106
+ if ! ok {
107
+ return nil , nil , goerrors .New ("wrong forwarding sub key generation" )
108
+ }
109
+
110
+ instance := ForwardingInstance {
111
+ ForwarderKeyId : forwarderSubKey .PublicKey .KeyId ,
112
+ }
113
+
114
+ instance .ProxyParameter , err = ecdh .DeriveProxyParam (forwarderEcdhKey , forwardeeEcdhKey )
115
+ if err != nil {
116
+ return nil , nil , err
117
+ }
118
+
119
+ kdf := ecdh.KDF {
120
+ Version : ecdh .KDFVersionForwarding ,
121
+ Hash : forwarderEcdhKey .KDF .Hash ,
122
+ Cipher : forwarderEcdhKey .KDF .Cipher ,
123
+ }
124
+
125
+ // If deriving a forwarding key from a forwarding key
126
+ if forwarderSubKey .Sig .FlagForward {
127
+ if forwarderEcdhKey .KDF .Version != ecdh .KDFVersionForwarding {
128
+ return nil , nil , goerrors .New ("malformed forwarder key" )
129
+ }
130
+ kdf .ReplacementFingerprint = forwarderEcdhKey .KDF .ReplacementFingerprint
131
+ } else {
132
+ kdf .ReplacementFingerprint = forwarderSubKey .PublicKey .Fingerprint
133
+ }
134
+
135
+ err = forwardeeSubKey .PublicKey .ReplaceKDF (kdf )
136
+ if err != nil {
137
+ return nil , nil , err
138
+ }
139
+
140
+ // Set ID after changing the KDF
141
+ instance .ForwardeeKeyId = forwardeeSubKey .PublicKey .KeyId
142
+
143
+ // 0x04 - This key may be used to encrypt communications.
144
+ forwardeeSubKey .Sig .FlagEncryptCommunications = false
145
+
146
+ // 0x08 - This key may be used to encrypt storage.
147
+ forwardeeSubKey .Sig .FlagEncryptStorage = false
148
+
149
+ // 0x10 - The private component of this key may have been split by a secret-sharing mechanism.
150
+ forwardeeSubKey .Sig .FlagSplitKey = true
151
+
152
+ // 0x40 - This key may be used for forwarded communications.
153
+ forwardeeSubKey .Sig .FlagForward = true
154
+
155
+ // Append each valid instance to the list
156
+ instances = append (instances , instance )
56
157
}
57
158
58
- err = forwardeeKey .Subkeys [0 ].PublicKey .ReplaceKDF (kdf )
59
- if err != nil {
60
- return nil , nil , err
159
+ if len (instances ) == 0 {
160
+ return nil , nil , errors .InvalidArgumentError ("no valid subkey found" )
61
161
}
62
162
63
- // 0x04 - This key may be used to encrypt communications.
64
- forwardeeKey .Subkeys [0 ].Sig .FlagEncryptCommunications = false
65
-
66
- // 0x08 - This key may be used to encrypt storage.
67
- forwardeeKey .Subkeys [0 ].Sig .FlagEncryptStorage = false
68
-
69
- // 0x10 - The private component of this key may have been split by a secret-sharing mechanism.
70
- forwardeeKey .Subkeys [0 ].Sig .FlagSplitKey = true
71
-
72
- // 0x40 - This key may be used for forwarded communications.
73
- forwardeeKey .Subkeys [0 ].Sig .FlagForward = true
74
-
75
- return forwardeeKey , proxyParam , nil
163
+ return forwardeeKey , instances , nil
76
164
}
0 commit comments