Просмотр исходного кода

Upgrade to refraction-networking/conjure v0.7.9

Rod Hynes 2 лет назад
Родитель
Сommit
327ce43010

+ 4 - 2
go.mod

@@ -32,7 +32,8 @@ require (
 	github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557
 	github.com/oschwald/maxminddb-golang v1.12.0
 	github.com/patrickmn/go-cache v2.1.0+incompatible
-	github.com/refraction-networking/conjure v0.7.8
+	github.com/pion/sctp v1.8.8
+	github.com/refraction-networking/conjure v0.7.9
 	github.com/refraction-networking/gotapdance v1.7.7
 	github.com/refraction-networking/utls v1.3.3
 	github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735
@@ -48,6 +49,8 @@ require (
 )
 
 require (
+	filippo.io/bigmod v0.0.1 // indirect
+	filippo.io/keygen v0.0.0-20230306160926-5201437acf8e // indirect
 	github.com/AndreasBriese/bbloom v0.0.0-20170702084017-28f7e881ca57 // indirect
 	github.com/BurntSushi/toml v1.3.2 // indirect
 	github.com/Psiphon-Labs/qtls-go1-19 v0.0.0-20230608213623-d58aa73e519a // indirect
@@ -75,7 +78,6 @@ require (
 	github.com/pion/dtls/v2 v2.2.7 // indirect
 	github.com/pion/logging v0.2.2 // indirect
 	github.com/pion/randutil v0.1.0 // indirect
-	github.com/pion/sctp v1.8.8 // indirect
 	github.com/pion/stun v0.6.1 // indirect
 	github.com/pion/transport/v2 v2.2.3 // indirect
 	github.com/pkg/errors v0.9.1 // indirect

+ 6 - 14
go.sum

@@ -1,3 +1,7 @@
+filippo.io/bigmod v0.0.1 h1:OaEqDr3gEbofpnHbGqZweSL/bLMhy1pb54puiCDeuOA=
+filippo.io/bigmod v0.0.1/go.mod h1:KyzqAbH7bRH6MOuOF1TPfUjvLoi0mRF2bIyD2ouRNQI=
+filippo.io/keygen v0.0.0-20230306160926-5201437acf8e h1:+xwUCyMiCWKWsI0RowhzB4sngpUdMHgU6lLuWJCX5Dg=
+filippo.io/keygen v0.0.0-20230306160926-5201437acf8e/go.mod h1:ZGSiF/b2hd6MRghF/cid0vXw8pXykRTmIu+JSPw/NCQ=
 github.com/AndreasBriese/bbloom v0.0.0-20170702084017-28f7e881ca57 h1:CVuXDbdzPW0XCNYTldy5dQues57geAs+vfwz3FTTpy8=
 github.com/AndreasBriese/bbloom v0.0.0-20170702084017-28f7e881ca57/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -172,12 +176,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
 github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
-github.com/refraction-networking/conjure v0.7.7 h1:8vWFmSzmkNSrVr1TI4BRbgCD1tc3FTIm40PzjI2olRQ=
-github.com/refraction-networking/conjure v0.7.7/go.mod h1:/UxAcot49ii6ejyvBrSo3g10yyUEavaGJT1Iy47oAfU=
-github.com/refraction-networking/conjure v0.7.8-0.20231019174926-d2f991831312 h1:IP2pvATIC1QBj2/+biLxTJa23PxRIiDwrPvvE4Sh6cw=
-github.com/refraction-networking/conjure v0.7.8-0.20231019174926-d2f991831312/go.mod h1:iOb7GmuSvk/LZsd40L+D/cKmVGIjpFWQkbtOPggJrcA=
-github.com/refraction-networking/conjure v0.7.8 h1:gPjb0iFyrxkcxc7eOKMjIgh/M4fPaP+plYw9PITWXYs=
-github.com/refraction-networking/conjure v0.7.8/go.mod h1:iOb7GmuSvk/LZsd40L+D/cKmVGIjpFWQkbtOPggJrcA=
+github.com/refraction-networking/conjure v0.7.9 h1:ABEtW1treui43vP0LlCslfw274bIyFaoxDB59BzUrl4=
+github.com/refraction-networking/conjure v0.7.9/go.mod h1:O5u/Mpg5b3whLF8L701pTMQW23SviS+rDKdWbY/BM0Q=
 github.com/refraction-networking/ed25519 v0.1.2 h1:08kJZUkAlY7a7cZGosl1teGytV+QEoNxPO7NnRvAB+g=
 github.com/refraction-networking/ed25519 v0.1.2/go.mod h1:nxYLUAYt/hmNpAh64PNSQ/tQ9gTIB89wCaGKJlRtZ9I=
 github.com/refraction-networking/gotapdance v1.7.7 h1:RSdDCA0v4n/iIxCnxLF6uCoJdlo000R+IKGvELfpc/A=
@@ -219,8 +219,6 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
 golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
-golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
-golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
 golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
 golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 h1:sBdrWpxhGDdTAYNqbgBLAR+ULAPPhfgncLr1X0lyWtg=
@@ -254,8 +252,6 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
 golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
-golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
 golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -299,8 +295,6 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
 golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -310,8 +304,6 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
 golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
-golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
-golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
 golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

+ 27 - 0
vendor/filippo.io/bigmod/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 714 - 0
vendor/filippo.io/bigmod/nat.go

@@ -0,0 +1,714 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bigmod implements constant-time big integer arithmetic modulo large
+// odd moduli. Unlike math/big, this package is suitable for implementing
+// security-sensitive cryptographic operations. It is a re-exported version the
+// standard library package crypto/internal/bigmod used to implement crypto/rsa
+// amongst others.
+//
+// The API is NOT stable. In particular, its safety is suboptimal, as the caller
+// is responsible for ensuring that Nats are reduced modulo the Modulus they are
+// used with.
+package bigmod
+
+import (
+	"errors"
+	"math/big"
+	"math/bits"
+)
+
+const (
+	// _W is the number of bits we use for our limbs.
+	_W = bits.UintSize - 1
+	// _MASK selects _W bits from a full machine word.
+	_MASK = (1 << _W) - 1
+)
+
+// choice represents a constant-time boolean. The value of choice is always
+// either 1 or 0. We use an int instead of bool in order to make decisions in
+// constant time by turning it into a mask.
+type choice uint
+
+func not(c choice) choice { return 1 ^ c }
+
+const yes = choice(1)
+const no = choice(0)
+
+// ctSelect returns x if on == 1, and y if on == 0. The execution time of this
+// function does not depend on its inputs. If on is any value besides 1 or 0,
+// the result is undefined.
+func ctSelect(on choice, x, y uint) uint {
+	// When on == 1, mask is 0b111..., otherwise mask is 0b000...
+	mask := -uint(on)
+	// When mask is all zeros, we just have y, otherwise, y cancels with itself.
+	return y ^ (mask & (y ^ x))
+}
+
+// ctEq returns 1 if x == y, and 0 otherwise. The execution time of this
+// function does not depend on its inputs.
+func ctEq(x, y uint) choice {
+	// If x != y, then either x - y or y - x will generate a carry.
+	_, c1 := bits.Sub(x, y, 0)
+	_, c2 := bits.Sub(y, x, 0)
+	return not(choice(c1 | c2))
+}
+
+// ctGeq returns 1 if x >= y, and 0 otherwise. The execution time of this
+// function does not depend on its inputs.
+func ctGeq(x, y uint) choice {
+	// If x < y, then x - y generates a carry.
+	_, carry := bits.Sub(x, y, 0)
+	return not(choice(carry))
+}
+
+// Nat represents an arbitrary natural number
+//
+// Each Nat has an announced length, which is the number of limbs it has stored.
+// Operations on this number are allowed to leak this length, but will not leak
+// any information about the values contained in those limbs.
+type Nat struct {
+	// limbs is a little-endian representation in base 2^W with
+	// W = bits.UintSize - 1. The top bit is always unset between operations.
+	//
+	// The top bit is left unset to optimize Montgomery multiplication, in the
+	// inner loop of exponentiation. Using fully saturated limbs would leave us
+	// working with 129-bit numbers on 64-bit platforms, wasting a lot of space,
+	// and thus time.
+	limbs []uint
+}
+
+// preallocTarget is the size in bits of the numbers used to implement the most
+// common and most performant RSA key size. It's also enough to cover some of
+// the operations of key sizes up to 4096.
+const preallocTarget = 2048
+const preallocLimbs = (preallocTarget + _W - 1) / _W
+
+// NewNat returns a new nat with a size of zero, just like new(Nat), but with
+// the preallocated capacity to hold a number of up to 2048 bits.
+// NewNat inlines, so the allocation can live on the stack.
+func NewNat() *Nat {
+	limbs := make([]uint, 0, preallocLimbs)
+	return &Nat{limbs}
+}
+
+// expand expands x to n limbs, leaving its value unchanged.
+func (x *Nat) expand(n int) *Nat {
+	if len(x.limbs) > n {
+		panic("bigmod: internal error: shrinking nat")
+	}
+	if cap(x.limbs) < n {
+		newLimbs := make([]uint, n)
+		copy(newLimbs, x.limbs)
+		x.limbs = newLimbs
+		return x
+	}
+	extraLimbs := x.limbs[len(x.limbs):n]
+	for i := range extraLimbs {
+		extraLimbs[i] = 0
+	}
+	x.limbs = x.limbs[:n]
+	return x
+}
+
+// reset returns a zero nat of n limbs, reusing x's storage if n <= cap(x.limbs).
+func (x *Nat) reset(n int) *Nat {
+	if cap(x.limbs) < n {
+		x.limbs = make([]uint, n)
+		return x
+	}
+	for i := range x.limbs {
+		x.limbs[i] = 0
+	}
+	x.limbs = x.limbs[:n]
+	return x
+}
+
+// set assigns x = y, optionally resizing x to the appropriate size.
+func (x *Nat) set(y *Nat) *Nat {
+	x.reset(len(y.limbs))
+	copy(x.limbs, y.limbs)
+	return x
+}
+
+// setBig assigns x = n, optionally resizing n to the appropriate size.
+//
+// The announced length of x is set based on the actual bit size of the input,
+// ignoring leading zeroes.
+func (x *Nat) setBig(n *big.Int) *Nat {
+	requiredLimbs := (n.BitLen() + _W - 1) / _W
+	x.reset(requiredLimbs)
+
+	outI := 0
+	shift := 0
+	limbs := n.Bits()
+	for i := range limbs {
+		xi := uint(limbs[i])
+		x.limbs[outI] |= (xi << shift) & _MASK
+		outI++
+		if outI == requiredLimbs {
+			return x
+		}
+		x.limbs[outI] = xi >> (_W - shift)
+		shift++ // this assumes bits.UintSize - _W = 1
+		if shift == _W {
+			shift = 0
+			outI++
+		}
+	}
+	return x
+}
+
+// Bytes returns x as a zero-extended big-endian byte slice. The size of the
+// slice will match the size of m.
+//
+// x must have the same size as m and it must be reduced modulo m.
+func (x *Nat) Bytes(m *Modulus) []byte {
+	bytes := make([]byte, m.Size())
+	shift := 0
+	outI := len(bytes) - 1
+	for _, limb := range x.limbs {
+		remainingBits := _W
+		for remainingBits >= 8 {
+			bytes[outI] |= byte(limb) << shift
+			consumed := 8 - shift
+			limb >>= consumed
+			remainingBits -= consumed
+			shift = 0
+			outI--
+			if outI < 0 {
+				return bytes
+			}
+		}
+		bytes[outI] = byte(limb)
+		shift = remainingBits
+	}
+	return bytes
+}
+
+// SetBytes assigns x = b, where b is a slice of big-endian bytes.
+// SetBytes returns an error if b >= m.
+//
+// The output will be resized to the size of m and overwritten.
+func (x *Nat) SetBytes(b []byte, m *Modulus) (*Nat, error) {
+	if err := x.setBytes(b, m); err != nil {
+		return nil, err
+	}
+	if x.cmpGeq(m.nat) == yes {
+		return nil, errors.New("input overflows the modulus")
+	}
+	return x, nil
+}
+
+// SetOverflowingBytes assigns x = b, where b is a slice of big-endian bytes. SetOverflowingBytes
+// returns an error if b has a longer bit length than m, but reduces overflowing
+// values up to 2^⌈log2(m)⌉ - 1.
+//
+// The output will be resized to the size of m and overwritten.
+func (x *Nat) SetOverflowingBytes(b []byte, m *Modulus) (*Nat, error) {
+	if err := x.setBytes(b, m); err != nil {
+		return nil, err
+	}
+	leading := _W - bitLen(x.limbs[len(x.limbs)-1])
+	if leading < m.leading {
+		return nil, errors.New("input overflows the modulus")
+	}
+	x.sub(x.cmpGeq(m.nat), m.nat)
+	return x, nil
+}
+
+func (x *Nat) setBytes(b []byte, m *Modulus) error {
+	outI := 0
+	shift := 0
+	x.resetFor(m)
+	for i := len(b) - 1; i >= 0; i-- {
+		bi := b[i]
+		x.limbs[outI] |= uint(bi) << shift
+		shift += 8
+		if shift >= _W {
+			shift -= _W
+			x.limbs[outI] &= _MASK
+			overflow := bi >> (8 - shift)
+			outI++
+			if outI >= len(x.limbs) {
+				if overflow > 0 || i > 0 {
+					return errors.New("input overflows the modulus")
+				}
+				break
+			}
+			x.limbs[outI] = uint(overflow)
+		}
+	}
+	return nil
+}
+
+// Equal returns 1 if x == y, and 0 otherwise.
+//
+// Both operands must have the same announced length.
+func (x *Nat) Equal(y *Nat) uint {
+	// Eliminate bounds checks in the loop.
+	size := len(x.limbs)
+	xLimbs := x.limbs[:size]
+	yLimbs := y.limbs[:size]
+
+	equal := yes
+	for i := 0; i < size; i++ {
+		equal &= ctEq(xLimbs[i], yLimbs[i])
+	}
+	return uint(equal)
+}
+
+// IsZero returns 1 if x == 0, and 0 otherwise.
+func (x *Nat) IsZero() uint {
+	// Eliminate bounds checks in the loop.
+	size := len(x.limbs)
+	xLimbs := x.limbs[:size]
+
+	zero := yes
+	for i := 0; i < size; i++ {
+		zero &= ctEq(xLimbs[i], 0)
+	}
+	return uint(zero)
+}
+
+// cmpGeq returns 1 if x >= y, and 0 otherwise.
+//
+// Both operands must have the same announced length.
+func (x *Nat) cmpGeq(y *Nat) choice {
+	// Eliminate bounds checks in the loop.
+	size := len(x.limbs)
+	xLimbs := x.limbs[:size]
+	yLimbs := y.limbs[:size]
+
+	var c uint
+	for i := 0; i < size; i++ {
+		c = (xLimbs[i] - yLimbs[i] - c) >> _W
+	}
+	// If there was a carry, then subtracting y underflowed, so
+	// x is not greater than or equal to y.
+	return not(choice(c))
+}
+
+// assign sets x <- y if on == 1, and does nothing otherwise.
+//
+// Both operands must have the same announced length.
+func (x *Nat) assign(on choice, y *Nat) *Nat {
+	// Eliminate bounds checks in the loop.
+	size := len(x.limbs)
+	xLimbs := x.limbs[:size]
+	yLimbs := y.limbs[:size]
+
+	for i := 0; i < size; i++ {
+		xLimbs[i] = ctSelect(on, yLimbs[i], xLimbs[i])
+	}
+	return x
+}
+
+// add computes x += y if on == 1, and does nothing otherwise. It returns the
+// carry of the addition regardless of on.
+//
+// Both operands must have the same announced length.
+func (x *Nat) add(on choice, y *Nat) (c uint) {
+	// Eliminate bounds checks in the loop.
+	size := len(x.limbs)
+	xLimbs := x.limbs[:size]
+	yLimbs := y.limbs[:size]
+
+	for i := 0; i < size; i++ {
+		res := xLimbs[i] + yLimbs[i] + c
+		xLimbs[i] = ctSelect(on, res&_MASK, xLimbs[i])
+		c = res >> _W
+	}
+	return
+}
+
+// sub computes x -= y if on == 1, and does nothing otherwise. It returns the
+// borrow of the subtraction regardless of on.
+//
+// Both operands must have the same announced length.
+func (x *Nat) sub(on choice, y *Nat) (c uint) {
+	// Eliminate bounds checks in the loop.
+	size := len(x.limbs)
+	xLimbs := x.limbs[:size]
+	yLimbs := y.limbs[:size]
+
+	for i := 0; i < size; i++ {
+		res := xLimbs[i] - yLimbs[i] - c
+		xLimbs[i] = ctSelect(on, res&_MASK, xLimbs[i])
+		c = res >> _W
+	}
+	return
+}
+
+// Modulus is used for modular arithmetic, precomputing relevant constants.
+//
+// Moduli are assumed to be odd numbers. Moduli can also leak the exact
+// number of bits needed to store their value, and are stored without padding.
+//
+// Their actual value is still kept secret.
+type Modulus struct {
+	// The underlying natural number for this modulus.
+	//
+	// This will be stored without any padding, and shouldn't alias with any
+	// other natural number being used.
+	nat     *Nat
+	leading int  // number of leading zeros in the modulus
+	m0inv   uint // -nat.limbs[0]⁻¹ mod _W
+	rr      *Nat // R*R for montgomeryRepresentation
+}
+
+// rr returns R*R with R = 2^(_W * n) and n = len(m.nat.limbs).
+func rr(m *Modulus) *Nat {
+	rr := NewNat().ExpandFor(m)
+	// R*R is 2^(2 * _W * n). We can safely get 2^(_W * (n - 1)) by setting the
+	// most significant limb to 1. We then get to R*R by shifting left by _W
+	// n + 1 times.
+	n := len(rr.limbs)
+	rr.limbs[n-1] = 1
+	for i := n - 1; i < 2*n; i++ {
+		rr.shiftIn(0, m) // x = x * 2^_W mod m
+	}
+	return rr
+}
+
+// minusInverseModW computes -x⁻¹ mod _W with x odd.
+//
+// This operation is used to precompute a constant involved in Montgomery
+// multiplication.
+func minusInverseModW(x uint) uint {
+	// Every iteration of this loop doubles the least-significant bits of
+	// correct inverse in y. The first three bits are already correct (1⁻¹ = 1,
+	// 3⁻¹ = 3, 5⁻¹ = 5, and 7⁻¹ = 7 mod 8), so doubling five times is enough
+	// for 61 bits (and wastes only one iteration for 31 bits).
+	//
+	// See https://crypto.stackexchange.com/a/47496.
+	y := x
+	for i := 0; i < 5; i++ {
+		y = y * (2 - x*y)
+	}
+	return (1 << _W) - (y & _MASK)
+}
+
+// NewModulusFromBig creates a new Modulus from a [big.Int].
+//
+// The Int must be odd. The number of significant bits must be leakable.
+func NewModulusFromBig(n *big.Int) *Modulus {
+	m := &Modulus{}
+	m.nat = NewNat().setBig(n)
+	m.leading = _W - bitLen(m.nat.limbs[len(m.nat.limbs)-1])
+	m.m0inv = minusInverseModW(m.nat.limbs[0])
+	m.rr = rr(m)
+	return m
+}
+
+// bitLen is a version of bits.Len that only leaks the bit length of n, but not
+// its value. bits.Len and bits.LeadingZeros use a lookup table for the
+// low-order bits on some architectures.
+func bitLen(n uint) int {
+	var len int
+	// We assume, here and elsewhere, that comparison to zero is constant time
+	// with respect to different non-zero values.
+	for n != 0 {
+		len++
+		n >>= 1
+	}
+	return len
+}
+
+// Size returns the size of m in bytes.
+func (m *Modulus) Size() int {
+	return (m.BitLen() + 7) / 8
+}
+
+// BitLen returns the size of m in bits.
+func (m *Modulus) BitLen() int {
+	return len(m.nat.limbs)*_W - int(m.leading)
+}
+
+// Nat returns m as a Nat. The return value must not be written to.
+func (m *Modulus) Nat() *Nat {
+	return m.nat
+}
+
+// shiftIn calculates x = x << _W + y mod m.
+//
+// This assumes that x is already reduced mod m, and that y < 2^_W.
+func (x *Nat) shiftIn(y uint, m *Modulus) *Nat {
+	d := NewNat().resetFor(m)
+
+	// Eliminate bounds checks in the loop.
+	size := len(m.nat.limbs)
+	xLimbs := x.limbs[:size]
+	dLimbs := d.limbs[:size]
+	mLimbs := m.nat.limbs[:size]
+
+	// Each iteration of this loop computes x = 2x + b mod m, where b is a bit
+	// from y. Effectively, it left-shifts x and adds y one bit at a time,
+	// reducing it every time.
+	//
+	// To do the reduction, each iteration computes both 2x + b and 2x + b - m.
+	// The next iteration (and finally the return line) will use either result
+	// based on whether the subtraction underflowed.
+	needSubtraction := no
+	for i := _W - 1; i >= 0; i-- {
+		carry := (y >> i) & 1
+		var borrow uint
+		for i := 0; i < size; i++ {
+			l := ctSelect(needSubtraction, dLimbs[i], xLimbs[i])
+
+			res := l<<1 + carry
+			xLimbs[i] = res & _MASK
+			carry = res >> _W
+
+			res = xLimbs[i] - mLimbs[i] - borrow
+			dLimbs[i] = res & _MASK
+			borrow = res >> _W
+		}
+		// See Add for how carry (aka overflow), borrow (aka underflow), and
+		// needSubtraction relate.
+		needSubtraction = ctEq(carry, borrow)
+	}
+	return x.assign(needSubtraction, d)
+}
+
+// Mod calculates out = y mod m.
+//
+// This works regardless how large the value of y is.
+//
+// The output will be resized to the size of m and overwritten.
+func (x *Nat) Mod(y *Nat, m *Modulus) *Nat {
+	out, x := x, y
+	out.resetFor(m)
+	// Working our way from the most significant to the least significant limb,
+	// we can insert each limb at the least significant position, shifting all
+	// previous limbs left by _W. This way each limb will get shifted by the
+	// correct number of bits. We can insert at least N - 1 limbs without
+	// overflowing m. After that, we need to reduce every time we shift.
+	i := len(x.limbs) - 1
+	// For the first N - 1 limbs we can skip the actual shifting and position
+	// them at the shifted position, which starts at min(N - 2, i).
+	start := len(m.nat.limbs) - 2
+	if i < start {
+		start = i
+	}
+	for j := start; j >= 0; j-- {
+		out.limbs[j] = x.limbs[i]
+		i--
+	}
+	// We shift in the remaining limbs, reducing modulo m each time.
+	for i >= 0 {
+		out.shiftIn(x.limbs[i], m)
+		i--
+	}
+	return out
+}
+
+// ExpandFor ensures x has the right size to work with operations modulo m.
+//
+// The announced size of x must be smaller than or equal to that of m.
+func (x *Nat) ExpandFor(m *Modulus) *Nat {
+	return x.expand(len(m.nat.limbs))
+}
+
+// resetFor ensures x has the right size to work with operations modulo m.
+//
+// x is zeroed and may start at any size.
+func (x *Nat) resetFor(m *Modulus) *Nat {
+	return x.reset(len(m.nat.limbs))
+}
+
+// Sub computes x = x - y mod m.
+//
+// The length of both operands must be the same as the modulus. Both operands
+// must already be reduced modulo m.
+func (x *Nat) Sub(y *Nat, m *Modulus) *Nat {
+	underflow := x.sub(yes, y)
+	// If the subtraction underflowed, add m.
+	x.add(choice(underflow), m.nat)
+	return x
+}
+
+// Add computes x = x + y mod m.
+//
+// The length of both operands must be the same as the modulus. Both operands
+// must already be reduced modulo m.
+func (x *Nat) Add(y *Nat, m *Modulus) *Nat {
+	overflow := x.add(yes, y)
+	underflow := not(x.cmpGeq(m.nat)) // x < m
+
+	// Three cases are possible:
+	//
+	//   - overflow = 0, underflow = 0
+	//
+	// In this case, addition fits in our limbs, but we can still subtract away
+	// m without an underflow, so we need to perform the subtraction to reduce
+	// our result.
+	//
+	//   - overflow = 0, underflow = 1
+	//
+	// The addition fits in our limbs, but we can't subtract m without
+	// underflowing. The result is already reduced.
+	//
+	//   - overflow = 1, underflow = 1
+	//
+	// The addition does not fit in our limbs, and the subtraction's borrow
+	// would cancel out with the addition's carry. We need to subtract m to
+	// reduce our result.
+	//
+	// The overflow = 1, underflow = 0 case is not possible, because y is at
+	// most m - 1, and if adding m - 1 overflows, then subtracting m must
+	// necessarily underflow.
+	needSubtraction := ctEq(overflow, uint(underflow))
+
+	x.sub(needSubtraction, m.nat)
+	return x
+}
+
+// montgomeryRepresentation calculates x = x * R mod m, with R = 2^(_W * n) and
+// n = len(m.nat.limbs).
+//
+// Faster Montgomery multiplication replaces standard modular multiplication for
+// numbers in this representation.
+//
+// This assumes that x is already reduced mod m.
+func (x *Nat) montgomeryRepresentation(m *Modulus) *Nat {
+	// A Montgomery multiplication (which computes a * b / R) by R * R works out
+	// to a multiplication by R, which takes the value out of the Montgomery domain.
+	return x.montgomeryMul(NewNat().set(x), m.rr, m)
+}
+
+// montgomeryReduction calculates x = x / R mod m, with R = 2^(_W * n) and
+// n = len(m.nat.limbs).
+//
+// This assumes that x is already reduced mod m.
+func (x *Nat) montgomeryReduction(m *Modulus) *Nat {
+	// By Montgomery multiplying with 1 not in Montgomery representation, we
+	// convert out back from Montgomery representation, because it works out to
+	// dividing by R.
+	t0 := NewNat().set(x)
+	t1 := NewNat().ExpandFor(m)
+	t1.limbs[0] = 1
+	return x.montgomeryMul(t0, t1, m)
+}
+
+// montgomeryMul calculates d = a * b / R mod m, with R = 2^(_W * n) and
+// n = len(m.nat.limbs), using the Montgomery Multiplication technique.
+//
+// All inputs should be the same length, not aliasing d, and already
+// reduced modulo m. d will be resized to the size of m and overwritten.
+func (d *Nat) montgomeryMul(a *Nat, b *Nat, m *Modulus) *Nat {
+	d.resetFor(m)
+	if len(a.limbs) != len(m.nat.limbs) || len(b.limbs) != len(m.nat.limbs) {
+		panic("bigmod: invalid montgomeryMul input")
+	}
+
+	// See https://bearssl.org/bigint.html#montgomery-reduction-and-multiplication
+	// for a description of the algorithm implemented mostly in montgomeryLoop.
+	// See Add for how overflow, underflow, and needSubtraction relate.
+	overflow := montgomeryLoop(d.limbs, a.limbs, b.limbs, m.nat.limbs, m.m0inv)
+	underflow := not(d.cmpGeq(m.nat)) // d < m
+	needSubtraction := ctEq(overflow, uint(underflow))
+	d.sub(needSubtraction, m.nat)
+
+	return d
+}
+
+func montgomeryLoopGeneric(d, a, b, m []uint, m0inv uint) (overflow uint) {
+	// Eliminate bounds checks in the loop.
+	size := len(d)
+	a = a[:size]
+	b = b[:size]
+	m = m[:size]
+
+	for _, ai := range a {
+		// This is an unrolled iteration of the loop below with j = 0.
+		hi, lo := bits.Mul(ai, b[0])
+		z_lo, c := bits.Add(d[0], lo, 0)
+		f := (z_lo * m0inv) & _MASK // (d[0] + a[i] * b[0]) * m0inv
+		z_hi, _ := bits.Add(0, hi, c)
+		hi, lo = bits.Mul(f, m[0])
+		z_lo, c = bits.Add(z_lo, lo, 0)
+		z_hi, _ = bits.Add(z_hi, hi, c)
+		carry := z_hi<<1 | z_lo>>_W
+
+		for j := 1; j < size; j++ {
+			// z = d[j] + a[i] * b[j] + f * m[j] + carry <= 2^(2W+1) - 2^(W+1) + 2^W
+			hi, lo := bits.Mul(ai, b[j])
+			z_lo, c := bits.Add(d[j], lo, 0)
+			z_hi, _ := bits.Add(0, hi, c)
+			hi, lo = bits.Mul(f, m[j])
+			z_lo, c = bits.Add(z_lo, lo, 0)
+			z_hi, _ = bits.Add(z_hi, hi, c)
+			z_lo, c = bits.Add(z_lo, carry, 0)
+			z_hi, _ = bits.Add(z_hi, 0, c)
+			d[j-1] = z_lo & _MASK
+			carry = z_hi<<1 | z_lo>>_W // carry <= 2^(W+1) - 2
+		}
+
+		z := overflow + carry // z <= 2^(W+1) - 1
+		d[size-1] = z & _MASK
+		overflow = z >> _W // overflow <= 1
+	}
+	return
+}
+
+// Mul calculates x *= y mod m.
+//
+// x and y must already be reduced modulo m, they must share its announced
+// length, and they may not alias.
+func (x *Nat) Mul(y *Nat, m *Modulus) *Nat {
+	// A Montgomery multiplication by a value out of the Montgomery domain
+	// takes the result out of Montgomery representation.
+	xR := NewNat().set(x).montgomeryRepresentation(m) // xR = x * R mod m
+	return x.montgomeryMul(xR, y, m)                  // x = xR * y / R mod m
+}
+
+// Exp calculates x = y^e mod m.
+//
+// The exponent e is represented in big-endian order. The output will be resized
+// to the size of m and overwritten. y must already be reduced modulo m.
+func (x *Nat) Exp(y *Nat, e []byte, m *Modulus) *Nat {
+	out, x := x, y
+	// We use a 4 bit window. For our RSA workload, 4 bit windows are faster
+	// than 2 bit windows, but use an extra 12 nats worth of scratch space.
+	// Using bit sizes that don't divide 8 are more complex to implement.
+
+	table := [(1 << 4) - 1]*Nat{ // table[i] = x ^ (i+1)
+		// newNat calls are unrolled so they are allocated on the stack.
+		NewNat(), NewNat(), NewNat(), NewNat(), NewNat(),
+		NewNat(), NewNat(), NewNat(), NewNat(), NewNat(),
+		NewNat(), NewNat(), NewNat(), NewNat(), NewNat(),
+	}
+	table[0].set(x).montgomeryRepresentation(m)
+	for i := 1; i < len(table); i++ {
+		table[i].montgomeryMul(table[i-1], table[0], m)
+	}
+
+	out.resetFor(m)
+	out.limbs[0] = 1
+	out.montgomeryRepresentation(m)
+	t0 := NewNat().ExpandFor(m)
+	t1 := NewNat().ExpandFor(m)
+	for _, b := range e {
+		for _, j := range []int{4, 0} {
+			// Square four times.
+			t1.montgomeryMul(out, out, m)
+			out.montgomeryMul(t1, t1, m)
+			t1.montgomeryMul(out, out, m)
+			out.montgomeryMul(t1, t1, m)
+
+			// Select x^k in constant time from the table.
+			k := uint((b >> j) & 0b1111)
+			for i := range table {
+				t0.assign(ctEq(k, uint(i+1)), table[i])
+			}
+
+			// Multiply by x^k, discarding the result if k = 0.
+			t1.montgomeryMul(out, t0, m)
+			out.assign(not(ctEq(k, 0)), t1)
+		}
+	}
+
+	return out.montgomeryReduction(m)
+}

+ 8 - 0
vendor/filippo.io/bigmod/nat_amd64.go

@@ -0,0 +1,8 @@
+// Code generated by command: go run nat_amd64_asm.go -out ../nat_amd64.s -stubs ../nat_amd64.go -pkg bigmod. DO NOT EDIT.
+
+//go:build amd64 && gc && !purego
+
+package bigmod
+
+//go:noescape
+func montgomeryLoop(d []uint, a []uint, b []uint, m []uint, m0inv uint) uint

+ 68 - 0
vendor/filippo.io/bigmod/nat_amd64.s

@@ -0,0 +1,68 @@
+// Code generated by command: go run nat_amd64_asm.go -out ../nat_amd64.s -stubs ../nat_amd64.go -pkg bigmod. DO NOT EDIT.
+
+//go:build amd64 && gc && !purego
+
+// func montgomeryLoop(d []uint, a []uint, b []uint, m []uint, m0inv uint) uint
+TEXT ·montgomeryLoop(SB), $8-112
+	MOVQ d_len+8(FP), CX
+	MOVQ d_base+0(FP), BX
+	MOVQ b_base+48(FP), SI
+	MOVQ m_base+72(FP), DI
+	MOVQ m0inv+96(FP), R8
+	XORQ R9, R9
+	XORQ R10, R10
+
+outerLoop:
+	MOVQ  a_base+24(FP), R11
+	MOVQ  (R11)(R10*8), R11
+	MOVQ  (SI), AX
+	MULQ  R11
+	MOVQ  AX, R13
+	MOVQ  DX, R12
+	ADDQ  (BX), R13
+	ADCQ  $0x00, R12
+	MOVQ  R8, R14
+	IMULQ R13, R14
+	BTRQ  $0x3f, R14
+	MOVQ  (DI), AX
+	MULQ  R14
+	ADDQ  AX, R13
+	ADCQ  DX, R12
+	SHRQ  $0x3f, R12, R13
+	XORQ  R12, R12
+	INCQ  R12
+	JMP   innerLoopCondition
+
+innerLoop:
+	MOVQ (SI)(R12*8), AX
+	MULQ R11
+	MOVQ AX, BP
+	MOVQ DX, R15
+	MOVQ (DI)(R12*8), AX
+	MULQ R14
+	ADDQ AX, BP
+	ADCQ DX, R15
+	ADDQ (BX)(R12*8), BP
+	ADCQ $0x00, R15
+	ADDQ R13, BP
+	ADCQ $0x00, R15
+	MOVQ BP, AX
+	BTRQ $0x3f, AX
+	MOVQ AX, -8(BX)(R12*8)
+	SHRQ $0x3f, R15, BP
+	MOVQ BP, R13
+	INCQ R12
+
+innerLoopCondition:
+	CMPQ CX, R12
+	JGT  innerLoop
+	ADDQ R13, R9
+	MOVQ R9, AX
+	BTRQ $0x3f, AX
+	MOVQ AX, -8(BX)(CX*8)
+	SHRQ $0x3f, R9
+	INCQ R10
+	CMPQ CX, R10
+	JGT  outerLoop
+	MOVQ R9, ret+104(FP)
+	RET

+ 11 - 0
vendor/filippo.io/bigmod/nat_noasm.go

@@ -0,0 +1,11 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 || !gc || purego
+
+package bigmod
+
+func montgomeryLoop(d, a, b, m []uint, m0inv uint) uint {
+	return montgomeryLoopGeneric(d, a, b, m, m0inv)
+}

+ 15 - 0
vendor/filippo.io/keygen/LICENSE

@@ -0,0 +1,15 @@
+ISC License
+
+Copyright 2023 Filippo Valsorda
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ 99 - 0
vendor/filippo.io/keygen/ecdsa.go

@@ -0,0 +1,99 @@
+package keygen
+
+import (
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/sha512"
+	"fmt"
+	"io"
+	"math/big"
+
+	"filippo.io/bigmod"
+	"golang.org/x/crypto/hkdf"
+)
+
+// ECDSA generates an ECDSA key deterministically from a random secret using a
+// procedure equivalent to that in FIPS 186-5, Appendix A.2.2.
+//
+// The secret should be uniform, must be at least 128 bits long (ideally, 256
+// bits long), and should not be reused for other purposes.
+//
+// The output MAY CHANGE until this package reaches v1.0.0.
+func ECDSA(c elliptic.Curve, secret []byte) (*ecdsa.PrivateKey, error) {
+	if len(secret) < 16 {
+		return nil, fmt.Errorf("input secret must be at least 128 bits")
+	}
+
+	var salt string
+	switch c {
+	case elliptic.P256():
+		salt = "ECDSA key generation: NIST P-256"
+	case elliptic.P384():
+		salt = "ECDSA key generation: NIST P-384"
+	case elliptic.P521():
+		salt = "ECDSA key generation: NIST P-521"
+	default:
+		return nil, fmt.Errorf("unsupported curve %s", c.Params().Name)
+	}
+
+	prk := hkdf.Extract(sha512.New, secret, []byte(salt))
+	r := hkdf.Expand(sha512.New, prk, nil)
+
+	N := bigmod.NewModulusFromBig(c.Params().N)
+
+	b := make([]byte, N.Size())
+	if _, err := io.ReadFull(r, b); err != nil {
+		return nil, fmt.Errorf("HKDF error %v", err)
+	}
+
+	// Since P-521's order bitsize is not a multiple of 8, mask off the excess
+	// bits to increase the chance of hitting a value in (0, N).
+	if c == elliptic.P521() {
+		b[0] &= 0b0000_0001
+	}
+
+	// FIPS 186-4 checks k <= N - 2 and then adds one. Checking 0 < k <= N - 1
+	// is strictly equivalent but is more API-friendly, since SetBytes already
+	// checks for overflows and doesn't require an addition.
+	// (None of this matters anyway because the chance of selecting zero is
+	// cryptographically negligible.)
+	k := bigmod.NewNat()
+	if _, err := k.SetBytes(b, N); err != nil || k.IsZero() == 1 {
+		return ECDSA(c, prk)
+	}
+
+	priv := new(ecdsa.PrivateKey)
+	priv.PublicKey.Curve = c
+	priv.D = new(big.Int).SetBytes(k.Bytes(N))
+	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes(N))
+	return priv, nil
+}
+
+// ECDSALegacy generates an ECDSA key deterministically from a random stream
+// using the procedure given in FIPS 186-5, Appendix A.2.1, in a way compatible
+// with Go 1.19.
+//
+// Note that ECDSALegacy may leak bits of the key through timing side-channels.
+func ECDSALegacy(c elliptic.Curve, rand io.Reader) (*ecdsa.PrivateKey, error) {
+	params := c.Params()
+	// Note that for P-521 this will actually be 63 bits more than the order, as
+	// division rounds down, but the extra bit is inconsequential and we want to
+	// retain compatibility with Go 1.19 as was implemented.
+	b := make([]byte, params.N.BitLen()/8+8)
+	_, err := io.ReadFull(rand, b)
+	if err != nil {
+		return nil, err
+	}
+
+	one := big.NewInt(1)
+	k := new(big.Int).SetBytes(b)
+	n := new(big.Int).Sub(params.N, one)
+	k.Mod(k, n)
+	k.Add(k, one)
+
+	priv := new(ecdsa.PrivateKey)
+	priv.PublicKey.Curve = c
+	priv.D = k
+	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
+	return priv, nil
+}

+ 1 - 6
vendor/github.com/refraction-networking/conjure/pkg/dtls/listener.go

@@ -256,10 +256,5 @@ func (l *Listener) getCertificateFromClientHello(clientHello *dtls.ClientHelloIn
 }
 
 func randomCertificate() (*tls.Certificate, error) {
-	seedBytes := []byte{}
-	_, err := rand.Read(seedBytes)
-	if err != nil {
-		return nil, err
-	}
-	return newCertificate(seedBytes)
+	return newCertificate(rand.Reader)
 }

+ 19 - 19
vendor/github.com/refraction-networking/conjure/pkg/dtls/seedtocert.go

@@ -16,12 +16,13 @@ import (
 	"math/big"
 	"time"
 
+	"filippo.io/keygen"
 	"github.com/pion/dtls/v2/pkg/protocol/handshake"
 	"golang.org/x/crypto/hkdf"
 )
 
 func clientHelloRandomFromSeed(seed []byte) ([handshake.RandomBytesLength]byte, error) {
-	randSource := hkdf.New(sha256.New, seed, nil, nil)
+	randSource := hkdf.New(sha256.New, seed, []byte("clientHelloRandomFromSeed"), nil)
 	randomBytes := [handshake.RandomBytesLength]byte{}
 
 	_, err := io.ReadFull(randSource, randomBytes[:])
@@ -33,19 +34,17 @@ func clientHelloRandomFromSeed(seed []byte) ([handshake.RandomBytesLength]byte,
 }
 
 // getPrivkey creates ECDSA private key used in DTLS Certificates
-func getPrivkey(seed []byte) (*ecdsa.PrivateKey, error) {
-	randSource := hkdf.New(sha256.New, seed, nil, nil)
-
-	privkey, err := ecdsa.GenerateKey(elliptic.P256(), &Not1Reader{r: randSource})
+func getPrivkey(randSource io.Reader) (*ecdsa.PrivateKey, error) {
+	privkey, err := keygen.ECDSALegacy(elliptic.P256(), randSource)
 	if err != nil {
 		return &ecdsa.PrivateKey{}, err
 	}
+
 	return privkey, nil
 }
 
 // getX509Tpl creates x509 template for x509 Certificates generation used in DTLS Certificates.
-func getX509Tpl(seed []byte) (*x509.Certificate, error) {
-	randSource := hkdf.New(sha256.New, seed, nil, nil)
+func getX509Tpl(randSource io.Reader) (*x509.Certificate, error) {
 
 	maxBigInt := new(big.Int)
 	maxBigInt.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(maxBigInt, big.NewInt(1))
@@ -85,20 +84,19 @@ func getX509Tpl(seed []byte) (*x509.Certificate, error) {
 	}, nil
 }
 
-func newCertificate(seed []byte) (*tls.Certificate, error) {
-	privkey, err := getPrivkey(seed)
+func newCertificate(randSource io.Reader) (*tls.Certificate, error) {
+
+	privkey, err := getPrivkey(randSource)
 	if err != nil {
 		return &tls.Certificate{}, err
 	}
 
-	tpl, err := getX509Tpl(seed)
+	tpl, err := getX509Tpl(randSource)
 	if err != nil {
 		return &tls.Certificate{}, err
 	}
 
-	randSource := hkdf.New(sha256.New, seed, nil, nil)
-
-	certDER, err := x509.CreateCertificate(randSource, tpl, tpl, privkey.Public(), privkey)
+	certDER, err := x509.CreateCertificate(rand.Reader, tpl, tpl, privkey.Public(), privkey)
 	if err != nil {
 		return &tls.Certificate{}, err
 	}
@@ -110,15 +108,17 @@ func newCertificate(seed []byte) (*tls.Certificate, error) {
 }
 
 func certsFromSeed(seed []byte) (*tls.Certificate, *tls.Certificate, error) {
-	clientCert, err := newCertificate(seed)
+	randSource := hkdf.New(sha256.New, seed, []byte("certsFromSeed"), nil)
+
+	clientCert, err := newCertificate(randSource)
 	if err != nil {
 		return &tls.Certificate{}, &tls.Certificate{}, fmt.Errorf("error generate cert: %v", err)
 	}
 
-	// serverCert, err := newCertificate(seed)
-	// if err != nil {
-	// 	return &tls.Certificate{}, &tls.Certificate{}, fmt.Errorf("error generate cert: %v", err)
-	// }
+	serverCert, err := newCertificate(randSource)
+	if err != nil {
+		return &tls.Certificate{}, &tls.Certificate{}, fmt.Errorf("error generate cert: %v", err)
+	}
 
-	return clientCert, clientCert, nil
+	return clientCert, serverCert, nil
 }

+ 7 - 1
vendor/modules.txt

@@ -1,3 +1,9 @@
+# filippo.io/bigmod v0.0.1
+## explicit; go 1.20
+filippo.io/bigmod
+# filippo.io/keygen v0.0.0-20230306160926-5201437acf8e
+## explicit; go 1.20
+filippo.io/keygen
 # github.com/AndreasBriese/bbloom v0.0.0-20170702084017-28f7e881ca57
 ## explicit
 github.com/AndreasBriese/bbloom
@@ -254,7 +260,7 @@ github.com/pmezard/go-difflib/difflib
 # github.com/quic-go/qpack v0.4.0
 ## explicit; go 1.18
 github.com/quic-go/qpack
-# github.com/refraction-networking/conjure v0.7.8
+# github.com/refraction-networking/conjure v0.7.9
 ## explicit; go 1.18
 github.com/refraction-networking/conjure/pkg/client/assets
 github.com/refraction-networking/conjure/pkg/core