--You received this message because you are subscribed to the Google Groups "golang-dev" group.To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.To view this discussion on the web visit https://groups.google.com/d/msgid/golang-dev/CAE33SMOEF8L-K0BDEhudxxPTdQ37mOe5XdGX4WwvF7zqrJML0Q%40mail.gmail.com.
// CurvePreferences contains the elliptic curves that will be used in // an ECDHE handshake, in preference order. If empty, the default will // be used. The client will use the first preference as the type for // its key share in TLS 1.3. This may change in the future. CurvePreferences []CurveID
crypto/tls benefited greatly from keeping close control of low-level details. For example, we took over cipher suite ordering from the application to ensure we can deprioritize less secure suites. https://go.dev/blog/tls-cipher-suites Maybe we'll want to do the same thing with CurvePreferences (maybe we will specifically to address the needs of the PQ transition), which would bring back all the ordering complexity I mentioned if we supported external KEMs.Also, I don't think your proposal directly addresses any of the following questions in my previous email. They're not insurmountable, but they are additional complexity.
- Which one(s) do we select for the KeyShare?
GroupSelection:
for _, preferredGroup := range c.config.curvePreferences() {
for _, ks := range hs.clientHello.keyShares {
if ks.group == preferredGroup {
selectedGroup = ks.group
clientKeyShare = &ks
break GroupSelection
}
}
if selectedGroup != 0 {
continue
}
for _, group := range hs.clientHello.supportedCurves {
if group == preferredGroup {
selectedGroup = group
break
}
}
}
if selectedGroup == 0 {
c.sendAlert(alertHandshakeFailure)
return errors.New("tls: no ECDHE curve supported by both client and server")
}
if clientKeyShare == nil {
if err := hs.doHelloRetryRequest(selectedGroup); err != nil {
return err
}
clientKeyShare = &hs.clientHello.keyShares[0]
}
if _, ok := curveForCurveID(selectedGroup); !ok {
c.sendAlert(alertInternalError)
return errors.New("tls: CurvePreferences includes unsupported curve")
}
key, err := generateECDHEKey(c.config.rand(), selectedGroup)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
hs.hello.serverShare = keyShare{group: selectedGroup, data: key.PublicKey().Bytes()}
peerKey, err := key.Curve().NewPublicKey(clientKeyShare.data)
if err != nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid client key share")
}
hs.sharedKey, err = key.ECDH(peerKey)
if err != nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid client key share")
}
curveID := config.curvePreferences()[0]
if _, ok := curveForCurveID(curveID); !ok {
return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
}
key, err = generateECDHEKey(config.rand(), curveID)
if err != nil {
return nil, nil, err
}
hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}}
if kem := c.config.getKemForCurve(selectedGroup); kem != nil {
//user wants to specify a kem
serverData, sharedKey, err := kem.Encapsulate(clientKeyShare.data)
if err != nil {
return err
}
hs.hello.serverShare = keyShare{group: selectedGroup, data: serverData}
hs.sharedKey = sharedKey
} else {
//existing code path...
//you would later add the built-in kem selection here...
if _, ok := curveForCurveID(selectedGroup); !ok {
c.sendAlert(alertInternalError)
return errors.New("tls: CurvePreferences includes unsupported curve")
}
key, err := generateECDHEKey(c.config.rand(), selectedGroup)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
hs.hello.serverShare = keyShare{group: selectedGroup, data: key.PublicKey().Bytes()}
peerKey, err := key.Curve().NewPublicKey(clientKeyShare.data)
if err != nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid client key share")
}
hs.sharedKey, err = key.ECDH(peerKey)
if err != nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: invalid client key share")
}
}
func (c *tls.Config) getKemForCurve(curve CurveID) Kem {
if c.GetKemForCurve != nil {
return c.GetKemForCurve(curve)
}
return nil
}
- How do we avoid duplication of work across a user-defined X25519 hybrid and our own X25519? [Note that I am not talking about programmer work, I am talking about generating the X25519 key share.
- What if we later implement one that the application was defining?
Ultimately, crypto/tls is a production library, designed to make it easy to build safe applications. That goal is in contrast with the goals of an experimentation toolkit (or of a testing tool, which is the other source of commonly refused proposals). I'm always hoping that the community will coalesce around one or two forks for testing and experimentation, and I encourage anyone who's thinking about it to give it a go.
This is my personal position FWIW, you're free to file a proposal if you wish, but I assumed you were emailing golang-dev to get a pulse on our appetite for this.
On Apr 9, 2024, at 9:29 AM, Scott Wisniewski <sc...@agile.security> wrote:
On Tue, Apr 9, 2024 at 3:19 AM Filippo Valsorda <fil...@golang.org> wrote:crypto/tls benefited greatly from keeping close control of low-level details. For example, we took over cipher suite ordering from the application to ensure we can deprioritize less secure suites. https://go.dev/blog/tls-cipher-suites Maybe we'll want to do the same thing with CurvePreferences (maybe we will specifically to address the needs of the PQ transition), which would bring back all the ordering complexity I mentioned if we supported external KEMs.Also, I don't think your proposal directly addresses any of the following questions in my previous email. They're not insurmountable, but they are additional complexity.
- Which one(s) do we select for the KeyShare?
I'm saying that the logic for selecting a named group on the server doesn't change.
- How do we avoid duplication of work across a user-defined X25519 hybrid and our own X25519? [Note that I am not talking about programmer work, I am talking about generating the X25519 key share.
There's no duplication of work. Either a user supplied kem is used or the existing code runs.
- What if we later implement one that the application was defining?
The application selection would win, because the user supplied GetKemForCurve would return non nil.
Ultimately, crypto/tls is a production library, designed to make it easy to build safe applications. That goal is in contrast with the goals of an experimentation toolkit (or of a testing tool, which is the other source of commonly refused proposals). I'm always hoping that the community will coalesce around one or two forks for testing and experimentation, and I encourage anyone who's thinking about it to give it a go.I actually want this for production code. There's a lot of production code that enables "experimental" PQC features, including Chrome and Firefox. There are re-usable Kyber implementations from Google (Boring SSL), Cloudflare (circl) and Amazon (s2n-tls). I know both the Cloudflare implementation and the Amazon implementation are used in production. I want to be able to use these implementations now.
Also, I assume that the algorithms and standards are going to change frequently... because these are new algorithms... So even more importantly I want to be able to rapidly iterate (in production) on PQC extensions to TLS.
This is my personal position FWIW, you're free to file a proposal if you wish, but I assumed you were emailing golang-dev to get a pulse on our appetite for this.Yes, I wanted to get the general appetite for this.I'm hearing a lot of push back. I think the code change is very very simple (much smaller than this email thread), so a proposal wouldn't be pretty easy.This would obviously be easier to get approved if there was agreement on the direction beforehand.What do I need to do to convince you on this?