Skip to content

Commit fb43278

Browse files
FiloSottilegopherbot
authored andcommitted
crypto/ecdh: revamp FIPS ECDH API
This makes it more similar to the ECDSA API, introducing proper key types that can correctly "cache" the key check. The new API also has a better compliance profile. Note how the old ECDHPnnn functions were not doing the PCT, instead delegating to the caller an invocation of ImportKeyPnnn. Change-Id: Ic6cf834427fd790324919b4d92bdaa2aac840016 Reviewed-on: https://go-review.googlesource.com/c/go/+/630098 Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Filippo Valsorda <[email protected]> Reviewed-by: Russ Cox <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Daniel McCarney <[email protected]>
1 parent d524c95 commit fb43278

File tree

6 files changed

+221
-194
lines changed

6 files changed

+221
-194
lines changed

src/crypto/ecdh/ecdh.go

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package ecdh
99
import (
1010
"crypto"
1111
"crypto/internal/boring"
12+
"crypto/internal/fips140/ecdh"
1213
"crypto/subtle"
1314
"errors"
1415
"io"
@@ -60,6 +61,7 @@ type PublicKey struct {
6061
curve Curve
6162
publicKey []byte
6263
boring *boring.PublicKeyECDH
64+
fips *ecdh.PublicKey
6365
}
6466

6567
// Bytes returns a copy of the encoding of the public key.
@@ -100,6 +102,7 @@ type PrivateKey struct {
100102
privateKey []byte
101103
publicKey *PublicKey
102104
boring *boring.PrivateKeyECDH
105+
fips *ecdh.PrivateKey
103106
}
104107

105108
// ECDH performs an ECDH exchange and returns the shared secret. The [PrivateKey]

src/crypto/ecdh/nist.go

+63-28
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import (
1313
)
1414

1515
type nistCurve struct {
16-
name string
17-
generate func(io.Reader) (privateKey, publicKey []byte, err error)
18-
importKey func([]byte) (publicKey []byte, err error)
19-
checkPubkey func(publicKey []byte) error
20-
sharedSecret func(privateKey, publicKey []byte) (sharedSecret []byte, err error)
16+
name string
17+
generate func(io.Reader) (*ecdh.PrivateKey, error)
18+
newPrivateKey func([]byte) (*ecdh.PrivateKey, error)
19+
newPublicKey func(publicKey []byte) (*ecdh.PublicKey, error)
20+
sharedSecret func(*ecdh.PrivateKey, *ecdh.PublicKey) (sharedSecret []byte, err error)
2121
}
2222

2323
func (c *nistCurve) String() string {
@@ -43,15 +43,20 @@ func (c *nistCurve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
4343
return k, nil
4444
}
4545

46-
privateKey, publicKey, err := c.generate(rand)
46+
privateKey, err := c.generate(rand)
4747
if err != nil {
4848
return nil, err
4949
}
5050

5151
k := &PrivateKey{
5252
curve: c,
53-
privateKey: privateKey,
54-
publicKey: &PublicKey{curve: c, publicKey: publicKey},
53+
privateKey: privateKey.Bytes(),
54+
fips: privateKey,
55+
publicKey: &PublicKey{
56+
curve: c,
57+
publicKey: privateKey.PublicKey().Bytes(),
58+
fips: privateKey.PublicKey(),
59+
},
5560
}
5661
if boring.Enabled {
5762
bk, err := boring.NewPrivateKeyECDH(c.name, k.privateKey)
@@ -87,15 +92,19 @@ func (c *nistCurve) NewPrivateKey(key []byte) (*PrivateKey, error) {
8792
return k, nil
8893
}
8994

90-
publicKey, err := c.importKey(key)
95+
fk, err := c.newPrivateKey(key)
9196
if err != nil {
9297
return nil, err
9398
}
94-
9599
k := &PrivateKey{
96100
curve: c,
97101
privateKey: bytes.Clone(key),
98-
publicKey: &PublicKey{curve: c, publicKey: publicKey},
102+
fips: fk,
103+
publicKey: &PublicKey{
104+
curve: c,
105+
publicKey: fk.PublicKey().Bytes(),
106+
fips: fk.PublicKey(),
107+
},
99108
}
100109
return k, nil
101110
}
@@ -117,9 +126,11 @@ func (c *nistCurve) NewPublicKey(key []byte) (*PublicKey, error) {
117126
}
118127
k.boring = bk
119128
} else {
120-
if err := c.checkPubkey(k.publicKey); err != nil {
129+
fk, err := c.newPublicKey(key)
130+
if err != nil {
121131
return nil, err
122132
}
133+
k.fips = fk
123134
}
124135
return k, nil
125136
}
@@ -135,7 +146,7 @@ func (c *nistCurve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {
135146
if boring.Enabled {
136147
return boring.ECDH(local.boring, remote.boring)
137148
}
138-
return c.sharedSecret(local.privateKey, remote.publicKey)
149+
return c.sharedSecret(local.fips, remote.fips)
139150
}
140151

141152
// P256 returns a [Curve] which implements NIST P-256 (FIPS 186-3, section D.2.3),
@@ -146,11 +157,19 @@ func (c *nistCurve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {
146157
func P256() Curve { return p256 }
147158

148159
var p256 = &nistCurve{
149-
name: "P-256",
150-
generate: ecdh.GenerateKeyP256,
151-
importKey: ecdh.ImportKeyP256,
152-
checkPubkey: ecdh.CheckPublicKeyP256,
153-
sharedSecret: ecdh.ECDHP256,
160+
name: "P-256",
161+
generate: func(r io.Reader) (*ecdh.PrivateKey, error) {
162+
return ecdh.GenerateKey(ecdh.P256(), r)
163+
},
164+
newPrivateKey: func(b []byte) (*ecdh.PrivateKey, error) {
165+
return ecdh.NewPrivateKey(ecdh.P256(), b)
166+
},
167+
newPublicKey: func(publicKey []byte) (*ecdh.PublicKey, error) {
168+
return ecdh.NewPublicKey(ecdh.P256(), publicKey)
169+
},
170+
sharedSecret: func(priv *ecdh.PrivateKey, pub *ecdh.PublicKey) (sharedSecret []byte, err error) {
171+
return ecdh.ECDH(ecdh.P256(), priv, pub)
172+
},
154173
}
155174

156175
// P384 returns a [Curve] which implements NIST P-384 (FIPS 186-3, section D.2.4),
@@ -161,11 +180,19 @@ var p256 = &nistCurve{
161180
func P384() Curve { return p384 }
162181

163182
var p384 = &nistCurve{
164-
name: "P-384",
165-
generate: ecdh.GenerateKeyP384,
166-
importKey: ecdh.ImportKeyP384,
167-
checkPubkey: ecdh.CheckPublicKeyP384,
168-
sharedSecret: ecdh.ECDHP384,
183+
name: "P-384",
184+
generate: func(r io.Reader) (*ecdh.PrivateKey, error) {
185+
return ecdh.GenerateKey(ecdh.P384(), r)
186+
},
187+
newPrivateKey: func(b []byte) (*ecdh.PrivateKey, error) {
188+
return ecdh.NewPrivateKey(ecdh.P384(), b)
189+
},
190+
newPublicKey: func(publicKey []byte) (*ecdh.PublicKey, error) {
191+
return ecdh.NewPublicKey(ecdh.P384(), publicKey)
192+
},
193+
sharedSecret: func(priv *ecdh.PrivateKey, pub *ecdh.PublicKey) (sharedSecret []byte, err error) {
194+
return ecdh.ECDH(ecdh.P384(), priv, pub)
195+
},
169196
}
170197

171198
// P521 returns a [Curve] which implements NIST P-521 (FIPS 186-3, section D.2.5),
@@ -176,9 +203,17 @@ var p384 = &nistCurve{
176203
func P521() Curve { return p521 }
177204

178205
var p521 = &nistCurve{
179-
name: "P-521",
180-
generate: ecdh.GenerateKeyP521,
181-
importKey: ecdh.ImportKeyP521,
182-
checkPubkey: ecdh.CheckPublicKeyP521,
183-
sharedSecret: ecdh.ECDHP521,
206+
name: "P-521",
207+
generate: func(r io.Reader) (*ecdh.PrivateKey, error) {
208+
return ecdh.GenerateKey(ecdh.P521(), r)
209+
},
210+
newPrivateKey: func(b []byte) (*ecdh.PrivateKey, error) {
211+
return ecdh.NewPrivateKey(ecdh.P521(), b)
212+
},
213+
newPublicKey: func(publicKey []byte) (*ecdh.PublicKey, error) {
214+
return ecdh.NewPublicKey(ecdh.P521(), publicKey)
215+
},
216+
sharedSecret: func(priv *ecdh.PrivateKey, pub *ecdh.PublicKey) (sharedSecret []byte, err error) {
217+
return ecdh.ECDH(ecdh.P521(), priv, pub)
218+
},
184219
}

src/crypto/internal/fips140/ecdh/cast.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"bytes"
99
"crypto/internal/fips140"
1010
_ "crypto/internal/fips140/check"
11-
"crypto/internal/fips140/nistec"
1211
"errors"
1312
"sync"
1413
)
@@ -39,7 +38,9 @@ var fipsSelfTest = sync.OnceFunc(func() {
3938
0x83, 0x48, 0x40, 0x56, 0x69, 0xa1, 0x95, 0xfa,
4039
0xc5, 0x35, 0x04, 0x06, 0xba, 0x76, 0xbc, 0xce,
4140
}
42-
got, err := ecdh(privateKey, publicKey, nistec.NewP256Point)
41+
k := &PrivateKey{d: privateKey, pub: PublicKey{curve: p256}}
42+
peer := &PublicKey{curve: p256, q: publicKey}
43+
got, err := ecdh(P256(), k, peer)
4344
if err != nil {
4445
return err
4546
}

0 commit comments

Comments
 (0)