diff --git a/external/README.md b/external/README.md deleted file mode 100644 index 193416294..000000000 --- a/external/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Note - -The `external` dir in the project exists for historical reasons. We will migrate to use go mod to maintain 3rd party libraries. - -Fow now, all modules under external are used by "quic-go" to support quic protocol, and can't migrate without a breaking change. - -The plan is that we will remove the whole `external` dir when `quic-go` is tested to be matured enough in production. \ No newline at end of file diff --git a/external/github.com/cheekybits/genny/LICENSE b/external/github.com/cheekybits/genny/LICENSE deleted file mode 100644 index 519d7f227..000000000 --- a/external/github.com/cheekybits/genny/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 cheekybits - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/external/github.com/cheekybits/genny/generic/doc.go b/external/github.com/cheekybits/genny/generic/doc.go deleted file mode 100644 index 3bd6c869c..000000000 --- a/external/github.com/cheekybits/genny/generic/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package generic contains the generic marker types. -package generic diff --git a/external/github.com/cheekybits/genny/generic/generic.go b/external/github.com/cheekybits/genny/generic/generic.go deleted file mode 100644 index 80cc48ca9..000000000 --- a/external/github.com/cheekybits/genny/generic/generic.go +++ /dev/null @@ -1,13 +0,0 @@ -package generic - -// Type is the placeholder type that indicates a generic value. -// When genny is executed, variables of this type will be replaced with -// references to the specific types. -// var GenericType generic.Type -type Type interface{} - -// Number is the placeholder type that indiccates a generic numerical value. -// When genny is executed, variables of this type will be replaced with -// references to the specific types. -// var GenericType generic.Number -type Number float64 diff --git a/external/github.com/cloudflare/sidh/LICENSE b/external/github.com/cloudflare/sidh/LICENSE deleted file mode 100644 index ea60699d7..000000000 --- a/external/github.com/cloudflare/sidh/LICENSE +++ /dev/null @@ -1,57 +0,0 @@ -Copyright (c) 2017 Cloudflare. 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 Cloudflare 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. - -======================================================================== - -The x64 field arithmetic implementation was derived from the Microsoft Research -SIDH implementation, , available -under the following license: - -======================================================================== - -MIT License - -Copyright (c) Microsoft Corporation. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE diff --git a/external/github.com/cloudflare/sidh/internal/arith/generic.go b/external/github.com/cloudflare/sidh/internal/arith/generic.go deleted file mode 100644 index dc84892d3..000000000 --- a/external/github.com/cloudflare/sidh/internal/arith/generic.go +++ /dev/null @@ -1,66 +0,0 @@ -// +build noasm !amd64 - -package internal - -// helper used for Uint128 representation -type Uint128 struct { - H, L uint64 -} - -// Adds 2 64bit digits in constant time. -// Returns result and carry (1 or 0) -func Addc64(cin, a, b uint64) (ret, cout uint64) { - t := a + cin - ret = b + t - cout = ((a & b) | ((a | b) & (^ret))) >> 63 - return -} - -// Subtracts 2 64bit digits in constant time. -// Returns result and borrow (1 or 0) -func Subc64(bIn, a, b uint64) (ret, bOut uint64) { - var tmp1 = a - b - // Set bOut if bIn!=0 and tmp1==0 in constant time - bOut = bIn & (1 ^ ((tmp1 | uint64(0-tmp1)) >> 63)) - // Constant time check if x> 63 - ret = tmp1 - bIn - return -} - -// Multiplies 2 64bit digits in constant time -func Mul64(a, b uint64) (res Uint128) { - var al, bl, ah, bh, albl, albh, ahbl, ahbh uint64 - var res1, res2, res3 uint64 - var carry, maskL, maskH, temp uint64 - - maskL = (^maskL) >> 32 - maskH = ^maskL - - al = a & maskL - ah = a >> 32 - bl = b & maskL - bh = b >> 32 - - albl = al * bl - albh = al * bh - ahbl = ah * bl - ahbh = ah * bh - res.L = albl & maskL - - res1 = albl >> 32 - res2 = ahbl & maskL - res3 = albh & maskL - temp = res1 + res2 + res3 - carry = temp >> 32 - res.L ^= temp << 32 - - res1 = ahbl >> 32 - res2 = albh >> 32 - res3 = ahbh & maskL - temp = res1 + res2 + res3 + carry - res.H = temp & maskL - carry = temp & maskH - res.H ^= (ahbh & maskH) + carry - return -} diff --git a/external/github.com/cloudflare/sidh/internal/isogeny/curve_ops.go b/external/github.com/cloudflare/sidh/internal/isogeny/curve_ops.go deleted file mode 100644 index d658d81a2..000000000 --- a/external/github.com/cloudflare/sidh/internal/isogeny/curve_ops.go +++ /dev/null @@ -1,440 +0,0 @@ -package internal - -type CurveOperations struct { - Params *SidhParams -} - -// Computes j-invariant for a curve y2=x3+A/Cx+x with A,C in F_(p^2). Result -// is returned in jBytes buffer, encoded in little-endian format. Caller -// provided jBytes buffer has to be big enough to j-invariant value. In case -// of SIDH, buffer size must be at least size of shared secret. -// Implementation corresponds to Algorithm 9 from SIKE. -func (c *CurveOperations) Jinvariant(cparams *ProjectiveCurveParameters, jBytes []byte) { - var j, t0, t1 Fp2Element - - op := c.Params.Op - op.Square(&j, &cparams.A) // j = A^2 - op.Square(&t1, &cparams.C) // t1 = C^2 - op.Add(&t0, &t1, &t1) // t0 = t1 + t1 - op.Sub(&t0, &j, &t0) // t0 = j - t0 - op.Sub(&t0, &t0, &t1) // t0 = t0 - t1 - op.Sub(&j, &t0, &t1) // t0 = t0 - t1 - op.Square(&t1, &t1) // t1 = t1^2 - op.Mul(&j, &j, &t1) // j = j * t1 - op.Add(&t0, &t0, &t0) // t0 = t0 + t0 - op.Add(&t0, &t0, &t0) // t0 = t0 + t0 - op.Square(&t1, &t0) // t1 = t0^2 - op.Mul(&t0, &t0, &t1) // t0 = t0 * t1 - op.Add(&t0, &t0, &t0) // t0 = t0 + t0 - op.Add(&t0, &t0, &t0) // t0 = t0 + t0 - op.Inv(&j, &j) // j = 1/j - op.Mul(&j, &t0, &j) // j = t0 * j - - c.Fp2ToBytes(jBytes, &j) -} - -// Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function -// recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE. -func (c *CurveOperations) RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2Element) { - var t0, t1 Fp2Element - - op := c.Params.Op - op.Add(&t1, xp, xq) // t1 = Xp + Xq - op.Mul(&t0, xp, xq) // t0 = Xp * Xq - op.Mul(&curve.A, xr, &t1) // A = X(q-p) * t1 - op.Add(&curve.A, &curve.A, &t0) // A = A + t0 - op.Mul(&t0, &t0, xr) // t0 = t0 * X(q-p) - op.Sub(&curve.A, &curve.A, &c.Params.OneFp2) // A = A - 1 - op.Add(&t0, &t0, &t0) // t0 = t0 + t0 - op.Add(&t1, &t1, xr) // t1 = t1 + X(q-p) - op.Add(&t0, &t0, &t0) // t0 = t0 + t0 - op.Square(&curve.A, &curve.A) // A = A^2 - op.Inv(&t0, &t0) // t0 = 1/t0 - op.Mul(&curve.A, &curve.A, &t0) // A = A * t0 - op.Sub(&curve.A, &curve.A, &t1) // A = A - t1 -} - -// Computes equivalence (A:C) ~ (A+2C : A-2C) -func (c *CurveOperations) CalcCurveParamsEquiv3(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv { - var coef CurveCoefficientsEquiv - var c2 Fp2Element - var op = c.Params.Op - - op.Add(&c2, &cparams.C, &cparams.C) - // A24p = A+2*C - op.Add(&coef.A, &cparams.A, &c2) - // A24m = A-2*C - op.Sub(&coef.C, &cparams.A, &c2) - return coef -} - -// Computes equivalence (A:C) ~ (A+2C : 4C) -func (c *CurveOperations) CalcCurveParamsEquiv4(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv { - var coefEq CurveCoefficientsEquiv - var op = c.Params.Op - - op.Add(&coefEq.C, &cparams.C, &cparams.C) - // A24p = A+2C - op.Add(&coefEq.A, &cparams.A, &coefEq.C) - // C24 = 4*C - op.Add(&coefEq.C, &coefEq.C, &coefEq.C) - return coefEq -} - -// Helper function for RightToLeftLadder(). Returns A+2C / 4. -func (c *CurveOperations) CalcAplus2Over4(cparams *ProjectiveCurveParameters) (ret Fp2Element) { - var tmp Fp2Element - var op = c.Params.Op - - // 2C - op.Add(&tmp, &cparams.C, &cparams.C) - // A+2C - op.Add(&ret, &cparams.A, &tmp) - // 1/4C - op.Add(&tmp, &tmp, &tmp) - op.Inv(&tmp, &tmp) - // A+2C/4C - op.Mul(&ret, &ret, &tmp) - return -} - -// Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C). -func (c *CurveOperations) RecoverCurveCoefficients3(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) { - var op = c.Params.Op - - op.Add(&cparams.A, &coefEq.A, &coefEq.C) - // cparams.A = 2*(A+2C+A-2C) = 4A - op.Add(&cparams.A, &cparams.A, &cparams.A) - // cparams.C = (A+2C-A+2C) = 4C - op.Sub(&cparams.C, &coefEq.A, &coefEq.C) - return -} - -// Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C). -func (c *CurveOperations) RecoverCurveCoefficients4(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) { - var op = c.Params.Op - // cparams.C = (4C)*1/2=2C - op.Mul(&cparams.C, &coefEq.C, &c.Params.HalfFp2) - // cparams.A = A+2C - 2C = A - op.Sub(&cparams.A, &coefEq.A, &cparams.C) - // cparams.C = 2C * 1/2 = C - op.Mul(&cparams.C, &cparams.C, &c.Params.HalfFp2) - return -} - -// Combined coordinate doubling and differential addition. Takes projective points -// P,Q,Q-P and (A+2C)/4C curve E coefficient. Returns 2*P and P+Q calculated on E. -// Function is used only by RightToLeftLadder. Corresponds to Algorithm 5 of SIKE -func (c *CurveOperations) xDblAdd(P, Q, QmP *ProjectivePoint, a24 *Fp2Element) (dblP, PaQ ProjectivePoint) { - var t0, t1, t2 Fp2Element - var op = c.Params.Op - - xQmP, zQmP := &QmP.X, &QmP.Z - xPaQ, zPaQ := &PaQ.X, &PaQ.Z - x2P, z2P := &dblP.X, &dblP.Z - xP, zP := &P.X, &P.Z - xQ, zQ := &Q.X, &Q.Z - - op.Add(&t0, xP, zP) // t0 = Xp+Zp - op.Sub(&t1, xP, zP) // t1 = Xp-Zp - op.Square(x2P, &t0) // 2P.X = t0^2 - op.Sub(&t2, xQ, zQ) // t2 = Xq-Zq - op.Add(xPaQ, xQ, zQ) // Xp+q = Xq+Zq - op.Mul(&t0, &t0, &t2) // t0 = t0 * t2 - op.Mul(z2P, &t1, &t1) // 2P.Z = t1 * t1 - op.Mul(&t1, &t1, xPaQ) // t1 = t1 * Xp+q - op.Sub(&t2, x2P, z2P) // t2 = 2P.X - 2P.Z - op.Mul(x2P, x2P, z2P) // 2P.X = 2P.X * 2P.Z - op.Mul(xPaQ, a24, &t2) // Xp+q = A24 * t2 - op.Sub(zPaQ, &t0, &t1) // Zp+q = t0 - t1 - op.Add(z2P, xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z - op.Add(xPaQ, &t0, &t1) // Xp+q = t0 + t1 - op.Mul(z2P, z2P, &t2) // 2P.Z = 2P.Z * t2 - op.Square(zPaQ, zPaQ) // Zp+q = Zp+q ^ 2 - op.Square(xPaQ, xPaQ) // Xp+q = Xp+q ^ 2 - op.Mul(zPaQ, xQmP, zPaQ) // Zp+q = Xq-p * Zp+q - op.Mul(xPaQ, zQmP, xPaQ) // Xp+q = Zq-p * Xp+q - return -} - -// Given the curve parameters, xP = x(P), computes xP = x([2^k]P) -// Safe to overlap xP, x2P. -func (c *CurveOperations) Pow2k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) { - var t0, t1 Fp2Element - var op = c.Params.Op - - x, z := &xP.X, &xP.Z - for i := uint32(0); i < k; i++ { - op.Sub(&t0, x, z) // t0 = Xp - Zp - op.Add(&t1, x, z) // t1 = Xp + Zp - op.Square(&t0, &t0) // t0 = t0 ^ 2 - op.Square(&t1, &t1) // t1 = t1 ^ 2 - op.Mul(z, ¶ms.C, &t0) // Z2p = C24 * t0 - op.Mul(x, z, &t1) // X2p = Z2p * t1 - op.Sub(&t1, &t1, &t0) // t1 = t1 - t0 - op.Mul(&t0, ¶ms.A, &t1) // t0 = A24+ * t1 - op.Add(z, z, &t0) // Z2p = Z2p + t0 - op.Mul(z, z, &t1) // Zp = Z2p * t1 - } -} - -// Given the curve parameters, xP = x(P), and k >= 0, compute xP = x([3^k]P). -// -// Safe to overlap xP, xR. -func (c *CurveOperations) Pow3k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) { - var t0, t1, t2, t3, t4, t5, t6 Fp2Element - var op = c.Params.Op - - x, z := &xP.X, &xP.Z - for i := uint32(0); i < k; i++ { - op.Sub(&t0, x, z) // t0 = Xp - Zp - op.Square(&t2, &t0) // t2 = t0^2 - op.Add(&t1, x, z) // t1 = Xp + Zp - op.Square(&t3, &t1) // t3 = t1^2 - op.Add(&t4, &t1, &t0) // t4 = t1 + t0 - op.Sub(&t0, &t1, &t0) // t0 = t1 - t0 - op.Square(&t1, &t4) // t1 = t4^2 - op.Sub(&t1, &t1, &t3) // t1 = t1 - t3 - op.Sub(&t1, &t1, &t2) // t1 = t1 - t2 - op.Mul(&t5, &t3, ¶ms.A) // t5 = t3 * A24+ - op.Mul(&t3, &t3, &t5) // t3 = t5 * t3 - op.Mul(&t6, &t2, ¶ms.C) // t6 = t2 * A24- - op.Mul(&t2, &t2, &t6) // t2 = t2 * t6 - op.Sub(&t3, &t2, &t3) // t3 = t2 - t3 - op.Sub(&t2, &t5, &t6) // t2 = t5 - t6 - op.Mul(&t1, &t2, &t1) // t1 = t2 * t1 - op.Add(&t2, &t3, &t1) // t2 = t3 + t1 - op.Square(&t2, &t2) // t2 = t2^2 - op.Mul(x, &t2, &t4) // X3p = t2 * t4 - op.Sub(&t1, &t3, &t1) // t1 = t3 - t1 - op.Square(&t1, &t1) // t1 = t1^2 - op.Mul(z, &t1, &t0) // Z3p = t1 * t0 - } -} - -// Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3). -// -// All xi, yi must be distinct. -func (c *CurveOperations) Fp2Batch3Inv(x1, x2, x3, y1, y2, y3 *Fp2Element) { - var x1x2, t Fp2Element - var op = c.Params.Op - - op.Mul(&x1x2, x1, x2) // x1*x2 - op.Mul(&t, &x1x2, x3) // 1/(x1*x2*x3) - op.Inv(&t, &t) - op.Mul(y1, &t, x2) // 1/x1 - op.Mul(y1, y1, x3) - op.Mul(y2, &t, x1) // 1/x2 - op.Mul(y2, y2, x3) - op.Mul(y3, &t, &x1x2) // 1/x3 -} - -// ScalarMul3Pt is a right-to-left point multiplication that given the -// x-coordinate of P, Q and P-Q calculates the x-coordinate of R=Q+[scalar]P. -// nbits must be smaller or equal to len(scalar). -func (c *CurveOperations) ScalarMul3Pt(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint, scalar []uint8) ProjectivePoint { - var R0, R2, R1 ProjectivePoint - var op = c.Params.Op - aPlus2Over4 := c.CalcAplus2Over4(cparams) - R1 = *P - R2 = *PmQ - R0 = *Q - - // Iterate over the bits of the scalar, bottom to top - prevBit := uint8(0) - for i := uint(0); i < nbits; i++ { - bit := (scalar[i>>3] >> (i & 7) & 1) - swap := prevBit ^ bit - prevBit = bit - op.CondSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, swap) - R0, R2 = c.xDblAdd(&R0, &R2, &R1, &aPlus2Over4) - } - op.CondSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, prevBit) - return R1 -} - -// Convert the input to wire format. -// -// The output byte slice must be at least 2*bytelen(p) bytes long. -func (c *CurveOperations) Fp2ToBytes(output []byte, fp2 *Fp2Element) { - if len(output) < 2*c.Params.Bytelen { - panic("output byte slice too short") - } - var a Fp2Element - c.Params.Op.FromMontgomery(fp2, &a) - - // convert to bytes in little endian form - for i := 0; i < c.Params.Bytelen; i++ { - // set i = j*8 + k - fp2 := i / 8 - k := uint64(i % 8) - output[i] = byte(a.A[fp2] >> (8 * k)) - output[i+c.Params.Bytelen] = byte(a.B[fp2] >> (8 * k)) - } -} - -// Read 2*bytelen(p) bytes into the given ExtensionFieldElement. -// -// It is an error to call this function if the input byte slice is less than 2*bytelen(p) bytes long. -func (c *CurveOperations) Fp2FromBytes(fp2 *Fp2Element, input []byte) { - if len(input) < 2*c.Params.Bytelen { - panic("input byte slice too short") - } - - for i := 0; i < c.Params.Bytelen; i++ { - j := i / 8 - k := uint64(i % 8) - fp2.A[j] |= uint64(input[i]) << (8 * k) - fp2.B[j] |= uint64(input[i+c.Params.Bytelen]) << (8 * k) - } - c.Params.Op.ToMontgomery(fp2) -} - -/* ------------------------------------------------------------------------- - Mechnisms used for isogeny calculations - -------------------------------------------------------------------------*/ - -// Constructs isogeny3 objects -func Newisogeny3(op FieldOps) Isogeny { - return &isogeny3{Field: op} -} - -// Constructs isogeny4 objects -func Newisogeny4(op FieldOps) Isogeny { - return &isogeny4{isogeny3: isogeny3{Field: op}} -} - -// Given a three-torsion point p = x(PB) on the curve E_(A:C), construct the -// three-isogeny phi : E_(A:C) -> E_(A:C)/ = E_(A':C'). -// -// Input: (XP_3: ZP_3), where P_3 has exact order 3 on E_A/C -// Output: * Curve coordinates (A' + 2C', A' - 2C') corresponding to E_A'/C' = A_E/C/ -// * Isogeny phi with constants in F_p^2 -func (phi *isogeny3) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv { - var t0, t1, t2, t3, t4 Fp2Element - var coefEq CurveCoefficientsEquiv - var K1, K2 = &phi.K1, &phi.K2 - - op := phi.Field - op.Sub(K1, &p.X, &p.Z) // K1 = XP3 - ZP3 - op.Square(&t0, K1) // t0 = K1^2 - op.Add(K2, &p.X, &p.Z) // K2 = XP3 + ZP3 - op.Square(&t1, K2) // t1 = K2^2 - op.Add(&t2, &t0, &t1) // t2 = t0 + t1 - op.Add(&t3, K1, K2) // t3 = K1 + K2 - op.Square(&t3, &t3) // t3 = t3^2 - op.Sub(&t3, &t3, &t2) // t3 = t3 - t2 - op.Add(&t2, &t1, &t3) // t2 = t1 + t3 - op.Add(&t3, &t3, &t0) // t3 = t3 + t0 - op.Add(&t4, &t3, &t0) // t4 = t3 + t0 - op.Add(&t4, &t4, &t4) // t4 = t4 + t4 - op.Add(&t4, &t1, &t4) // t4 = t1 + t4 - op.Mul(&coefEq.C, &t2, &t4) // A24m = t2 * t4 - op.Add(&t4, &t1, &t2) // t4 = t1 + t2 - op.Add(&t4, &t4, &t4) // t4 = t4 + t4 - op.Add(&t4, &t0, &t4) // t4 = t0 + t4 - op.Mul(&t4, &t3, &t4) // t4 = t3 * t4 - op.Sub(&t0, &t4, &coefEq.C) // t0 = t4 - A24m - op.Add(&coefEq.A, &coefEq.C, &t0) // A24p = A24m + t0 - return coefEq -} - -// Given a 3-isogeny phi and a point pB = x(PB), compute x(QB), the x-coordinate -// of the image QB = phi(PB) of PB under phi : E_(A:C) -> E_(A':C'). -// -// The output xQ = x(Q) is then a point on the curve E_(A':C'); the curve -// parameters are returned by the GenerateCurve function used to construct phi. -func (phi *isogeny3) EvaluatePoint(p *ProjectivePoint) ProjectivePoint { - var t0, t1, t2 Fp2Element - var q ProjectivePoint - var K1, K2 = &phi.K1, &phi.K2 - var px, pz = &p.X, &p.Z - - op := phi.Field - op.Add(&t0, px, pz) // t0 = XQ + ZQ - op.Sub(&t1, px, pz) // t1 = XQ - ZQ - op.Mul(&t0, K1, &t0) // t2 = K1 * t0 - op.Mul(&t1, K2, &t1) // t1 = K2 * t1 - op.Add(&t2, &t0, &t1) // t2 = t0 + t1 - op.Sub(&t0, &t1, &t0) // t0 = t1 - t0 - op.Square(&t2, &t2) // t2 = t2 ^ 2 - op.Square(&t0, &t0) // t0 = t0 ^ 2 - op.Mul(&q.X, px, &t2) // XQ'= XQ * t2 - op.Mul(&q.Z, pz, &t0) // ZQ'= ZQ * t0 - return q -} - -// Given a four-torsion point p = x(PB) on the curve E_(A:C), construct the -// four-isogeny phi : E_(A:C) -> E_(A:C)/ = E_(A':C'). -// -// Input: (XP_4: ZP_4), where P_4 has exact order 4 on E_A/C -// Output: * Curve coordinates (A' + 2C', 4C') corresponding to E_A'/C' = A_E/C/ -// * Isogeny phi with constants in F_p^2 -func (phi *isogeny4) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv { - var coefEq CurveCoefficientsEquiv - var xp4, zp4 = &p.X, &p.Z - var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3 - - op := phi.Field - op.Sub(K2, xp4, zp4) - op.Add(K3, xp4, zp4) - op.Square(K1, zp4) - op.Add(K1, K1, K1) - op.Square(&coefEq.C, K1) - op.Add(K1, K1, K1) - op.Square(&coefEq.A, xp4) - op.Add(&coefEq.A, &coefEq.A, &coefEq.A) - op.Square(&coefEq.A, &coefEq.A) - return coefEq -} - -// Given a 4-isogeny phi and a point xP = x(P), compute x(Q), the x-coordinate -// of the image Q = phi(P) of P under phi : E_(A:C) -> E_(A':C'). -// -// Input: Isogeny returned by GenerateCurve and point q=(Qx,Qz) from E0_A/C -// Output: Corresponding point q from E1_A'/C', where E1 is 4-isogenous to E0 -func (phi *isogeny4) EvaluatePoint(p *ProjectivePoint) ProjectivePoint { - var t0, t1 Fp2Element - var q = *p - var xq, zq = &q.X, &q.Z - var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3 - - op := phi.Field - op.Add(&t0, xq, zq) - op.Sub(&t1, xq, zq) - op.Mul(xq, &t0, K2) - op.Mul(zq, &t1, K3) - op.Mul(&t0, &t0, &t1) - op.Mul(&t0, &t0, K1) - op.Add(&t1, xq, zq) - op.Sub(zq, xq, zq) - op.Square(&t1, &t1) - op.Square(zq, zq) - op.Add(xq, &t0, &t1) - op.Sub(&t0, zq, &t0) - op.Mul(xq, xq, &t1) - op.Mul(zq, zq, &t0) - return q -} - -/* ------------------------------------------------------------------------- - Utils - -------------------------------------------------------------------------*/ -func (point *ProjectivePoint) ToAffine(c *CurveOperations) *Fp2Element { - var affine_x Fp2Element - c.Params.Op.Inv(&affine_x, &point.Z) - c.Params.Op.Mul(&affine_x, &affine_x, &point.X) - return &affine_x -} - -// Cleans data in fp -func (fp *Fp2Element) Zeroize() { - // Zeroizing in 2 separated loops tells compiler to - // use fast runtime.memclr() - for i := range fp.A { - fp.A[i] = 0 - } - for i := range fp.B { - fp.B[i] = 0 - } -} diff --git a/external/github.com/cloudflare/sidh/internal/isogeny/types.go b/external/github.com/cloudflare/sidh/internal/isogeny/types.go deleted file mode 100644 index ecf0129e4..000000000 --- a/external/github.com/cloudflare/sidh/internal/isogeny/types.go +++ /dev/null @@ -1,140 +0,0 @@ -package internal - -const ( - FP_MAX_WORDS = 12 // Currently p751.NumWords -) - -// Representation of an element of the base field F_p. -// -// No particular meaning is assigned to the representation -- it could represent -// an element in Montgomery form, or not. Tracking the meaning of the field -// element is left to higher types. -type FpElement [FP_MAX_WORDS]uint64 - -// Represents an intermediate product of two elements of the base field F_p. -type FpElementX2 [2 * FP_MAX_WORDS]uint64 - -// Represents an element of the extended field Fp^2 = Fp(x+i) -type Fp2Element struct { - A FpElement - B FpElement -} - -type DomainParams struct { - // P, Q and R=P-Q base points - Affine_P, Affine_Q, Affine_R Fp2Element - // Size of a compuatation strategy for x-torsion group - IsogenyStrategy []uint32 - // Max size of secret key for x-torsion group - SecretBitLen uint - // Max size of secret key for x-torsion group - SecretByteLen uint -} - -type SidhParams struct { - Id uint8 - // Bytelen of P - Bytelen int - // The public key size, in bytes. - PublicKeySize int - // The shared secret size, in bytes. - SharedSecretSize uint - // 2- and 3-torsion group parameter definitions - A, B DomainParams - // Precomputed identity element in the Fp2 in Montgomery domain - OneFp2 Fp2Element - // Precomputed 1/2 in the Fp2 in Montgomery domain - HalfFp2 Fp2Element - // Length of SIKE secret message. Must be one of {24,32,40}, - // depending on size of prime field used (see [SIKE], 1.4 and 5.1) - MsgLen uint - // Length of SIKE ephemeral KEM key (see [SIKE], 1.4 and 5.1) - KemSize uint - // Access to field arithmetic - Op FieldOps -} - -// Interface for working with isogenies. -type Isogeny interface { - // Given a torsion point on a curve computes isogenous curve. - // Returns curve coefficients (A:C), so that E_(A/C) = E_(A/C)/

, - // where P is a provided projective point. Sets also isogeny constants - // that are needed for isogeny evaluation. - GenerateCurve(*ProjectivePoint) CurveCoefficientsEquiv - // Evaluates isogeny at caller provided point. Requires isogeny curve constants - // to be earlier computed by GenerateCurve. - EvaluatePoint(*ProjectivePoint) ProjectivePoint -} - -// Stores curve projective parameters equivalent to A/C. Meaning of the -// values depends on the context. When working with isogenies over -// subgroup that are powers of: -// * three then (A:C) ~ (A+2C:A-2C) -// * four then (A:C) ~ (A+2C: 4C) -// See Appendix A of SIKE for more details -type CurveCoefficientsEquiv struct { - A Fp2Element - C Fp2Element -} - -// A point on the projective line P^1(F_{p^2}). -// -// This represents a point on the Kummer line of a Montgomery curve. The -// curve is specified by a ProjectiveCurveParameters struct. -type ProjectivePoint struct { - X Fp2Element - Z Fp2Element -} - -// A point on the projective line P^1(F_{p^2}). -// -// This is used to work projectively with the curve coefficients. -type ProjectiveCurveParameters struct { - A Fp2Element - C Fp2Element -} - -// Stores Isogeny 3 curve constants -type isogeny3 struct { - Field FieldOps - K1 Fp2Element - K2 Fp2Element -} - -// Stores Isogeny 4 curve constants -type isogeny4 struct { - isogeny3 - K3 Fp2Element -} - -type FieldOps interface { - // Set res = lhs + rhs. - // - // Allowed to overlap lhs or rhs with res. - Add(res, lhs, rhs *Fp2Element) - - // Set res = lhs - rhs. - // - // Allowed to overlap lhs or rhs with res. - Sub(res, lhs, rhs *Fp2Element) - - // Set res = lhs * rhs. - // - // Allowed to overlap lhs or rhs with res. - Mul(res, lhs, rhs *Fp2Element) - // Set res = x * x - // - // Allowed to overlap res with x. - Square(res, x *Fp2Element) - // Set res = 1/x - // - // Allowed to overlap res with x. - Inv(res, x *Fp2Element) - // If choice = 1u8, set (x,y) = (y,x). If choice = 0u8, set (x,y) = (x,y). - CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8) - // Converts Fp2Element to Montgomery domain (x*R mod p) - ToMontgomery(x *Fp2Element) - // Converts 'a' in montgomery domain to element from Fp2Element - // and stores it in 'x' - FromMontgomery(x *Fp2Element, a *Fp2Element) -} diff --git a/external/github.com/cloudflare/sidh/internal/utils/cpu.go b/external/github.com/cloudflare/sidh/internal/utils/cpu.go deleted file mode 100644 index 817a85e2f..000000000 --- a/external/github.com/cloudflare/sidh/internal/utils/cpu.go +++ /dev/null @@ -1,11 +0,0 @@ -package utils - -type x86 struct { - // Signals support for MULX which is in BMI2 - HasBMI2 bool - - // Signals support for ADX - HasADX bool -} - -var X86 x86 diff --git a/external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.go b/external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.go deleted file mode 100644 index 2666b7aa4..000000000 --- a/external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build amd64,!noasm - -// Sets capabilities flags for x86 according to information received from -// CPUID. It was written in accordance with -// "Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 2A". -// https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html - -package utils - -// Performs CPUID and returns values of registers -// go:nosplit -func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) - -// Returns true in case bit 'n' in 'bits' is set, otherwise false -func bitn(bits uint32, n uint8) bool { - return (bits>>n)&1 == 1 -} - -func init() { - // CPUID returns max possible input that can be requested - max, _, _, _ := cpuid(0, 0) - if max < 7 { - return - } - - _, ebx, _, _ := cpuid(7, 0) - X86.HasBMI2 = bitn(ebx, 8) - X86.HasADX = bitn(ebx, 19) -} diff --git a/external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.s b/external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.s deleted file mode 100644 index 2dff942dc..000000000 --- a/external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.s +++ /dev/null @@ -1,13 +0,0 @@ -// +build amd64,!noasm - -#include "textflag.h" - -TEXT ·cpuid(SB), NOSPLIT, $0-4 - MOVL eaxArg+0(FP), AX - MOVL ecxArg+4(FP), CX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET diff --git a/external/github.com/cloudflare/sidh/p503/arith_amd64.s b/external/github.com/cloudflare/sidh/p503/arith_amd64.s deleted file mode 100644 index 2068e4ec1..000000000 --- a/external/github.com/cloudflare/sidh/p503/arith_amd64.s +++ /dev/null @@ -1,1708 +0,0 @@ -// +build amd64,!noasm - -#include "textflag.h" - -// p503 -#define P503_0 $0xFFFFFFFFFFFFFFFF -#define P503_1 $0xFFFFFFFFFFFFFFFF -#define P503_2 $0xFFFFFFFFFFFFFFFF -#define P503_3 $0xABFFFFFFFFFFFFFF -#define P503_4 $0x13085BDA2211E7A0 -#define P503_5 $0x1B9BF6C87B7E7DAF -#define P503_6 $0x6045C6BDDA77A4D0 -#define P503_7 $0x004066F541811E1E - -// p503+1 -#define P503P1_3 $0xAC00000000000000 -#define P503P1_4 $0x13085BDA2211E7A0 -#define P503P1_5 $0x1B9BF6C87B7E7DAF -#define P503P1_6 $0x6045C6BDDA77A4D0 -#define P503P1_7 $0x004066F541811E1E - -// p503x2 -#define P503X2_0 $0xFFFFFFFFFFFFFFFE -#define P503X2_1 $0xFFFFFFFFFFFFFFFF -#define P503X2_2 $0xFFFFFFFFFFFFFFFF -#define P503X2_3 $0x57FFFFFFFFFFFFFF -#define P503X2_4 $0x2610B7B44423CF41 -#define P503X2_5 $0x3737ED90F6FCFB5E -#define P503X2_6 $0xC08B8D7BB4EF49A0 -#define P503X2_7 $0x0080CDEA83023C3C - -#define REG_P1 DI -#define REG_P2 SI -#define REG_P3 DX - -// Performs schoolbook multiplication of 2 256-bit numbers. This optimized version -// uses MULX instruction. Macro smashes value in DX. -// Input: I0 and I1. -// Output: O -// All the other arguments are resgisters, used for storing temporary values -#define MULS256_MULX(O, I0, I1, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) \ - MOVQ I0, DX \ - MULXQ I1, T1, T0 \ // T0:T1 = A0*B0 - MOVQ T1, O \ // O[0] - MULXQ 8+I1, T2, T1 \ // T1:T2 = U0*V1 - ADDQ T2, T0 \ - MULXQ 16+I1, T3, T2 \ // T2:T3 = U0*V2 - ADCQ T3, T1 \ - MULXQ 24+I1, T4, T3 \ // T3:T4 = U0*V3 - ADCQ T4, T2 \ - \ // Column U1 - MOVQ 8+I0, DX \ - ADCQ $0, T3 \ - MULXQ 0+I1, T4, T5 \ // T5:T4 = U1*V0 - MULXQ 8+I1, T7, T6 \ // T6:T7 = U1*V1 - ADDQ T7, T5 \ - MULXQ 16+I1, T8, T7 \ // T7:T8 = U1*V2 - ADCQ T8, T6 \ - MULXQ 24+I1, T9, T8 \ // T8:T9 = U1*V3 - ADCQ T9, T7 \ - ADCQ $0, T8 \ - ADDQ T0, T4 \ - MOVQ T4, 8+O \ // O[1] - ADCQ T1, T5 \ - ADCQ T2, T6 \ - ADCQ T3, T7 \ - \ // Column U2 - MOVQ 16+I0, DX \ - ADCQ $0, T8 \ - MULXQ 0+I1, T0, T1 \ // T1:T0 = U2*V0 - MULXQ 8+I1, T3, T2 \ // T2:T3 = U2*V1 - ADDQ T3, T1 \ - MULXQ 16+I1, T4, T3 \ // T3:T4 = U2*V2 - ADCQ T4, T2 \ - MULXQ 24+I1, T9, T4 \ // T4:T9 = U2*V3 - ADCQ T9, T3 \ - \ // Column U3 - MOVQ 24+I0, DX \ - ADCQ $0, T4 \ - ADDQ T5, T0 \ - MOVQ T0, 16+O \ // O[2] - ADCQ T6, T1 \ - ADCQ T7, T2 \ - ADCQ T8, T3 \ - ADCQ $0, T4 \ - MULXQ 0+I1, T0, T5 \ // T5:T0 = U3*V0 - MULXQ 8+I1, T7, T6 \ // T6:T7 = U3*V1 - ADDQ T7, T5 \ - MULXQ 16+I1, T8, T7 \ // T7:T8 = U3*V2 - ADCQ T8, T6 \ - MULXQ 24+I1, T9, T8 \ // T8:T9 = U3*V3 - ADCQ T9, T7 \ - ADCQ $0, T8 \ - \ // Add values in remaining columns - ADDQ T0, T1 \ - MOVQ T1, 24+O \ // O[3] - ADCQ T5, T2 \ - MOVQ T2, 32+O \ // O[4] - ADCQ T6, T3 \ - MOVQ T3, 40+O \ // O[5] - ADCQ T7, T4 \ - MOVQ T4, 48+O \ // O[6] - ADCQ $0, T8 \ // O[7] - MOVQ T8, 56+O - -// Performs schoolbook multiplication of 2 256-bit numbers. This optimized version -// uses ADOX, ADCX and MULX instructions. Macro smashes values in AX and DX. -// Input: I0 and I1. -// Output: O -// All the other arguments resgisters are used for storing temporary values -#define MULS256_MULX_ADCX_ADOX(O, I0, I1, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) \ - \ // U0[0] - MOVQ 0+I0, DX \ // MULX requires multiplayer in DX - \ // T0:T1 = I1*DX - MULXQ I1, T1, T0 \ // T0:T1 = U0*V0 (low:high) - MOVQ T1, O \ // O0[0] - MULXQ 8+I1, T2, T1 \ // T2:T1 = U0*V1 - XORQ AX, AX \ - ADOXQ T2, T0 \ - MULXQ 16+I1, T3, T2 \ // T2:T3 = U0*V2 - ADOXQ T3, T1 \ - MULXQ 24+I1, T4, T3 \ // T3:T4 = U0*V3 - ADOXQ T4, T2 \ - \ // Column U1 - MOVQ 8+I0, DX \ - MULXQ I1, T4, T5 \ // T5:T4 = U1*V0 - ADOXQ AX, T3 \ - XORQ AX, AX \ - MULXQ 8+I1, T7, T6 \ // T6:T7 = U1*V1 - ADOXQ T0, T4 \ - MOVQ T4, 8+O \ // O[1] - ADCXQ T7, T5 \ - MULXQ 16+I1, T8, T7 \ // T7:T8 = U1*V2 - ADCXQ T8, T6 \ - ADOXQ T1, T5 \ - MULXQ 24+I1, T9, T8 \ // T8:T9 = U1*V3 - ADCXQ T9, T7 \ - ADCXQ AX, T8 \ - ADOXQ T2, T6 \ - \ // Column U2 - MOVQ 16+I0, DX \ - MULXQ I1, T0, T1 \ // T1:T0 = U2*V0 - ADOXQ T3, T7 \ - ADOXQ AX, T8 \ - XORQ AX, AX \ - MULXQ 8+I1, T3, T2 \ // T2:T3 = U2*V1 - ADOXQ T5, T0 \ - MOVQ T0, 16+O \ // O[2] - ADCXQ T3, T1 \ - MULXQ 16+I1, T4, T3 \ // T3:T4 = U2*V2 - ADCXQ T4, T2 \ - ADOXQ T6, T1 \ - MULXQ 24+I1, T9, T4 \ // T9:T4 = U2*V3 - ADCXQ T9, T3 \ - MOVQ 24+I0, DX \ - ADCXQ AX, T4 \ - \ - ADOXQ T7, T2 \ - ADOXQ T8, T3 \ - ADOXQ AX, T4 \ - \ // Column U3 - MULXQ I1, T0, T5 \ // T5:T0 = U3*B0 - XORQ AX, AX \ - MULXQ 8+I1, T7, T6 \ // T6:T7 = U3*B1 - ADCXQ T7, T5 \ - ADOXQ T0, T1 \ - MULXQ 16+I1, T8, T7 \ // T7:T8 = U3*V2 - ADCXQ T8, T6 \ - ADOXQ T5, T2 \ - MULXQ 24+I1, T9, T8 \ // T8:T9 = U3*V3 - ADCXQ T9, T7 \ - ADCXQ AX, T8 \ - \ - ADOXQ T6, T3 \ - ADOXQ T7, T4 \ - ADOXQ AX, T8 \ - MOVQ T1, 24+O \ // O[3] - MOVQ T2, 32+O \ // O[4] - MOVQ T3, 40+O \ // O[5] - MOVQ T4, 48+O \ // O[6] and O[7] below - MOVQ T8, 56+O - -// Template of a macro that performs schoolbook multiplication of 128-bit with 320-bit -// number. It uses MULX instruction This template must be customized with functions -// performing ADD (add1, add2) and ADD-with-carry (adc1, adc2). addX/adcX may or may -// not be instructions that use two independent carry chains. -// Input: -// * I0 128-bit number -// * I1 320-bit number -// * add1, add2: instruction performing integer addition and starting carry chain -// * adc1, adc2: instruction performing integer addition with carry -// Output: T[0-6] registers -#define MULS_128x320(I0, I1, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, add1, add2, adc1, adc2) \ - \ // Column 0 - MOVQ I0, DX \ - MULXQ I1+24(SB), T0, T1 \ - MULXQ I1+32(SB), T4, T2 \ - XORQ AX, AX \ - MULXQ I1+40(SB), T5, T3 \ - add1 T4, T1 \ - adc1 T5, T2 \ - MULXQ I1+48(SB), T7, T4 \ - adc1 T7, T3 \ - MULXQ I1+56(SB), T6, T5 \ - adc1 T6, T4 \ - adc1 AX, T5 \ - \ // Column 1 - MOVQ 8+I0, DX \ - MULXQ I1+24(SB), T6, T7 \ - add2 T6, T1 \ - adc2 T7, T2 \ - MULXQ I1+32(SB), T8, T6 \ - adc2 T6, T3 \ - MULXQ I1+40(SB), T7, T9 \ - adc2 T9, T4 \ - MULXQ I1+48(SB), T9, T6 \ - adc2 T6, T5 \ - MULXQ I1+56(SB), DX, T6 \ - adc2 AX, T6 \ - \ // Output - XORQ AX, AX \ - add1 T8, T2 \ - adc1 T7, T3 \ - adc1 T9, T4 \ - adc1 DX, T5 \ - adc1 AX, T6 - -// Multiplies 128-bit with 320-bit integer. Optimized with MULX instruction. -#define MULS_128x320_MULX(I0, I1, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) \ - MULS_128x320(I0, I1, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, ADDQ, ADDQ, ADCQ, ADCQ) - -// Multiplies 128-bit with 320-bit integer. Optimized with MULX, ADOX and ADCX instructions -#define MULS_128x320_MULX_ADCX_ADOX(I0, I1, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) \ - MULS_128x320(I0, I1, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, ADOXQ, ADCXQ, ADOXQ, ADCXQ) - -// Template of a macro performing multiplication of two 512-bit numbers. It uses one -// level of Karatsuba and one level of schoolbook multiplication. Template must be -// customized with macro performing schoolbook multiplication. -// Input: -// * I0, I1 - two 512-bit numbers -// * MULS - either MULS256_MULX or MULS256_MULX_ADCX_ADOX -// Output: OUT - 1024-bit long -#define MUL(OUT, I0, I1, MULS) \ - \ // R[8-11]: U1+U0 - XORQ AX, AX \ - MOVQ ( 0)(I0), R8 \ - MOVQ ( 8)(I0), R9 \ - MOVQ (16)(I0), R10 \ - MOVQ (24)(I0), R11 \ - ADDQ (32)(I0), R8 \ - ADCQ (40)(I0), R9 \ - ADCQ (48)(I0), R10 \ - ADCQ (56)(I0), R11 \ - SBBQ $0, AX \ // store mask - MOVQ R8, ( 0)(SP) \ - MOVQ R9, ( 8)(SP) \ - MOVQ R10, (16)(SP) \ - MOVQ R11, (24)(SP) \ - \ - \ // R[12-15]: V1+V0 - XORQ BX, BX \ - MOVQ ( 0)(I1), R12 \ - MOVQ ( 8)(I1), R13 \ - MOVQ (16)(I1), R14 \ - MOVQ (24)(I1), R15 \ - ADDQ (32)(I1), R12 \ - ADCQ (40)(I1), R13 \ - ADCQ (48)(I1), R14 \ - ADCQ (56)(I1), R15 \ - SBBQ $0, BX \ // store mask - MOVQ R12, (32)(SP) \ - MOVQ R13, (40)(SP) \ - MOVQ R14, (48)(SP) \ - MOVQ R15, (56)(SP) \ - \ // Prepare mask for U0+U1 (U1+U0 mod 256^4 if U1+U0 sets carry flag, otherwise 0) - ANDQ AX, R12 \ - ANDQ AX, R13 \ - ANDQ AX, R14 \ - ANDQ AX, R15 \ - \ // Prepare mask for V0+V1 (V1+V0 mod 256^4 if U1+U0 sets carry flag, otherwise 0) - ANDQ BX, R8 \ - ANDQ BX, R9 \ - ANDQ BX, R10 \ - ANDQ BX, R11 \ - \ // res = masked(U0+U1) + masked(V0 + V1) - ADDQ R12, R8 \ - ADCQ R13, R9 \ - ADCQ R14, R10 \ - ADCQ R15, R11 \ - \ // SP[64-96] <- res - MOVQ R8, (64)(SP) \ - MOVQ R9, (72)(SP) \ - MOVQ R10, (80)(SP) \ - MOVQ R11, (88)(SP) \ - \ // BP will be used for schoolbook multiplication below - MOVQ BP, 96(SP) \ - \ // (U1+U0)*(V1+V0) - MULS((64)(OUT), 0(SP), 32(SP), R8, R9, R10, R11, R12, R13, R14, R15, BX, BP) \ - \ // U0 x V0 - MULS(0(OUT), 0(I0), 0(I1), R8, R9, R10, R11, R12, R13, R14, R15, BX, BP) \ - \ // U1 x V1 - MULS(0(SP), 32(I0), 32(I1), R8, R9, R10, R11, R12, R13, R14, R15, BX, BP) \ - \ // Recover BP - MOVQ 96(SP), BP \ - \ // Final part of schoolbook multiplication; R[8-11] = (U0+U1) x (V0+V1) - MOVQ (64)(SP), R8 \ - MOVQ (72)(SP), R9 \ - MOVQ (80)(SP), R10 \ - MOVQ (88)(SP), R11 \ - MOVQ (96)(OUT), AX \ - ADDQ AX, R8 \ - MOVQ (104)(OUT), AX \ - ADCQ AX, R9 \ - MOVQ (112)(OUT), AX \ - ADCQ AX, R10 \ - MOVQ (120)(OUT), AX \ - ADCQ AX, R11 \ - \ // R[12-15, 8-11] = (U0+U1) x (V0+V1) - U0xV0 - MOVQ (64)(OUT), R12 \ - MOVQ (72)(OUT), R13 \ - MOVQ (80)(OUT), R14 \ - MOVQ (88)(OUT), R15 \ - SUBQ ( 0)(OUT), R12 \ - SBBQ ( 8)(OUT), R13 \ - SBBQ (16)(OUT), R14 \ - SBBQ (24)(OUT), R15 \ - SBBQ (32)(OUT), R8 \ - SBBQ (40)(OUT), R9 \ - SBBQ (48)(OUT), R10 \ - SBBQ (56)(OUT), R11 \ - \ // r8-r15 <- (U0+U1) x (V0+V1) - U0xV0 - U1xV1 - SUBQ ( 0)(SP), R12 \ - SBBQ ( 8)(SP), R13 \ - SBBQ (16)(SP), R14 \ - SBBQ (24)(SP), R15 \ - SBBQ (32)(SP), R8 \ - SBBQ (40)(SP), R9 \ - SBBQ (48)(SP), R10 \ - SBBQ (56)(SP), R11 \ - \ - ; ADDQ (32)(OUT), R12; MOVQ R12, ( 32)(OUT) \ - ; ADCQ (40)(OUT), R13; MOVQ R13, ( 40)(OUT) \ - ; ADCQ (48)(OUT), R14; MOVQ R14, ( 48)(OUT) \ - ; ADCQ (56)(OUT), R15; MOVQ R15, ( 56)(OUT) \ - MOVQ ( 0)(SP), AX; ADCQ AX, R8; MOVQ R8, ( 64)(OUT) \ - MOVQ ( 8)(SP), AX; ADCQ AX, R9; MOVQ R9, ( 72)(OUT) \ - MOVQ (16)(SP), AX; ADCQ AX, R10; MOVQ R10, ( 80)(OUT) \ - MOVQ (24)(SP), AX; ADCQ AX, R11; MOVQ R11, ( 88)(OUT) \ - MOVQ (32)(SP), R12; ADCQ $0, R12; MOVQ R12, ( 96)(OUT) \ - MOVQ (40)(SP), R13; ADCQ $0, R13; MOVQ R13, (104)(OUT) \ - MOVQ (48)(SP), R14; ADCQ $0, R14; MOVQ R14, (112)(OUT) \ - MOVQ (56)(SP), R15; ADCQ $0, R15; MOVQ R15, (120)(OUT) - -// Template for calculating the Montgomery reduction algorithm described in -// section 5.2.3 of https://eprint.iacr.org/2017/1015.pdf. Template must be -// customized with schoolbook multiplicaton for 128 x 320-bit number. -// This macro reuses memory of IN value and *changes* it. Smashes registers -// R[8-15], BX, CX -// Input: -// * IN: 1024-bit number to be reduced -// * MULS: either MULS_128x320_MULX or MULS_128x320_MULX_ADCX_ADOX -// Output: OUT 512-bit -#define REDC(OUT, IN, MULS) \ - MULS(0(IN), ·p503p1, R8, R9, R10, R11, R12, R13, R14, BX, CX, R15) \ - XORQ R15, R15 \ - ADDQ (24)(IN), R8 \ - ADCQ (32)(IN), R9 \ - ADCQ (40)(IN), R10 \ - ADCQ (48)(IN), R11 \ - ADCQ (56)(IN), R12 \ - ADCQ (64)(IN), R13 \ - ADCQ (72)(IN), R14 \ - ADCQ (80)(IN), R15 \ - MOVQ R8, (24)(IN) \ - MOVQ R9, (32)(IN) \ - MOVQ R10, (40)(IN) \ - MOVQ R11, (48)(IN) \ - MOVQ R12, (56)(IN) \ - MOVQ R13, (64)(IN) \ - MOVQ R14, (72)(IN) \ - MOVQ R15, (80)(IN) \ - MOVQ (88)(IN), R8 \ - MOVQ (96)(IN), R9 \ - MOVQ (104)(IN), R10 \ - MOVQ (112)(IN), R11 \ - MOVQ (120)(IN), R12 \ - ADCQ $0, R8 \ - ADCQ $0, R9 \ - ADCQ $0, R10 \ - ADCQ $0, R11 \ - ADCQ $0, R12 \ - MOVQ R8, (88)(IN) \ - MOVQ R9, (96)(IN) \ - MOVQ R10, (104)(IN) \ - MOVQ R11, (112)(IN) \ - MOVQ R12, (120)(IN) \ - \ - MULS(16(IN), ·p503p1, R8, R9, R10, R11, R12, R13, R14, BX, CX, R15) \ - XORQ R15, R15 \ - ADDQ (40)(IN), R8 \ - ADCQ (48)(IN), R9 \ - ADCQ (56)(IN), R10 \ - ADCQ (64)(IN), R11 \ - ADCQ (72)(IN), R12 \ - ADCQ (80)(IN), R13 \ - ADCQ (88)(IN), R14 \ - ADCQ (96)(IN), R15 \ - MOVQ R8, (40)(IN) \ - MOVQ R9, (48)(IN) \ - MOVQ R10, (56)(IN) \ - MOVQ R11, (64)(IN) \ - MOVQ R12, (72)(IN) \ - MOVQ R13, (80)(IN) \ - MOVQ R14, (88)(IN) \ - MOVQ R15, (96)(IN) \ - MOVQ (104)(IN), R8 \ - MOVQ (112)(IN), R9 \ - MOVQ (120)(IN), R10 \ - ADCQ $0, R8 \ - ADCQ $0, R9 \ - ADCQ $0, R10 \ - MOVQ R8, (104)(IN) \ - MOVQ R9, (112)(IN) \ - MOVQ R10, (120)(IN) \ - \ - MULS(32(IN), ·p503p1, R8, R9, R10, R11, R12, R13, R14, BX, CX, R15) \ - XORQ R15, R15 \ - XORQ BX, BX \ - ADDQ ( 56)(IN), R8 \ - ADCQ ( 64)(IN), R9 \ - ADCQ ( 72)(IN), R10 \ - ADCQ ( 80)(IN), R11 \ - ADCQ ( 88)(IN), R12 \ - ADCQ ( 96)(IN), R13 \ - ADCQ (104)(IN), R14 \ - ADCQ (112)(IN), R15 \ - ADCQ (120)(IN), BX \ - MOVQ R8, ( 56)(IN) \ - MOVQ R10, ( 72)(IN) \ - MOVQ R11, ( 80)(IN) \ - MOVQ R12, ( 88)(IN) \ - MOVQ R13, ( 96)(IN) \ - MOVQ R14, (104)(IN) \ - MOVQ R15, (112)(IN) \ - MOVQ BX, (120)(IN) \ - MOVQ R9, ( 0)(OUT) \ // Result: OUT[0] - \ - MULS(48(IN), ·p503p1, R8, R9, R10, R11, R12, R13, R14, BX, CX, R15) \ - ADDQ ( 72)(IN), R8 \ - ADCQ ( 80)(IN), R9 \ - ADCQ ( 88)(IN), R10 \ - ADCQ ( 96)(IN), R11 \ - ADCQ (104)(IN), R12 \ - ADCQ (112)(IN), R13 \ - ADCQ (120)(IN), R14 \ - MOVQ R8, ( 8)(OUT) \ // Result: OUT[1] - MOVQ R9, (16)(OUT) \ // Result: OUT[2] - MOVQ R10, (24)(OUT) \ // Result: OUT[3] - MOVQ R11, (32)(OUT) \ // Result: OUT[4] - MOVQ R12, (40)(OUT) \ // Result: OUT[5] - MOVQ R13, (48)(OUT) \ // Result: OUT[6] and OUT[7] - MOVQ R14, (56)(OUT) - -TEXT ·fp503StrongReduce(SB), NOSPLIT, $0-8 - MOVQ x+0(FP), REG_P1 - - // Zero AX for later use: - XORQ AX, AX - - // Load p into registers: - MOVQ P503_0, R8 - // P503_{1,2} = P503_0, so reuse R8 - MOVQ P503_3, R9 - MOVQ P503_4, R10 - MOVQ P503_5, R11 - MOVQ P503_6, R12 - MOVQ P503_7, R13 - - // Set x <- x - p - SUBQ R8, ( 0)(REG_P1) - SBBQ R8, ( 8)(REG_P1) - SBBQ R8, (16)(REG_P1) - SBBQ R9, (24)(REG_P1) - SBBQ R10, (32)(REG_P1) - SBBQ R11, (40)(REG_P1) - SBBQ R12, (48)(REG_P1) - SBBQ R13, (56)(REG_P1) - - // Save carry flag indicating x-p < 0 as a mask - SBBQ $0, AX - - // Conditionally add p to x if x-p < 0 - ANDQ AX, R8 - ANDQ AX, R9 - ANDQ AX, R10 - ANDQ AX, R11 - ANDQ AX, R12 - ANDQ AX, R13 - - ADDQ R8, ( 0)(REG_P1) - ADCQ R8, ( 8)(REG_P1) - ADCQ R8, (16)(REG_P1) - ADCQ R9, (24)(REG_P1) - ADCQ R10,(32)(REG_P1) - ADCQ R11,(40)(REG_P1) - ADCQ R12,(48)(REG_P1) - ADCQ R13,(56)(REG_P1) - - RET - -TEXT ·fp503ConditionalSwap(SB),NOSPLIT,$0-17 - - MOVQ x+0(FP), REG_P1 - MOVQ y+8(FP), REG_P2 - MOVB choice+16(FP), AL // AL = 0 or 1 - MOVBLZX AL, AX // AX = 0 or 1 - NEGQ AX // AX = 0x00..00 or 0xff..ff - -#ifndef CSWAP_BLOCK -#define CSWAP_BLOCK(idx) \ - MOVQ (idx*8)(REG_P1), BX \ // BX = x[idx] - MOVQ (idx*8)(REG_P2), CX \ // CX = y[idx] - MOVQ CX, DX \ // DX = y[idx] - XORQ BX, DX \ // DX = y[idx] ^ x[idx] - ANDQ AX, DX \ // DX = (y[idx] ^ x[idx]) & mask - XORQ DX, BX \ // BX = (y[idx] ^ x[idx]) & mask) ^ x[idx] = x[idx] or y[idx] - XORQ DX, CX \ // CX = (y[idx] ^ x[idx]) & mask) ^ y[idx] = y[idx] or x[idx] - MOVQ BX, (idx*8)(REG_P1) \ - MOVQ CX, (idx*8)(REG_P2) -#endif - - CSWAP_BLOCK(0) - CSWAP_BLOCK(1) - CSWAP_BLOCK(2) - CSWAP_BLOCK(3) - CSWAP_BLOCK(4) - CSWAP_BLOCK(5) - CSWAP_BLOCK(6) - CSWAP_BLOCK(7) - -#ifdef CSWAP_BLOCK -#undef CSWAP_BLOCK -#endif - - RET - -TEXT ·fp503AddReduced(SB),NOSPLIT,$0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - // Used later to calculate a mask - XORQ CX, CX - - // [R8-R15]: z = x + y - MOVQ ( 0)(REG_P1), R8 - MOVQ ( 8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - ADDQ ( 0)(REG_P2), R8 - ADCQ ( 8)(REG_P2), R9 - ADCQ (16)(REG_P2), R10 - ADCQ (24)(REG_P2), R11 - ADCQ (32)(REG_P2), R12 - ADCQ (40)(REG_P2), R13 - ADCQ (48)(REG_P2), R14 - ADCQ (56)(REG_P2), R15 - - MOVQ P503X2_0, AX - SUBQ AX, R8 - MOVQ P503X2_1, AX - SBBQ AX, R9 - SBBQ AX, R10 - MOVQ P503X2_3, AX - SBBQ AX, R11 - MOVQ P503X2_4, AX - SBBQ AX, R12 - MOVQ P503X2_5, AX - SBBQ AX, R13 - MOVQ P503X2_6, AX - SBBQ AX, R14 - MOVQ P503X2_7, AX - SBBQ AX, R15 - - // mask - SBBQ $0, CX - - // move z to REG_P3 - MOVQ R8, ( 0)(REG_P3) - MOVQ R9, ( 8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - - // if z<0 add p503x2 back - MOVQ P503X2_0, R8 - MOVQ P503X2_1, R9 - MOVQ P503X2_3, R10 - MOVQ P503X2_4, R11 - MOVQ P503X2_5, R12 - MOVQ P503X2_6, R13 - MOVQ P503X2_7, R14 - ANDQ CX, R8 - ANDQ CX, R9 - ANDQ CX, R10 - ANDQ CX, R11 - ANDQ CX, R12 - ANDQ CX, R13 - ANDQ CX, R14 - MOVQ ( 0)(REG_P3), AX; ADDQ R8, AX; MOVQ AX, ( 0)(REG_P3) - MOVQ ( 8)(REG_P3), AX; ADCQ R9, AX; MOVQ AX, ( 8)(REG_P3) - MOVQ (16)(REG_P3), AX; ADCQ R9, AX; MOVQ AX, (16)(REG_P3) - MOVQ (24)(REG_P3), AX; ADCQ R10, AX; MOVQ AX, (24)(REG_P3) - MOVQ (32)(REG_P3), AX; ADCQ R11, AX; MOVQ AX, (32)(REG_P3) - MOVQ (40)(REG_P3), AX; ADCQ R12, AX; MOVQ AX, (40)(REG_P3) - MOVQ (48)(REG_P3), AX; ADCQ R13, AX; MOVQ AX, (48)(REG_P3) - MOVQ (56)(REG_P3), AX; ADCQ R14, AX; MOVQ AX, (56)(REG_P3) - RET - -TEXT ·fp503SubReduced(SB), NOSPLIT, $0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - // Used later to calculate a mask - XORQ CX, CX - - MOVQ ( 0)(REG_P1), R8 - MOVQ ( 8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - - SUBQ ( 0)(REG_P2), R8 - SBBQ ( 8)(REG_P2), R9 - SBBQ (16)(REG_P2), R10 - SBBQ (24)(REG_P2), R11 - SBBQ (32)(REG_P2), R12 - SBBQ (40)(REG_P2), R13 - SBBQ (48)(REG_P2), R14 - SBBQ (56)(REG_P2), R15 - - // mask - SBBQ $0, CX - - // store x-y in REG_P3 - MOVQ R8, ( 0)(REG_P3) - MOVQ R9, ( 8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - - // if z<0 add p503x2 back - MOVQ P503X2_0, R8 - MOVQ P503X2_1, R9 - MOVQ P503X2_3, R10 - MOVQ P503X2_4, R11 - MOVQ P503X2_5, R12 - MOVQ P503X2_6, R13 - MOVQ P503X2_7, R14 - ANDQ CX, R8 - ANDQ CX, R9 - ANDQ CX, R10 - ANDQ CX, R11 - ANDQ CX, R12 - ANDQ CX, R13 - ANDQ CX, R14 - MOVQ ( 0)(REG_P3), AX; ADDQ R8, AX; MOVQ AX, ( 0)(REG_P3) - MOVQ ( 8)(REG_P3), AX; ADCQ R9, AX; MOVQ AX, ( 8)(REG_P3) - MOVQ (16)(REG_P3), AX; ADCQ R9, AX; MOVQ AX, (16)(REG_P3) - MOVQ (24)(REG_P3), AX; ADCQ R10, AX; MOVQ AX, (24)(REG_P3) - MOVQ (32)(REG_P3), AX; ADCQ R11, AX; MOVQ AX, (32)(REG_P3) - MOVQ (40)(REG_P3), AX; ADCQ R12, AX; MOVQ AX, (40)(REG_P3) - MOVQ (48)(REG_P3), AX; ADCQ R13, AX; MOVQ AX, (48)(REG_P3) - MOVQ (56)(REG_P3), AX; ADCQ R14, AX; MOVQ AX, (56)(REG_P3) - - RET - -TEXT ·fp503Mul(SB), NOSPLIT, $104-24 - MOVQ z+ 0(FP), CX - MOVQ x+ 8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - // Check wether to use optimized implementation - CMPB ·HasADXandBMI2(SB), $1 - JE mul_with_mulx_adcx_adox - CMPB ·HasBMI2(SB), $1 - JE mul_with_mulx - - // Generic x86 implementation (below) uses variant of Karatsuba method. - // - // Here we store the destination in CX instead of in REG_P3 because the - // multiplication instructions use DX as an implicit destination - // operand: MULQ $REG sets DX:AX <-- AX * $REG. - - // RAX and RDX will be used for a mask (0-borrow) - XORQ AX, AX - - // RCX[0-3]: U1+U0 - MOVQ (32)(REG_P1), R8 - MOVQ (40)(REG_P1), R9 - MOVQ (48)(REG_P1), R10 - MOVQ (56)(REG_P1), R11 - ADDQ ( 0)(REG_P1), R8 - ADCQ ( 8)(REG_P1), R9 - ADCQ (16)(REG_P1), R10 - ADCQ (24)(REG_P1), R11 - MOVQ R8, ( 0)(CX) - MOVQ R9, ( 8)(CX) - MOVQ R10, (16)(CX) - MOVQ R11, (24)(CX) - - SBBQ $0, AX - - // R12-R15: V1+V0 - XORQ DX, DX - MOVQ (32)(REG_P2), R12 - MOVQ (40)(REG_P2), R13 - MOVQ (48)(REG_P2), R14 - MOVQ (56)(REG_P2), R15 - ADDQ ( 0)(REG_P2), R12 - ADCQ ( 8)(REG_P2), R13 - ADCQ (16)(REG_P2), R14 - ADCQ (24)(REG_P2), R15 - - SBBQ $0, DX - - // Store carries on stack - MOVQ AX, (64)(SP) - MOVQ DX, (72)(SP) - - // (SP[0-3],R8,R9,R10,R11) <- (U0+U1)*(V0+V1). - // MUL using comba; In comments below U=U0+U1 V=V0+V1 - - // U0*V0 - MOVQ (CX), AX - MULQ R12 - MOVQ AX, (SP) // C0 - MOVQ DX, R8 - - // U0*V1 - XORQ R9, R9 - MOVQ (CX), AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - - // U1*V0 - XORQ R10, R10 - MOVQ (8)(CX), AX - MULQ R12 - ADDQ AX, R8 - MOVQ R8, (8)(SP) // C1 - ADCQ DX, R9 - ADCQ $0, R10 - - // U0*V2 - XORQ R8, R8 - MOVQ (CX), AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - // U2*V0 - MOVQ (16)(CX), AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - // U1*V1 - MOVQ (8)(CX), AX - MULQ R13 - ADDQ AX, R9 - MOVQ R9, (16)(SP) // C2 - ADCQ DX, R10 - ADCQ $0, R8 - - // U0*V3 - XORQ R9, R9 - MOVQ (CX), AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - // U3*V0 - MOVQ (24)(CX), AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - // U1*V2 - MOVQ (8)(CX), AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - // U2*V1 - MOVQ (16)(CX), AX - MULQ R13 - ADDQ AX, R10 - MOVQ R10, (24)(SP) // C3 - ADCQ DX, R8 - ADCQ $0, R9 - - // U1*V3 - XORQ R10, R10 - MOVQ (8)(CX), AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - // U3*V1 - MOVQ (24)(CX), AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - // U2*V2 - MOVQ (16)(CX), AX - MULQ R14 - ADDQ AX, R8 - MOVQ R8, (32)(SP) // C4 - ADCQ DX, R9 - ADCQ $0, R10 - - // U2*V3 - XORQ R11, R11 - MOVQ (16)(CX), AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R11 - - // U3*V2 - MOVQ (24)(CX), AX - MULQ R14 - ADDQ AX, R9 // C5 - ADCQ DX, R10 - ADCQ $0, R11 - - // U3*V3 - MOVQ (24)(CX), AX - MULQ R15 - ADDQ AX, R10 // C6 - ADCQ DX, R11 // C7 - - MOVQ (64)(SP), AX - ANDQ AX, R12 - ANDQ AX, R13 - ANDQ AX, R14 - ANDQ AX, R15 - ADDQ R8, R12 - ADCQ R9, R13 - ADCQ R10, R14 - ADCQ R11, R15 - - MOVQ (72)(SP), AX - MOVQ (CX), R8 - MOVQ (8)(CX), R9 - MOVQ (16)(CX), R10 - MOVQ (24)(CX), R11 - ANDQ AX, R8 - ANDQ AX, R9 - ANDQ AX, R10 - ANDQ AX, R11 - ADDQ R12, R8 - ADCQ R13, R9 - ADCQ R14, R10 - ADCQ R15, R11 - MOVQ R8, (32)(SP) - MOVQ R9, (40)(SP) - MOVQ R10, (48)(SP) - MOVQ R11, (56)(SP) - - // CX[0-7] <- AL*BL - - // U0*V0 - MOVQ (REG_P1), R11 - MOVQ (REG_P2), AX - MULQ R11 - XORQ R9, R9 - MOVQ AX, (CX) // C0 - MOVQ DX, R8 - - // U0*V1 - MOVQ (16)(REG_P1), R14 - MOVQ (8)(REG_P2), AX - MULQ R11 - XORQ R10, R10 - ADDQ AX, R8 - ADCQ DX, R9 - - // U1*V0 - MOVQ (8)(REG_P1), R12 - MOVQ (REG_P2), AX - MULQ R12 - ADDQ AX, R8 - MOVQ R8, (8)(CX) // C1 - ADCQ DX, R9 - ADCQ $0, R10 - - // U0*V2 - XORQ R8, R8 - MOVQ (16)(REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - // U2*V0 - MOVQ (REG_P2), R13 - MOVQ R14, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - // U1*V1 - MOVQ (8)(REG_P2), AX - MULQ R12 - ADDQ AX, R9 - MOVQ R9, (16)(CX) // C2 - ADCQ DX, R10 - ADCQ $0, R8 - - // U0*V3 - XORQ R9, R9 - MOVQ (24)(REG_P2), AX - MULQ R11 - MOVQ (24)(REG_P1), R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - // U3*V1 - MOVQ R15, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - // U2*V2 - MOVQ (16)(REG_P2), AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - // U2*V3 - MOVQ (8)(REG_P2), AX - MULQ R14 - ADDQ AX, R10 - MOVQ R10, (24)(CX) // C3 - ADCQ DX, R8 - ADCQ $0, R9 - - // U3*V2 - XORQ R10, R10 - MOVQ (24)(REG_P2), AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - // U3*V1 - MOVQ (8)(REG_P2), AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - // U2*V2 - MOVQ (16)(REG_P2), AX - MULQ R14 - ADDQ AX, R8 - MOVQ R8, (32)(CX) // C4 - ADCQ DX, R9 - ADCQ $0, R10 - - // U2*V3 - XORQ R8, R8 - MOVQ (24)(REG_P2), AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - // U3*V2 - MOVQ (16)(REG_P2), AX - MULQ R15 - ADDQ AX, R9 - MOVQ R9, (40)(CX) // C5 - ADCQ DX, R10 - ADCQ $0, R8 - - // U3*V3 - MOVQ (24)(REG_P2), AX - MULQ R15 - ADDQ AX, R10 - MOVQ R10, (48)(CX) // C6 - ADCQ DX, R8 - MOVQ R8, (56)(CX) // C7 - - // CX[8-15] <- U1*V1 - MOVQ (32)(REG_P1), R11 - MOVQ (32)(REG_P2), AX - MULQ R11 - XORQ R9, R9 - MOVQ AX, (64)(CX) // C0 - MOVQ DX, R8 - - MOVQ (48)(REG_P1), R14 - MOVQ (40)(REG_P2), AX - MULQ R11 - XORQ R10, R10 - ADDQ AX, R8 - ADCQ DX, R9 - - MOVQ (40)(REG_P1), R12 - MOVQ (32)(REG_P2), AX - MULQ R12 - ADDQ AX, R8 - MOVQ R8, (72)(CX) // C1 - ADCQ DX, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (48)(REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (32)(REG_P2), R13 - MOVQ R14, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (40)(REG_P2), AX - MULQ R12 - ADDQ AX, R9 - MOVQ R9, (80)(CX) // C2 - ADCQ DX, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ (56)(REG_P2), AX - MULQ R11 - MOVQ (56)(REG_P1), R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ R15, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (48)(REG_P2), AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (40)(REG_P2), AX - MULQ R14 - ADDQ AX, R10 - MOVQ R10, (88)(CX) // C3 - ADCQ DX, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ (56)(REG_P2), AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (40)(REG_P2), AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (48)(REG_P2), AX - MULQ R14 - ADDQ AX, R8 - MOVQ R8, (96)(CX) // C4 - ADCQ DX, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (56)(REG_P2), AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (48)(REG_P2), AX - MULQ R15 - ADDQ AX, R9 - MOVQ R9, (104)(CX) // C5 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (56)(REG_P2), AX - MULQ R15 - ADDQ AX, R10 - MOVQ R10, (112)(CX) // C6 - ADCQ DX, R8 - MOVQ R8, (120)(CX) // C7 - - // [R8-R15] <- (U0+U1)*(V0+V1) - U1*V1 - MOVQ (SP), R8 - SUBQ (CX), R8 - MOVQ (8)(SP), R9 - SBBQ (8)(CX), R9 - MOVQ (16)(SP), R10 - SBBQ (16)(CX), R10 - MOVQ (24)(SP), R11 - SBBQ (24)(CX), R11 - MOVQ (32)(SP), R12 - SBBQ (32)(CX), R12 - MOVQ (40)(SP), R13 - SBBQ (40)(CX), R13 - MOVQ (48)(SP), R14 - SBBQ (48)(CX), R14 - MOVQ (56)(SP), R15 - SBBQ (56)(CX), R15 - - // [R8-R15] <- (U0+U1)*(V0+V1) - U1*V0 - U0*U1 - MOVQ ( 64)(CX), AX; SUBQ AX, R8 - MOVQ ( 72)(CX), AX; SBBQ AX, R9 - MOVQ ( 80)(CX), AX; SBBQ AX, R10 - MOVQ ( 88)(CX), AX; SBBQ AX, R11 - MOVQ ( 96)(CX), AX; SBBQ AX, R12 - MOVQ (104)(CX), DX; SBBQ DX, R13 - MOVQ (112)(CX), DI; SBBQ DI, R14 - MOVQ (120)(CX), SI; SBBQ SI, R15 - - // Final result - ADDQ (32)(CX), R8; MOVQ R8, (32)(CX) - ADCQ (40)(CX), R9; MOVQ R9, (40)(CX) - ADCQ (48)(CX), R10; MOVQ R10, (48)(CX) - ADCQ (56)(CX), R11; MOVQ R11, (56)(CX) - ADCQ (64)(CX), R12; MOVQ R12, (64)(CX) - ADCQ (72)(CX), R13; MOVQ R13, (72)(CX) - ADCQ (80)(CX), R14; MOVQ R14, (80)(CX) - ADCQ (88)(CX), R15; MOVQ R15, (88)(CX) - ADCQ $0, AX; MOVQ AX, (96)(CX) - ADCQ $0, DX; MOVQ DX, (104)(CX) - ADCQ $0, DI; MOVQ DI, (112)(CX) - ADCQ $0, SI; MOVQ SI, (120)(CX) - RET - -mul_with_mulx_adcx_adox: - // Mul implementation for CPUs supporting two independent carry chain - // (ADOX/ADCX) instructions and carry-less MULX multiplier - MUL(CX, REG_P1, REG_P2, MULS256_MULX_ADCX_ADOX) - RET - -mul_with_mulx: - // Mul implementation for CPUs supporting carry-less MULX multiplier. - MUL(CX, REG_P1, REG_P2, MULS256_MULX) - RET - -TEXT ·fp503MontgomeryReduce(SB), $0-16 - MOVQ z+0(FP), REG_P2 - MOVQ x+8(FP), REG_P1 - - // Check wether to use optimized implementation - CMPB ·HasADXandBMI2(SB), $1 - JE redc_with_mulx_adcx_adox - CMPB ·HasBMI2(SB), $1 - JE redc_with_mulx - - MOVQ (REG_P1), R11 - MOVQ P503P1_3, AX - MULQ R11 - XORQ R8, R8 - ADDQ (24)(REG_P1), AX - MOVQ AX, (24)(REG_P2) - ADCQ DX, R8 - - XORQ R9, R9 - MOVQ P503P1_4, AX - MULQ R11 - XORQ R10, R10 - ADDQ AX, R8 - ADCQ DX, R9 - - MOVQ (8)(REG_P1), R12 - MOVQ P503P1_3, AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (32)(REG_P1), R8 - MOVQ R8, (32)(REG_P2) // Z4 - ADCQ $0, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ P503P1_5, AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P503P1_4, AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (16)(REG_P1), R13 - MOVQ P503P1_3, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - ADDQ (40)(REG_P1), R9 - MOVQ R9, (40)(REG_P2) // Z5 - ADCQ $0, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ P503P1_6, AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P503P1_5, AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P503P1_4, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (24)(REG_P2), R14 - MOVQ P503P1_3, AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - ADDQ (48)(REG_P1), R10 - MOVQ R10, (48)(REG_P2) // Z6 - ADCQ $0, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ P503P1_7, AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P503P1_6, AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P503P1_5, AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P503P1_4, AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (32)(REG_P2), R15 - MOVQ P503P1_3, AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (56)(REG_P1), R8 - MOVQ R8, (56)(REG_P2) // Z7 - ADCQ $0, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ P503P1_7, AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P503P1_6, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P503P1_5, AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P503P1_4, AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (40)(REG_P2), CX - MOVQ P503P1_3, AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - ADDQ (64)(REG_P1), R9 - MOVQ R9, (REG_P2) // Z0 - ADCQ $0, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ P503P1_7, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P503P1_6, AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P503P1_5, AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P503P1_4, AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (48)(REG_P2), R13 - MOVQ P503P1_3, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - ADDQ (72)(REG_P1), R10 - MOVQ R10, (8)(REG_P2) // Z1 - ADCQ $0, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ P503P1_7, AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P503P1_6, AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P503P1_5, AX - MULQ CX - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P503P1_4, AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (56)(REG_P2), R14 - MOVQ P503P1_3, AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (80)(REG_P1), R8 - MOVQ R8, (16)(REG_P2) // Z2 - ADCQ $0, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ P503P1_7, AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P503P1_6, AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P503P1_5, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P503P1_4, AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - ADDQ (88)(REG_P1), R9 - MOVQ R9, (24)(REG_P2) // Z3 - ADCQ $0, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ P503P1_7, AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P503P1_6, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P503P1_5, AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - ADDQ (96)(REG_P1), R10 - MOVQ R10, (32)(REG_P2) // Z4 - ADCQ $0, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ P503P1_7, AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P503P1_6, AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (104)(REG_P1), R8 // Z5 - MOVQ R8, (40)(REG_P2) // Z5 - ADCQ $0, R9 - ADCQ $0, R10 - - MOVQ P503P1_7, AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADDQ (112)(REG_P1), R9 // Z6 - MOVQ R9, (48)(REG_P2) // Z6 - ADCQ $0, R10 - ADDQ (120)(REG_P1), R10 // Z7 - MOVQ R10, (56)(REG_P2) // Z7 - RET - -redc_with_mulx_adcx_adox: - // Implementation of the Montgomery reduction for CPUs - // supporting two independent carry chain (ADOX/ADCX) - // instructions and carry-less MULX multiplier - REDC(REG_P2, REG_P1, MULS_128x320_MULX_ADCX_ADOX) - RET - -redc_with_mulx: - // Implementation of the Montgomery reduction for CPUs - // supporting carry-less MULX multiplier. - REDC(REG_P2, REG_P1, MULS_128x320_MULX) - RET - -TEXT ·fp503AddLazy(SB), NOSPLIT, $0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - MOVQ (REG_P1), R8 - MOVQ (8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - - ADDQ (REG_P2), R8 - ADCQ (8)(REG_P2), R9 - ADCQ (16)(REG_P2), R10 - ADCQ (24)(REG_P2), R11 - ADCQ (32)(REG_P2), R12 - ADCQ (40)(REG_P2), R13 - ADCQ (48)(REG_P2), R14 - ADCQ (56)(REG_P2), R15 - - MOVQ R8, (REG_P3) - MOVQ R9, (8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - - RET - -TEXT ·fp503X2AddLazy(SB), NOSPLIT, $0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - MOVQ (REG_P1), R8 - MOVQ (8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - MOVQ (64)(REG_P1), AX - MOVQ (72)(REG_P1), BX - MOVQ (80)(REG_P1), CX - - ADDQ (REG_P2), R8 - ADCQ (8)(REG_P2), R9 - ADCQ (16)(REG_P2), R10 - ADCQ (24)(REG_P2), R11 - ADCQ (32)(REG_P2), R12 - ADCQ (40)(REG_P2), R13 - ADCQ (48)(REG_P2), R14 - ADCQ (56)(REG_P2), R15 - ADCQ (64)(REG_P2), AX - ADCQ (72)(REG_P2), BX - ADCQ (80)(REG_P2), CX - - MOVQ R8, (REG_P3) - MOVQ R9, (8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - MOVQ AX, (64)(REG_P3) - MOVQ BX, (72)(REG_P3) - MOVQ CX, (80)(REG_P3) - - MOVQ (88)(REG_P1), R8 - MOVQ (96)(REG_P1), R9 - MOVQ (104)(REG_P1), R10 - MOVQ (112)(REG_P1), R11 - MOVQ (120)(REG_P1), R12 - - ADCQ (88)(REG_P2), R8 - ADCQ (96)(REG_P2), R9 - ADCQ (104)(REG_P2), R10 - ADCQ (112)(REG_P2), R11 - ADCQ (120)(REG_P2), R12 - - MOVQ R8, (88)(REG_P3) - MOVQ R9, (96)(REG_P3) - MOVQ R10, (104)(REG_P3) - MOVQ R11, (112)(REG_P3) - MOVQ R12, (120)(REG_P3) - - RET - -TEXT ·fp503X2SubLazy(SB), NOSPLIT, $0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - // Used later to store result of 0-borrow - XORQ CX, CX - - // SUBC for first 11 limbs - MOVQ (REG_P1), R8 - MOVQ (8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - MOVQ (64)(REG_P1), AX - MOVQ (72)(REG_P1), BX - - SUBQ (REG_P2), R8 - SBBQ (8)(REG_P2), R9 - SBBQ (16)(REG_P2), R10 - SBBQ (24)(REG_P2), R11 - SBBQ (32)(REG_P2), R12 - SBBQ (40)(REG_P2), R13 - SBBQ (48)(REG_P2), R14 - SBBQ (56)(REG_P2), R15 - SBBQ (64)(REG_P2), AX - SBBQ (72)(REG_P2), BX - - MOVQ R8, (REG_P3) - MOVQ R9, (8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - MOVQ AX, (64)(REG_P3) - MOVQ BX, (72)(REG_P3) - - // SUBC for last 5 limbs - MOVQ (80)(REG_P1), R8 - MOVQ (88)(REG_P1), R9 - MOVQ (96)(REG_P1), R10 - MOVQ (104)(REG_P1), R11 - MOVQ (112)(REG_P1), R12 - MOVQ (120)(REG_P1), R13 - - SBBQ (80)(REG_P2), R8 - SBBQ (88)(REG_P2), R9 - SBBQ (96)(REG_P2), R10 - SBBQ (104)(REG_P2), R11 - SBBQ (112)(REG_P2), R12 - SBBQ (120)(REG_P2), R13 - - MOVQ R8, (80)(REG_P3) - MOVQ R9, (88)(REG_P3) - MOVQ R10, (96)(REG_P3) - MOVQ R11, (104)(REG_P3) - MOVQ R12, (112)(REG_P3) - MOVQ R13, (120)(REG_P3) - - // Now the carry flag is 1 if x-y < 0. If so, add p*2^512. - SBBQ $0, CX - - // Load p into registers: - MOVQ P503_0, R8 - // P503_{1,2} = P503_0, so reuse R8 - MOVQ P503_3, R9 - MOVQ P503_4, R10 - MOVQ P503_5, R11 - MOVQ P503_6, R12 - MOVQ P503_7, R13 - - ANDQ CX, R8 - ANDQ CX, R9 - ANDQ CX, R10 - ANDQ CX, R11 - ANDQ CX, R12 - ANDQ CX, R13 - - MOVQ (64 )(REG_P3), AX; ADDQ R8, AX; MOVQ AX, (64 )(REG_P3) - MOVQ (64+ 8)(REG_P3), AX; ADCQ R8, AX; MOVQ AX, (64+ 8)(REG_P3) - MOVQ (64+16)(REG_P3), AX; ADCQ R8, AX; MOVQ AX, (64+16)(REG_P3) - MOVQ (64+24)(REG_P3), AX; ADCQ R9, AX; MOVQ AX, (64+24)(REG_P3) - MOVQ (64+32)(REG_P3), AX; ADCQ R10, AX; MOVQ AX, (64+32)(REG_P3) - MOVQ (64+40)(REG_P3), AX; ADCQ R11, AX; MOVQ AX, (64+40)(REG_P3) - MOVQ (64+48)(REG_P3), AX; ADCQ R12, AX; MOVQ AX, (64+48)(REG_P3) - MOVQ (64+56)(REG_P3), AX; ADCQ R13, AX; MOVQ AX, (64+56)(REG_P3) - - RET diff --git a/external/github.com/cloudflare/sidh/p503/arith_arm64.s b/external/github.com/cloudflare/sidh/p503/arith_arm64.s deleted file mode 100644 index 03eabe9e2..000000000 --- a/external/github.com/cloudflare/sidh/p503/arith_arm64.s +++ /dev/null @@ -1,802 +0,0 @@ -// +build arm64,!noasm - -#include "textflag.h" - -TEXT ·fp503ConditionalSwap(SB), NOSPLIT, $0-17 - MOVD x+0(FP), R0 - MOVD y+8(FP), R1 - MOVB choice+16(FP), R2 - - // Set flags - // If choice is not 0 or 1, this implementation will swap completely - CMP $0, R2 - - LDP 0(R0), (R3, R4) - LDP 0(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 0(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 0(R1) - - LDP 16(R0), (R3, R4) - LDP 16(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 16(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 16(R1) - - LDP 32(R0), (R3, R4) - LDP 32(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 32(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 32(R1) - - LDP 48(R0), (R3, R4) - LDP 48(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 48(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 48(R1) - - RET - -TEXT ·fp503AddReduced(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - // Load first summand into R3-R10 - // Add first summand and second summand and store result in R3-R10 - LDP 0(R0), (R3, R4) - LDP 0(R1), (R11, R12) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R13, R14) - ADDS R11, R3 - ADCS R12, R4 - ADCS R13, R5 - ADCS R14, R6 - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R11, R12) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R13, R14) - ADCS R11, R7 - ADCS R12, R8 - ADCS R13, R9 - ADC R14, R10 - - // Subtract 2 * p503 in R11-R17 from the result in R3-R10 - LDP ·p503x2+0(SB), (R11, R12) - LDP ·p503x2+24(SB), (R13, R14) - SUBS R11, R3 - SBCS R12, R4 - LDP ·p503x2+40(SB), (R15, R16) - SBCS R12, R5 - SBCS R13, R6 - MOVD ·p503x2+56(SB), R17 - SBCS R14, R7 - SBCS R15, R8 - SBCS R16, R9 - SBCS R17, R10 - SBC ZR, ZR, R19 - - // If x + y - 2 * p503 < 0, R19 is 1 and 2 * p503 should be added - AND R19, R11 - AND R19, R12 - AND R19, R13 - AND R19, R14 - AND R19, R15 - AND R19, R16 - AND R19, R17 - - ADDS R11, R3 - ADCS R12, R4 - STP (R3, R4), 0(R2) - ADCS R12, R5 - ADCS R13, R6 - STP (R5, R6), 16(R2) - ADCS R14, R7 - ADCS R15, R8 - STP (R7, R8), 32(R2) - ADCS R16, R9 - ADC R17, R10 - STP (R9, R10), 48(R2) - - RET - -TEXT ·fp503SubReduced(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - // Load x into R3-R10 - // Subtract y from x and store result in R3-R10 - LDP 0(R0), (R3, R4) - LDP 0(R1), (R11, R12) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R13, R14) - SUBS R11, R3 - SBCS R12, R4 - SBCS R13, R5 - SBCS R14, R6 - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R11, R12) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R13, R14) - SBCS R11, R7 - SBCS R12, R8 - SBCS R13, R9 - SBCS R14, R10 - SBC ZR, ZR, R19 - - // If x - y < 0, R19 is 1 and 2 * p503 should be added - LDP ·p503x2+0(SB), (R11, R12) - LDP ·p503x2+24(SB), (R13, R14) - AND R19, R11 - AND R19, R12 - LDP ·p503x2+40(SB), (R15, R16) - AND R19, R13 - AND R19, R14 - MOVD ·p503x2+56(SB), R17 - AND R19, R15 - AND R19, R16 - AND R19, R17 - - ADDS R11, R3 - ADCS R12, R4 - STP (R3, R4), 0(R2) - ADCS R12, R5 - ADCS R13, R6 - STP (R5, R6), 16(R2) - ADCS R14, R7 - ADCS R15, R8 - STP (R7, R8), 32(R2) - ADCS R16, R9 - ADC R17, R10 - STP (R9, R10), 48(R2) - - RET - -TEXT ·fp503AddLazy(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - // Load first summand into R3-R10 - // Add first summand and second summand and store result in R3-R10 - LDP 0(R0), (R3, R4) - LDP 0(R1), (R11, R12) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R13, R14) - ADDS R11, R3 - ADCS R12, R4 - STP (R3, R4), 0(R2) - ADCS R13, R5 - ADCS R14, R6 - STP (R5, R6), 16(R2) - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R11, R12) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R13, R14) - ADCS R11, R7 - ADCS R12, R8 - STP (R7, R8), 32(R2) - ADCS R13, R9 - ADC R14, R10 - STP (R9, R10), 48(R2) - - RET - -TEXT ·fp503X2AddLazy(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - LDP 0(R0), (R3, R4) - LDP 0(R1), (R11, R12) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R13, R14) - ADDS R11, R3 - ADCS R12, R4 - STP (R3, R4), 0(R2) - ADCS R13, R5 - ADCS R14, R6 - STP (R5, R6), 16(R2) - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R11, R12) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R13, R14) - ADCS R11, R7 - ADCS R12, R8 - STP (R7, R8), 32(R2) - ADCS R13, R9 - ADCS R14, R10 - STP (R9, R10), 48(R2) - - LDP 64(R0), (R3, R4) - LDP 64(R1), (R11, R12) - LDP 80(R0), (R5, R6) - LDP 80(R1), (R13, R14) - ADCS R11, R3 - ADCS R12, R4 - STP (R3, R4), 64(R2) - ADCS R13, R5 - ADCS R14, R6 - STP (R5, R6), 80(R2) - - LDP 96(R0), (R7, R8) - LDP 96(R1), (R11, R12) - LDP 112(R0), (R9, R10) - LDP 112(R1), (R13, R14) - ADCS R11, R7 - ADCS R12, R8 - STP (R7, R8), 96(R2) - ADCS R13, R9 - ADC R14, R10 - STP (R9, R10), 112(R2) - - RET - -TEXT ·fp503X2SubLazy(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - LDP 0(R0), (R3, R4) - LDP 0(R1), (R11, R12) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R13, R14) - SUBS R11, R3 - SBCS R12, R4 - STP (R3, R4), 0(R2) - SBCS R13, R5 - SBCS R14, R6 - STP (R5, R6), 16(R2) - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R11, R12) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R13, R14) - SBCS R11, R7 - SBCS R12, R8 - STP (R7, R8), 32(R2) - SBCS R13, R9 - SBCS R14, R10 - STP (R9, R10), 48(R2) - - LDP 64(R0), (R3, R4) - LDP 64(R1), (R11, R12) - LDP 80(R0), (R5, R6) - LDP 80(R1), (R13, R14) - SBCS R11, R3 - SBCS R12, R4 - SBCS R13, R5 - SBCS R14, R6 - - LDP 96(R0), (R7, R8) - LDP 96(R1), (R11, R12) - LDP 112(R0), (R9, R10) - LDP 112(R1), (R13, R14) - SBCS R11, R7 - SBCS R12, R8 - SBCS R13, R9 - SBCS R14, R10 - SBC ZR, ZR, R15 - - // If x - y < 0, R15 is 1 and p503 should be added - LDP ·p503+16(SB), (R16, R17) - LDP ·p503+32(SB), (R19, R20) - AND R15, R16 - AND R15, R17 - LDP ·p503+48(SB), (R21, R22) - AND R15, R19 - AND R15, R20 - AND R15, R21 - AND R15, R22 - - ADDS R16, R3 - ADCS R16, R4 - STP (R3, R4), 64(R2) - ADCS R16, R5 - ADCS R17, R6 - STP (R5, R6), 80(R2) - ADCS R19, R7 - ADCS R20, R8 - STP (R7, R8), 96(R2) - ADCS R21, R9 - ADC R22, R10 - STP (R9, R10), 112(R2) - - RET - -// Expects that X0*Y0 is already in Z0(low),Z3(high) and X0*Y1 in Z1(low),Z2(high) -// Z0 is not actually touched -// Result of (X0-X1) * (Y0-Y1) will be in Z0-Z3 -// Inputs get overwritten, except for X1 -#define mul128x128comba(X0, X1, Y0, Y1, Z0, Z1, Z2, Z3, T0) \ - MUL X1, Y0, X0 \ - UMULH X1, Y0, Y0 \ - ADDS Z3, Z1 \ - ADC ZR, Z2 \ - \ - MUL Y1, X1, T0 \ - UMULH Y1, X1, Y1 \ - ADDS X0, Z1 \ - ADCS Y0, Z2 \ - ADC ZR, ZR, Z3 \ - \ - ADDS T0, Z2 \ - ADC Y1, Z3 - -// Expects that X points to (X0-X1) -// Result of (X0-X3) * (Y0-Y3) will be in Z0-Z7 -// Inputs get overwritten, except X2-X3 and Y2-Y3 -#define mul256x256karatsuba(X, X0, X1, X2, X3, Y0, Y1, Y2, Y3, Z0, Z1, Z2, Z3, Z4, Z5, Z6, Z7, T0, T1)\ - ADDS X2, X0 \ // xH + xL, destroys xL - ADCS X3, X1 \ - ADCS ZR, ZR, T0 \ - \ - ADDS Y2, Y0, Z6 \ // yH + yL - ADCS Y3, Y1, T1 \ - ADC ZR, ZR, Z7 \ - \ - SUB T0, ZR, Z2 \ - SUB Z7, ZR, Z3 \ - AND Z7, T0 \ // combined carry - \ - AND Z2, Z6, Z0 \ // masked(yH + yL) - AND Z2, T1, Z1 \ - \ - AND Z3, X0, Z4 \ // masked(xH + xL) - AND Z3, X1, Z5 \ - \ - MUL Z6, X0, Z2 \ - MUL T1, X0, Z3 \ - \ - ADDS Z4, Z0 \ - UMULH T1, X0, Z4 \ - ADCS Z5, Z1 \ - UMULH Z6, X0, Z5 \ - ADC ZR, T0 \ - \ // (xH + xL) * (yH + yL) - mul128x128comba(X0, X1, Z6, T1, Z2, Z3, Z4, Z5, Z7)\ - \ - LDP 0+X, (X0, X1) \ - \ - ADDS Z0, Z4 \ - UMULH Y0, X0, Z7 \ - UMULH Y1, X0, T1 \ - ADCS Z1, Z5 \ - MUL Y0, X0, Z0 \ - MUL Y1, X0, Z1 \ - ADC ZR, T0 \ - \ // xL * yL - mul128x128comba(X0, X1, Y0, Y1, Z0, Z1, T1, Z7, Z6)\ - \ - MUL Y2, X2, X0 \ - UMULH Y2, X2, Y0 \ - SUBS Z0, Z2 \ // (xH + xL) * (yH + yL) - xL * yL - SBCS Z1, Z3 \ - SBCS T1, Z4 \ - MUL Y3, X2, X1 \ - UMULH Y3, X2, Z6 \ - SBCS Z7, Z5 \ - SBCS ZR, T0 \ - \ // xH * yH - mul128x128comba(X2, X3, Y2, Y3, X0, X1, Z6, Y0, Y1)\ - \ - SUBS X0, Z2 \ // (xH + xL) * (yH + yL) - xL * yL - xH * yH - SBCS X1, Z3 \ - SBCS Z6, Z4 \ - SBCS Y0, Z5 \ - SBCS ZR, T0 \ - \ - ADDS T1, Z2 \ // (xH * yH) * 2^256 + ((xH + xL) * (yH + yL) - xL * yL - xH * yH) * 2^128 + xL * yL - ADCS Z7, Z3 \ - ADCS X0, Z4 \ - ADCS X1, Z5 \ - ADCS T0, Z6 \ - ADC Y0, ZR, Z7 - - -// This implements two-level Karatsuba with a 128x128 Comba multiplier -// at the bottom -TEXT ·fp503Mul(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - // Load xL in R3-R6, xH in R7-R10 - // (xH + xL) in R25-R29 - LDP 0(R0), (R3, R4) - LDP 32(R0), (R7, R8) - ADDS R3, R7, R25 - ADCS R4, R8, R26 - LDP 16(R0), (R5, R6) - LDP 48(R0), (R9, R10) - ADCS R5, R9, R27 - ADCS R6, R10, R29 - ADC ZR, ZR, R7 - - // Load yL in R11-R14, yH in R15-19 - // (yH + yL) in R11-R14, destroys yL - LDP 0(R1), (R11, R12) - LDP 32(R1), (R15, R16) - ADDS R15, R11 - ADCS R16, R12 - LDP 16(R1), (R13, R14) - LDP 48(R1), (R17, R19) - ADCS R17, R13 - ADCS R19, R14 - ADC ZR, ZR, R8 - - // Compute maskes and combined carry - SUB R7, ZR, R9 - SUB R8, ZR, R10 - AND R8, R7 - - // masked(yH + yL) - AND R9, R11, R15 - AND R9, R12, R16 - AND R9, R13, R17 - AND R9, R14, R19 - - // masked(xH + xL) - AND R10, R25, R20 - AND R10, R26, R21 - AND R10, R27, R22 - AND R10, R29, R23 - - // masked(xH + xL) + masked(yH + yL) in R15-R19 - ADDS R20, R15 - ADCS R21, R16 - ADCS R22, R17 - ADCS R23, R19 - ADC ZR, R7 - - // Use z as temporary storage - STP (R25, R26), 0(R2) - - // (xH + xL) * (yH + yL) - mul256x256karatsuba(0(R2), R25, R26, R27, R29, R11, R12, R13, R14, R8, R9, R10, R20, R21, R22, R23, R24, R0, R1) - - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - ADDS R21, R15 - ADCS R22, R16 - ADCS R23, R17 - ADCS R24, R19 - ADC ZR, R7 - - // Load yL in R11-R14 - LDP 0(R1), (R11, R12) - LDP 16(R1), (R13, R14) - - // xL * yL - mul256x256karatsuba(0(R0), R3, R4, R5, R6, R11, R12, R13, R14, R21, R22, R23, R24, R25, R26, R27, R29, R1, R2) - - MOVD z+0(FP), R2 - MOVD y+16(FP), R1 - - // (xH + xL) * (yH + yL) - xL * yL - SUBS R21, R8 - SBCS R22, R9 - STP (R21, R22), 0(R2) - SBCS R23, R10 - SBCS R24, R20 - STP (R23, R24), 16(R2) - SBCS R25, R15 - SBCS R26, R16 - SBCS R27, R17 - SBCS R29, R19 - SBC ZR, R7 - - // Load xH in R3-R6, yH in R11-R14 - LDP 32(R0), (R3, R4) - LDP 48(R0), (R5, R6) - LDP 32(R1), (R11, R12) - LDP 48(R1), (R13, R14) - - ADDS R25, R8 - ADCS R26, R9 - ADCS R27, R10 - ADCS R29, R20 - ADC ZR, ZR, R1 - - MOVD R20, 32(R2) - - // xH * yH - mul256x256karatsuba(32(R0), R3, R4, R5, R6, R11, R12, R13, R14, R21, R22, R23, R24, R25, R26, R27, R29, R2, R20) - NEG R1, R1 - - MOVD z+0(FP), R2 - MOVD 32(R2), R20 - - // (xH + xL) * (yH + yL) - xL * yL - xH * yH in R8-R10,R20,R15-R19 - // Store lower half in z, that's done - SUBS R21, R8 - SBCS R22, R9 - STP (R8, R9), 32(R2) - SBCS R23, R10 - SBCS R24, R20 - STP (R10, R20), 48(R2) - SBCS R25, R15 - SBCS R26, R16 - SBCS R27, R17 - SBCS R29, R19 - SBC ZR, R7 - - // (xH * yH) * 2^512 + ((xH + xL) * (yH + yL) - xL * yL - xH * yH) * 2^256 + xL * yL - // Store remaining limbs in z - ADDS $1, R1 - ADCS R21, R15 - ADCS R22, R16 - STP (R15, R16), 64(R2) - ADCS R23, R17 - ADCS R24, R19 - STP (R17, R19), 80(R2) - ADCS R7, R25 - ADCS ZR, R26 - STP (R25, R26), 96(R2) - ADCS ZR, R27 - ADC ZR, R29 - STP (R27, R29), 112(R2) - - RET - -// Expects that X0*Y0 is already in Z0(low),Z3(high) and X0*Y1 in Z1(low),Z2(high) -// Z0 is not actually touched -// Result of (X0-X1) * (Y0-Y3) will be in Z0-Z5 -// Inputs remain intact -#define mul128x256comba(X0, X1, Y0, Y1, Y2, Y3, Z0, Z1, Z2, Z3, Z4, Z5, T0, T1, T2, T3)\ - MUL X1, Y0, T0 \ - UMULH X1, Y0, T1 \ - ADDS Z3, Z1 \ - ADC ZR, Z2 \ - \ - MUL X0, Y2, T2 \ - UMULH X0, Y2, T3 \ - ADDS T0, Z1 \ - ADCS T1, Z2 \ - ADC ZR, ZR, Z3 \ - \ - MUL X1, Y1, T0 \ - UMULH X1, Y1, T1 \ - ADDS T2, Z2 \ - ADCS T3, Z3 \ - ADC ZR, ZR, Z4 \ - \ - MUL X0, Y3, T2 \ - UMULH X0, Y3, T3 \ - ADDS T0, Z2 \ - ADCS T1, Z3 \ - ADC ZR, Z4 \ - \ - MUL X1, Y2, T0 \ - UMULH X1, Y2, T1 \ - ADDS T2, Z3 \ - ADCS T3, Z4 \ - ADC ZR, ZR, Z5 \ - \ - MUL X1, Y3, T2 \ - UMULH X1, Y3, T3 \ - ADDS T0, Z3 \ - ADCS T1, Z4 \ - ADC ZR, Z5 \ - ADDS T2, Z4 \ - ADC T3, Z5 - -// This implements the shifted 2^(B*w) Montgomery reduction from -// https://eprint.iacr.org/2016/986.pdf, section Section 3.2, with -// B = 4, w = 64. Performance results were reported in -// https://eprint.iacr.org/2018/700.pdf Section 6. -TEXT ·fp503MontgomeryReduce(SB), NOSPLIT, $0-16 - MOVD x+8(FP), R0 - - // Load x0-x1 - LDP 0(R0), (R2, R3) - - // Load the prime constant in R25-R29 - LDP ·p503p1s8+32(SB), (R25, R26) - LDP ·p503p1s8+48(SB), (R27, R29) - - // [x0,x1] * p503p1s8 to R4-R9 - MUL R2, R25, R4 // x0 * p503p1s8[0] - UMULH R2, R25, R7 - MUL R2, R26, R5 // x0 * p503p1s8[1] - UMULH R2, R26, R6 - - mul128x256comba(R2, R3, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13) - - LDP 16(R0), (R3, R11) // x2 - LDP 32(R0), (R12, R13) - LDP 48(R0), (R14, R15) - - // Left-shift result in R4-R9 by 56 to R4-R10 - ORR R9>>8, ZR, R10 - LSL $56, R9 - ORR R8>>8, R9 - LSL $56, R8 - ORR R7>>8, R8 - LSL $56, R7 - ORR R6>>8, R7 - LSL $56, R6 - ORR R5>>8, R6 - LSL $56, R5 - ORR R4>>8, R5 - LSL $56, R4 - - ADDS R4, R11 // x3 - ADCS R5, R12 // x4 - ADCS R6, R13 - ADCS R7, R14 - ADCS R8, R15 - LDP 64(R0), (R16, R17) - LDP 80(R0), (R19, R20) - MUL R3, R25, R4 // x2 * p503p1s8[0] - UMULH R3, R25, R7 - ADCS R9, R16 - ADCS R10, R17 - ADCS ZR, R19 - ADCS ZR, R20 - LDP 96(R0), (R21, R22) - LDP 112(R0), (R23, R24) - MUL R3, R26, R5 // x2 * p503p1s8[1] - UMULH R3, R26, R6 - ADCS ZR, R21 - ADCS ZR, R22 - ADCS ZR, R23 - ADC ZR, R24 - - // [x2,x3] * p503p1s8 to R4-R9 - mul128x256comba(R3, R11, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R0, R1, R2) - - ORR R9>>8, ZR, R10 - LSL $56, R9 - ORR R8>>8, R9 - LSL $56, R8 - ORR R7>>8, R8 - LSL $56, R7 - ORR R6>>8, R7 - LSL $56, R6 - ORR R5>>8, R6 - LSL $56, R5 - ORR R4>>8, R5 - LSL $56, R4 - - ADDS R4, R13 // x5 - ADCS R5, R14 // x6 - ADCS R6, R15 - ADCS R7, R16 - MUL R12, R25, R4 // x4 * p503p1s8[0] - UMULH R12, R25, R7 - ADCS R8, R17 - ADCS R9, R19 - ADCS R10, R20 - ADCS ZR, R21 - MUL R12, R26, R5 // x4 * p503p1s8[1] - UMULH R12, R26, R6 - ADCS ZR, R22 - ADCS ZR, R23 - ADC ZR, R24 - - // [x4,x5] * p503p1s8 to R4-R9 - mul128x256comba(R12, R13, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R0, R1, R2) - - ORR R9>>8, ZR, R10 - LSL $56, R9 - ORR R8>>8, R9 - LSL $56, R8 - ORR R7>>8, R8 - LSL $56, R7 - ORR R6>>8, R7 - LSL $56, R6 - ORR R5>>8, R6 - LSL $56, R5 - ORR R4>>8, R5 - LSL $56, R4 - - ADDS R4, R15 // x7 - ADCS R5, R16 // x8 - ADCS R6, R17 - ADCS R7, R19 - MUL R14, R25, R4 // x6 * p503p1s8[0] - UMULH R14, R25, R7 - ADCS R8, R20 - ADCS R9, R21 - ADCS R10, R22 - MUL R14, R26, R5 // x6 * p503p1s8[1] - UMULH R14, R26, R6 - ADCS ZR, R23 - ADC ZR, R24 - - // [x6,x7] * p503p1s8 to R4-R9 - mul128x256comba(R14, R15, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R0, R1, R2) - - ORR R9>>8, ZR, R10 - LSL $56, R9 - ORR R8>>8, R9 - LSL $56, R8 - ORR R7>>8, R8 - LSL $56, R7 - ORR R6>>8, R7 - LSL $56, R6 - ORR R5>>8, R6 - LSL $56, R5 - ORR R4>>8, R5 - LSL $56, R4 - - MOVD z+0(FP), R0 - ADDS R4, R17 - ADCS R5, R19 - STP (R16, R17), 0(R0) // Store final result to z - ADCS R6, R20 - ADCS R7, R21 - STP (R19, R20), 16(R0) - ADCS R8, R22 - ADCS R9, R23 - STP (R21, R22), 32(R0) - ADC R10, R24 - STP (R23, R24), 48(R0) - - RET - -TEXT ·fp503StrongReduce(SB), NOSPLIT, $0-8 - MOVD x+0(FP), R0 - - // Keep x in R1-R8, p503 in R9-R14, subtract to R1-R8 - LDP ·p503+16(SB), (R9, R10) - LDP 0(R0), (R1, R2) - LDP 16(R0), (R3, R4) - SUBS R9, R1 - SBCS R9, R2 - - LDP 32(R0), (R5, R6) - LDP ·p503+32(SB), (R11, R12) - SBCS R9, R3 - SBCS R10, R4 - - LDP 48(R0), (R7, R8) - LDP ·p503+48(SB), (R13, R14) - SBCS R11, R5 - SBCS R12, R6 - - SBCS R13, R7 - SBCS R14, R8 - SBC ZR, ZR, R15 - - // Mask with the borrow and add p503 - AND R15, R9 - AND R15, R10 - AND R15, R11 - AND R15, R12 - AND R15, R13 - AND R15, R14 - - ADDS R9, R1 - ADCS R9, R2 - STP (R1, R2), 0(R0) - ADCS R9, R3 - ADCS R10, R4 - STP (R3, R4), 16(R0) - ADCS R11, R5 - ADCS R12, R6 - STP (R5, R6), 32(R0) - ADCS R13, R7 - ADCS R14, R8 - STP (R7, R8), 48(R0) - - RET diff --git a/external/github.com/cloudflare/sidh/p503/arith_decl.go b/external/github.com/cloudflare/sidh/p503/arith_decl.go deleted file mode 100644 index 2929561d2..000000000 --- a/external/github.com/cloudflare/sidh/p503/arith_decl.go +++ /dev/null @@ -1,46 +0,0 @@ -// +build amd64,!noasm arm64,!noasm - -package p503 - -import ( - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" -) - -// If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x. -// If choice is neither 0 nor 1 then behaviour is undefined. -// This function executes in constant time. -//go:noescape -func fp503ConditionalSwap(x, y *FpElement, choice uint8) - -// Compute z = x + y (mod p). -//go:noescape -func fp503AddReduced(z, x, y *FpElement) - -// Compute z = x - y (mod p). -//go:noescape -func fp503SubReduced(z, x, y *FpElement) - -// Compute z = x + y, without reducing mod p. -//go:noescape -func fp503AddLazy(z, x, y *FpElement) - -// Compute z = x + y, without reducing mod p. -//go:noescape -func fp503X2AddLazy(z, x, y *FpElementX2) - -// Compute z = x - y, without reducing mod p. -//go:noescape -func fp503X2SubLazy(z, x, y *FpElementX2) - -// Reduce a field element in [0, 2*p) to one in [0,p). -//go:noescape -func fp503StrongReduce(x *FpElement) - -// Computes z = x * y. -//go:noescape -func fp503Mul(z *FpElementX2, x, y *FpElement) - -// Computes the Montgomery reduction z = x R^{-1} (mod 2*p). On return value -// of x may be changed. z=x not allowed. -//go:noescape -func fp503MontgomeryReduce(z *FpElement, x *FpElementX2) diff --git a/external/github.com/cloudflare/sidh/p503/arith_generic.go b/external/github.com/cloudflare/sidh/p503/arith_generic.go deleted file mode 100644 index 2437f0e3c..000000000 --- a/external/github.com/cloudflare/sidh/p503/arith_generic.go +++ /dev/null @@ -1,197 +0,0 @@ -// +build noasm !amd64,!arm64 - -package p503 - -import ( - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/arith" - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" -) - -// Compute z = x + y (mod p). -func fp503AddReduced(z, x, y *FpElement) { - var carry uint64 - - // z=x+y % p503 - for i := 0; i < NumWords; i++ { - z[i], carry = Addc64(carry, x[i], y[i]) - } - - // z = z - p503x2 - carry = 0 - for i := 0; i < NumWords; i++ { - z[i], carry = Subc64(carry, z[i], p503x2[i]) - } - - // if z<0 add p503x2 back - mask := uint64(0 - carry) - carry = 0 - for i := 0; i < NumWords; i++ { - z[i], carry = Addc64(carry, z[i], p503x2[i]&mask) - } -} - -// Compute z = x - y (mod p). -func fp503SubReduced(z, x, y *FpElement) { - var borrow uint64 - - // z = z - p503x2 - for i := 0; i < NumWords; i++ { - z[i], borrow = Subc64(borrow, x[i], y[i]) - } - - // if z<0 add p503x2 back - mask := uint64(0 - borrow) - borrow = 0 - for i := 0; i < NumWords; i++ { - z[i], borrow = Addc64(borrow, z[i], p503x2[i]&mask) - } -} - -// Conditionally swaps bits in x and y in constant time. -// mask indicates bits to be swapped (set bits are swapped) -// For details see "Hackers Delight, 2.20" -// -// Implementation doesn't actually depend on a prime field. -func fp503ConditionalSwap(x, y *FpElement, mask uint8) { - var tmp, mask64 uint64 - - mask64 = 0 - uint64(mask) - for i := 0; i < NumWords; i++ { - tmp = mask64 & (x[i] ^ y[i]) - x[i] = tmp ^ x[i] - y[i] = tmp ^ y[i] - } -} - -// Perform Montgomery reduction: set z = x R^{-1} (mod 2*p) -// with R=2^512. Destroys the input value. -func fp503MontgomeryReduce(z *FpElement, x *FpElementX2) { - var carry, t, u, v uint64 - var uv Uint128 - var count int - - count = 3 // number of 0 digits in the least significant part of p503 + 1 - - for i := 0; i < NumWords; i++ { - for j := 0; j < i; j++ { - if j < (i - count + 1) { - uv = Mul64(z[j], p503p1[i-j]) - v, carry = Addc64(0, uv.L, v) - u, carry = Addc64(carry, uv.H, u) - t += carry - } - } - v, carry = Addc64(0, v, x[i]) - u, carry = Addc64(carry, u, 0) - t += carry - - z[i] = v - v = u - u = t - t = 0 - } - - for i := NumWords; i < 2*NumWords-1; i++ { - if count > 0 { - count-- - } - for j := i - NumWords + 1; j < NumWords; j++ { - if j < (NumWords - count) { - uv = Mul64(z[j], p503p1[i-j]) - v, carry = Addc64(0, uv.L, v) - u, carry = Addc64(carry, uv.H, u) - t += carry - } - } - v, carry = Addc64(0, v, x[i]) - u, carry = Addc64(carry, u, 0) - - t += carry - z[i-NumWords] = v - v = u - u = t - t = 0 - } - v, carry = Addc64(0, v, x[2*NumWords-1]) - z[NumWords-1] = v -} - -// Compute z = x * y. -func fp503Mul(z *FpElementX2, x, y *FpElement) { - var u, v, t uint64 - var carry uint64 - var uv Uint128 - - for i := uint64(0); i < NumWords; i++ { - for j := uint64(0); j <= i; j++ { - uv = Mul64(x[j], y[i-j]) - v, carry = Addc64(0, uv.L, v) - u, carry = Addc64(carry, uv.H, u) - t += carry - } - z[i] = v - v = u - u = t - t = 0 - } - - for i := NumWords; i < (2*NumWords)-1; i++ { - for j := i - NumWords + 1; j < NumWords; j++ { - uv = Mul64(x[j], y[i-j]) - v, carry = Addc64(0, uv.L, v) - u, carry = Addc64(carry, uv.H, u) - t += carry - } - z[i] = v - v = u - u = t - t = 0 - } - z[2*NumWords-1] = v -} - -// Compute z = x + y, without reducing mod p. -func fp503AddLazy(z, x, y *FpElement) { - var carry uint64 - for i := 0; i < NumWords; i++ { - z[i], carry = Addc64(carry, x[i], y[i]) - } -} - -// Compute z = x + y, without reducing mod p. -func fp503X2AddLazy(z, x, y *FpElementX2) { - var carry uint64 - for i := 0; i < 2*NumWords; i++ { - z[i], carry = Addc64(carry, x[i], y[i]) - } -} - -// Reduce a field element in [0, 2*p) to one in [0,p). -func fp503StrongReduce(x *FpElement) { - var borrow, mask uint64 - for i := 0; i < NumWords; i++ { - x[i], borrow = Subc64(borrow, x[i], p503[i]) - } - - // Sets all bits if borrow = 1 - mask = 0 - borrow - borrow = 0 - for i := 0; i < NumWords; i++ { - x[i], borrow = Addc64(borrow, x[i], p503[i]&mask) - } -} - -// Compute z = x - y, without reducing mod p. -func fp503X2SubLazy(z, x, y *FpElementX2) { - var borrow, mask uint64 - for i := 0; i < 2*NumWords; i++ { - z[i], borrow = Subc64(borrow, x[i], y[i]) - } - - // Sets all bits if borrow = 1 - mask = 0 - borrow - borrow = 0 - for i := NumWords; i < 2*NumWords; i++ { - z[i], borrow = Addc64(borrow, z[i], p503[i-NumWords]&mask) - } -} diff --git a/external/github.com/cloudflare/sidh/p503/consts.go b/external/github.com/cloudflare/sidh/p503/consts.go deleted file mode 100644 index fddf6be62..000000000 --- a/external/github.com/cloudflare/sidh/p503/consts.go +++ /dev/null @@ -1,178 +0,0 @@ -package p503 - -import ( - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" - cpu "v2ray.com/core/external/github.com/cloudflare/sidh/internal/utils" -) - -const ( - // SIDH public key byte size - P503_PublicKeySize = 378 - // SIDH shared secret byte size. - P503_SharedSecretSize = 126 - // Max size of secret key for 2-torsion group, corresponds to 2^e2 - 1 - P503_SecretBitLenA = 250 - // Size of secret key for 3-torsion group, corresponds to log_2(3^e3) - 1 - P503_SecretBitLenB = 252 - // Size of a compuatation strategy for 2-torsion group - strategySizeA = 124 - // Size of a compuatation strategy for 3-torsion group - strategySizeB = 158 - // ceil(503+7/8) - P503_Bytelen = 63 - // Number of limbs for a field element - NumWords = 8 -) - -// CPU Capabilities. Those flags are referred by assembly code. According to -// https://github.com/golang/go/issues/28230, variables referred from the -// assembly must be in the same package. -// We declare them variables not constants in order to facilitate testing. -var ( - // Signals support for MULX which is in BMI2 - HasBMI2 = cpu.X86.HasBMI2 - // Signals support for ADX and BMI2 - HasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX -) - -// The x-coordinate of PA -var P503_affine_PA = Fp2Element{ - A: FpElement{ - 0xE7EF4AA786D855AF, 0xED5758F03EB34D3B, 0x09AE172535A86AA9, 0x237B9CC07D622723, - 0xE3A284CBA4E7932D, 0x27481D9176C5E63F, 0x6A323FF55C6E71BF, 0x002ECC31A6FB8773, - }, - B: FpElement{ - 0x64D02E4E90A620B8, 0xDAB8128537D4B9F1, 0x4BADF77B8A228F98, 0x0F5DBDF9D1FB7D1B, - 0xBEC4DB288E1A0DCC, 0xE76A8665E80675DB, 0x6D6F252E12929463, 0x003188BD1463FACC, - }, -} - -// The x-coordinate of QA -var P503_affine_QA = Fp2Element{ - A: FpElement{ - 0xB79D41025DE85D56, 0x0B867DA9DF169686, 0x740E5368021C827D, 0x20615D72157BF25C, - 0xFF1590013C9B9F5B, 0xC884DCADE8C16CEA, 0xEBD05E53BF724E01, 0x0032FEF8FDA5748C, - }, - B: FpElement{ - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - }, -} - -// The x-coordinate of RA = PA-QA -var P503_affine_RA = Fp2Element{ - A: FpElement{ - 0x12E2E849AA0A8006, 0x41CF47008635A1E8, 0x9CD720A70798AED7, 0x42A820B42FCF04CF, - 0x7BF9BAD32AAE88B1, 0xF619127A54090BBE, 0x1CB10D8F56408EAA, 0x001D6B54C3C0EDEB, - }, - B: FpElement{ - 0x34DB54931CBAAC36, 0x420A18CB8DD5F0C4, 0x32008C1A48C0F44D, 0x3B3BA772B1CFD44D, - 0xA74B058FDAF13515, 0x095FC9CA7EEC17B4, 0x448E829D28F120F8, 0x00261EC3ED16A489, - }, -} - -// The x-coordinate of PB -var P503_affine_PB = Fp2Element{ - A: FpElement{ - 0x7EDE37F4FA0BC727, 0xF7F8EC5C8598941C, 0xD15519B516B5F5C8, 0xF6D5AC9B87A36282, - 0x7B19F105B30E952E, 0x13BD8B2025B4EBEE, 0x7B96D27F4EC579A2, 0x00140850CAB7E5DE, - }, - B: FpElement{ - 0x7764909DAE7B7B2D, 0x578ABB16284911AB, 0x76E2BFD146A6BF4D, 0x4824044B23AA02F0, - 0x1105048912A321F3, 0xB8A2E482CF0F10C1, 0x42FF7D0BE2152085, 0x0018E599C5223352, - }, -} - -// The x-coordinate of QB -var P503_affine_QB = Fp2Element{ - A: FpElement{ - 0x4256C520FB388820, 0x744FD7C3BAAF0A13, 0x4B6A2DDDB12CBCB8, 0xE46826E27F427DF8, - 0xFE4A663CD505A61B, 0xD6B3A1BAF025C695, 0x7C3BB62B8FCC00BD, 0x003AFDDE4A35746C, - }, - B: FpElement{ - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - }, -} - -// The x-coordinate of RB = PB - QB -var P503_affine_RB = Fp2Element{ - A: FpElement{ - 0x75601CD1E6C0DFCB, 0x1A9007239B58F93E, 0xC1F1BE80C62107AC, 0x7F513B898F29FF08, - 0xEA0BEDFF43E1F7B2, 0x2C6D94018CBAE6D0, 0x3A430D31BCD84672, 0x000D26892ECCFE83, - }, - B: FpElement{ - 0x1119D62AEA3007A1, 0xE3702AA4E04BAE1B, 0x9AB96F7D59F990E7, 0xF58440E8B43319C0, - 0xAF8134BEE1489775, 0xE7F7774E905192AA, 0xF54AE09308E98039, 0x001EF7A041A86112, - }, -} - -// 2-torsion group computation strategy -var P503_AliceIsogenyStrategy = [strategySizeA]uint32{ - 0x3D, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, - 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, - 0x01, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, - 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, - 0x1D, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, - 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, - 0x0D, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, - 0x05, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01} - -// 3-torsion group computation strategy -var P503_BobIsogenyStrategy = [strategySizeB]uint32{ - 0x47, 0x26, 0x15, 0x0D, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, - 0x02, 0x01, 0x01, 0x05, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, - 0x05, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x01, - 0x02, 0x01, 0x01, 0x11, 0x09, 0x05, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, - 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, - 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x21, 0x11, 0x09, 0x05, 0x03, 0x02, 0x01, 0x01, - 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04, - 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x10, 0x08, - 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, - 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01} - -// Used internally by this package -// ------------------------------- - -var p503 = FpElement{ - 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xABFFFFFFFFFFFFFF, - 0x13085BDA2211E7A0, 0x1B9BF6C87B7E7DAF, 0x6045C6BDDA77A4D0, 0x004066F541811E1E, -} - -// 2*503 -var p503x2 = FpElement{ - 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x57FFFFFFFFFFFFFF, - 0x2610B7B44423CF41, 0x3737ED90F6FCFB5E, 0xC08B8D7BB4EF49A0, 0x0080CDEA83023C3C, -} - -// p503 + 1 -var p503p1 = FpElement{ - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xAC00000000000000, - 0x13085BDA2211E7A0, 0x1B9BF6C87B7E7DAF, 0x6045C6BDDA77A4D0, 0x004066F541811E1E, -} - -// R^2=(2^512)^2 mod p -var p503R2 = FpElement{ - 0x5289A0CF641D011F, 0x9B88257189FED2B9, 0xA3B365D58DC8F17A, 0x5BC57AB6EFF168EC, - 0x9E51998BD84D4423, 0xBF8999CBAC3B5695, 0x46E9127BCE14CDB6, 0x003F6CFCE8B81771, -} - -// p503 + 1 left-shifted by 8, assuming little endianness -var p503p1s8 = FpElement{ - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x085BDA2211E7A0AC, 0x9BF6C87B7E7DAF13, 0x45C6BDDA77A4D01B, 0x4066F541811E1E60, -} - -// 1*R mod p -var P503_OneFp2 = Fp2Element{ - A: FpElement{ - 0x00000000000003F9, 0x0000000000000000, 0x0000000000000000, 0xB400000000000000, - 0x63CB1A6EA6DED2B4, 0x51689D8D667EB37D, 0x8ACD77C71AB24142, 0x0026FBAEC60F5953}, -} - -// 1/2 * R mod p -var P503_HalfFp2 = Fp2Element{ - A: FpElement{ - 0x00000000000001FC, 0x0000000000000000, 0x0000000000000000, 0xB000000000000000, - 0x3B69BB2464785D2A, 0x36824A2AF0FE9896, 0xF5899F427A94F309, 0x0033B15203C83BB8}, -} diff --git a/external/github.com/cloudflare/sidh/p503/field_ops.go b/external/github.com/cloudflare/sidh/p503/field_ops.go deleted file mode 100644 index 45ea570c9..000000000 --- a/external/github.com/cloudflare/sidh/p503/field_ops.go +++ /dev/null @@ -1,249 +0,0 @@ -package p503 - -import ( - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" -) - -type fp503Ops struct{} - -func FieldOperations() FieldOps { - return &fp503Ops{} -} - -func (fp503Ops) Add(dest, lhs, rhs *Fp2Element) { - fp503AddReduced(&dest.A, &lhs.A, &rhs.A) - fp503AddReduced(&dest.B, &lhs.B, &rhs.B) -} - -func (fp503Ops) Sub(dest, lhs, rhs *Fp2Element) { - fp503SubReduced(&dest.A, &lhs.A, &rhs.A) - fp503SubReduced(&dest.B, &lhs.B, &rhs.B) -} - -func (fp503Ops) Mul(dest, lhs, rhs *Fp2Element) { - // Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b). - a := &lhs.A - b := &lhs.B - c := &rhs.A - d := &rhs.B - - // We want to compute - // - // (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i - // - // Use Karatsuba's trick: note that - // - // (b - a)*(c - d) = (b*c + a*d) - a*c - b*d - // - // so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d. - - var ac, bd FpElementX2 - fp503Mul(&ac, a, c) // = a*c*R*R - fp503Mul(&bd, b, d) // = b*d*R*R - - var b_minus_a, c_minus_d FpElement - fp503SubReduced(&b_minus_a, b, a) // = (b-a)*R - fp503SubReduced(&c_minus_d, c, d) // = (c-d)*R - - var ad_plus_bc FpElementX2 - fp503Mul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R - fp503X2AddLazy(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R - fp503X2AddLazy(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R - - fp503MontgomeryReduce(&dest.B, &ad_plus_bc) // = (a*d + b*c)*R mod p - - var ac_minus_bd FpElementX2 - fp503X2SubLazy(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R - fp503MontgomeryReduce(&dest.A, &ac_minus_bd) // = (a*c - b*d)*R mod p -} - -// Set dest = 1/x -// -// Allowed to overlap dest with x. -// -// Returns dest to allow chaining operations. -func (fp503Ops) Inv(dest, x *Fp2Element) { - a := &x.A - b := &x.B - - // We want to compute - // - // 1 1 (a - bi) (a - bi) - // -------- = -------- -------- = ----------- - // (a + bi) (a + bi) (a - bi) (a^2 + b^2) - // - // Letting c = 1/(a^2 + b^2), this is - // - // 1/(a+bi) = a*c - b*ci. - - var asq_plus_bsq primeFieldElement - var asq, bsq FpElementX2 - fp503Mul(&asq, a, a) // = a*a*R*R - fp503Mul(&bsq, b, b) // = b*b*R*R - fp503X2AddLazy(&asq, &asq, &bsq) // = (a^2 + b^2)*R*R - fp503MontgomeryReduce(&asq_plus_bsq.A, &asq) // = (a^2 + b^2)*R mod p - // Now asq_plus_bsq = a^2 + b^2 - - inv := asq_plus_bsq - inv.Mul(&asq_plus_bsq, &asq_plus_bsq) - inv.P34(&inv) - inv.Mul(&inv, &inv) - inv.Mul(&inv, &asq_plus_bsq) - - var ac FpElementX2 - fp503Mul(&ac, a, &inv.A) - fp503MontgomeryReduce(&dest.A, &ac) - - var minus_b FpElement - fp503SubReduced(&minus_b, &minus_b, b) - var minus_bc FpElementX2 - fp503Mul(&minus_bc, &minus_b, &inv.A) - fp503MontgomeryReduce(&dest.B, &minus_bc) -} - -func (fp503Ops) Square(dest, x *Fp2Element) { - a := &x.A - b := &x.B - - // We want to compute - // - // (a + bi)*(a + bi) = (a^2 - b^2) + 2abi. - - var a2, a_plus_b, a_minus_b FpElement - fp503AddReduced(&a2, a, a) // = a*R + a*R = 2*a*R - fp503AddReduced(&a_plus_b, a, b) // = a*R + b*R = (a+b)*R - fp503SubReduced(&a_minus_b, a, b) // = a*R - b*R = (a-b)*R - - var asq_minus_bsq, ab2 FpElementX2 - fp503Mul(&asq_minus_bsq, &a_plus_b, &a_minus_b) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R - fp503Mul(&ab2, &a2, b) // = 2*a*b*R*R - - fp503MontgomeryReduce(&dest.A, &asq_minus_bsq) // = (a^2 - b^2)*R mod p - fp503MontgomeryReduce(&dest.B, &ab2) // = 2*a*b*R mod p -} - -// In case choice == 1, performs following swap in constant time: -// xPx <-> xQx -// xPz <-> xQz -// Otherwise returns xPx, xPz, xQx, xQz unchanged -func (fp503Ops) CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8) { - fp503ConditionalSwap(&xPx.A, &xQx.A, choice) - fp503ConditionalSwap(&xPx.B, &xQx.B, choice) - fp503ConditionalSwap(&xPz.A, &xQz.A, choice) - fp503ConditionalSwap(&xPz.B, &xQz.B, choice) -} - -// Converts values in x.A and x.B to Montgomery domain -// x.A = x.A * R mod p -// x.B = x.B * R mod p -// Performs v = v*R^2*R^(-1) mod p, for both x.A and x.B -func (fp503Ops) ToMontgomery(x *Fp2Element) { - var aRR FpElementX2 - - // convert to montgomery domain - fp503Mul(&aRR, &x.A, &p503R2) // = a*R*R - fp503MontgomeryReduce(&x.A, &aRR) // = a*R mod p - fp503Mul(&aRR, &x.B, &p503R2) - fp503MontgomeryReduce(&x.B, &aRR) -} - -// Converts values in x.A and x.B from Montgomery domain -// a = x.A mod p -// b = x.B mod p -// -// After returning from the call x is not modified. -func (fp503Ops) FromMontgomery(x *Fp2Element, out *Fp2Element) { - var aR FpElementX2 - - // convert from montgomery domain - // TODO: make fpXXXMontgomeryReduce use stack instead of reusing aR - // so that we don't have do this copy here - copy(aR[:], x.A[:]) - fp503MontgomeryReduce(&out.A, &aR) // = a mod p in [0, 2p) - fp503StrongReduce(&out.A) // = a mod p in [0, p) - for i := range aR { - aR[i] = 0 - } - copy(aR[:], x.B[:]) - fp503MontgomeryReduce(&out.B, &aR) - fp503StrongReduce(&out.B) -} - -//------------------------------------------------------------------------------ -// Prime Field -//------------------------------------------------------------------------------ - -// Represents an element of the prime field F_p. -type primeFieldElement struct { - // This field element is in Montgomery form, so that the value `A` is - // represented by `aR mod p`. - A FpElement -} - -// Set dest = lhs * rhs. -// -// Allowed to overlap lhs or rhs with dest. -// -// Returns dest to allow chaining operations. -func (dest *primeFieldElement) Mul(lhs, rhs *primeFieldElement) *primeFieldElement { - a := &lhs.A // = a*R - b := &rhs.A // = b*R - - var ab FpElementX2 - fp503Mul(&ab, a, b) // = a*b*R*R - fp503MontgomeryReduce(&dest.A, &ab) // = a*b*R mod p - - return dest -} - -// Set dest = x^(2^k), for k >= 1, by repeated squarings. -// -// Allowed to overlap x with dest. -// -// Returns dest to allow chaining operations. -func (dest *primeFieldElement) Pow2k(x *primeFieldElement, k uint8) *primeFieldElement { - dest.Mul(x, x) - for i := uint8(1); i < k; i++ { - dest.Mul(dest, dest) - } - - return dest -} - -// Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x). -// Uses variation of sliding-window algorithm from with window size -// of 5 and least to most significant bit sliding (left-to-right) -// See HAC 14.85 for general description. -// -// Allowed to overlap x with dest. -// -// Returns dest to allow chaining operations. -func (dest *primeFieldElement) P34(x *primeFieldElement) *primeFieldElement { - // Sliding-window strategy computed with etc/scripts/sliding_window_start_calc.py - // - // This performs sum(powStrategy) + 1 squarings and len(lookup) + len(mulStrategy) - // multiplications. - powStrategy := []uint8{1, 12, 5, 5, 2, 7, 11, 3, 8, 4, 11, 4, 7, 5, 6, 3, 7, 5, 7, 2, 12, 5, 6, 4, 6, 8, 6, 4, 7, 5, 5, 8, 5, 8, 5, 5, 8, 9, 3, 6, 2, 10, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3} - mulStrategy := []uint8{0, 12, 11, 10, 0, 1, 8, 3, 7, 1, 8, 3, 6, 7, 14, 2, 14, 14, 9, 0, 13, 9, 15, 5, 12, 7, 13, 7, 15, 6, 7, 9, 0, 5, 7, 6, 8, 8, 3, 7, 0, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3} - - // Precompute lookup table of odd multiples of x for window - // size k=5. - lookup := [16]primeFieldElement{} - xx := &primeFieldElement{} - xx.Mul(x, x) - lookup[0] = *x - for i := 1; i < 16; i++ { - lookup[i].Mul(&lookup[i-1], xx) - } - - // Now lookup = {x, x^3, x^5, ... } - // so that lookup[i] = x^{2*i + 1} - // so that lookup[k/2] = x^k, for odd k - *dest = lookup[mulStrategy[0]] - for i := uint8(1); i < uint8(len(powStrategy)); i++ { - dest.Pow2k(dest, powStrategy[i]) - dest.Mul(dest, &lookup[mulStrategy[i]]) - } - - return dest -} diff --git a/external/github.com/cloudflare/sidh/p751/arith_amd64.s b/external/github.com/cloudflare/sidh/p751/arith_amd64.s deleted file mode 100644 index 5213ca387..000000000 --- a/external/github.com/cloudflare/sidh/p751/arith_amd64.s +++ /dev/null @@ -1,2620 +0,0 @@ -// +build amd64,!noasm - -#include "textflag.h" - -// p751 + 1 -#define P751P1_5 $0xEEB0000000000000 -#define P751P1_6 $0xE3EC968549F878A8 -#define P751P1_7 $0xDA959B1A13F7CC76 -#define P751P1_8 $0x084E9867D6EBE876 -#define P751P1_9 $0x8562B5045CB25748 -#define P751P1_10 $0x0E12909F97BADC66 -#define P751P1_11 $0x00006FE5D541F71C - -#define P751_0 $0xFFFFFFFFFFFFFFFF -#define P751_5 $0xEEAFFFFFFFFFFFFF -#define P751_6 $0xE3EC968549F878A8 -#define P751_7 $0xDA959B1A13F7CC76 -#define P751_8 $0x084E9867D6EBE876 -#define P751_9 $0x8562B5045CB25748 -#define P751_10 $0x0E12909F97BADC66 -#define P751_11 $0x00006FE5D541F71C - -#define P751X2_0 $0xFFFFFFFFFFFFFFFE -#define P751X2_1 $0xFFFFFFFFFFFFFFFF -#define P751X2_5 $0xDD5FFFFFFFFFFFFF -#define P751X2_6 $0xC7D92D0A93F0F151 -#define P751X2_7 $0xB52B363427EF98ED -#define P751X2_8 $0x109D30CFADD7D0ED -#define P751X2_9 $0x0AC56A08B964AE90 -#define P751X2_10 $0x1C25213F2F75B8CD -#define P751X2_11 $0x0000DFCBAA83EE38 - -// The MSR code uses these registers for parameter passing. Keep using -// them to avoid significant code changes. This means that when the Go -// assembler does something strange, we can diff the machine code -// against a different assembler to find out what Go did. - -#define REG_P1 DI -#define REG_P2 SI -#define REG_P3 DX - -TEXT ·fp751StrongReduce(SB), NOSPLIT, $0-8 - MOVQ x+0(FP), REG_P1 - - // Zero AX for later use: - XORQ AX, AX - - // Load p into registers: - MOVQ P751_0, R8 - // P751_{1,2,3,4} = P751_0, so reuse R8 - MOVQ P751_5, R9 - MOVQ P751_6, R10 - MOVQ P751_7, R11 - MOVQ P751_8, R12 - MOVQ P751_9, R13 - MOVQ P751_10, R14 - MOVQ P751_11, R15 - - // Set x <- x - p - SUBQ R8, (REG_P1) - SBBQ R8, (8)(REG_P1) - SBBQ R8, (16)(REG_P1) - SBBQ R8, (24)(REG_P1) - SBBQ R8, (32)(REG_P1) - SBBQ R9, (40)(REG_P1) - SBBQ R10, (48)(REG_P1) - SBBQ R11, (56)(REG_P1) - SBBQ R12, (64)(REG_P1) - SBBQ R13, (72)(REG_P1) - SBBQ R14, (80)(REG_P1) - SBBQ R15, (88)(REG_P1) - - // Save carry flag indicating x-p < 0 as a mask in AX - SBBQ $0, AX - - // Conditionally add p to x if x-p < 0 - ANDQ AX, R8 - ANDQ AX, R9 - ANDQ AX, R10 - ANDQ AX, R11 - ANDQ AX, R12 - ANDQ AX, R13 - ANDQ AX, R14 - ANDQ AX, R15 - - ADDQ R8, (REG_P1) - ADCQ R8, (8)(REG_P1) - ADCQ R8, (16)(REG_P1) - ADCQ R8, (24)(REG_P1) - ADCQ R8, (32)(REG_P1) - ADCQ R9, (40)(REG_P1) - ADCQ R10, (48)(REG_P1) - ADCQ R11, (56)(REG_P1) - ADCQ R12, (64)(REG_P1) - ADCQ R13, (72)(REG_P1) - ADCQ R14, (80)(REG_P1) - ADCQ R15, (88)(REG_P1) - - RET - -TEXT ·fp751ConditionalSwap(SB), NOSPLIT, $0-17 - - MOVQ x+0(FP), REG_P1 - MOVQ y+8(FP), REG_P2 - MOVB choice+16(FP), AL // AL = 0 or 1 - MOVBLZX AL, AX // AX = 0 or 1 - NEGQ AX // RAX = 0x00..00 or 0xff..ff - - MOVQ (0*8)(REG_P1), BX // BX = x[0] - MOVQ (0*8)(REG_P2), CX // CX = y[0] - MOVQ CX, DX // DX = y[0] - XORQ BX, DX // DX = y[0] ^ x[0] - ANDQ AX, DX // DX = (y[0] ^ x[0]) & mask - XORQ DX, BX // BX = (y[0] ^ x[0]) & mask) ^ x[0] = x[0] or y[0] - XORQ DX, CX // CX = (y[0] ^ x[0]) & mask) ^ y[0] = y[0] or x[0] - MOVQ BX, (0*8)(REG_P1) - MOVQ CX, (0*8)(REG_P2) - - MOVQ (1*8)(REG_P1), BX - MOVQ (1*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (1*8)(REG_P1) - MOVQ CX, (1*8)(REG_P2) - - MOVQ (2*8)(REG_P1), BX - MOVQ (2*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (2*8)(REG_P1) - MOVQ CX, (2*8)(REG_P2) - - MOVQ (3*8)(REG_P1), BX - MOVQ (3*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (3*8)(REG_P1) - MOVQ CX, (3*8)(REG_P2) - - MOVQ (4*8)(REG_P1), BX - MOVQ (4*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (4*8)(REG_P1) - MOVQ CX, (4*8)(REG_P2) - - MOVQ (5*8)(REG_P1), BX - MOVQ (5*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (5*8)(REG_P1) - MOVQ CX, (5*8)(REG_P2) - - MOVQ (6*8)(REG_P1), BX - MOVQ (6*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (6*8)(REG_P1) - MOVQ CX, (6*8)(REG_P2) - - MOVQ (7*8)(REG_P1), BX - MOVQ (7*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (7*8)(REG_P1) - MOVQ CX, (7*8)(REG_P2) - - MOVQ (8*8)(REG_P1), BX - MOVQ (8*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (8*8)(REG_P1) - MOVQ CX, (8*8)(REG_P2) - - MOVQ (9*8)(REG_P1), BX - MOVQ (9*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (9*8)(REG_P1) - MOVQ CX, (9*8)(REG_P2) - - MOVQ (10*8)(REG_P1), BX - MOVQ (10*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (10*8)(REG_P1) - MOVQ CX, (10*8)(REG_P2) - - MOVQ (11*8)(REG_P1), BX - MOVQ (11*8)(REG_P2), CX - MOVQ CX, DX - XORQ BX, DX - ANDQ AX, DX - XORQ DX, BX - XORQ DX, CX - MOVQ BX, (11*8)(REG_P1) - MOVQ CX, (11*8)(REG_P2) - - RET - -TEXT ·fp751AddReduced(SB), NOSPLIT, $0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - MOVQ (REG_P1), R8 - MOVQ (8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - MOVQ (64)(REG_P1), CX - ADDQ (REG_P2), R8 - ADCQ (8)(REG_P2), R9 - ADCQ (16)(REG_P2), R10 - ADCQ (24)(REG_P2), R11 - ADCQ (32)(REG_P2), R12 - ADCQ (40)(REG_P2), R13 - ADCQ (48)(REG_P2), R14 - ADCQ (56)(REG_P2), R15 - ADCQ (64)(REG_P2), CX - MOVQ (72)(REG_P1), AX - ADCQ (72)(REG_P2), AX - MOVQ AX, (72)(REG_P3) - MOVQ (80)(REG_P1), AX - ADCQ (80)(REG_P2), AX - MOVQ AX, (80)(REG_P3) - MOVQ (88)(REG_P1), AX - ADCQ (88)(REG_P2), AX - MOVQ AX, (88)(REG_P3) - - MOVQ P751X2_0, AX - SUBQ AX, R8 - MOVQ P751X2_1, AX - SBBQ AX, R9 - SBBQ AX, R10 - SBBQ AX, R11 - SBBQ AX, R12 - MOVQ P751X2_5, AX - SBBQ AX, R13 - MOVQ P751X2_6, AX - SBBQ AX, R14 - MOVQ P751X2_7, AX - SBBQ AX, R15 - MOVQ P751X2_8, AX - SBBQ AX, CX - MOVQ R8, (REG_P3) - MOVQ R9, (8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - MOVQ CX, (64)(REG_P3) - MOVQ (72)(REG_P3), R8 - MOVQ (80)(REG_P3), R9 - MOVQ (88)(REG_P3), R10 - MOVQ P751X2_9, AX - SBBQ AX, R8 - MOVQ P751X2_10, AX - SBBQ AX, R9 - MOVQ P751X2_11, AX - SBBQ AX, R10 - MOVQ R8, (72)(REG_P3) - MOVQ R9, (80)(REG_P3) - MOVQ R10, (88)(REG_P3) - MOVQ $0, AX - SBBQ $0, AX - - MOVQ P751X2_0, SI - ANDQ AX, SI - MOVQ P751X2_1, R8 - ANDQ AX, R8 - MOVQ P751X2_5, R9 - ANDQ AX, R9 - MOVQ P751X2_6, R10 - ANDQ AX, R10 - MOVQ P751X2_7, R11 - ANDQ AX, R11 - MOVQ P751X2_8, R12 - ANDQ AX, R12 - MOVQ P751X2_9, R13 - ANDQ AX, R13 - MOVQ P751X2_10, R14 - ANDQ AX, R14 - MOVQ P751X2_11, R15 - ANDQ AX, R15 - - MOVQ (REG_P3), AX - ADDQ SI, AX - MOVQ AX, (REG_P3) - MOVQ (8)(REG_P3), AX - ADCQ R8, AX - MOVQ AX, (8)(REG_P3) - MOVQ (16)(REG_P3), AX - ADCQ R8, AX - MOVQ AX, (16)(REG_P3) - MOVQ (24)(REG_P3), AX - ADCQ R8, AX - MOVQ AX, (24)(REG_P3) - MOVQ (32)(REG_P3), AX - ADCQ R8, AX - MOVQ AX, (32)(REG_P3) - MOVQ (40)(REG_P3), AX - ADCQ R9, AX - MOVQ AX, (40)(REG_P3) - MOVQ (48)(REG_P3), AX - ADCQ R10, AX - MOVQ AX, (48)(REG_P3) - MOVQ (56)(REG_P3), AX - ADCQ R11, AX - MOVQ AX, (56)(REG_P3) - MOVQ (64)(REG_P3), AX - ADCQ R12, AX - MOVQ AX, (64)(REG_P3) - MOVQ (72)(REG_P3), AX - ADCQ R13, AX - MOVQ AX, (72)(REG_P3) - MOVQ (80)(REG_P3), AX - ADCQ R14, AX - MOVQ AX, (80)(REG_P3) - MOVQ (88)(REG_P3), AX - ADCQ R15, AX - MOVQ AX, (88)(REG_P3) - - RET - -TEXT ·fp751SubReduced(SB), NOSPLIT, $0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - MOVQ (REG_P1), R8 - MOVQ (8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - MOVQ (64)(REG_P1), CX - SUBQ (REG_P2), R8 - SBBQ (8)(REG_P2), R9 - SBBQ (16)(REG_P2), R10 - SBBQ (24)(REG_P2), R11 - SBBQ (32)(REG_P2), R12 - SBBQ (40)(REG_P2), R13 - SBBQ (48)(REG_P2), R14 - SBBQ (56)(REG_P2), R15 - SBBQ (64)(REG_P2), CX - MOVQ R8, (REG_P3) - MOVQ R9, (8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - MOVQ CX, (64)(REG_P3) - MOVQ (72)(REG_P1), AX - SBBQ (72)(REG_P2), AX - MOVQ AX, (72)(REG_P3) - MOVQ (80)(REG_P1), AX - SBBQ (80)(REG_P2), AX - MOVQ AX, (80)(REG_P3) - MOVQ (88)(REG_P1), AX - SBBQ (88)(REG_P2), AX - MOVQ AX, (88)(REG_P3) - MOVQ $0, AX - SBBQ $0, AX - - MOVQ P751X2_0, SI - ANDQ AX, SI - MOVQ P751X2_1, R8 - ANDQ AX, R8 - MOVQ P751X2_5, R9 - ANDQ AX, R9 - MOVQ P751X2_6, R10 - ANDQ AX, R10 - MOVQ P751X2_7, R11 - ANDQ AX, R11 - MOVQ P751X2_8, R12 - ANDQ AX, R12 - MOVQ P751X2_9, R13 - ANDQ AX, R13 - MOVQ P751X2_10, R14 - ANDQ AX, R14 - MOVQ P751X2_11, R15 - ANDQ AX, R15 - - MOVQ (REG_P3), AX - ADDQ SI, AX - MOVQ AX, (REG_P3) - MOVQ (8)(REG_P3), AX - ADCQ R8, AX - MOVQ AX, (8)(REG_P3) - MOVQ (16)(REG_P3), AX - ADCQ R8, AX - MOVQ AX, (16)(REG_P3) - MOVQ (24)(REG_P3), AX - ADCQ R8, AX - MOVQ AX, (24)(REG_P3) - MOVQ (32)(REG_P3), AX - ADCQ R8, AX - MOVQ AX, (32)(REG_P3) - MOVQ (40)(REG_P3), AX - ADCQ R9, AX - MOVQ AX, (40)(REG_P3) - MOVQ (48)(REG_P3), AX - ADCQ R10, AX - MOVQ AX, (48)(REG_P3) - MOVQ (56)(REG_P3), AX - ADCQ R11, AX - MOVQ AX, (56)(REG_P3) - MOVQ (64)(REG_P3), AX - ADCQ R12, AX - MOVQ AX, (64)(REG_P3) - MOVQ (72)(REG_P3), AX - ADCQ R13, AX - MOVQ AX, (72)(REG_P3) - MOVQ (80)(REG_P3), AX - ADCQ R14, AX - MOVQ AX, (80)(REG_P3) - MOVQ (88)(REG_P3), AX - ADCQ R15, AX - MOVQ AX, (88)(REG_P3) - - RET - -TEXT ·fp751Mul(SB), $96-24 - - // Here we store the destination in CX instead of in REG_P3 because the - // multiplication instructions use DX as an implicit destination - // operand: MULQ $REG sets DX:AX <-- AX * $REG. - - MOVQ z+0(FP), CX - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - XORQ AX, AX - MOVQ (48)(REG_P1), R8 - MOVQ (56)(REG_P1), R9 - MOVQ (64)(REG_P1), R10 - MOVQ (72)(REG_P1), R11 - MOVQ (80)(REG_P1), R12 - MOVQ (88)(REG_P1), R13 - ADDQ (REG_P1), R8 - ADCQ (8)(REG_P1), R9 - ADCQ (16)(REG_P1), R10 - ADCQ (24)(REG_P1), R11 - ADCQ (32)(REG_P1), R12 - ADCQ (40)(REG_P1), R13 - MOVQ R8, (CX) - MOVQ R9, (8)(CX) - MOVQ R10, (16)(CX) - MOVQ R11, (24)(CX) - MOVQ R12, (32)(CX) - MOVQ R13, (40)(CX) - SBBQ $0, AX - - XORQ DX, DX - MOVQ (48)(REG_P2), R8 - MOVQ (56)(REG_P2), R9 - MOVQ (64)(REG_P2), R10 - MOVQ (72)(REG_P2), R11 - MOVQ (80)(REG_P2), R12 - MOVQ (88)(REG_P2), R13 - ADDQ (REG_P2), R8 - ADCQ (8)(REG_P2), R9 - ADCQ (16)(REG_P2), R10 - ADCQ (24)(REG_P2), R11 - ADCQ (32)(REG_P2), R12 - ADCQ (40)(REG_P2), R13 - MOVQ R8, (48)(CX) - MOVQ R9, (56)(CX) - MOVQ R10, (64)(CX) - MOVQ R11, (72)(CX) - MOVQ R12, (80)(CX) - MOVQ R13, (88)(CX) - SBBQ $0, DX - MOVQ AX, (80)(SP) - MOVQ DX, (88)(SP) - - // (SP[0-8],R10,R8,R9) <- (AH+AL)*(BH+BL) - - MOVQ (CX), R11 - MOVQ R8, AX - MULQ R11 - MOVQ AX, (SP) // c0 - MOVQ DX, R14 - - XORQ R15, R15 - MOVQ R9, AX - MULQ R11 - XORQ R9, R9 - ADDQ AX, R14 - ADCQ DX, R9 - - MOVQ (8)(CX), R12 - MOVQ R8, AX - MULQ R12 - ADDQ AX, R14 - MOVQ R14, (8)(SP) // c1 - ADCQ DX, R9 - ADCQ $0, R15 - - XORQ R8, R8 - MOVQ R10, AX - MULQ R11 - ADDQ AX, R9 - MOVQ (48)(CX), R13 - ADCQ DX, R15 - ADCQ $0, R8 - - MOVQ (16)(CX), AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R15 - MOVQ (56)(CX), AX - ADCQ $0, R8 - - MULQ R12 - ADDQ AX, R9 - MOVQ R9, (16)(SP) // c2 - ADCQ DX, R15 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ (72)(CX), AX - MULQ R11 - ADDQ AX, R15 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (24)(CX), AX - MULQ R13 - ADDQ AX, R15 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ R10, AX - MULQ R12 - ADDQ AX, R15 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (16)(CX), R14 - MOVQ (56)(CX), AX - MULQ R14 - ADDQ AX, R15 - MOVQ R15, (24)(SP) // c3 - ADCQ DX, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ (80)(CX), AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (64)(CX), AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (48)(CX), R15 - MOVQ (32)(CX), AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (72)(CX), AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (24)(CX), R13 - MOVQ (56)(CX), AX - MULQ R13 - ADDQ AX, R8 - MOVQ R8, (32)(SP) // c4 - ADCQ DX, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (88)(CX), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (64)(CX), AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (72)(CX), AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (40)(CX), AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (80)(CX), AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (32)(CX), R15 - MOVQ (56)(CX), AX - MULQ R15 - ADDQ AX, R9 - MOVQ R9, (40)(SP) // c5 - ADCQ DX, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ (64)(CX), AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (88)(CX), AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (80)(CX), AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (40)(CX), R11 - MOVQ (56)(CX), AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (72)(CX), AX - MULQ R13 - ADDQ AX, R10 - MOVQ R10, (48)(SP) // c6 - ADCQ DX, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ (88)(CX), AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (64)(CX), AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (80)(CX), AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (72)(CX), AX - MULQ R15 - ADDQ AX, R8 - MOVQ R8, (56)(SP) // c7 - ADCQ DX, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (72)(CX), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (80)(CX), AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (88)(CX), AX - MULQ R13 - ADDQ AX, R9 - MOVQ R9, (64)(SP) // c8 - ADCQ DX, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ (88)(CX), AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (80)(CX), AX - MULQ R11 - ADDQ AX, R10 // c9 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (88)(CX), AX - MULQ R11 - ADDQ AX, R8 // c10 - ADCQ DX, R9 // c11 - - MOVQ (88)(SP), AX - MOVQ (CX), DX - ANDQ AX, R12 - ANDQ AX, R14 - ANDQ AX, DX - ANDQ AX, R13 - ANDQ AX, R15 - ANDQ AX, R11 - MOVQ (48)(SP), AX - ADDQ AX, DX - MOVQ (56)(SP), AX - ADCQ AX, R12 - MOVQ (64)(SP), AX - ADCQ AX, R14 - ADCQ R10, R13 - ADCQ R8, R15 - ADCQ R9, R11 - MOVQ (80)(SP), AX - MOVQ DX, (48)(SP) - MOVQ R12, (56)(SP) - MOVQ R14, (64)(SP) - MOVQ R13, (72)(SP) - MOVQ R15, (80)(SP) - MOVQ R11, (88)(SP) - - MOVQ (48)(CX), R8 - MOVQ (56)(CX), R9 - MOVQ (64)(CX), R10 - MOVQ (72)(CX), R11 - MOVQ (80)(CX), R12 - MOVQ (88)(CX), R13 - ANDQ AX, R8 - ANDQ AX, R9 - ANDQ AX, R10 - ANDQ AX, R11 - ANDQ AX, R12 - ANDQ AX, R13 - MOVQ (48)(SP), AX - ADDQ AX, R8 - MOVQ (56)(SP), AX - ADCQ AX, R9 - MOVQ (64)(SP), AX - ADCQ AX, R10 - MOVQ (72)(SP), AX - ADCQ AX, R11 - MOVQ (80)(SP), AX - ADCQ AX, R12 - MOVQ (88)(SP), AX - ADCQ AX, R13 - MOVQ R8, (48)(SP) - MOVQ R9, (56)(SP) - MOVQ R11, (72)(SP) - - // CX[0-11] <- AL*BL - MOVQ (REG_P1), R11 - MOVQ (REG_P2), AX - MULQ R11 - XORQ R9, R9 - MOVQ AX, (CX) // c0 - MOVQ R10, (64)(SP) - MOVQ DX, R8 - - MOVQ (8)(REG_P2), AX - MULQ R11 - XORQ R10, R10 - ADDQ AX, R8 - MOVQ R12, (80)(SP) - ADCQ DX, R9 - - MOVQ (8)(REG_P1), R12 - MOVQ (REG_P2), AX - MULQ R12 - ADDQ AX, R8 - MOVQ R8, (8)(CX) // c1 - ADCQ DX, R9 - MOVQ R13, (88)(SP) - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (16)(REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (REG_P2), R13 - MOVQ (16)(REG_P1), AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (8)(REG_P2), AX - MULQ R12 - ADDQ AX, R9 - MOVQ R9, (16)(CX) // c2 - ADCQ DX, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ (24)(REG_P2), AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (24)(REG_P1), AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (16)(REG_P2), AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (16)(REG_P1), R14 - MOVQ (8)(REG_P2), AX - MULQ R14 - ADDQ AX, R10 - MOVQ R10, (24)(CX) // c3 - ADCQ DX, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ (32)(REG_P2), AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (16)(REG_P2), AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (32)(REG_P1), AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (24)(REG_P2), AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (24)(REG_P1), R13 - MOVQ (8)(REG_P2), AX - MULQ R13 - ADDQ AX, R8 - MOVQ R8, (32)(CX) // c4 - ADCQ DX, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (40)(REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (16)(REG_P2), AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (24)(REG_P2), AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (40)(REG_P1), R11 - MOVQ (REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (32)(REG_P2), AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (32)(REG_P1), R15 - MOVQ (8)(REG_P2), AX - MULQ R15 - ADDQ AX, R9 - MOVQ R9, (40)(CX) //c5 - ADCQ DX, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ (16)(REG_P2), AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (40)(REG_P2), AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (32)(REG_P2), AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (8)(REG_P2), AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (24)(REG_P2), AX - MULQ R13 - ADDQ AX, R10 - MOVQ R10, (48)(CX) // c6 - ADCQ DX, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ (40)(REG_P2), AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (16)(REG_P2), AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (32)(REG_P2), AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (24)(REG_P2), AX - MULQ R15 - ADDQ AX, R8 - MOVQ R8, (56)(CX) // c7 - ADCQ DX, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (24)(REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (32)(REG_P2), AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (40)(REG_P2), AX - MULQ R13 - ADDQ AX, R9 - MOVQ R9, (64)(CX) // c8 - ADCQ DX, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ (40)(REG_P2), AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (32)(REG_P2), AX - MULQ R11 - ADDQ AX, R10 - MOVQ R10, (72)(CX) // c9 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (40)(REG_P2), AX - MULQ R11 - ADDQ AX, R8 - MOVQ R8, (80)(CX) // c10 - ADCQ DX, R9 - MOVQ R9, (88)(CX) // c11 - - // CX[12-23] <- AH*BH - MOVQ (48)(REG_P1), R11 - MOVQ (48)(REG_P2), AX - MULQ R11 - XORQ R9, R9 - MOVQ AX, (96)(CX) // c0 - MOVQ DX, R8 - - MOVQ (56)(REG_P2), AX - MULQ R11 - XORQ R10, R10 - ADDQ AX, R8 - ADCQ DX, R9 - - MOVQ (56)(REG_P1), R12 - MOVQ (48)(REG_P2), AX - MULQ R12 - ADDQ AX, R8 - MOVQ R8, (104)(CX) // c1 - ADCQ DX, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (64)(REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (48)(REG_P2), R13 - MOVQ (64)(REG_P1), AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (56)(REG_P2), AX - MULQ R12 - ADDQ AX, R9 - MOVQ R9, (112)(CX) // c2 - ADCQ DX, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ (72)(REG_P2), AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (72)(REG_P1), AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (64)(REG_P2), AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (64)(REG_P1), R14 - MOVQ (56)(REG_P2), AX - MULQ R14 - ADDQ AX, R10 - MOVQ R10, (120)(CX) // c3 - ADCQ DX, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ (80)(REG_P2), AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (64)(REG_P2), AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (80)(REG_P1), R15 - MOVQ R13, AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (72)(REG_P2), AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (72)(REG_P1), R13 - MOVQ (56)(REG_P2), AX - MULQ R13 - ADDQ AX, R8 - MOVQ R8, (128)(CX) // c4 - ADCQ DX, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (88)(REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (64)(REG_P2), AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (72)(REG_P2), AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (88)(REG_P1), R11 - MOVQ (48)(REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (80)(REG_P2), AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (56)(REG_P2), AX - MULQ R15 - ADDQ AX, R9 - MOVQ R9, (136)(CX) // c5 - ADCQ DX, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ (64)(REG_P2), AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (88)(REG_P2), AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (80)(REG_P2), AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (56)(REG_P2), AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (72)(REG_P2), AX - MULQ R13 - ADDQ AX, R10 - MOVQ R10, (144)(CX) // c6 - ADCQ DX, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ (88)(REG_P2), AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (64)(REG_P2), AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (80)(REG_P2), AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (72)(REG_P2), AX - MULQ R15 - ADDQ AX, R8 - MOVQ R8, (152)(CX) // c7 - ADCQ DX, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ (72)(REG_P2), AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (80)(REG_P2), AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (88)(REG_P2), AX - MULQ R13 - ADDQ AX, R9 - MOVQ R9, (160)(CX) // c8 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (88)(REG_P2), AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - - MOVQ (80)(REG_P2), AX - MULQ R11 - ADDQ AX, R10 - MOVQ R10, (168)(CX) // c9 - ADCQ DX, R8 - - MOVQ (88)(REG_P2), AX - MULQ R11 - ADDQ AX, R8 - MOVQ R8, (176)(CX) // c10 - ADCQ $0, DX - MOVQ DX, (184)(CX) // c11 - - // [R8-R15,AX,DX,DI,(SP)] <- (AH+AL)*(BH+BL)-AL*BL - MOVQ (SP), R8 - SUBQ (CX), R8 - MOVQ (8)(SP), R9 - SBBQ (8)(CX), R9 - MOVQ (16)(SP), R10 - SBBQ (16)(CX), R10 - MOVQ (24)(SP), R11 - SBBQ (24)(CX), R11 - MOVQ (32)(SP), R12 - SBBQ (32)(CX), R12 - MOVQ (40)(SP), R13 - SBBQ (40)(CX), R13 - MOVQ (48)(SP), R14 - SBBQ (48)(CX), R14 - MOVQ (56)(SP), R15 - SBBQ (56)(CX), R15 - MOVQ (64)(SP), AX - SBBQ (64)(CX), AX - MOVQ (72)(SP), DX - SBBQ (72)(CX), DX - MOVQ (80)(SP), DI - SBBQ (80)(CX), DI - MOVQ (88)(SP), SI - SBBQ (88)(CX), SI - MOVQ SI, (SP) - - // [R8-R15,AX,DX,DI,(SP)] <- (AH+AL)*(BH+BL) - AL*BL - AH*BH - MOVQ (96)(CX), SI - SUBQ SI, R8 - MOVQ (104)(CX), SI - SBBQ SI, R9 - MOVQ (112)(CX), SI - SBBQ SI, R10 - MOVQ (120)(CX), SI - SBBQ SI, R11 - MOVQ (128)(CX), SI - SBBQ SI, R12 - MOVQ (136)(CX), SI - SBBQ SI, R13 - MOVQ (144)(CX), SI - SBBQ SI, R14 - MOVQ (152)(CX), SI - SBBQ SI, R15 - MOVQ (160)(CX), SI - SBBQ SI, AX - MOVQ (168)(CX), SI - SBBQ SI, DX - MOVQ (176)(CX), SI - SBBQ SI, DI - MOVQ (SP), SI - SBBQ (184)(CX), SI - - // FINAL RESULT - ADDQ (48)(CX), R8 - MOVQ R8, (48)(CX) - ADCQ (56)(CX), R9 - MOVQ R9, (56)(CX) - ADCQ (64)(CX), R10 - MOVQ R10, (64)(CX) - ADCQ (72)(CX), R11 - MOVQ R11, (72)(CX) - ADCQ (80)(CX), R12 - MOVQ R12, (80)(CX) - ADCQ (88)(CX), R13 - MOVQ R13, (88)(CX) - ADCQ (96)(CX), R14 - MOVQ R14, (96)(CX) - ADCQ (104)(CX), R15 - MOVQ R15, (104)(CX) - ADCQ (112)(CX), AX - MOVQ AX, (112)(CX) - ADCQ (120)(CX), DX - MOVQ DX, (120)(CX) - ADCQ (128)(CX), DI - MOVQ DI, (128)(CX) - ADCQ (136)(CX), SI - MOVQ SI, (136)(CX) - MOVQ (144)(CX), AX - ADCQ $0, AX - MOVQ AX, (144)(CX) - MOVQ (152)(CX), AX - ADCQ $0, AX - MOVQ AX, (152)(CX) - MOVQ (160)(CX), AX - ADCQ $0, AX - MOVQ AX, (160)(CX) - MOVQ (168)(CX), AX - ADCQ $0, AX - MOVQ AX, (168)(CX) - MOVQ (176)(CX), AX - ADCQ $0, AX - MOVQ AX, (176)(CX) - MOVQ (184)(CX), AX - ADCQ $0, AX - MOVQ AX, (184)(CX) - - RET - -// This multiplies a 256-bit number pointed to by M0 with p751+1. -// It is assumed that M1 points to p751+1 stored as a 768-bit Fp751Element. -// C points to the place to store the result and should be at least 192 bits. -// This should only be used when the BMI2 and ADX instruction set extensions -// are available. -#define mul256x448bmi2adx(M0, M1, C, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) \ - MOVQ 0+M0, DX \ - MULXQ M1+40(SB), T1, T0 \ - MULXQ M1+48(SB), T3, T2 \ - MOVQ T1, 0+C \ // C0_final - XORQ AX, AX \ - MULXQ M1+56(SB), T5, T4 \ - ADOXQ T3, T0 \ - ADOXQ T5, T2 \ - MULXQ M1+64(SB), T3, T1 \ - ADOXQ T3, T4 \ - MULXQ M1+72(SB), T6, T5 \ - ADOXQ T6, T1 \ - MULXQ M1+80(SB), T7, T3 \ - ADOXQ T7, T5 \ - MULXQ M1+88(SB), T8, T6 \ - ADOXQ T8, T3 \ - ADOXQ AX, T6 \ - \ - MOVQ 8+M0, DX \ - MULXQ M1+40(SB), T7, T8 \ - XORQ AX, AX \ - ADCXQ T7, T0 \ - MOVQ T0, 8+C \ // C1_final - ADCXQ T8, T2 \ - MULXQ M1+48(SB), T8, T7 \ - ADOXQ T8, T2 \ - ADCXQ T7, T4 \ - MULXQ M1+56(SB), T8, T0 \ - ADOXQ T8, T4 \ - ADCXQ T1, T0 \ - MULXQ M1+64(SB), T7, T1 \ - ADCXQ T5, T1 \ - MULXQ M1+72(SB), T8, T5 \ - ADCXQ T5, T3 \ - MULXQ M1+80(SB), T9, T5 \ - ADCXQ T5, T6 \ - MULXQ M1+88(SB), DX, T5 \ - ADCXQ AX, T5 \ - \ - ADOXQ T7, T0 \ - ADOXQ T8, T1 \ - ADOXQ T9, T3 \ - ADOXQ DX, T6 \ - ADOXQ AX, T5 \ - \ - MOVQ 16+M0, DX \ - MULXQ M1+40(SB), T7, T8 \ - XORQ AX, AX \ - ADCXQ T7, T2 \ - MOVQ T2, 16+C \ // C2_final - ADCXQ T8, T4 \ - MULXQ M1+48(SB), T7, T8 \ - ADOXQ T7, T4 \ - ADCXQ T8, T0 \ - MULXQ M1+56(SB), T8, T2 \ - ADOXQ T8, T0 \ - ADCXQ T2, T1 \ - MULXQ M1+64(SB), T7, T2 \ - ADCXQ T2, T3 \ - MULXQ M1+72(SB), T8, T2 \ - ADCXQ T2, T6 \ - MULXQ M1+80(SB), T9, T2 \ - ADCXQ T2, T5 \ - MULXQ M1+88(SB), DX, T2 \ - ADCXQ AX, T2 \ - \ - ADOXQ T7, T1 \ - ADOXQ T8, T3 \ - ADOXQ T9, T6 \ - ADOXQ DX, T5 \ - ADOXQ AX, T2 \ - \ - MOVQ 24+M0, DX \ - MULXQ M1+40(SB), T7, T8 \ - XORQ AX, AX \ - ADCXQ T4, T7 \ - ADCXQ T8, T0 \ - MULXQ M1+48(SB), T10, T8 \ - ADOXQ T10, T0 \ - ADCXQ T8, T1 \ - MULXQ M1+56(SB), T8, T4 \ - ADOXQ T8, T1 \ - ADCXQ T4, T3 \ - MULXQ M1+64(SB), T10, T4 \ - ADCXQ T4, T6 \ - MULXQ M1+72(SB), T8, T4 \ - ADCXQ T4, T5 \ - MULXQ M1+80(SB), T9, T4 \ - ADCXQ T4, T2 \ - MULXQ M1+88(SB), DX, T4 \ - ADCXQ AX, T4 \ - \ - ADOXQ T10, T3 \ - ADOXQ T8, T6 \ - ADOXQ T9, T5 \ - ADOXQ DX, T2 \ - ADOXQ AX, T4 - -// This multiplies a 256-bit number pointed to by M0 with p751+1. -// It is assumed that M1 points to p751+1 stored as a 768-bit Fp751Element. -// C points to the place to store the result and should be at least 192 bits. -// This should only be used when the BMI2 instruction set extension is -// available. -#define mul256x448bmi2(M0, M1, C, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) \ - MOVQ 0+M0, DX \ - MULXQ M1+40(SB), T1, T0 \ - MULXQ M1+48(SB), T3, T2 \ - MOVQ T1, 0+C \ // C0_final - XORQ AX, AX \ - MULXQ M1+56(SB), T5, T4 \ - ADDQ T3, T0 \ - ADCQ T5, T2 \ - MULXQ M1+64(SB), T3, T1 \ - ADCQ T3, T4 \ - MULXQ M1+72(SB), T6, T5 \ - ADCQ T6, T1 \ - MULXQ M1+80(SB), T7, T3 \ - ADCQ T7, T5 \ - MULXQ M1+88(SB), T8, T6 \ - ADCQ T8, T3 \ - ADCQ AX, T6 \ - \ - MOVQ 8+M0, DX \ - MULXQ M1+40(SB), T7, T8 \ - ADDQ T7, T0 \ - MOVQ T0, 8+C \ // C1_final - ADCQ T8, T2 \ - MULXQ M1+48(SB), T8, T7 \ - MOVQ T8, 32+C \ - ADCQ T7, T4 \ - MULXQ M1+56(SB), T8, T0 \ - MOVQ T8, 40+C \ - ADCQ T1, T0 \ - MULXQ M1+64(SB), T7, T1 \ - ADCQ T5, T1 \ - MULXQ M1+72(SB), T8, T5 \ - ADCQ T5, T3 \ - MULXQ M1+80(SB), T9, T5 \ - ADCQ T5, T6 \ - MULXQ M1+88(SB), DX, T5 \ - ADCQ AX, T5 \ - \ - XORQ AX, AX \ - ADDQ 32+C, T2 \ - ADCQ 40+C, T4 \ - ADCQ T7, T0 \ - ADCQ T8, T1 \ - ADCQ T9, T3 \ - ADCQ DX, T6 \ - ADCQ AX, T5 \ - \ - MOVQ 16+M0, DX \ - MULXQ M1+40(SB), T7, T8 \ - ADDQ T7, T2 \ - MOVQ T2, 16+C \ // C2_final - ADCQ T8, T4 \ - MULXQ M1+48(SB), T7, T8 \ - MOVQ T7, 32+C \ - ADCQ T8, T0 \ - MULXQ M1+56(SB), T8, T2 \ - MOVQ T8, 40+C \ - ADCQ T2, T1 \ - MULXQ M1+64(SB), T7, T2 \ - ADCQ T2, T3 \ - MULXQ M1+72(SB), T8, T2 \ - ADCQ T2, T6 \ - MULXQ M1+80(SB), T9, T2 \ - ADCQ T2, T5 \ - MULXQ M1+88(SB), DX, T2 \ - ADCQ AX, T2 \ - \ - XORQ AX, AX \ - ADDQ 32+C, T4 \ - ADCQ 40+C, T0 \ - ADCQ T7, T1 \ - ADCQ T8, T3 \ - ADCQ T9, T6 \ - ADCQ DX, T5 \ - ADCQ AX, T2 \ - \ - MOVQ 24+M0, DX \ - MULXQ M1+40(SB), T7, T8 \ - ADDQ T4, T7 \ - ADCQ T8, T0 \ - MULXQ M1+48(SB), T10, T8 \ - MOVQ T10, 32+C \ - ADCQ T8, T1 \ - MULXQ M1+56(SB), T8, T4 \ - MOVQ T8, 40+C \ - ADCQ T4, T3 \ - MULXQ M1+64(SB), T10, T4 \ - ADCQ T4, T6 \ - MULXQ M1+72(SB), T8, T4 \ - ADCQ T4, T5 \ - MULXQ M1+80(SB), T9, T4 \ - ADCQ T4, T2 \ - MULXQ M1+88(SB), DX, T4 \ - ADCQ AX, T4 \ - \ - XORQ AX, AX \ - ADDQ 32+C, T0 \ - ADCQ 40+C, T1 \ - ADCQ T10, T3 \ - ADCQ T8, T6 \ - ADCQ T9, T5 \ - ADCQ DX, T2 \ - ADCQ AX, T4 - -// Template for calculating the Montgomery reduction algorithm described in -// section 5.2.3 of https://eprint.iacr.org/2017/1015.pdf. Template must be -// customized with schoolbook multiplicaton for 256 x 448-bit number. -// This macro reuses memory of IN value and *changes* it. Smashes registers -// R[8-15], AX, BX, CX, DX, BP. -// Input: -// * M0: 1536-bit number to be reduced -// * C : either mul256x448bmi2 or mul256x448bmi2adx -// Output: OUT 768-bit -#define REDC(C, M0, MULS) \ - \ // a[0-3] x p751p1_nz --> result: [reg_p2+48], [reg_p2+56], [reg_p2+64], and rbp, r8:r14 - MULS(M0, ·p751p1, 48+C, R8, R9, R13, R10, R14, R12, R11, BP, BX, CX, R15) \ - XORQ R15, R15 \ - MOVQ 48+C, AX \ - MOVQ 56+C, DX \ - MOVQ 64+C, BX \ - ADDQ 40+M0, AX \ - ADCQ 48+M0, DX \ - ADCQ 56+M0, BX \ - MOVQ AX, 40+M0 \ - MOVQ DX, 48+M0 \ - MOVQ BX, 56+M0 \ - ADCQ 64+M0, BP \ - ADCQ 72+M0, R8 \ - ADCQ 80+M0, R9 \ - ADCQ 88+M0, R10 \ - ADCQ 96+M0, R11 \ - ADCQ 104+M0, R12 \ - ADCQ 112+M0, R13 \ - ADCQ 120+M0, R14 \ - ADCQ 128+M0, R15 \ - MOVQ BP, 64+M0 \ - MOVQ R8, 72+M0 \ - MOVQ R9, 80+M0 \ - MOVQ R10, 88+M0 \ - MOVQ R11, 96+M0 \ - MOVQ R12, 104+M0 \ - MOVQ R13, 112+M0 \ - MOVQ R14, 120+M0 \ - MOVQ R15, 128+M0 \ - MOVQ 136+M0, R8 \ - MOVQ 144+M0, R9 \ - MOVQ 152+M0, R10 \ - MOVQ 160+M0, R11 \ - MOVQ 168+M0, R12 \ - MOVQ 176+M0, R13 \ - MOVQ 184+M0, R14 \ - ADCQ $0, R8 \ - ADCQ $0, R9 \ - ADCQ $0, R10 \ - ADCQ $0, R11 \ - ADCQ $0, R12 \ - ADCQ $0, R13 \ - ADCQ $0, R14 \ - MOVQ R8, 136+M0 \ - MOVQ R9, 144+M0 \ - MOVQ R10, 152+M0 \ - MOVQ R11, 160+M0 \ - MOVQ R12, 168+M0 \ - MOVQ R13, 176+M0 \ - MOVQ R14, 184+M0 \ - \ // a[4-7] x p751p1_nz --> result: [reg_p2+48], [reg_p2+56], [reg_p2+64], and rbp, r8:r14 - MULS(32+M0, ·p751p1, 48+C, R8, R9, R13, R10, R14, R12, R11, BP, BX, CX, R15) \ - XORQ R15, R15 \ - MOVQ 48+C, AX \ - MOVQ 56+C, DX \ - MOVQ 64+C, BX \ - ADDQ 72+M0, AX \ - ADCQ 80+M0, DX \ - ADCQ 88+M0, BX \ - MOVQ AX, 72+M0 \ - MOVQ DX, 80+M0 \ - MOVQ BX, 88+M0 \ - ADCQ 96+M0, BP \ - ADCQ 104+M0, R8 \ - ADCQ 112+M0, R9 \ - ADCQ 120+M0, R10 \ - ADCQ 128+M0, R11 \ - ADCQ 136+M0, R12 \ - ADCQ 144+M0, R13 \ - ADCQ 152+M0, R14 \ - ADCQ 160+M0, R15 \ - MOVQ BP, 0+C \ // Final result c0 - MOVQ R8, 104+M0 \ - MOVQ R9, 112+M0 \ - MOVQ R10, 120+M0 \ - MOVQ R11, 128+M0 \ - MOVQ R12, 136+M0 \ - MOVQ R13, 144+M0 \ - MOVQ R14, 152+M0 \ - MOVQ R15, 160+M0 \ - MOVQ 168+M0, R12 \ - MOVQ 176+M0, R13 \ - MOVQ 184+M0, R14 \ - ADCQ $0, R12 \ - ADCQ $0, R13 \ - ADCQ $0, R14 \ - MOVQ R12, 168+M0 \ - MOVQ R13, 176+M0 \ - MOVQ R14, 184+M0 \ - \ // a[8-11] x p751p1_nz --> result: [reg_p2+48], [reg_p2+56], [reg_p2+64], and rbp, r8:r14 - MULS(64+M0, ·p751p1, 48+C, R8, R9, R13, R10, R14, R12, R11, BP, BX, CX, R15) \ - MOVQ 48+C, AX \ // Final result c1:c11 - MOVQ 56+C, DX \ - MOVQ 64+C, BX \ - ADDQ 104+M0, AX \ - ADCQ 112+M0, DX \ - ADCQ 120+M0, BX \ - MOVQ AX, 8+C \ - MOVQ DX, 16+C \ - MOVQ BX, 24+C \ - ADCQ 128+M0, BP \ - ADCQ 136+M0, R8 \ - ADCQ 144+M0, R9 \ - ADCQ 152+M0, R10 \ - ADCQ 160+M0, R11 \ - ADCQ 168+M0, R12 \ - ADCQ 176+M0, R13 \ - ADCQ 184+M0, R14 \ - MOVQ BP, 32+C \ - MOVQ R8, 40+C \ - MOVQ R9, 48+C \ - MOVQ R10, 56+C \ - MOVQ R11, 64+C \ - MOVQ R12, 72+C \ - MOVQ R13, 80+C \ - MOVQ R14, 88+C - -TEXT ·fp751MontgomeryReduce(SB), $0-16 - MOVQ z+0(FP), REG_P2 - MOVQ x+8(FP), REG_P1 - - // Check wether to use optimized implementation - CMPB ·HasADXandBMI2(SB), $1 - JE redc_with_mulx_adcx_adox - CMPB ·HasBMI2(SB), $1 - JE redc_with_mulx - - MOVQ (REG_P1), R11 - MOVQ P751P1_5, AX - MULQ R11 - XORQ R8, R8 - ADDQ (40)(REG_P1), AX - MOVQ AX, (40)(REG_P2) // Z5 - ADCQ DX, R8 - - XORQ R9, R9 - MOVQ P751P1_6, AX - MULQ R11 - XORQ R10, R10 - ADDQ AX, R8 - ADCQ DX, R9 - - MOVQ (8)(REG_P1), R12 - MOVQ P751P1_5, AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (48)(REG_P1), R8 - MOVQ R8, (48)(REG_P2) // Z6 - ADCQ $0, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ P751P1_7, AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_6, AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (16)(REG_P1), R13 - MOVQ P751P1_5, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - ADDQ (56)(REG_P1), R9 - MOVQ R9, (56)(REG_P2) // Z7 - ADCQ $0, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ P751P1_8, AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_7, AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_6, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (24)(REG_P1), R14 - MOVQ P751P1_5, AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - ADDQ (64)(REG_P1), R10 - MOVQ R10, (64)(REG_P2) // Z8 - ADCQ $0, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ P751P1_9, AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_8, AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_7, AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_6, AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (32)(REG_P1), R15 - MOVQ P751P1_5, AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (72)(REG_P1), R8 - MOVQ R8, (72)(REG_P2) // Z9 - ADCQ $0, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ P751P1_10, AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_9, AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_8, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_7, AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_6, AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (40)(REG_P2), CX - MOVQ P751P1_5, AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - ADDQ (80)(REG_P1), R9 - MOVQ R9, (80)(REG_P2) // Z10 - ADCQ $0, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ P751P1_11, AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_10, AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_9, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_8, AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_7, AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_6, AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (48)(REG_P2), R11 - MOVQ P751P1_5, AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - ADDQ (88)(REG_P1), R10 - MOVQ R10, (88)(REG_P2) // Z11 - ADCQ $0, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ P751P1_11, AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_10, AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_9, AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_8, AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_7, AX - MULQ CX - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_6, AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (56)(REG_P2), R12 - MOVQ P751P1_5, AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (96)(REG_P1), R8 - MOVQ R8, (REG_P2) // Z0 - ADCQ $0, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ P751P1_11, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_10, AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_9, AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_8, AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_7, AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_6, AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (64)(REG_P2), R13 - MOVQ P751P1_5, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - ADDQ (104)(REG_P1), R9 - MOVQ R9, (8)(REG_P2) // Z1 - ADCQ $0, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ P751P1_11, AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_10, AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_9, AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_8, AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_7, AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_6, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ (72)(REG_P2), R14 - MOVQ P751P1_5, AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - ADDQ (112)(REG_P1), R10 - MOVQ R10, (16)(REG_P2) // Z2 - ADCQ $0, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ P751P1_11, AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_10, AX - MULQ CX - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_9, AX - MULQ R11 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_8, AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_7, AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_6, AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ (80)(REG_P2), R15 - MOVQ P751P1_5, AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (120)(REG_P1), R8 - MOVQ R8, (24)(REG_P2) // Z3 - ADCQ $0, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ P751P1_11, AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_10, AX - MULQ R11 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_9, AX - MULQ R12 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_8, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_7, AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_6, AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ (88)(REG_P2), CX - MOVQ P751P1_5, AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - ADDQ (128)(REG_P1), R9 - MOVQ R9, (32)(REG_P2) // Z4 - ADCQ $0, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ P751P1_11, AX - MULQ R11 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_10, AX - MULQ R12 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_9, AX - MULQ R13 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_8, AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_7, AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_6, AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - ADDQ (136)(REG_P1), R10 - MOVQ R10, (40)(REG_P2) // Z5 - ADCQ $0, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ P751P1_11, AX - MULQ R12 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_10, AX - MULQ R13 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_9, AX - MULQ R14 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_8, AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_7, AX - MULQ CX - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (144)(REG_P1), R8 - MOVQ R8, (48)(REG_P2) // Z6 - ADCQ $0, R9 - ADCQ $0, R10 - - XORQ R8, R8 - MOVQ P751P1_11, AX - MULQ R13 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_10, AX - MULQ R14 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_9, AX - MULQ R15 - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - - MOVQ P751P1_8, AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADCQ $0, R8 - ADDQ (152)(REG_P1), R9 - MOVQ R9, (56)(REG_P2) // Z7 - ADCQ $0, R10 - ADCQ $0, R8 - - XORQ R9, R9 - MOVQ P751P1_11, AX - MULQ R14 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_10, AX - MULQ R15 - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - - MOVQ P751P1_9, AX - MULQ CX - ADDQ AX, R10 - ADCQ DX, R8 - ADCQ $0, R9 - ADDQ (160)(REG_P1), R10 - MOVQ R10, (64)(REG_P2) // Z8 - ADCQ $0, R8 - ADCQ $0, R9 - - XORQ R10, R10 - MOVQ P751P1_11, AX - MULQ R15 - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - - MOVQ P751P1_10, AX - MULQ CX - ADDQ AX, R8 - ADCQ DX, R9 - ADCQ $0, R10 - ADDQ (168)(REG_P1), R8 // Z9 - MOVQ R8, (72)(REG_P2) // Z9 - ADCQ $0, R9 - ADCQ $0, R10 - - MOVQ P751P1_11, AX - MULQ CX - ADDQ AX, R9 - ADCQ DX, R10 - ADDQ (176)(REG_P1), R9 // Z10 - MOVQ R9, (80)(REG_P2) // Z10 - ADCQ $0, R10 - ADDQ (184)(REG_P1), R10 // Z11 - MOVQ R10, (88)(REG_P2) // Z11 - RET - -redc_with_mulx_adcx_adox: - // This implements the Montgomery reduction algorithm described in - // section 5.2.3 of https://eprint.iacr.org/2017/1015.pdf. - // This assumes that the BMI2 and ADX instruction set extensions are available. - REDC(0(REG_P2), 0(REG_P1), mul256x448bmi2adx) - RET - -redc_with_mulx: - // This implements the Montgomery reduction algorithm described in - // section 5.2.3 of https://eprint.iacr.org/2017/1015.pdf. - // This assumes that the BMI2 instruction set extension is available. - REDC(0(REG_P2), 0(REG_P1), mul256x448bmi2) - RET - -TEXT ·fp751AddLazy(SB), NOSPLIT, $0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - MOVQ (REG_P1), R8 - MOVQ (8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - MOVQ (64)(REG_P1), AX - MOVQ (72)(REG_P1), BX - MOVQ (80)(REG_P1), CX - MOVQ (88)(REG_P1), DI - - ADDQ (REG_P2), R8 - ADCQ (8)(REG_P2), R9 - ADCQ (16)(REG_P2), R10 - ADCQ (24)(REG_P2), R11 - ADCQ (32)(REG_P2), R12 - ADCQ (40)(REG_P2), R13 - ADCQ (48)(REG_P2), R14 - ADCQ (56)(REG_P2), R15 - ADCQ (64)(REG_P2), AX - ADCQ (72)(REG_P2), BX - ADCQ (80)(REG_P2), CX - ADCQ (88)(REG_P2), DI - - MOVQ R8, (REG_P3) - MOVQ R9, (8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - MOVQ AX, (64)(REG_P3) - MOVQ BX, (72)(REG_P3) - MOVQ CX, (80)(REG_P3) - MOVQ DI, (88)(REG_P3) - - RET - -TEXT ·fp751X2AddLazy(SB), NOSPLIT, $0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - MOVQ (REG_P1), R8 - MOVQ (8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - MOVQ (64)(REG_P1), AX - MOVQ (72)(REG_P1), BX - MOVQ (80)(REG_P1), CX - - ADDQ (REG_P2), R8 - ADCQ (8)(REG_P2), R9 - ADCQ (16)(REG_P2), R10 - ADCQ (24)(REG_P2), R11 - ADCQ (32)(REG_P2), R12 - ADCQ (40)(REG_P2), R13 - ADCQ (48)(REG_P2), R14 - ADCQ (56)(REG_P2), R15 - ADCQ (64)(REG_P2), AX - ADCQ (72)(REG_P2), BX - ADCQ (80)(REG_P2), CX - - MOVQ R8, (REG_P3) - MOVQ R9, (8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - MOVQ AX, (64)(REG_P3) - MOVQ BX, (72)(REG_P3) - MOVQ CX, (80)(REG_P3) - MOVQ (88)(REG_P1), AX - ADCQ (88)(REG_P2), AX - MOVQ AX, (88)(REG_P3) - - MOVQ (96)(REG_P1), R8 - MOVQ (104)(REG_P1), R9 - MOVQ (112)(REG_P1), R10 - MOVQ (120)(REG_P1), R11 - MOVQ (128)(REG_P1), R12 - MOVQ (136)(REG_P1), R13 - MOVQ (144)(REG_P1), R14 - MOVQ (152)(REG_P1), R15 - MOVQ (160)(REG_P1), AX - MOVQ (168)(REG_P1), BX - MOVQ (176)(REG_P1), CX - MOVQ (184)(REG_P1), DI - - ADCQ (96)(REG_P2), R8 - ADCQ (104)(REG_P2), R9 - ADCQ (112)(REG_P2), R10 - ADCQ (120)(REG_P2), R11 - ADCQ (128)(REG_P2), R12 - ADCQ (136)(REG_P2), R13 - ADCQ (144)(REG_P2), R14 - ADCQ (152)(REG_P2), R15 - ADCQ (160)(REG_P2), AX - ADCQ (168)(REG_P2), BX - ADCQ (176)(REG_P2), CX - ADCQ (184)(REG_P2), DI - - MOVQ R8, (96)(REG_P3) - MOVQ R9, (104)(REG_P3) - MOVQ R10, (112)(REG_P3) - MOVQ R11, (120)(REG_P3) - MOVQ R12, (128)(REG_P3) - MOVQ R13, (136)(REG_P3) - MOVQ R14, (144)(REG_P3) - MOVQ R15, (152)(REG_P3) - MOVQ AX, (160)(REG_P3) - MOVQ BX, (168)(REG_P3) - MOVQ CX, (176)(REG_P3) - MOVQ DI, (184)(REG_P3) - - RET - - -TEXT ·fp751X2SubLazy(SB), NOSPLIT, $0-24 - - MOVQ z+0(FP), REG_P3 - MOVQ x+8(FP), REG_P1 - MOVQ y+16(FP), REG_P2 - - MOVQ (REG_P1), R8 - MOVQ (8)(REG_P1), R9 - MOVQ (16)(REG_P1), R10 - MOVQ (24)(REG_P1), R11 - MOVQ (32)(REG_P1), R12 - MOVQ (40)(REG_P1), R13 - MOVQ (48)(REG_P1), R14 - MOVQ (56)(REG_P1), R15 - MOVQ (64)(REG_P1), AX - MOVQ (72)(REG_P1), BX - MOVQ (80)(REG_P1), CX - - SUBQ (REG_P2), R8 - SBBQ (8)(REG_P2), R9 - SBBQ (16)(REG_P2), R10 - SBBQ (24)(REG_P2), R11 - SBBQ (32)(REG_P2), R12 - SBBQ (40)(REG_P2), R13 - SBBQ (48)(REG_P2), R14 - SBBQ (56)(REG_P2), R15 - SBBQ (64)(REG_P2), AX - SBBQ (72)(REG_P2), BX - SBBQ (80)(REG_P2), CX - - MOVQ R8, (REG_P3) - MOVQ R9, (8)(REG_P3) - MOVQ R10, (16)(REG_P3) - MOVQ R11, (24)(REG_P3) - MOVQ R12, (32)(REG_P3) - MOVQ R13, (40)(REG_P3) - MOVQ R14, (48)(REG_P3) - MOVQ R15, (56)(REG_P3) - MOVQ AX, (64)(REG_P3) - MOVQ BX, (72)(REG_P3) - MOVQ CX, (80)(REG_P3) - MOVQ (88)(REG_P1), AX - SBBQ (88)(REG_P2), AX - MOVQ AX, (88)(REG_P3) - - MOVQ (96)(REG_P1), R8 - MOVQ (104)(REG_P1), R9 - MOVQ (112)(REG_P1), R10 - MOVQ (120)(REG_P1), R11 - MOVQ (128)(REG_P1), R12 - MOVQ (136)(REG_P1), R13 - MOVQ (144)(REG_P1), R14 - MOVQ (152)(REG_P1), R15 - MOVQ (160)(REG_P1), AX - MOVQ (168)(REG_P1), BX - MOVQ (176)(REG_P1), CX - MOVQ (184)(REG_P1), DI - - SBBQ (96)(REG_P2), R8 - SBBQ (104)(REG_P2), R9 - SBBQ (112)(REG_P2), R10 - SBBQ (120)(REG_P2), R11 - SBBQ (128)(REG_P2), R12 - SBBQ (136)(REG_P2), R13 - SBBQ (144)(REG_P2), R14 - SBBQ (152)(REG_P2), R15 - SBBQ (160)(REG_P2), AX - SBBQ (168)(REG_P2), BX - SBBQ (176)(REG_P2), CX - SBBQ (184)(REG_P2), DI - - MOVQ R8, (96)(REG_P3) - MOVQ R9, (104)(REG_P3) - MOVQ R10, (112)(REG_P3) - MOVQ R11, (120)(REG_P3) - MOVQ R12, (128)(REG_P3) - MOVQ R13, (136)(REG_P3) - MOVQ R14, (144)(REG_P3) - MOVQ R15, (152)(REG_P3) - MOVQ AX, (160)(REG_P3) - MOVQ BX, (168)(REG_P3) - MOVQ CX, (176)(REG_P3) - MOVQ DI, (184)(REG_P3) - - // Now the carry flag is 1 if x-y < 0. If so, add p*2^768. - MOVQ $0, AX - SBBQ $0, AX - - // Load p into registers: - MOVQ P751_0, R8 - // P751_{1,2,3,4} = P751_0, so reuse R8 - MOVQ P751_5, R9 - MOVQ P751_6, R10 - MOVQ P751_7, R11 - MOVQ P751_8, R12 - MOVQ P751_9, R13 - MOVQ P751_10, R14 - MOVQ P751_11, R15 - - ANDQ AX, R8 - ANDQ AX, R9 - ANDQ AX, R10 - ANDQ AX, R11 - ANDQ AX, R12 - ANDQ AX, R13 - ANDQ AX, R14 - ANDQ AX, R15 - - ADDQ R8, (96 )(REG_P3) - ADCQ R8, (96+ 8)(REG_P3) - ADCQ R8, (96+16)(REG_P3) - ADCQ R8, (96+24)(REG_P3) - ADCQ R8, (96+32)(REG_P3) - ADCQ R9, (96+40)(REG_P3) - ADCQ R10, (96+48)(REG_P3) - ADCQ R11, (96+56)(REG_P3) - ADCQ R12, (96+64)(REG_P3) - ADCQ R13, (96+72)(REG_P3) - ADCQ R14, (96+80)(REG_P3) - ADCQ R15, (96+88)(REG_P3) - - RET - diff --git a/external/github.com/cloudflare/sidh/p751/arith_arm64.s b/external/github.com/cloudflare/sidh/p751/arith_arm64.s deleted file mode 100644 index 730936e1e..000000000 --- a/external/github.com/cloudflare/sidh/p751/arith_arm64.s +++ /dev/null @@ -1,1520 +0,0 @@ -// +build arm64,!noasm - -#include "textflag.h" - -TEXT ·fp751ConditionalSwap(SB), NOSPLIT, $0-17 - MOVD x+0(FP), R0 - MOVD y+8(FP), R1 - MOVB choice+16(FP), R2 - - // Set flags - // If choice is not 0 or 1, this implementation will swap completely - CMP $0, R2 - - LDP 0(R0), (R3, R4) - LDP 0(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 0(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 0(R1) - - LDP 16(R0), (R3, R4) - LDP 16(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 16(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 16(R1) - - LDP 32(R0), (R3, R4) - LDP 32(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 32(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 32(R1) - - LDP 48(R0), (R3, R4) - LDP 48(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 48(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 48(R1) - - LDP 64(R0), (R3, R4) - LDP 64(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 64(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 64(R1) - - LDP 80(R0), (R3, R4) - LDP 80(R1), (R5, R6) - CSEL EQ, R3, R5, R7 - CSEL EQ, R4, R6, R8 - STP (R7, R8), 80(R0) - CSEL NE, R3, R5, R9 - CSEL NE, R4, R6, R10 - STP (R9, R10), 80(R1) - - RET - -TEXT ·fp751AddReduced(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - // Load first summand into R3-R14 - // Add first summand and second summand and store result in R3-R14 - LDP 0(R0), (R3, R4) - LDP 0(R1), (R15, R16) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R17, R19) - ADDS R15, R3 - ADCS R16, R4 - ADCS R17, R5 - ADCS R19, R6 - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R15, R16) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R17, R19) - ADCS R15, R7 - ADCS R16, R8 - ADCS R17, R9 - ADCS R19, R10 - - LDP 64(R0), (R11, R12) - LDP 64(R1), (R15, R16) - LDP 80(R0), (R13, R14) - LDP 80(R1), (R17, R19) - ADCS R15, R11 - ADCS R16, R12 - ADCS R17, R13 - ADC R19, R14 - - // Subtract 2 * p751 in R15-R24 from the result in R3-R14 - LDP ·p751x2+0(SB), (R15, R16) - SUBS R15, R3 - SBCS R16, R4 - LDP ·p751x2+40(SB), (R17, R19) - SBCS R16, R5 - SBCS R16, R6 - SBCS R16, R7 - LDP ·p751x2+56(SB), (R20, R21) - SBCS R17, R8 - SBCS R19, R9 - LDP ·p751x2+72(SB), (R22, R23) - SBCS R20, R10 - SBCS R21, R11 - MOVD ·p751x2+88(SB), R24 - SBCS R22, R12 - SBCS R23, R13 - SBCS R24, R14 - SBC ZR, ZR, R25 - - // If x + y - 2 * p751 < 0, R25 is 1 and 2 * p751 should be added - AND R25, R15 - AND R25, R16 - AND R25, R17 - AND R25, R19 - AND R25, R20 - AND R25, R21 - AND R25, R22 - AND R25, R23 - AND R25, R24 - - ADDS R15, R3 - ADCS R16, R4 - STP (R3, R4), 0(R2) - ADCS R16, R5 - ADCS R16, R6 - STP (R5, R6), 16(R2) - ADCS R16, R7 - ADCS R17, R8 - STP (R7, R8), 32(R2) - ADCS R19, R9 - ADCS R20, R10 - STP (R9, R10), 48(R2) - ADCS R21, R11 - ADCS R22, R12 - STP (R11, R12), 64(R2) - ADCS R23, R13 - ADC R24, R14 - STP (R13, R14), 80(R2) - - RET - -TEXT ·fp751SubReduced(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - // Load x into R3-R14 - // Subtract y from x and store result in R3-R14 - LDP 0(R0), (R3, R4) - LDP 0(R1), (R15, R16) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R17, R19) - SUBS R15, R3 - SBCS R16, R4 - SBCS R17, R5 - SBCS R19, R6 - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R15, R16) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R17, R19) - SBCS R15, R7 - SBCS R16, R8 - SBCS R17, R9 - SBCS R19, R10 - - LDP 64(R0), (R11, R12) - LDP 64(R1), (R15, R16) - LDP 80(R0), (R13, R14) - LDP 80(R1), (R17, R19) - SBCS R15, R11 - SBCS R16, R12 - SBCS R17, R13 - SBCS R19, R14 - SBC ZR, ZR, R15 - - // If x - y < 0, R15 is 1 and 2 * p751 should be added - LDP ·p751x2+0(SB), (R16, R17) - AND R15, R16 - AND R15, R17 - LDP ·p751x2+40(SB), (R19, R20) - AND R15, R19 - AND R15, R20 - - ADDS R16, R3 - ADCS R17, R4 - STP (R3, R4), 0(R2) - ADCS R17, R5 - ADCS R17, R6 - STP (R5, R6), 16(R2) - ADCS R17, R7 - ADCS R19, R8 - STP (R7, R8), 32(R2) - ADCS R20, R9 - - LDP ·p751x2+56(SB), (R16, R17) - AND R15, R16 - AND R15, R17 - LDP ·p751x2+72(SB), (R19, R20) - AND R15, R19 - AND R15, R20 - - ADCS R16, R10 - STP (R9, R10), 48(R2) - ADCS R17, R11 - ADCS R19, R12 - STP (R11, R12), 64(R2) - ADCS R20, R13 - - MOVD ·p751x2+88(SB), R16 - AND R15, R16 - ADC R16, R14 - STP (R13, R14), 80(R2) - - RET - -TEXT ·fp751AddLazy(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - // Load first summand into R3-R14 - // Add first summand and second summand and store result in R3-R14 - LDP 0(R0), (R3, R4) - LDP 0(R1), (R15, R16) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R17, R19) - ADDS R15, R3 - ADCS R16, R4 - STP (R3, R4), 0(R2) - ADCS R17, R5 - ADCS R19, R6 - STP (R5, R6), 16(R2) - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R15, R16) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R17, R19) - ADCS R15, R7 - ADCS R16, R8 - STP (R7, R8), 32(R2) - ADCS R17, R9 - ADCS R19, R10 - STP (R9, R10), 48(R2) - - LDP 64(R0), (R11, R12) - LDP 64(R1), (R15, R16) - LDP 80(R0), (R13, R14) - LDP 80(R1), (R17, R19) - ADCS R15, R11 - ADCS R16, R12 - STP (R11, R12), 64(R2) - ADCS R17, R13 - ADC R19, R14 - STP (R13, R14), 80(R2) - - RET - -TEXT ·fp751X2AddLazy(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - LDP 0(R0), (R3, R4) - LDP 0(R1), (R15, R16) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R17, R19) - ADDS R15, R3 - ADCS R16, R4 - STP (R3, R4), 0(R2) - ADCS R17, R5 - ADCS R19, R6 - STP (R5, R6), 16(R2) - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R15, R16) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R17, R19) - ADCS R15, R7 - ADCS R16, R8 - STP (R7, R8), 32(R2) - ADCS R17, R9 - ADCS R19, R10 - STP (R9, R10), 48(R2) - - LDP 64(R0), (R11, R12) - LDP 64(R1), (R15, R16) - LDP 80(R0), (R13, R14) - LDP 80(R1), (R17, R19) - ADCS R15, R11 - ADCS R16, R12 - STP (R11, R12), 64(R2) - ADCS R17, R13 - ADCS R19, R14 - STP (R13, R14), 80(R2) - - LDP 96(R0), (R3, R4) - LDP 96(R1), (R15, R16) - LDP 112(R0), (R5, R6) - LDP 112(R1), (R17, R19) - ADCS R15, R3 - ADCS R16, R4 - STP (R3, R4), 96(R2) - ADCS R17, R5 - ADCS R19, R6 - STP (R5, R6), 112(R2) - - LDP 128(R0), (R7, R8) - LDP 128(R1), (R15, R16) - LDP 144(R0), (R9, R10) - LDP 144(R1), (R17, R19) - ADCS R15, R7 - ADCS R16, R8 - STP (R7, R8), 128(R2) - ADCS R17, R9 - ADCS R19, R10 - STP (R9, R10), 144(R2) - - LDP 160(R0), (R11, R12) - LDP 160(R1), (R15, R16) - LDP 176(R0), (R13, R14) - LDP 176(R1), (R17, R19) - ADCS R15, R11 - ADCS R16, R12 - STP (R11, R12), 160(R2) - ADCS R17, R13 - ADC R19, R14 - STP (R13, R14), 176(R2) - - RET - -TEXT ·fp751X2SubLazy(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - LDP 0(R0), (R3, R4) - LDP 0(R1), (R15, R16) - LDP 16(R0), (R5, R6) - LDP 16(R1), (R17, R19) - SUBS R15, R3 - SBCS R16, R4 - STP (R3, R4), 0(R2) - SBCS R17, R5 - SBCS R19, R6 - STP (R5, R6), 16(R2) - - LDP 32(R0), (R7, R8) - LDP 32(R1), (R15, R16) - LDP 48(R0), (R9, R10) - LDP 48(R1), (R17, R19) - SBCS R15, R7 - SBCS R16, R8 - STP (R7, R8), 32(R2) - SBCS R17, R9 - SBCS R19, R10 - STP (R9, R10), 48(R2) - - LDP 64(R0), (R11, R12) - LDP 64(R1), (R15, R16) - LDP 80(R0), (R13, R14) - LDP 80(R1), (R17, R19) - SBCS R15, R11 - SBCS R16, R12 - STP (R11, R12), 64(R2) - SBCS R17, R13 - SBCS R19, R14 - STP (R13, R14), 80(R2) - - LDP 96(R0), (R3, R4) - LDP 96(R1), (R15, R16) - LDP 112(R0), (R5, R6) - LDP 112(R1), (R17, R19) - SBCS R15, R3 - SBCS R16, R4 - SBCS R17, R5 - SBCS R19, R6 - - LDP 128(R0), (R7, R8) - LDP 128(R1), (R15, R16) - LDP 144(R0), (R9, R10) - LDP 144(R1), (R17, R19) - SBCS R15, R7 - SBCS R16, R8 - SBCS R17, R9 - SBCS R19, R10 - - LDP 160(R0), (R11, R12) - LDP 160(R1), (R15, R16) - LDP 176(R0), (R13, R14) - LDP 176(R1), (R17, R19) - SBCS R15, R11 - SBCS R16, R12 - SBCS R17, R13 - SBCS R19, R14 - SBC ZR, ZR, R15 - - // If x - y < 0, R15 is 1 and p751 should be added - MOVD ·p751+0(SB), R20 - AND R15, R20 - LDP ·p751+40(SB), (R16, R17) - ADDS R20, R3 - ADCS R20, R4 - STP (R3, R4), 96(R2) - ADCS R20, R5 - ADCS R20, R6 - STP (R5, R6), 112(R2) - ADCS R20, R7 - - LDP ·p751+56(SB), (R19, R20) - AND R15, R16 - AND R15, R17 - ADCS R16, R8 - STP (R7, R8), 128(R2) - ADCS R17, R9 - - LDP ·p751+72(SB), (R16, R17) - AND R15, R19 - AND R15, R20 - ADCS R19, R10 - STP (R9, R10), 144(R2) - ADCS R20, R11 - - MOVD ·p751+88(SB), R19 - AND R15, R16 - AND R15, R17 - ADCS R16, R12 - STP (R11, R12), 160(R2) - ADCS R17, R13 - - AND R15, R19 - ADC R19, R14 - STP (R13, R14), 176(R2) - - RET - -// Expects that X0*Y0 is already in Z0(low),Z3(high) and X0*Y1 in Z1(low),Z2(high) -// Z0 is not actually touched -// Result of (X0-X2) * (Y0-Y2) will be in Z0-Z5 -// Inputs remain intact -#define mul192x192comba(X0, X1, X2, Y0, Y1, Y2, Z0, Z1, Z2, Z3, Z4, Z5, T0, T1, T2, T3) \ - MUL X1, Y0, T2 \ - UMULH X1, Y0, T3 \ - \ - ADDS Z3, Z1 \ - ADCS ZR, Z2 \ - ADC ZR, ZR, Z3 \ - \ - MUL X0, Y2, T0 \ - UMULH X0, Y2, T1 \ - \ - ADDS T2, Z1 \ - ADCS T3, Z2 \ - ADC ZR, Z3 \ - \ - MUL X1, Y1, T2 \ - UMULH X1, Y1, T3 \ - \ - ADDS T0, Z2 \ - ADCS T1, Z3 \ - ADC ZR, ZR, Z4 \ - \ - MUL X2, Y0, T0 \ - UMULH X2, Y0, T1 \ - \ - ADDS T2, Z2 \ - ADCS T3, Z3 \ - ADC ZR, Z4 \ - \ - MUL X1, Y2, T2 \ - UMULH X1, Y2, T3 \ - \ - ADDS T0, Z2 \ - ADCS T1, Z3 \ - ADC ZR, Z4 \ - \ - MUL X2, Y1, T0 \ - UMULH X2, Y1, T1 \ - \ - ADDS T2, Z3 \ - ADCS T3, Z4 \ - ADC ZR, ZR, Z5 \ - \ - MUL X2, Y2, T2 \ - UMULH X2, Y2, T3 \ - \ - ADDS T0, Z3 \ - ADCS T1, Z4 \ - ADC ZR, Z5 \ - \ - ADDS T2, Z4 \ - ADC T3, Z5 - -// Expects that X points to (X4-X6), Y to (Y4-Y6) -// Result of (X0-X5) * (Y0-Y5) will be in (0(Z), 8(Z), 16(Z), T0-T8) -// Inputs get overwritten -#define mul384x384karatsuba(X, Y, Z, X0, X1, X2, X3, X4, X5, Y0, Y1, Y2, Y3, Y4, Y5, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)\ - ADDS X0, X3 \ // xH + xL, destroys xH - ADCS X1, X4 \ - ADCS X2, X5 \ - ADC ZR, ZR, T10 \ - \ - ADDS Y0, Y3 \ // yH + yL, destroys yH - ADCS Y1, Y4 \ - ADCS Y2, Y5 \ - ADC ZR, ZR, T6 \ - \ - SUB T10, ZR, T7 \ - SUB T6, ZR, T8 \ - AND T6, T10 \ // combined carry - \ - AND T7, Y3, T0 \ // masked(yH + yL) - AND T7, Y4, T1 \ - AND T7, Y5, T2 \ - \ - AND T8, X3, T3 \ // masked(xH + xL) - AND T8, X4, T4 \ - AND T8, X5, T5 \ - \ - ADDS T3, T0 \ - ADCS T4, T1 \ - STP (T0, T1), 0+Z \ - \ - MUL X3, Y3, T0 \ - MUL X3, Y4, T1 \ - \ - ADCS T5, T2 \ - MOVD T2, 16+Z \ - \ - UMULH X3, Y4, T2 \ - UMULH X3, Y3, T3 \ - \ - ADC ZR, T10 \ - \ // (xH + xL) * (yH + yL) - mul192x192comba(X3, X4, X5, Y3, Y4, Y5, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)\ - \ - MUL X0, Y0, X3 \ - LDP 0+Z, (T6, T7) \ - MOVD 16+Z, T8 \ - \ - UMULH X0, Y0, Y3 \ - ADDS T6, T3 \ - ADCS T7, T4 \ - MUL X0, Y1, X4 \ - ADCS T8, T5 \ - ADC ZR, T10 \ - UMULH X0, Y1, X5 \ - \ // xL * yL - mul192x192comba(X0, X1, X2, Y0, Y1, Y2, X3, X4, X5, Y3, Y4, Y5, T6, T7, T8, T9)\ - \ - STP (X3, X4), 0+Z \ - MOVD X5, 16+Z \ - \ - SUBS X3, T0 \ // (xH + xL) * (yH + yL) - xL * yL - SBCS X4, T1 \ - LDP 0+X, (X3, X4) \ - SBCS X5, T2 \ - MOVD 16+X, X5 \ - SBCS Y3, T3 \ - SBCS Y4, T4 \ - SBCS Y5, T5 \ - SBC ZR, T10 \ - \ - ADDS Y3, T0 \ // ((xH + xL) * (yH + yL) - xL * yL) * 2^192 + xL * yL - ADCS Y4, T1 \ - LDP 0+Y, (Y3, Y4) \ - MUL X3, Y3, X0 \ - ADCS Y5, T2 \ - UMULH X3, Y3, Y0 \ - MOVD 16+Y, Y5 \ - MUL X3, Y4, X1 \ - ADCS ZR, T3 \ - UMULH X3, Y4, X2 \ - ADCS ZR, T4 \ - ADCS ZR, T5 \ - ADC ZR, T10 \ - \ // xH * yH, overwrite xLow, yLow - mul192x192comba(X3, X4, X5, Y3, Y4, Y5, X0, X1, X2, Y0, Y1, Y2, T6, T7, T8, T9)\ - \ - SUBS X0, T0 \ // ((xH + xL) * (yH + yL) - xL * yL - xH * yH) - SBCS X1, T1 \ - SBCS X2, T2 \ - SBCS Y0, T3 \ - SBCS Y1, T4 \ - SBCS Y2, T5 \ - SBC ZR, T10 \ - \ - ADDS X0, T3 \ - ADCS X1, T4 \ - ADCS X2, T5 \ - ADCS T10, Y0, T6 \ - ADCS ZR, Y1, T7 \ - ADC ZR, Y2, T8 - - -TEXT ·fp751Mul(SB), NOSPLIT, $0-24 - MOVD z+0(FP), R2 - MOVD x+8(FP), R0 - MOVD y+16(FP), R1 - - // Load xL in R3-R8, xH in R9-R14 - // (xH + xL) in R3-R8, destroys xH - LDP 0(R0), (R3, R4) - LDP 48(R0), (R9, R10) - ADDS R9, R3 - ADCS R10, R4 - LDP 16(R0), (R5, R6) - LDP 64(R0), (R11, R12) - ADCS R11, R5 - ADCS R12, R6 - LDP 32(R0), (R7, R8) - LDP 80(R0), (R13, R14) - ADCS R13, R7 - ADCS R14, R8 - ADC ZR, ZR, R22 - - // Load yL in R9-R14, yH in R15-21 - // (yH + yL) in R9-R14, destroys yH - LDP 0(R1), (R9, R10) - LDP 48(R1), (R15, R16) - ADDS R15, R9 - ADCS R16, R10 - LDP 16(R1), (R11, R12) - LDP 64(R1), (R17, R19) - ADCS R17, R11 - ADCS R19, R12 - LDP 32(R1), (R13, R14) - LDP 80(R1), (R20, R21) - ADCS R20, R13 - ADCS R21, R14 - ADC ZR, ZR, R23 - - // Compute masks and combined carry - SUB R22, ZR, R24 - SUB R23, ZR, R25 - AND R23, R22 - - // Store xH, yH in z so mul384x384karatsuba can retrieve them from memory - // It doesn't have enough registers - // Meanwhile computed masked(xH + xL) in R15-R21 - STP (R6, R7), 0(R2) - AND R25, R3, R15 - AND R25, R4, R16 - STP (R8, R12), 16(R2) - AND R25, R5, R17 - AND R25, R6, R19 - STP (R13, R14), 32(R2) - AND R25, R7, R20 - AND R25, R8, R21 - - // Masked(xH + xL) + masked(yH + yL) in R15-R21 - // Store intermediate values in z - AND R24, R9, R25 - AND R24, R10, R26 - ADDS R25, R15 - ADCS R26, R16 - STP (R15, R16), 96(R2) - AND R24, R11, R25 - AND R24, R12, R26 - ADCS R25, R17 - ADCS R26, R19 - STP (R17, R19), 112(R2) - AND R24, R13, R25 - AND R24, R14, R26 - ADCS R25, R20 - ADCS R26, R21 - STP (R20, R21), 128(R2) - // Store carry in R29 so it can remain there - ADC ZR, R22, R29 - - // (xH + xL) * (yH + yL) - mul384x384karatsuba(0(R2), 24(R2), 48(R2), R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R19, R20, R21, R22, R23, R24, R25, R26) - - // Load masked(xH + xL) + masked(yH + yL) and add that to its top half - // Store the result back in z - STP (R15, R16), 72(R2) - LDP 96(R2), (R3, R4) - ADDS R3, R19 - STP (R17, R19), 88(R2) - ADCS R4, R20 - LDP 112(R2), (R5, R6) - ADCS R5, R21 - STP (R20, R21), 104(R2) - ADCS R6, R22 - LDP 128(R2), (R7, R8) - ADCS R7, R23 - STP (R22, R23), 120(R2) - ADCS R8, R24 - MOVD R24, 136(R2) - ADC ZR, R29 - - // Load xL, yL - LDP 0(R0), (R3, R4) - LDP 16(R0), (R5, R6) - LDP 32(R0), (R7, R8) - LDP 0(R1), (R9, R10) - LDP 16(R1), (R11, R12) - LDP 32(R1), (R13, R14) - - // xL * yL - mul384x384karatsuba(24(R0), 24(R1), 0(R2), R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R19, R20, R21, R22, R23, R24, R25, R26) - - // (xH + xL) * (yH + yL) - xL * yL in R3-R14 - LDP 0(R2), (R12, R13) - LDP 48(R2), (R3, R4) - SUBS R12, R3 - LDP 64(R2), (R5, R6) - MOVD 16(R2), R14 - SBCS R13, R4 - SBCS R14, R5 - LDP 80(R2), (R7, R8) - SBCS R15, R6 - SBCS R16, R7 - LDP 96(R2), (R9, R10) - SBCS R17, R8 - SBCS R19, R9 - LDP 112(R2), (R11, R12) - SBCS R20, R10 - SBCS R21, R11 - LDP 128(R2), (R13, R14) - SBCS R22, R12 - SBCS R23, R13 - SBCS R24, R14 - SBC ZR, R29 - - STP (R15, R16), 24(R2) - MOVD R17, 40(R2) - - // ((xH + xL) * (yH + yL) - xL * yL) * 2^384 + xL * yL and store back in z - ADDS R19, R3 - ADCS R20, R4 - STP (R3, R4), 48(R2) - ADCS R21, R5 - ADCS R22, R6 - STP (R5, R6), 64(R2) - ADCS R23, R7 - ADCS R24, R8 - STP (R7, R8), 80(R2) - ADCS ZR, R9 - ADCS ZR, R10 - STP (R9, R10), 96(R2) - ADCS ZR, R11 - ADCS ZR, R12 - STP (R11, R12), 112(R2) - ADCS ZR, R13 - ADCS ZR, R14 - STP (R13, R14), 128(R2) - ADC ZR, R29 - - // Load xH, yH - LDP 48(R0), (R3, R4) - LDP 64(R0), (R5, R6) - LDP 80(R0), (R7, R8) - LDP 48(R1), (R9, R10) - LDP 64(R1), (R11, R12) - LDP 80(R1), (R13, R14) - - // xH * yH - mul384x384karatsuba(72(R0), 72(R1), 144(R2), R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R19, R20, R21, R22, R23, R24, R25, R26) - - LDP 144(R2), (R12, R13) - MOVD 160(R2), R14 - - // (xH + xL) * (yH + yL) - xL * yL - xH * yH in R3-R14 - // Store lower half in z, that's done - LDP 48(R2), (R3, R4) - SUBS R12, R3 - LDP 64(R2), (R5, R6) - SBCS R13, R4 - SBCS R14, R5 - LDP 80(R2), (R7, R8) - SBCS R15, R6 - SBCS R16, R7 - LDP 96(R2), (R9, R10) - SBCS R17, R8 - SBCS R19, R9 - LDP 112(R2), (R11, R12) - SBCS R20, R10 - SBCS R21, R11 - LDP 128(R2), (R13, R14) - SBCS R22, R12 - SBCS R23, R13 - STP (R3, R4), 48(R2) - SBCS R24, R14 - STP (R5, R6), 64(R2) - SBC ZR, R29 - STP (R7, R8), 80(R2) - - // (xH * yH) * 2^768 + ((xH + xL) * (yH + yL) - xL * yL - xH * yH) * 2^384 + xL * yL - // Store remaining limbs in z - LDP 144(R2), (R3, R4) - MOVD 160(R2), R5 - - ADDS R3, R9 - ADCS R4, R10 - STP (R9, R10), 96(R2) - ADCS R5, R11 - ADCS R15, R12 - STP (R11, R12), 112(R2) - ADCS R16, R13 - ADCS R17, R14 - STP (R13, R14), 128(R2) - - ADCS R29, R19 - ADCS ZR, R20 - STP (R19, R20), 144(R2) - ADCS ZR, R21 - ADCS ZR, R22 - STP (R21, R22), 160(R2) - ADCS ZR, R23 - ADC ZR, R24 - STP (R23, R24), 176(R2) - - RET - -TEXT ·fp751MontgomeryReduce(SB), NOSPLIT, $0-16 - MOVD z+0(FP), R0 - MOVD x+8(FP), R1 - - // Load p751+1 in R14-R17, R29, R19-R20, spread over arithmetic - LDP ·p751p1+40(SB), (R14, R15) - // z0-z11 will be R2-R13 - // Load x0-x4 to z0-z4 and x5, spread over arithmetic - LDP 0(R1), (R2, R3) - - // x5 iteration - MUL R2, R14, R22 - LDP 32(R1), (R6, R21) - UMULH R2, R14, R23 - ADDS R21, R22, R7 // Set z5 - ADC ZR, R23, R25 - - // x6 iteration - MUL R2, R15, R22 - MOVD 48(R1), R21 - UMULH R2, R15, R23 - ADDS R22, R25 - ADC R23, ZR, R26 - - MUL R3, R14, R22 - LDP ·p751p1+56(SB), (R16, R17) - UMULH R3, R14, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, ZR, R24 - - ADDS R21, R25, R8 // Set z6 - ADCS ZR, R26 - ADC ZR, R24 - - // x7 iteration - MUL R2, R16, R22 - MOVD 56(R1), R21 - UMULH R2, R16, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, ZR, R25 - - MUL R3, R15, R22 - LDP 16(R1), (R4, R5) - UMULH R3, R15, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R4, R14, R22 - LDP ·p751p1+72(SB), (R29, R19) - UMULH R4, R14, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - ADDS R21, R26, R9 // Set z7 - ADCS ZR, R24 - ADC ZR, R25 - - // x8 iteration - MUL R2, R17, R22 - MOVD 64(R1), R21 - UMULH R2, R17, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, ZR, R26 - - MUL R3, R16, R22 - MOVD ·p751p1+88(SB), R20 - UMULH R3, R16, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R4, R15, R22 - UMULH R4, R15, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R5, R14, R22 - UMULH R5, R14, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - ADDS R24, R21, R10 // Set z8 - ADCS ZR, R25 - ADC ZR, R26 - - // x9 iteration - MUL R2, R29, R22 - MOVD 72(R1), R21 - UMULH R2, R29, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, ZR, R24 - - MUL R3, R17, R22 - UMULH R3, R17, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R4, R16, R22 - UMULH R4, R16, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R5, R15, R22 - UMULH R5, R15, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R6, R14, R22 - UMULH R6, R14, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - ADDS R21, R25, R11 // Set z9 - ADCS ZR, R26 - ADC ZR, R24 - - // x10 iteration - MUL R2, R19, R22 - MOVD 80(R1), R21 - UMULH R2, R19, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, ZR, R25 - - MUL R3, R29, R22 - UMULH R3, R29, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R4, R17, R22 - UMULH R4, R17, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R5, R16, R22 - UMULH R5, R16, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R6, R15, R22 - UMULH R6, R15, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R7, R14, R22 - UMULH R7, R14, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - ADDS R21, R26, R12 // Set z10 - ADCS ZR, R24 - ADC ZR, R25 - - // x11 iteration - MUL R2, R20, R22 - MOVD 88(R1), R21 - UMULH R2, R20, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, ZR, R26 - - MUL R3, R19, R22 - UMULH R3, R19, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R4, R29, R22 - UMULH R4, R29, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R5, R17, R22 - UMULH R5, R17, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R6, R16, R22 - UMULH R6, R16, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R7, R15, R22 - UMULH R7, R15, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R8, R14, R22 - UMULH R8, R14, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - ADDS R21, R24, R13 // Set z11 - ADCS ZR, R25 - ADC ZR, R26 - - // x12 iteration - MUL R3, R20, R22 - MOVD 96(R1), R21 - UMULH R3, R20, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, ZR, R24 - - MUL R4, R19, R22 - UMULH R4, R19, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R5, R29, R22 - UMULH R5, R29, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R6, R17, R22 - UMULH R6, R17, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R7, R16, R22 - UMULH R7, R16, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R8, R15, R22 - UMULH R8, R15, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R9, R14, R22 - UMULH R9, R14, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - ADDS R21, R25, R2 // Set z0 - ADCS ZR, R26 - ADC ZR, R24 - - // x13 iteration - MUL R4, R20, R22 - MOVD 104(R1), R21 - UMULH R4, R20, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, ZR, R25 - - MUL R5, R19, R22 - UMULH R5, R19, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R6, R29, R22 - UMULH R6, R29, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R7, R17, R22 - UMULH R7, R17, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R8, R16, R22 - UMULH R8, R16, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R9, R15, R22 - UMULH R9, R15, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R10, R14, R22 - UMULH R10, R14, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - ADDS R21, R26, R3 // Set z1 - STP (R2, R3), 0(R0) - ADCS ZR, R24 - ADC ZR, R25 - - // x14 iteration - MUL R5, R20, R22 - MOVD 112(R1), R21 - UMULH R5, R20, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, ZR, R26 - - MUL R6, R19, R22 - UMULH R6, R19, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R7, R29, R22 - UMULH R7, R29, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R8, R17, R22 - UMULH R8, R17, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R9, R16, R22 - UMULH R9, R16, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R10, R15, R22 - UMULH R10, R15, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R11, R14, R22 - UMULH R11, R14, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - ADDS R21, R24, R4 // Set z2 - ADCS ZR, R25 - ADC ZR, R26 - - // x15 iteration - MUL R6, R20, R22 - MOVD 120(R1), R21 - UMULH R6, R20, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, ZR, R24 - - MUL R7, R19, R22 - UMULH R7, R19, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R8, R29, R22 - UMULH R8, R29, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R9, R17, R22 - UMULH R9, R17, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R10, R16, R22 - UMULH R10, R16, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R11, R15, R22 - UMULH R11, R15, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R12, R14, R22 - UMULH R12, R14, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - ADDS R21, R25, R5 // Set z3 - STP (R4, R5), 16(R0) - ADCS ZR, R26 - ADC ZR, R24 - - // x16 iteration - MUL R7, R20, R22 - MOVD 128(R1), R21 - UMULH R7, R20, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, ZR, R25 - - MUL R8, R19, R22 - UMULH R8, R19, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R9, R29, R22 - UMULH R9, R29, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R10, R17, R22 - UMULH R10, R17, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R11, R16, R22 - UMULH R11, R16, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R12, R15, R22 - UMULH R12, R15, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R13, R14, R22 - UMULH R13, R14, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - ADDS R21, R26, R6 // Set z4 - ADCS ZR, R24 - ADC ZR, R25 - - // x17 iteration - MUL R8, R20, R22 - MOVD 136(R1), R21 - UMULH R8, R20, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, ZR, R26 - - MUL R9, R19, R22 - UMULH R9, R19, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R10, R29, R22 - UMULH R10, R29, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R11, R17, R22 - UMULH R11, R17, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R12, R16, R22 - UMULH R12, R16, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R13, R15, R22 - UMULH R13, R15, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - ADDS R21, R24, R7 // Set z5 - STP (R6, R7), 32(R0) - ADCS ZR, R25 - ADC ZR, R26 - - // x18 iteration - MUL R9, R20, R22 - MOVD 144(R1), R21 - UMULH R9, R20, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, ZR, R24 - - MUL R10, R19, R22 - UMULH R10, R19, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R11, R29, R22 - UMULH R11, R29, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R12, R17, R22 - UMULH R12, R17, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - MUL R13, R16, R22 - UMULH R13, R16, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - ADDS R21, R25, R8 // Set z6 - ADCS ZR, R26 - ADC ZR, R24 - - // x19 iteration - MUL R10, R20, R22 - MOVD 152(R1), R21 - UMULH R10, R20, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, ZR, R25 - - MUL R11, R19, R22 - UMULH R11, R19, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R12, R29, R22 - UMULH R12, R29, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - MUL R13, R17, R22 - UMULH R13, R17, R23 - ADDS R22, R26 - ADCS R23, R24 - ADC ZR, R25 - - ADDS R21, R26, R9 // Set z7 - STP (R8, R9), 48(R0) - ADCS ZR, R24 - ADC ZR, R25 - - // x20 iteration - MUL R11, R20, R22 - MOVD 160(R1), R21 - UMULH R11, R20, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, ZR, R26 - - MUL R12, R19, R22 - UMULH R12, R19, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - MUL R13, R29, R22 - UMULH R13, R29, R23 - ADDS R22, R24 - ADCS R23, R25 - ADC ZR, R26 - - ADDS R21, R24, R10 // Set z8 - ADCS ZR, R25 - ADC ZR, R26 - - // x21 iteration - MUL R12, R20, R22 - MOVD 168(R1), R21 - UMULH R12, R20, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, ZR, R24 - - MUL R13, R19, R22 - UMULH R13, R19, R23 - ADDS R22, R25 - ADCS R23, R26 - ADC ZR, R24 - - ADDS R21, R25, R11 // Set z9 - STP (R10, R11), 64(R0) - ADCS ZR, R26 - ADC ZR, R24 - - // x22 iteration - MUL R13, R20, R22 - MOVD 176(R1), R21 - UMULH R13, R20, R23 - ADDS R22, R26 - ADC R23, R24 - ADDS R21, R26, R12 // Set z10 - - MOVD 184(R1), R21 - ADC R21, R24, R13 // Set z11 - STP (R12, R13), 80(R0) - - RET - -TEXT ·fp751StrongReduce(SB), NOSPLIT, $0-8 - MOVD x+0(FP), R0 - - // Keep x in R1-R12, p751 in R13-R21, subtract to R1-R12 - MOVD ·p751+0(SB), R13 - LDP 0(R0), (R1, R2) - LDP 16(R0), (R3, R4) - SUBS R13, R1 - SBCS R13, R2 - - LDP 32(R0), (R5, R6) - LDP ·p751+40(SB), (R14, R15) - SBCS R13, R3 - SBCS R13, R4 - - LDP 48(R0), (R7, R8) - LDP ·p751+56(SB), (R16, R17) - SBCS R13, R5 - SBCS R14, R6 - - LDP 64(R0), (R9, R10) - LDP ·p751+72(SB), (R19, R20) - SBCS R15, R7 - SBCS R16, R8 - - LDP 80(R0), (R11, R12) - MOVD ·p751+88(SB), R21 - SBCS R17, R9 - SBCS R19, R10 - - SBCS R20, R11 - SBCS R21, R12 - SBC ZR, ZR, R22 - - // Mask with the borrow and add p751 - AND R22, R13 - AND R22, R14 - AND R22, R15 - AND R22, R16 - AND R22, R17 - AND R22, R19 - AND R22, R20 - AND R22, R21 - - ADDS R13, R1 - ADCS R13, R2 - STP (R1, R2), 0(R0) - ADCS R13, R3 - ADCS R13, R4 - STP (R3, R4), 16(R0) - ADCS R13, R5 - ADCS R14, R6 - STP (R5, R6), 32(R0) - ADCS R15, R7 - ADCS R16, R8 - STP (R7, R8), 48(R0) - ADCS R17, R9 - ADCS R19, R10 - STP (R9, R10), 64(R0) - ADCS R20, R11 - ADC R21, R12 - STP (R11, R12), 80(R0) - - RET diff --git a/external/github.com/cloudflare/sidh/p751/arith_decl.go b/external/github.com/cloudflare/sidh/p751/arith_decl.go deleted file mode 100644 index 6c48f4dd7..000000000 --- a/external/github.com/cloudflare/sidh/p751/arith_decl.go +++ /dev/null @@ -1,46 +0,0 @@ -// +build amd64,!noasm arm64,!noasm - -package p751 - -import ( - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" -) - -// If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x. -// If choice is neither 0 nor 1 then behaviour is undefined. -// This function executes in constant time. -//go:noescape -func fp751ConditionalSwap(x, y *FpElement, choice uint8) - -// Compute z = x + y (mod p). -//go:noescape -func fp751AddReduced(z, x, y *FpElement) - -// Compute z = x - y (mod p). -//go:noescape -func fp751SubReduced(z, x, y *FpElement) - -// Compute z = x + y, without reducing mod p. -//go:noescape -func fp751AddLazy(z, x, y *FpElement) - -// Compute z = x + y, without reducing mod p. -//go:noescape -func fp751X2AddLazy(z, x, y *FpElementX2) - -// Compute z = x - y, without reducing mod p. -//go:noescape -func fp751X2SubLazy(z, x, y *FpElementX2) - -// Compute z = x * y. -//go:noescape -func fp751Mul(z *FpElementX2, x, y *FpElement) - -// Compute Montgomery reduction: set z = x * R^{-1} (mod 2*p). -// It may destroy the input value. -//go:noescape -func fp751MontgomeryReduce(z *FpElement, x *FpElementX2) - -// Reduce a field element in [0, 2*p) to one in [0,p). -//go:noescape -func fp751StrongReduce(x *FpElement) diff --git a/external/github.com/cloudflare/sidh/p751/arith_generic.go b/external/github.com/cloudflare/sidh/p751/arith_generic.go deleted file mode 100644 index 3fdad5a15..000000000 --- a/external/github.com/cloudflare/sidh/p751/arith_generic.go +++ /dev/null @@ -1,196 +0,0 @@ -// +build noasm !amd64,!arm64 - -package p751 - -import ( - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/arith" - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" -) - -// Compute z = x + y (mod p). -func fp751AddReduced(z, x, y *FpElement) { - var carry uint64 - - // z=x+y % p751 - for i := 0; i < NumWords; i++ { - z[i], carry = Addc64(carry, x[i], y[i]) - } - - // z = z - p751x2 - carry = 0 - for i := 0; i < NumWords; i++ { - z[i], carry = Subc64(carry, z[i], p751x2[i]) - } - - // z = z + p751x2 - mask := uint64(0 - carry) - carry = 0 - for i := 0; i < NumWords; i++ { - z[i], carry = Addc64(carry, z[i], p751x2[i]&mask) - } -} - -// Compute z = x - y (mod p). -func fp751SubReduced(z, x, y *FpElement) { - var borrow uint64 - - for i := 0; i < NumWords; i++ { - z[i], borrow = Subc64(borrow, x[i], y[i]) - } - - mask := uint64(0 - borrow) - borrow = 0 - - for i := 0; i < NumWords; i++ { - z[i], borrow = Addc64(borrow, z[i], p751x2[i]&mask) - } -} - -// Conditionally swaps bits in x and y in constant time. -// mask indicates bits to be swaped (set bits are swapped) -// For details see "Hackers Delight, 2.20" -// -// Implementation doesn't actually depend on a prime field. -func fp751ConditionalSwap(x, y *FpElement, mask uint8) { - var tmp, mask64 uint64 - - mask64 = 0 - uint64(mask) - for i := 0; i < len(x); i++ { - tmp = mask64 & (x[i] ^ y[i]) - x[i] = tmp ^ x[i] - y[i] = tmp ^ y[i] - } -} - -// Perform Montgomery reduction: set z = x R^{-1} (mod 2*p) -// with R=2^768. Destroys the input value. -func fp751MontgomeryReduce(z *FpElement, x *FpElementX2) { - var carry, t, u, v uint64 - var uv Uint128 - var count int - - count = 5 // number of 0 digits in the least significant part of p751 + 1 - - for i := 0; i < NumWords; i++ { - for j := 0; j < i; j++ { - if j < (i - count + 1) { - uv = Mul64(z[j], p751p1[i-j]) - v, carry = Addc64(0, uv.L, v) - u, carry = Addc64(carry, uv.H, u) - t += carry - } - } - v, carry = Addc64(0, v, x[i]) - u, carry = Addc64(carry, u, 0) - t += carry - - z[i] = v - v = u - u = t - t = 0 - } - - for i := NumWords; i < 2*NumWords-1; i++ { - if count > 0 { - count-- - } - for j := i - NumWords + 1; j < NumWords; j++ { - if j < (NumWords - count) { - uv = Mul64(z[j], p751p1[i-j]) - v, carry = Addc64(0, uv.L, v) - u, carry = Addc64(carry, uv.H, u) - t += carry - } - } - v, carry = Addc64(0, v, x[i]) - u, carry = Addc64(carry, u, 0) - - t += carry - z[i-NumWords] = v - v = u - u = t - t = 0 - } - v, carry = Addc64(0, v, x[2*NumWords-1]) - z[NumWords-1] = v -} - -// Compute z = x * y. -func fp751Mul(z *FpElementX2, x, y *FpElement) { - var u, v, t uint64 - var carry uint64 - var uv Uint128 - - for i := uint64(0); i < NumWords; i++ { - for j := uint64(0); j <= i; j++ { - uv = Mul64(x[j], y[i-j]) - v, carry = Addc64(0, uv.L, v) - u, carry = Addc64(carry, uv.H, u) - t += carry - } - z[i] = v - v = u - u = t - t = 0 - } - - for i := NumWords; i < (2*NumWords)-1; i++ { - for j := i - NumWords + 1; j < NumWords; j++ { - uv = Mul64(x[j], y[i-j]) - v, carry = Addc64(0, uv.L, v) - u, carry = Addc64(carry, uv.H, u) - t += carry - } - z[i] = v - v = u - u = t - t = 0 - } - z[2*NumWords-1] = v -} - -// Compute z = x + y, without reducing mod p. -func fp751AddLazy(z, x, y *FpElement) { - var carry uint64 - for i := 0; i < NumWords; i++ { - z[i], carry = Addc64(carry, x[i], y[i]) - } -} - -// Compute z = x + y, without reducing mod p. -func fp751X2AddLazy(z, x, y *FpElementX2) { - var carry uint64 - for i := 0; i < 2*NumWords; i++ { - z[i], carry = Addc64(carry, x[i], y[i]) - } -} - -// Reduce a field element in [0, 2*p) to one in [0,p). -func fp751StrongReduce(x *FpElement) { - var borrow, mask uint64 - for i := 0; i < NumWords; i++ { - x[i], borrow = Subc64(borrow, x[i], p751[i]) - } - - // Sets all bits if borrow = 1 - mask = 0 - borrow - borrow = 0 - for i := 0; i < NumWords; i++ { - x[i], borrow = Addc64(borrow, x[i], p751[i]&mask) - } -} - -// Compute z = x - y, without reducing mod p. -func fp751X2SubLazy(z, x, y *FpElementX2) { - var borrow, mask uint64 - for i := 0; i < len(z); i++ { - z[i], borrow = Subc64(borrow, x[i], y[i]) - } - - // Sets all bits if borrow = 1 - mask = 0 - borrow - borrow = 0 - for i := NumWords; i < len(z); i++ { - z[i], borrow = Addc64(borrow, z[i], p751[i-NumWords]&mask) - } -} diff --git a/external/github.com/cloudflare/sidh/p751/consts.go b/external/github.com/cloudflare/sidh/p751/consts.go deleted file mode 100644 index 57e49faae..000000000 --- a/external/github.com/cloudflare/sidh/p751/consts.go +++ /dev/null @@ -1,227 +0,0 @@ -package p751 - -import ( - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" - cpu "v2ray.com/core/external/github.com/cloudflare/sidh/internal/utils" -) - -const ( - // SIDH public key byte size - P751_PublicKeySize = 564 - // SIDH shared secret byte size. - P751_SharedSecretSize = 188 - // Max size of secret key for 2-torsion group, corresponds to 2^e2 - P751_SecretBitLenA = 372 - // Size of secret key for 3-torsion group, corresponds to floor(log_2(3^e3)) - P751_SecretBitLenB = 378 - // P751 bytelen ceil(751/8) - P751_Bytelen = 94 - // Size of a compuatation strategy for 2-torsion group - strategySizeA = 185 - // Size of a compuatation strategy for 3-torsion group - strategySizeB = 238 - // Number of 64-bit limbs used to store Fp element - NumWords = 12 -) - -// CPU Capabilities. Those flags are referred by assembly code. According to -// https://github.com/golang/go/issues/28230, variables referred from the -// assembly must be in the same package. -// We declare them variables not constants in order to facilitate testing. -var ( - // Signals support for MULX which is in BMI2 - HasBMI2 = cpu.X86.HasBMI2 - // Signals support for ADX and BMI2 - HasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX -) - -// The x-coordinate of PA -var P751_affine_PA = Fp2Element{ - A: FpElement{ - 0xC2FC08CEAB50AD8B, 0x1D7D710F55E457B1, 0xE8738D92953DCD6E, - 0xBAA7EBEE8A3418AA, 0xC9A288345F03F46F, 0xC8D18D167CFE2616, - 0x02043761F6B1C045, 0xAA1975E13180E7E9, 0x9E13D3FDC6690DE6, - 0x3A024640A3A3BB4F, 0x4E5AD44E6ACBBDAE, 0x0000544BEB561DAD, - }, - B: FpElement{ - 0xE6CC41D21582E411, 0x07C2ECB7C5DF400A, 0xE8E34B521432AEC4, - 0x50761E2AB085167D, 0x032CFBCAA6094B3C, 0x6C522F5FDF9DDD71, - 0x1319217DC3A1887D, 0xDC4FB25803353A86, 0x362C8D7B63A6AB09, - 0x39DCDFBCE47EA488, 0x4C27C99A2C28D409, 0x00003CB0075527C4, - }, -} - -// The x-coordinate of QA -var P751_affine_QA = Fp2Element{ - A: FpElement{ - 0xD56FE52627914862, 0x1FAD60DC96B5BAEA, 0x01E137D0BF07AB91, - 0x404D3E9252161964, 0x3C5385E4CD09A337, 0x4476426769E4AF73, - 0x9790C6DB989DFE33, 0xE06E1C04D2AA8B5E, 0x38C08185EDEA73B9, - 0xAA41F678A4396CA6, 0x92B9259B2229E9A0, 0x00002F9326818BE0, - }, - B: FpElement{ - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - }, -} - -// The x-coordinate of RA = PA-QA -var P751_affine_RA = Fp2Element{ - A: FpElement{ - 0x0BB84441DFFD19B3, 0x84B4DEA99B48C18E, 0x692DE648AD313805, - 0xE6D72761B6DFAEE0, 0x223975C672C3058D, 0xA0FDE0C3CBA26FDC, - 0xA5326132A922A3CA, 0xCA5E7F5D5EA96FA4, 0x127C7EFE33FFA8C6, - 0x4749B1567E2A23C4, 0x2B7DF5B4AF413BFA, 0x0000656595B9623C, - }, - B: FpElement{ - 0xED78C17F1EC71BE8, 0xF824D6DF753859B1, 0x33A10839B2A8529F, - 0xFC03E9E25FDEA796, 0xC4708A8054DF1762, 0x4034F2EC034C6467, - 0xABFB70FBF06ECC79, 0xDABE96636EC108B7, 0x49CBCFB090605FD3, - 0x20B89711819A45A7, 0xFB8E1590B2B0F63E, 0x0000556A5F964AB2, - }, -} - -// The x-coordinate of PB -var P751_affine_PB = Fp2Element{ - A: FpElement{ - 0xCFB6D71EF867AB0B, 0x4A5FDD76E9A45C76, 0x38B1EE69194B1F03, - 0xF6E7B18A7761F3F0, 0xFCF01A486A52C84C, 0xCBE2F63F5AA75466, - 0x6487BCE837B5E4D6, 0x7747F5A8C622E9B8, 0x4CBFE1E4EE6AEBBA, - 0x8A8616A13FA91512, 0x53DB980E1579E0A5, 0x000058FEBFF3BE69, - }, - B: FpElement{ - 0xA492034E7C075CC3, 0x677BAF00B04AA430, 0x3AAE0C9A755C94C8, - 0x1DC4B064E9EBB08B, 0x3684EDD04E826C66, 0x9BAA6CB661F01B22, - 0x20285A00AD2EFE35, 0xDCE95ABD0497065F, 0x16C7FBB3778E3794, - 0x26B3AC29CEF25AAF, 0xFB3C28A31A30AC1D, 0x000046ED190624EE, - }, -} - -// The x-coordinate of QB -var P751_affine_QB = Fp2Element{ - A: FpElement{ - 0xF1A8C9ED7B96C4AB, 0x299429DA5178486E, 0xEF4926F20CD5C2F4, - 0x683B2E2858B4716A, 0xDDA2FBCC3CAC3EEB, 0xEC055F9F3A600460, - 0xD5A5A17A58C3848B, 0x4652D836F42EAED5, 0x2F2E71ED78B3A3B3, - 0xA771C057180ADD1D, 0xC780A5D2D835F512, 0x0000114EA3B55AC1, - }, - B: FpElement{ - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - }, -} - -// The x-coordinate of RB = PB - QB -var P751_affine_RB = Fp2Element{ - A: FpElement{ - 0x1C0D6733769D0F31, 0xF084C3086E2659D1, 0xE23D5DA27BCBD133, - 0xF38EC9A8D5864025, 0x6426DC781B3B645B, 0x4B24E8E3C9FB03EE, - 0x6432792F9D2CEA30, 0x7CC8E8B1AE76E857, 0x7F32BFB626BB8963, - 0xB9F05995B48D7B74, 0x4D71200A7D67E042, 0x0000228457AF0637, - }, - B: FpElement{ - 0x4AE37E7D8F72BD95, 0xDD2D504B3E993488, 0x5D14E7FA1ECB3C3E, - 0x127610CEB75D6350, 0x255B4B4CAC446B11, 0x9EA12336C1F70CAF, - 0x79FA68A2147BC2F8, 0x11E895CFDADBBC49, 0xE4B9D3C4D6356C18, - 0x44B25856A67F951C, 0x5851541F61308D0B, 0x00002FFD994F7E4C, - }, -} - -// 2-torsion group computation strategy -var P751_AliceIsogenyStrategy = [strategySizeA]uint32{ - 0x50, 0x30, 0x1B, 0x0F, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, - 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x07, - 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01, - 0x01, 0x01, 0x01, 0x0C, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02, - 0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x03, - 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x15, - 0x0C, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, - 0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x03, 0x02, 0x01, 0x01, - 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x05, 0x03, 0x02, - 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, - 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x21, 0x14, 0x0C, 0x07, - 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01, - 0x01, 0x01, 0x01, 0x05, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, - 0x02, 0x01, 0x01, 0x01, 0x08, 0x05, 0x03, 0x02, 0x01, 0x01, - 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, - 0x02, 0x01, 0x01, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, - 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, - 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, - 0x01, 0x01, 0x02, 0x01, 0x01} - -// 3-torsion group computation strategy -var P751_BobIsogenyStrategy = [strategySizeB]uint32{ - 0x70, 0x3F, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, - 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, - 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, - 0x01, 0x02, 0x01, 0x01, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, - 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, - 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, - 0x01, 0x01, 0x02, 0x01, 0x01, 0x1F, 0x10, 0x08, 0x04, 0x02, - 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, - 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, - 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x0F, 0x08, 0x04, - 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, - 0x02, 0x01, 0x01, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, - 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x31, 0x1F, 0x10, - 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, - 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, - 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, - 0x0F, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, - 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x07, 0x04, 0x02, 0x01, - 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, - 0x15, 0x0C, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, - 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x05, 0x03, 0x02, - 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x05, - 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, - 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01} - -// Used internally by this package. Not consts as Go doesn't allow arrays to be consts -// ------------------------------- - -// p751 -var p751 = FpElement{ - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xeeafffffffffffff, - 0xe3ec968549f878a8, 0xda959b1a13f7cc76, 0x084e9867d6ebe876, - 0x8562b5045cb25748, 0x0e12909f97badc66, 0x00006fe5d541f71c} - -// 2*p751 -var p751x2 = FpElement{ - 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xDD5FFFFFFFFFFFFF, - 0xC7D92D0A93F0F151, 0xB52B363427EF98ED, 0x109D30CFADD7D0ED, - 0x0AC56A08B964AE90, 0x1C25213F2F75B8CD, 0x0000DFCBAA83EE38} - -// p751 + 1 -var p751p1 = FpElement{ - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0xeeb0000000000000, - 0xe3ec968549f878a8, 0xda959b1a13f7cc76, 0x084e9867d6ebe876, - 0x8562b5045cb25748, 0x0e12909f97badc66, 0x00006fe5d541f71c} - -// R^2 = (2^768)^2 mod p -var p751R2 = FpElement{ - 2535603850726686808, 15780896088201250090, 6788776303855402382, - 17585428585582356230, 5274503137951975249, 2266259624764636289, - 11695651972693921304, 13072885652150159301, 4908312795585420432, - 6229583484603254826, 488927695601805643, 72213483953973} - -// 1*R mod p -var P751_OneFp2 = Fp2Element{ - A: FpElement{ - 0x249ad, 0x0, 0x0, 0x0, 0x0, 0x8310000000000000, 0x5527b1e4375c6c66, 0x697797bf3f4f24d0, 0xc89db7b2ac5c4e2e, 0x4ca4b439d2076956, 0x10f7926c7512c7e9, 0x2d5b24bce5e2}, -} - -// 1/2 * R mod p -var P751_HalfFp2 = Fp2Element{ - A: FpElement{ - 0x00000000000124D6, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0xB8E0000000000000, - 0x9C8A2434C0AA7287, 0xA206996CA9A378A3, 0x6876280D41A41B52, - 0xE903B49F175CE04F, 0x0F8511860666D227, 0x00004EA07CFF6E7F}, -} diff --git a/external/github.com/cloudflare/sidh/p751/field_ops.go b/external/github.com/cloudflare/sidh/p751/field_ops.go deleted file mode 100644 index c416c74ac..000000000 --- a/external/github.com/cloudflare/sidh/p751/field_ops.go +++ /dev/null @@ -1,254 +0,0 @@ -package p751 - -import . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" - -// 2*p751 -var () - -//------------------------------------------------------------------------------ -// Implementtaion of FieldOperations -//------------------------------------------------------------------------------ - -// Implements FieldOps -type fp751Ops struct{} - -func FieldOperations() FieldOps { - return &fp751Ops{} -} - -func (fp751Ops) Add(dest, lhs, rhs *Fp2Element) { - fp751AddReduced(&dest.A, &lhs.A, &rhs.A) - fp751AddReduced(&dest.B, &lhs.B, &rhs.B) -} - -func (fp751Ops) Sub(dest, lhs, rhs *Fp2Element) { - fp751SubReduced(&dest.A, &lhs.A, &rhs.A) - fp751SubReduced(&dest.B, &lhs.B, &rhs.B) -} - -func (fp751Ops) Mul(dest, lhs, rhs *Fp2Element) { - // Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b). - a := &lhs.A - b := &lhs.B - c := &rhs.A - d := &rhs.B - - // We want to compute - // - // (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i - // - // Use Karatsuba's trick: note that - // - // (b - a)*(c - d) = (b*c + a*d) - a*c - b*d - // - // so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d. - - var ac, bd FpElementX2 - fp751Mul(&ac, a, c) // = a*c*R*R - fp751Mul(&bd, b, d) // = b*d*R*R - - var b_minus_a, c_minus_d FpElement - fp751SubReduced(&b_minus_a, b, a) // = (b-a)*R - fp751SubReduced(&c_minus_d, c, d) // = (c-d)*R - - var ad_plus_bc FpElementX2 - fp751Mul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R - fp751X2AddLazy(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R - fp751X2AddLazy(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R - - fp751MontgomeryReduce(&dest.B, &ad_plus_bc) // = (a*d + b*c)*R mod p - - var ac_minus_bd FpElementX2 - fp751X2SubLazy(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R - fp751MontgomeryReduce(&dest.A, &ac_minus_bd) // = (a*c - b*d)*R mod p -} - -func (fp751Ops) Square(dest, x *Fp2Element) { - a := &x.A - b := &x.B - - // We want to compute - // - // (a + bi)*(a + bi) = (a^2 - b^2) + 2abi. - - var a2, a_plus_b, a_minus_b FpElement - fp751AddReduced(&a2, a, a) // = a*R + a*R = 2*a*R - fp751AddReduced(&a_plus_b, a, b) // = a*R + b*R = (a+b)*R - fp751SubReduced(&a_minus_b, a, b) // = a*R - b*R = (a-b)*R - - var asq_minus_bsq, ab2 FpElementX2 - fp751Mul(&asq_minus_bsq, &a_plus_b, &a_minus_b) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R - fp751Mul(&ab2, &a2, b) // = 2*a*b*R*R - - fp751MontgomeryReduce(&dest.A, &asq_minus_bsq) // = (a^2 - b^2)*R mod p - fp751MontgomeryReduce(&dest.B, &ab2) // = 2*a*b*R mod p -} - -// Set dest = 1/x -// -// Allowed to overlap dest with x. -// -// Returns dest to allow chaining operations. -func (fp751Ops) Inv(dest, x *Fp2Element) { - a := &x.A - b := &x.B - - // We want to compute - // - // 1 1 (a - bi) (a - bi) - // -------- = -------- -------- = ----------- - // (a + bi) (a + bi) (a - bi) (a^2 + b^2) - // - // Letting c = 1/(a^2 + b^2), this is - // - // 1/(a+bi) = a*c - b*ci. - - var asq_plus_bsq primeFieldElement - var asq, bsq FpElementX2 - fp751Mul(&asq, a, a) // = a*a*R*R - fp751Mul(&bsq, b, b) // = b*b*R*R - fp751X2AddLazy(&asq, &asq, &bsq) // = (a^2 + b^2)*R*R - fp751MontgomeryReduce(&asq_plus_bsq.A, &asq) // = (a^2 + b^2)*R mod p - // Now asq_plus_bsq = a^2 + b^2 - - // Invert asq_plus_bsq - inv := asq_plus_bsq - inv.Mul(&asq_plus_bsq, &asq_plus_bsq) - inv.P34(&inv) - inv.Mul(&inv, &inv) - inv.Mul(&inv, &asq_plus_bsq) - - var ac FpElementX2 - fp751Mul(&ac, a, &inv.A) - fp751MontgomeryReduce(&dest.A, &ac) - - var minus_b FpElement - fp751SubReduced(&minus_b, &minus_b, b) - var minus_bc FpElementX2 - fp751Mul(&minus_bc, &minus_b, &inv.A) - fp751MontgomeryReduce(&dest.B, &minus_bc) -} - -// In case choice == 1, performs following swap in constant time: -// xPx <-> xQx -// xPz <-> xQz -// Otherwise returns xPx, xPz, xQx, xQz unchanged -func (fp751Ops) CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8) { - fp751ConditionalSwap(&xPx.A, &xQx.A, choice) - fp751ConditionalSwap(&xPx.B, &xQx.B, choice) - fp751ConditionalSwap(&xPz.A, &xQz.A, choice) - fp751ConditionalSwap(&xPz.B, &xQz.B, choice) -} - -// Converts values in x.A and x.B to Montgomery domain -// x.A = x.A * R mod p -// x.B = x.B * R mod p -func (fp751Ops) ToMontgomery(x *Fp2Element) { - var aRR FpElementX2 - - // convert to montgomery domain - fp751Mul(&aRR, &x.A, &p751R2) // = a*R*R - fp751MontgomeryReduce(&x.A, &aRR) // = a*R mod p - fp751Mul(&aRR, &x.B, &p751R2) - fp751MontgomeryReduce(&x.B, &aRR) -} - -// Converts values in x.A and x.B from Montgomery domain -// a = x.A mod p -// b = x.B mod p -// -// After returning from the call x is not modified. -func (fp751Ops) FromMontgomery(x *Fp2Element, out *Fp2Element) { - var aR FpElementX2 - - // convert from montgomery domain - copy(aR[:], x.A[:]) - fp751MontgomeryReduce(&out.A, &aR) // = a mod p in [0, 2p) - fp751StrongReduce(&out.A) // = a mod p in [0, p) - for i := range aR { - aR[i] = 0 - } - copy(aR[:], x.B[:]) - fp751MontgomeryReduce(&out.B, &aR) - fp751StrongReduce(&out.B) -} - -//------------------------------------------------------------------------------ -// Prime Field -//------------------------------------------------------------------------------ - -// Represents an element of the prime field F_p in Montgomery domain -type primeFieldElement struct { - // The value `A`is represented by `aR mod p`. - A FpElement -} - -// Set dest = lhs * rhs. -// -// Allowed to overlap lhs or rhs with dest. -// -// Returns dest to allow chaining operations. -func (dest *primeFieldElement) Mul(lhs, rhs *primeFieldElement) *primeFieldElement { - a := &lhs.A // = a*R - b := &rhs.A // = b*R - - var ab FpElementX2 - fp751Mul(&ab, a, b) // = a*b*R*R - fp751MontgomeryReduce(&dest.A, &ab) // = a*b*R mod p - - return dest -} - -// Set dest = x^(2^k), for k >= 1, by repeated squarings. -// -// Allowed to overlap x with dest. -// -// Returns dest to allow chaining operations. -func (dest *primeFieldElement) Pow2k(x *primeFieldElement, k uint8) *primeFieldElement { - dest.Mul(x, x) - for i := uint8(1); i < k; i++ { - dest.Mul(dest, dest) - } - - return dest -} - -// Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x). -// -// Allowed to overlap x with dest. -// -// Returns dest to allow chaining operations. -func (dest *primeFieldElement) P34(x *primeFieldElement) *primeFieldElement { - // Sliding-window strategy computed with Sage, awk, sed, and tr. - // - // This performs sum(powStrategy) = 744 squarings and len(mulStrategy) - // = 137 multiplications, in addition to 1 squaring and 15 - // multiplications to build a lookup table. - // - // In total this is 745 squarings, 152 multiplications. Since squaring - // is not implemented for the prime field, this is 897 multiplications - // in total. - powStrategy := [137]uint8{5, 7, 6, 2, 10, 4, 6, 9, 8, 5, 9, 4, 7, 5, 5, 4, 8, 3, 9, 5, 5, 4, 10, 4, 6, 6, 6, 5, 8, 9, 3, 4, 9, 4, 5, 6, 6, 2, 9, 4, 5, 5, 5, 7, 7, 9, 4, 6, 4, 8, 5, 8, 6, 6, 2, 9, 7, 4, 8, 8, 8, 4, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2} - mulStrategy := [137]uint8{31, 23, 21, 1, 31, 7, 7, 7, 9, 9, 19, 15, 23, 23, 11, 7, 25, 5, 21, 17, 11, 5, 17, 7, 11, 9, 23, 9, 1, 19, 5, 3, 25, 15, 11, 29, 31, 1, 29, 11, 13, 9, 11, 27, 13, 19, 15, 31, 3, 29, 23, 31, 25, 11, 1, 21, 19, 15, 15, 21, 29, 13, 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 3} - initialMul := uint8(27) - - // Build a lookup table of odd multiples of x. - lookup := [16]primeFieldElement{} - xx := &primeFieldElement{} - xx.Mul(x, x) // Set xx = x^2 - lookup[0] = *x - for i := 1; i < 16; i++ { - lookup[i].Mul(&lookup[i-1], xx) - } - // Now lookup = {x, x^3, x^5, ... } - // so that lookup[i] = x^{2*i + 1} - // so that lookup[k/2] = x^k, for odd k - - *dest = lookup[initialMul/2] - for i := uint8(0); i < 137; i++ { - dest.Pow2k(dest, powStrategy[i]) - dest.Mul(dest, &lookup[mulStrategy[i]/2]) - } - - return dest -} diff --git a/external/github.com/cloudflare/sidh/sidh/api.go b/external/github.com/cloudflare/sidh/sidh/api.go deleted file mode 100644 index 5343006e5..000000000 --- a/external/github.com/cloudflare/sidh/sidh/api.go +++ /dev/null @@ -1,227 +0,0 @@ -package sidh - -import ( - "errors" - "io" - - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" -) - -// I keep it bool in order to be able to apply logical NOT -type KeyVariant uint - -// Id's correspond to bitlength of the prime field characteristic -// Currently FP_751 is the only one supported by this implementation -const ( - FP_503 uint8 = iota - FP_751 - FP_964 - maxPrimeFieldId -) - -const ( - // First 2 bits identify SIDH variant third bit indicates - // wether key is a SIKE variant (set) or SIDH (not set) - - // 001 - SIDH: corresponds to 2-torsion group - KeyVariant_SIDH_A KeyVariant = 1 << 0 - // 010 - SIDH: corresponds to 3-torsion group - KeyVariant_SIDH_B = 1 << 1 - // 110 - SIKE - KeyVariant_SIKE = 1<<2 | KeyVariant_SIDH_B -) - -// Base type for public and private key. Used mainly to carry domain -// parameters. -type key struct { - // Domain parameters of the algorithm to be used with a key - params *SidhParams - // Flag indicates wether corresponds to 2-, 3-torsion group or SIKE - keyVariant KeyVariant -} - -// Defines operations on public key -type PublicKey struct { - key - affine_xP Fp2Element - affine_xQ Fp2Element - affine_xQmP Fp2Element -} - -// Defines operations on private key -type PrivateKey struct { - key - // Secret key - Scalar []byte - // Used only by KEM - S []byte -} - -// Accessor to the domain parameters -func (key *key) Params() *SidhParams { - return key.params -} - -// Accessor to key variant -func (key *key) Variant() KeyVariant { - return key.keyVariant -} - -// NewPrivateKey initializes private key. -// Usage of this function guarantees that the object is correctly initialized. -func NewPrivateKey(id uint8, v KeyVariant) *PrivateKey { - prv := &PrivateKey{key: key{params: Params(id), keyVariant: v}} - if (v & KeyVariant_SIDH_A) == KeyVariant_SIDH_A { - prv.Scalar = make([]byte, prv.params.A.SecretByteLen) - } else { - prv.Scalar = make([]byte, prv.params.B.SecretByteLen) - } - if v == KeyVariant_SIKE { - prv.S = make([]byte, prv.params.MsgLen) - } - return prv -} - -// NewPublicKey initializes public key. -// Usage of this function guarantees that the object is correctly initialized. -func NewPublicKey(id uint8, v KeyVariant) *PublicKey { - return &PublicKey{key: key{params: Params(id), keyVariant: v}} -} - -// Import clears content of the public key currently stored in the structure -// and imports key stored in the byte string. Returns error in case byte string -// size is wrong. Doesn't perform any validation. -func (pub *PublicKey) Import(input []byte) error { - if len(input) != pub.Size() { - return errors.New("sidh: input to short") - } - op := CurveOperations{Params: pub.params} - ssSz := pub.params.SharedSecretSize - op.Fp2FromBytes(&pub.affine_xP, input[0:ssSz]) - op.Fp2FromBytes(&pub.affine_xQ, input[ssSz:2*ssSz]) - op.Fp2FromBytes(&pub.affine_xQmP, input[2*ssSz:3*ssSz]) - return nil -} - -// Exports currently stored key. In case structure hasn't been filled with key data -// returned byte string is filled with zeros. -func (pub *PublicKey) Export() []byte { - output := make([]byte, pub.params.PublicKeySize) - op := CurveOperations{Params: pub.params} - ssSz := pub.params.SharedSecretSize - op.Fp2ToBytes(output[0:ssSz], &pub.affine_xP) - op.Fp2ToBytes(output[ssSz:2*ssSz], &pub.affine_xQ) - op.Fp2ToBytes(output[2*ssSz:3*ssSz], &pub.affine_xQmP) - return output -} - -// Size returns size of the public key in bytes -func (pub *PublicKey) Size() int { - return pub.params.PublicKeySize -} - -// Exports currently stored key. In case structure hasn't been filled with key data -// returned byte string is filled with zeros. -func (prv *PrivateKey) Export() []byte { - ret := make([]byte, len(prv.Scalar)+len(prv.S)) - copy(ret, prv.S) - copy(ret[len(prv.S):], prv.Scalar) - return ret -} - -// Size returns size of the private key in bytes -func (prv *PrivateKey) Size() int { - tmp := len(prv.Scalar) - if prv.Variant() == KeyVariant_SIKE { - tmp += int(prv.params.MsgLen) - } - return tmp -} - -// Import clears content of the private key currently stored in the structure -// and imports key from octet string. In case of SIKE, the random value 'S' -// must be prepended to the value of actual private key (see SIKE spec for details). -// Function doesn't import public key value to PrivateKey object. -func (prv *PrivateKey) Import(input []byte) error { - if len(input) != prv.Size() { - return errors.New("sidh: input to short") - } - copy(prv.S, input[:len(prv.S)]) - copy(prv.Scalar, input[len(prv.S):]) - return nil -} - -// Generates random private key for SIDH or SIKE. Generated value is -// formed as little-endian integer from key-space <2^(e2-1)..2^e2 - 1> -// for KeyVariant_A or <2^(s-1)..2^s - 1>, where s = floor(log_2(3^e3)), -// for KeyVariant_B. -// -// Returns error in case user provided RNG fails. -func (prv *PrivateKey) Generate(rand io.Reader) error { - var err error - var dp *DomainParams - - if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A { - dp = &prv.params.A - } else { - dp = &prv.params.B - } - - if prv.keyVariant == KeyVariant_SIKE && err == nil { - _, err = io.ReadFull(rand, prv.S) - } - - // Private key generation takes advantage of the fact that keyspace for secret - // key is (0, 2^x - 1), for some possitivite value of 'x' (see SIKE, 1.3.8). - // It means that all bytes in the secret key, but the last one, can take any - // value between <0x00,0xFF>. Similarly for the last byte, but generation - // needs to chop off some bits, to make sure generated value is an element of - // a key-space. - _, err = io.ReadFull(rand, prv.Scalar) - if err != nil { - return err - } - prv.Scalar[len(prv.Scalar)-1] &= (1 << (dp.SecretBitLen % 8)) - 1 - // Make sure scalar is SecretBitLen long. SIKE spec says that key - // space starts from 0, but I'm not comfortable with having low - // value scalars used for private keys. It is still secrure as per - // table 5.1 in [SIKE]. - prv.Scalar[len(prv.Scalar)-1] |= 1 << ((dp.SecretBitLen % 8) - 1) - return err -} - -// Generates public key. -// -// Constant time. -func (prv *PrivateKey) GeneratePublicKey() *PublicKey { - if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A { - return publicKeyGenA(prv) - } - return publicKeyGenB(prv) -} - -// Computes a shared secret which is a j-invariant. Function requires that pub has -// different KeyVariant than prv. Length of returned output is 2*ceil(log_2 P)/8), -// where P is a prime defining finite field. -// -// It's important to notice that each keypair must not be used more than once -// to calculate shared secret. -// -// Function may return error. This happens only in case provided input is invalid. -// Constant time for properly initialized private and public key. -func DeriveSecret(prv *PrivateKey, pub *PublicKey) ([]byte, error) { - - if (pub == nil) || (prv == nil) { - return nil, errors.New("sidh: invalid arguments") - } - - if (pub.keyVariant == prv.keyVariant) || (pub.params.Id != prv.params.Id) { - return nil, errors.New("sidh: public and private are incompatbile") - } - - if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A { - return deriveSecretA(prv, pub), nil - } else { - return deriveSecretB(prv, pub), nil - } -} diff --git a/external/github.com/cloudflare/sidh/sidh/params.go b/external/github.com/cloudflare/sidh/sidh/params.go deleted file mode 100644 index d1e2c3912..000000000 --- a/external/github.com/cloudflare/sidh/sidh/params.go +++ /dev/null @@ -1,82 +0,0 @@ -package sidh - -import ( - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" - p503 "v2ray.com/core/external/github.com/cloudflare/sidh/p503" - p751 "v2ray.com/core/external/github.com/cloudflare/sidh/p751" -) - -// Keeps mapping: SIDH prime field ID to domain parameters -var sidhParams = make(map[uint8]SidhParams) - -// Params returns domain parameters corresponding to finite field and identified by -// `id` provieded by the caller. Function panics in case `id` wasn't registered earlier. -func Params(id uint8) *SidhParams { - if val, ok := sidhParams[id]; ok { - return &val - } - panic("sidh: SIDH Params ID unregistered") -} - -func init() { - p503 := SidhParams{ - Id: FP_503, - PublicKeySize: p503.P503_PublicKeySize, - SharedSecretSize: p503.P503_SharedSecretSize, - A: DomainParams{ - Affine_P: p503.P503_affine_PA, - Affine_Q: p503.P503_affine_QA, - Affine_R: p503.P503_affine_RA, - SecretBitLen: p503.P503_SecretBitLenA, - SecretByteLen: uint((p503.P503_SecretBitLenA + 7) / 8), - IsogenyStrategy: p503.P503_AliceIsogenyStrategy[:], - }, - B: DomainParams{ - Affine_P: p503.P503_affine_PB, - Affine_Q: p503.P503_affine_QB, - Affine_R: p503.P503_affine_RB, - SecretBitLen: p503.P503_SecretBitLenB, - SecretByteLen: uint((p503.P503_SecretBitLenB + 7) / 8), - IsogenyStrategy: p503.P503_BobIsogenyStrategy[:], - }, - OneFp2: p503.P503_OneFp2, - HalfFp2: p503.P503_HalfFp2, - MsgLen: 24, - // SIKEp751 provides 128 bit of classical security ([SIKE], 5.1) - KemSize: 16, - Bytelen: p503.P503_Bytelen, - Op: p503.FieldOperations(), - } - - p751 := SidhParams{ - Id: FP_751, - PublicKeySize: p751.P751_PublicKeySize, - SharedSecretSize: p751.P751_SharedSecretSize, - A: DomainParams{ - Affine_P: p751.P751_affine_PA, - Affine_Q: p751.P751_affine_QA, - Affine_R: p751.P751_affine_RA, - IsogenyStrategy: p751.P751_AliceIsogenyStrategy[:], - SecretBitLen: p751.P751_SecretBitLenA, - SecretByteLen: uint((p751.P751_SecretBitLenA + 7) / 8), - }, - B: DomainParams{ - Affine_P: p751.P751_affine_PB, - Affine_Q: p751.P751_affine_QB, - Affine_R: p751.P751_affine_RB, - IsogenyStrategy: p751.P751_BobIsogenyStrategy[:], - SecretBitLen: p751.P751_SecretBitLenB, - SecretByteLen: uint((p751.P751_SecretBitLenB + 7) / 8), - }, - OneFp2: p751.P751_OneFp2, - HalfFp2: p751.P751_HalfFp2, - MsgLen: 32, - // SIKEp751 provides 192 bit of classical security ([SIKE], 5.1) - KemSize: 24, - Bytelen: p751.P751_Bytelen, - Op: p751.FieldOperations(), - } - - sidhParams[FP_503] = p503 - sidhParams[FP_751] = p751 -} diff --git a/external/github.com/cloudflare/sidh/sidh/sidh.go b/external/github.com/cloudflare/sidh/sidh/sidh.go deleted file mode 100644 index a6f0cc435..000000000 --- a/external/github.com/cloudflare/sidh/sidh/sidh.go +++ /dev/null @@ -1,302 +0,0 @@ -package sidh - -import ( - . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny" -) - -// ----------------------------------------------------------------------------- -// Functions for traversing isogeny trees acoording to strategy. Key type 'A' is -// - -// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed -// for public key generation. -func traverseTreePublicKeyA(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) { - var points = make([]ProjectivePoint, 0, 8) - var indices = make([]int, 0, 8) - var i, sidx int - var op = CurveOperations{Params: pub.params} - - cparam := op.CalcCurveParamsEquiv4(curve) - phi := Newisogeny4(op.Params.Op) - strategy := pub.params.A.IsogenyStrategy - stratSz := len(strategy) - - for j := 1; j <= stratSz; j++ { - for i <= stratSz-j { - points = append(points, *xR) - indices = append(indices, i) - - k := strategy[sidx] - sidx++ - op.Pow2k(xR, &cparam, 2*k) - i += int(k) - } - - cparam = phi.GenerateCurve(xR) - for k := 0; k < len(points); k++ { - points[k] = phi.EvaluatePoint(&points[k]) - } - - *phiP = phi.EvaluatePoint(phiP) - *phiQ = phi.EvaluatePoint(phiQ) - *phiR = phi.EvaluatePoint(phiR) - - // pop xR from points - *xR, points = points[len(points)-1], points[:len(points)-1] - i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1] - } -} - -// Traverses isogeny tree in order to compute xR needed -// for public key generation. -func traverseTreeSharedKeyA(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) { - var points = make([]ProjectivePoint, 0, 8) - var indices = make([]int, 0, 8) - var i, sidx int - var op = CurveOperations{Params: pub.params} - - cparam := op.CalcCurveParamsEquiv4(curve) - phi := Newisogeny4(op.Params.Op) - strategy := pub.params.A.IsogenyStrategy - stratSz := len(strategy) - - for j := 1; j <= stratSz; j++ { - for i <= stratSz-j { - points = append(points, *xR) - indices = append(indices, i) - - k := strategy[sidx] - sidx++ - op.Pow2k(xR, &cparam, 2*k) - i += int(k) - } - - cparam = phi.GenerateCurve(xR) - for k := 0; k < len(points); k++ { - points[k] = phi.EvaluatePoint(&points[k]) - } - - // pop xR from points - *xR, points = points[len(points)-1], points[:len(points)-1] - i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1] - } -} - -// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed -// for public key generation. -func traverseTreePublicKeyB(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) { - var points = make([]ProjectivePoint, 0, 8) - var indices = make([]int, 0, 8) - var i, sidx int - var op = CurveOperations{Params: pub.params} - - cparam := op.CalcCurveParamsEquiv3(curve) - phi := Newisogeny3(op.Params.Op) - strategy := pub.params.B.IsogenyStrategy - stratSz := len(strategy) - - for j := 1; j <= stratSz; j++ { - for i <= stratSz-j { - points = append(points, *xR) - indices = append(indices, i) - - k := strategy[sidx] - sidx++ - op.Pow3k(xR, &cparam, k) - i += int(k) - } - - cparam = phi.GenerateCurve(xR) - for k := 0; k < len(points); k++ { - points[k] = phi.EvaluatePoint(&points[k]) - } - - *phiP = phi.EvaluatePoint(phiP) - *phiQ = phi.EvaluatePoint(phiQ) - *phiR = phi.EvaluatePoint(phiR) - - // pop xR from points - *xR, points = points[len(points)-1], points[:len(points)-1] - i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1] - } -} - -// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed -// for public key generation. -func traverseTreeSharedKeyB(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) { - var points = make([]ProjectivePoint, 0, 8) - var indices = make([]int, 0, 8) - var i, sidx int - var op = CurveOperations{Params: pub.params} - - cparam := op.CalcCurveParamsEquiv3(curve) - phi := Newisogeny3(op.Params.Op) - strategy := pub.params.B.IsogenyStrategy - stratSz := len(strategy) - - for j := 1; j <= stratSz; j++ { - for i <= stratSz-j { - points = append(points, *xR) - indices = append(indices, i) - - k := strategy[sidx] - sidx++ - op.Pow3k(xR, &cparam, k) - i += int(k) - } - - cparam = phi.GenerateCurve(xR) - for k := 0; k < len(points); k++ { - points[k] = phi.EvaluatePoint(&points[k]) - } - - // pop xR from points - *xR, points = points[len(points)-1], points[:len(points)-1] - i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1] - } -} - -// Generate a public key in the 2-torsion group -func publicKeyGenA(prv *PrivateKey) (pub *PublicKey) { - var xPA, xQA, xRA ProjectivePoint - var xPB, xQB, xRB, xR ProjectivePoint - var invZP, invZQ, invZR Fp2Element - var tmp ProjectiveCurveParameters - - pub = NewPublicKey(prv.params.Id, KeyVariant_SIDH_A) - var op = CurveOperations{Params: pub.params} - var phi = Newisogeny4(op.Params.Op) - - // Load points for A - xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2} - xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2} - xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2} - - // Load points for B - xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2} - xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2} - xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2} - - // Find isogeny kernel - tmp.C = pub.params.OneFp2 - xR = op.ScalarMul3Pt(&tmp, &xPA, &xQA, &xRA, prv.params.A.SecretBitLen, prv.Scalar) - - // Reset params object and travers isogeny tree - tmp.C = pub.params.OneFp2 - tmp.A.Zeroize() - traverseTreePublicKeyA(&tmp, &xR, &xPB, &xQB, &xRB, pub) - - // Secret isogeny - phi.GenerateCurve(&xR) - xPA = phi.EvaluatePoint(&xPB) - xQA = phi.EvaluatePoint(&xQB) - xRA = phi.EvaluatePoint(&xRB) - op.Fp2Batch3Inv(&xPA.Z, &xQA.Z, &xRA.Z, &invZP, &invZQ, &invZR) - - op.Params.Op.Mul(&pub.affine_xP, &xPA.X, &invZP) - op.Params.Op.Mul(&pub.affine_xQ, &xQA.X, &invZQ) - op.Params.Op.Mul(&pub.affine_xQmP, &xRA.X, &invZR) - return -} - -// Generate a public key in the 3-torsion group -func publicKeyGenB(prv *PrivateKey) (pub *PublicKey) { - var xPB, xQB, xRB, xR ProjectivePoint - var xPA, xQA, xRA ProjectivePoint - var invZP, invZQ, invZR Fp2Element - var tmp ProjectiveCurveParameters - - pub = NewPublicKey(prv.params.Id, prv.keyVariant) - var op = CurveOperations{Params: pub.params} - var phi = Newisogeny3(op.Params.Op) - - // Load points for B - xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2} - xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2} - xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2} - - // Load points for A - xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2} - xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2} - xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2} - - tmp.C = pub.params.OneFp2 - xR = op.ScalarMul3Pt(&tmp, &xPB, &xQB, &xRB, prv.params.B.SecretBitLen, prv.Scalar) - - tmp.C = pub.params.OneFp2 - tmp.A.Zeroize() - traverseTreePublicKeyB(&tmp, &xR, &xPA, &xQA, &xRA, pub) - - phi.GenerateCurve(&xR) - xPB = phi.EvaluatePoint(&xPA) - xQB = phi.EvaluatePoint(&xQA) - xRB = phi.EvaluatePoint(&xRA) - op.Fp2Batch3Inv(&xPB.Z, &xQB.Z, &xRB.Z, &invZP, &invZQ, &invZR) - - op.Params.Op.Mul(&pub.affine_xP, &xPB.X, &invZP) - op.Params.Op.Mul(&pub.affine_xQ, &xQB.X, &invZQ) - op.Params.Op.Mul(&pub.affine_xQmP, &xRB.X, &invZR) - return -} - -// ----------------------------------------------------------------------------- -// Key agreement functions -// - -// Establishing shared keys in in 2-torsion group -func deriveSecretA(prv *PrivateKey, pub *PublicKey) []byte { - var sharedSecret = make([]byte, pub.params.SharedSecretSize) - var cparam ProjectiveCurveParameters - var xP, xQ, xQmP ProjectivePoint - var xR ProjectivePoint - var op = CurveOperations{Params: prv.params} - var phi = Newisogeny4(op.Params.Op) - - // Recover curve coefficients - cparam.C = pub.params.OneFp2 - op.RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP) - - // Find kernel of the morphism - xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2} - xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2} - xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2} - xR = op.ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.A.SecretBitLen, prv.Scalar) - - // Traverse isogeny tree - traverseTreeSharedKeyA(&cparam, &xR, pub) - - // Calculate j-invariant on isogeneus curve - c := phi.GenerateCurve(&xR) - op.RecoverCurveCoefficients4(&cparam, &c) - op.Jinvariant(&cparam, sharedSecret) - return sharedSecret -} - -// Establishing shared keys in in 3-torsion group -func deriveSecretB(prv *PrivateKey, pub *PublicKey) []byte { - var sharedSecret = make([]byte, pub.params.SharedSecretSize) - var xP, xQ, xQmP ProjectivePoint - var xR ProjectivePoint - var cparam ProjectiveCurveParameters - var op = CurveOperations{Params: prv.params} - var phi = Newisogeny3(op.Params.Op) - - // Recover curve coefficients - cparam.C = pub.params.OneFp2 - op.RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP) - - // Find kernel of the morphism - xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2} - xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2} - xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2} - xR = op.ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.B.SecretBitLen, prv.Scalar) - - // Traverse isogeny tree - traverseTreeSharedKeyB(&cparam, &xR, pub) - - // Calculate j-invariant on isogeneus curve - c := phi.GenerateCurve(&xR) - op.RecoverCurveCoefficients3(&cparam, &c) - op.Jinvariant(&cparam, sharedSecret) - return sharedSecret -} diff --git a/external/github.com/lucas-clemente/quic-go/Changelog.md b/external/github.com/lucas-clemente/quic-go/Changelog.md deleted file mode 100644 index cbc88e73e..000000000 --- a/external/github.com/lucas-clemente/quic-go/Changelog.md +++ /dev/null @@ -1,44 +0,0 @@ -# Changelog - -## v0.10.0 (2018-08-28) - -- Add support for QUIC 44, drop support for QUIC 42. - -## v0.9.0 (2018-08-15) - -- Add a `quic.Config` option for the length of the connection ID (for IETF QUIC). -- Split Session.Close into one method for regular closing and one for closing with an error. - -## v0.8.0 (2018-06-26) - -- Add support for unidirectional streams (for IETF QUIC). -- Add a `quic.Config` option for the maximum number of incoming streams. -- Add support for QUIC 42 and 43. -- Add dial functions that use a context. -- Multiplex clients on a net.PacketConn, when using Dial(conn). - -## v0.7.0 (2018-02-03) - -- The lower boundary for packets included in ACKs is now derived, and the value sent in STOP_WAITING frames is ignored. -- Remove `DialNonFWSecure` and `DialAddrNonFWSecure`. -- Expose the `ConnectionState` in the `Session` (experimental API). -- Implement packet pacing. - -## v0.6.0 (2017-12-12) - -- Add support for QUIC 39, drop support for QUIC 35 - 37 -- Added `quic.Config` options for maximal flow control windows -- Add a `quic.Config` option for QUIC versions -- Add a `quic.Config` option to request omission of the connection ID from a server -- Add a `quic.Config` option to configure the source address validation -- Add a `quic.Config` option to configure the handshake timeout -- Add a `quic.Config` option to configure the idle timeout -- Add a `quic.Config` option to configure keep-alive -- Rename the STK to Cookie -- Implement `net.Conn`-style deadlines for streams -- Remove the `tls.Config` from the `quic.Config`. The `tls.Config` must now be passed to the `Dial` and `Listen` functions as a separate parameter. See the [Godoc](https://godoc.org/github.com/lucas-clemente/quic-go) for details. -- Changed the log level environment variable to only accept strings ("DEBUG", "INFO", "ERROR"), see [the wiki](https://github.com/lucas-clemente/quic-go/wiki/Logging) for more details. -- Rename the `h2quic.QuicRoundTripper` to `h2quic.RoundTripper` -- Changed `h2quic.Server.Serve()` to accept a `net.PacketConn` -- Drop support for Go 1.7 and 1.8. -- Various bugfixes diff --git a/external/github.com/lucas-clemente/quic-go/LICENSE b/external/github.com/lucas-clemente/quic-go/LICENSE deleted file mode 100644 index 51378befb..000000000 --- a/external/github.com/lucas-clemente/quic-go/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 the quic-go authors & Google, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/external/github.com/lucas-clemente/quic-go/README.md b/external/github.com/lucas-clemente/quic-go/README.md deleted file mode 100644 index ae1fa9cd2..000000000 --- a/external/github.com/lucas-clemente/quic-go/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# A QUIC implementation in pure Go - - - -[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/lucas-clemente/quic-go) -[![Travis Build Status](https://img.shields.io/travis/lucas-clemente/quic-go/master.svg?style=flat-square&label=Travis+build)](https://travis-ci.org/lucas-clemente/quic-go) -[![CircleCI Build Status](https://img.shields.io/circleci/project/github/lucas-clemente/quic-go.svg?style=flat-square&label=CircleCI+build)](https://circleci.com/gh/lucas-clemente/quic-go) -[![Windows Build Status](https://img.shields.io/appveyor/ci/lucas-clemente/quic-go/master.svg?style=flat-square&label=windows+build)](https://ci.appveyor.com/project/lucas-clemente/quic-go/branch/master) -[![Code Coverage](https://img.shields.io/codecov/c/github/lucas-clemente/quic-go/master.svg?style=flat-square)](https://codecov.io/gh/lucas-clemente/quic-go/) - -quic-go is an implementation of the [QUIC](https://en.wikipedia.org/wiki/QUIC) protocol in Go. It roughly implements the [IETF QUIC draft](https://github.com/quicwg/base-drafts), although we don't fully support any of the draft versions at the moment. - -## Version compatibility - -Since quic-go is under active development, there's no guarantee that two builds of different commits are interoperable. The QUIC version used in the *master* branch is just a placeholder, and should not be considered stable. - -If you want to use quic-go as a library in other projects, please consider using a [tagged release](https://github.com/lucas-clemente/quic-go/releases). These releases expose [experimental QUIC versions](https://github.com/quicwg/base-drafts/wiki/QUIC-Versions), which are guaranteed to be stable. - -## Google QUIC - -quic-go used to support both the QUIC versions supported by Google Chrome and QUIC as deployed on Google's servers, as well as IETF QUIC. Due to the divergence of the two protocols, we decided to not support both versions any more. - -The *master* branch **only** supports IETF QUIC. For Google QUIC support, please refer to the [gquic branch](https://github.com/lucas-clemente/quic-go/tree/gquic). - -## Guides - -We currently support Go 1.9+. - -Installing and updating dependencies: - - go get -t -u ./... - -Running tests: - - go test ./... - -### HTTP mapping - -We're currently not implementing the HTTP mapping as described in the [QUIC over HTTP draft](https://quicwg.org/base-drafts/draft-ietf-quic-http.html). The HTTP mapping here is a leftover from Google QUIC. - -### QUIC without HTTP/2 - -Take a look at [this echo example](example/echo/echo.go). - -## Usage - -### As a server - -See the [example server](example/main.go). Starting a QUIC server is very similar to the standard lib http in go: - -```go -http.Handle("/", http.FileServer(http.Dir(wwwDir))) -h2quic.ListenAndServeQUIC("localhost:4242", "/path/to/cert/chain.pem", "/path/to/privkey.pem", nil) -``` - -### As a client - -See the [example client](example/client/main.go). Use a `h2quic.RoundTripper` as a `Transport` in a `http.Client`. - -```go -http.Client{ - Transport: &h2quic.RoundTripper{}, -} -``` - -## Contributing - -We are always happy to welcome new contributors! We have a number of self-contained issues that are suitable for first-time contributors, they are tagged with [help wanted](https://github.com/lucas-clemente/quic-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). If you have any questions, please feel free to reach out by opening an issue or leaving a comment. diff --git a/external/github.com/lucas-clemente/quic-go/buffer_pool.go b/external/github.com/lucas-clemente/quic-go/buffer_pool.go deleted file mode 100644 index e196fae04..000000000 --- a/external/github.com/lucas-clemente/quic-go/buffer_pool.go +++ /dev/null @@ -1,56 +0,0 @@ -package quic - -import ( - "sync" - - "v2ray.com/core/common/bytespool" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -type packetBuffer struct { - Slice []byte - - // refCount counts how many packets the Slice is used in. - // It doesn't support concurrent use. - // It is > 1 when used for coalesced packet. - refCount int -} - -// Split increases the refCount. -// It must be called when a packet buffer is used for more than one packet, -// e.g. when splitting coalesced packets. -func (b *packetBuffer) Split() { - b.refCount++ -} - -// Release decreases the refCount. -// It should be called when processing the packet is finished. -// When the refCount reaches 0, the packet buffer is put back into the pool. -func (b *packetBuffer) Release() { - if cap(b.Slice) < 2048 { - return - } - b.refCount-- - if b.refCount < 0 { - panic("negative packetBuffer refCount") - } - // only put the packetBuffer back if it's not used any more - if b.refCount == 0 { - buffer := b.Slice[0:cap(b.Slice)] - bufferPool.Put(buffer) - } -} - -var bufferPool *sync.Pool - -func getPacketBuffer() *packetBuffer { - buffer := bufferPool.Get().([]byte) - return &packetBuffer{ - refCount: 1, - Slice: buffer[:protocol.MaxReceivePacketSize], - } -} - -func init() { - bufferPool = bytespool.GetPool(int32(protocol.MaxReceivePacketSize)) -} diff --git a/external/github.com/lucas-clemente/quic-go/client.go b/external/github.com/lucas-clemente/quic-go/client.go deleted file mode 100644 index 18391fd4f..000000000 --- a/external/github.com/lucas-clemente/quic-go/client.go +++ /dev/null @@ -1,443 +0,0 @@ -package quic - -import ( - "context" - "crypto/tls" - "fmt" - "net" - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/handshake" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type client struct { - mutex sync.Mutex - - conn connection - // If the client is created with DialAddr, we create a packet conn. - // If it is started with Dial, we take a packet conn as a parameter. - createdPacketConn bool - - packetHandlers packetHandlerManager - - token []byte - - versionNegotiated utils.AtomicBool // has the server accepted our version - receivedVersionNegotiationPacket bool - negotiatedVersions []protocol.VersionNumber // the list of versions from the version negotiation packet - - tlsConf *tls.Config - config *Config - - srcConnID protocol.ConnectionID - destConnID protocol.ConnectionID - origDestConnID protocol.ConnectionID // the destination conn ID used on the first Initial (before a Retry) - - initialPacketNumber protocol.PacketNumber - - initialVersion protocol.VersionNumber - version protocol.VersionNumber - - handshakeChan chan struct{} - - session quicSession - - logger utils.Logger -} - -var _ packetHandler = &client{} - -var ( - // make it possible to mock connection ID generation in the tests - generateConnectionID = protocol.GenerateConnectionID - generateConnectionIDForInitial = protocol.GenerateConnectionIDForInitial -) - -// DialAddr establishes a new QUIC connection to a server. -// It uses a new UDP connection and closes this connection when the QUIC session is closed. -// The hostname for SNI is taken from the given address. -func DialAddr( - addr string, - tlsConf *tls.Config, - config *Config, -) (Session, error) { - return DialAddrContext(context.Background(), addr, tlsConf, config) -} - -// DialAddrContext establishes a new QUIC connection to a server using the provided context. -// See DialAddr for details. -func DialAddrContext( - ctx context.Context, - addr string, - tlsConf *tls.Config, - config *Config, -) (Session, error) { - udpAddr, err := net.ResolveUDPAddr("udp", addr) - if err != nil { - return nil, err - } - udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) - if err != nil { - return nil, err - } - return dialContext(ctx, udpConn, udpAddr, addr, tlsConf, config, true) -} - -// Dial establishes a new QUIC connection to a server using a net.PacketConn. -// The same PacketConn can be used for multiple calls to Dial and Listen, -// QUIC connection IDs are used for demultiplexing the different connections. -// The host parameter is used for SNI. -func Dial( - pconn net.PacketConn, - remoteAddr net.Addr, - host string, - tlsConf *tls.Config, - config *Config, -) (Session, error) { - return DialContext(context.Background(), pconn, remoteAddr, host, tlsConf, config) -} - -// DialContext establishes a new QUIC connection to a server using a net.PacketConn using the provided context. -// See Dial for details. -func DialContext( - ctx context.Context, - pconn net.PacketConn, - remoteAddr net.Addr, - host string, - tlsConf *tls.Config, - config *Config, -) (Session, error) { - return dialContext(ctx, pconn, remoteAddr, host, tlsConf, config, false) -} - -func dialContext( - ctx context.Context, - pconn net.PacketConn, - remoteAddr net.Addr, - host string, - tlsConf *tls.Config, - config *Config, - createdPacketConn bool, -) (Session, error) { - config = populateClientConfig(config, createdPacketConn) - packetHandlers, err := getMultiplexer().AddConn(pconn, config.ConnectionIDLength) - if err != nil { - return nil, err - } - c, err := newClient(pconn, remoteAddr, config, tlsConf, host, createdPacketConn) - if err != nil { - return nil, err - } - c.packetHandlers = packetHandlers - if err := c.dial(ctx); err != nil { - return nil, err - } - return c.session, nil -} - -func newClient( - pconn net.PacketConn, - remoteAddr net.Addr, - config *Config, - tlsConf *tls.Config, - host string, - createdPacketConn bool, -) (*client, error) { - if tlsConf == nil { - tlsConf = &tls.Config{} - } - if tlsConf.ServerName == "" { - var err error - tlsConf.ServerName, _, err = net.SplitHostPort(host) - if err != nil { - return nil, err - } - } - - // check that all versions are actually supported - if config != nil { - for _, v := range config.Versions { - if !protocol.IsValidVersion(v) { - return nil, fmt.Errorf("%s is not a valid QUIC version", v) - } - } - } - - srcConnID, err := generateConnectionID(config.ConnectionIDLength) - if err != nil { - return nil, err - } - destConnID, err := generateConnectionIDForInitial() - if err != nil { - return nil, err - } - c := &client{ - srcConnID: srcConnID, - destConnID: destConnID, - conn: &conn{pconn: pconn, currentAddr: remoteAddr}, - createdPacketConn: createdPacketConn, - tlsConf: tlsConf, - config: config, - version: config.Versions[0], - handshakeChan: make(chan struct{}), - logger: utils.DefaultLogger.WithPrefix("client"), - } - return c, nil -} - -// populateClientConfig populates fields in the quic.Config with their default values, if none are set -// it may be called with nil -func populateClientConfig(config *Config, createdPacketConn bool) *Config { - if config == nil { - config = &Config{} - } - versions := config.Versions - if len(versions) == 0 { - versions = protocol.SupportedVersions - } - - handshakeTimeout := protocol.DefaultHandshakeTimeout - if config.HandshakeTimeout != 0 { - handshakeTimeout = config.HandshakeTimeout - } - idleTimeout := protocol.DefaultIdleTimeout - if config.IdleTimeout != 0 { - idleTimeout = config.IdleTimeout - } - - maxReceiveStreamFlowControlWindow := config.MaxReceiveStreamFlowControlWindow - if maxReceiveStreamFlowControlWindow == 0 { - maxReceiveStreamFlowControlWindow = protocol.DefaultMaxReceiveStreamFlowControlWindow - } - maxReceiveConnectionFlowControlWindow := config.MaxReceiveConnectionFlowControlWindow - if maxReceiveConnectionFlowControlWindow == 0 { - maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindow - } - maxIncomingStreams := config.MaxIncomingStreams - if maxIncomingStreams == 0 { - maxIncomingStreams = protocol.DefaultMaxIncomingStreams - } else if maxIncomingStreams < 0 { - maxIncomingStreams = 0 - } - maxIncomingUniStreams := config.MaxIncomingUniStreams - if maxIncomingUniStreams == 0 { - maxIncomingUniStreams = protocol.DefaultMaxIncomingUniStreams - } else if maxIncomingUniStreams < 0 { - maxIncomingUniStreams = 0 - } - connIDLen := config.ConnectionIDLength - if connIDLen == 0 && !createdPacketConn { - connIDLen = protocol.DefaultConnectionIDLength - } - - return &Config{ - Versions: versions, - HandshakeTimeout: handshakeTimeout, - IdleTimeout: idleTimeout, - ConnectionIDLength: connIDLen, - MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow, - MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow, - MaxIncomingStreams: maxIncomingStreams, - MaxIncomingUniStreams: maxIncomingUniStreams, - KeepAlive: config.KeepAlive, - } -} - -func (c *client) dial(ctx context.Context) error { - c.logger.Infof("Starting new connection to %s (%s -> %s), source connection ID %s, destination connection ID %s, version %s", c.tlsConf.ServerName, c.conn.LocalAddr(), c.conn.RemoteAddr(), c.srcConnID, c.destConnID, c.version) - - if err := c.createNewTLSSession(c.version); err != nil { - return err - } - err := c.establishSecureConnection(ctx) - if err == errCloseForRecreating { - return c.dial(ctx) - } - return err -} - -// establishSecureConnection runs the session, and tries to establish a secure connection -// It returns: -// - errCloseSessionRecreating when the server sends a version negotiation packet, or a stateless retry is performed -// - any other error that might occur -// - when the connection is forward-secure -func (c *client) establishSecureConnection(ctx context.Context) error { - errorChan := make(chan error, 1) - - go func() { - err := c.session.run() // returns as soon as the session is closed - if err != errCloseForRecreating && c.createdPacketConn { - c.conn.Close() - } - errorChan <- err - }() - - select { - case <-ctx.Done(): - // The session will send a PeerGoingAway error to the server. - c.session.Close() - return ctx.Err() - case err := <-errorChan: - return err - case <-c.handshakeChan: - // handshake successfully completed - return nil - } -} - -func (c *client) handlePacket(p *receivedPacket) { - if p.hdr.IsVersionNegotiation() { - go c.handleVersionNegotiationPacket(p.hdr) - return - } - - if p.hdr.Type == protocol.PacketTypeRetry { - go c.handleRetryPacket(p.hdr) - return - } - - // this is the first packet we are receiving - // since it is not a Version Negotiation Packet, this means the server supports the suggested version - if !c.versionNegotiated.Get() { - c.versionNegotiated.Set(true) - } - - c.session.handlePacket(p) -} - -func (c *client) handleVersionNegotiationPacket(hdr *wire.Header) { - c.mutex.Lock() - defer c.mutex.Unlock() - - // ignore delayed / duplicated version negotiation packets - if c.receivedVersionNegotiationPacket || c.versionNegotiated.Get() { - c.logger.Debugf("Received a delayed Version Negotiation packet.") - return - } - - for _, v := range hdr.SupportedVersions { - if v == c.version { - // The Version Negotiation packet contains the version that we offered. - // This might be a packet sent by an attacker (or by a terribly broken server implementation). - return - } - } - - c.logger.Infof("Received a Version Negotiation packet. Supported Versions: %s", hdr.SupportedVersions) - newVersion, ok := protocol.ChooseSupportedVersion(c.config.Versions, hdr.SupportedVersions) - if !ok { - c.session.destroy(qerr.InvalidVersion) - c.logger.Debugf("No compatible version found.") - return - } - c.receivedVersionNegotiationPacket = true - c.negotiatedVersions = hdr.SupportedVersions - - // switch to negotiated version - c.initialVersion = c.version - c.version = newVersion - - c.logger.Infof("Switching to QUIC version %s. New connection ID: %s", newVersion, c.destConnID) - c.initialPacketNumber = c.session.closeForRecreating() -} - -func (c *client) handleRetryPacket(hdr *wire.Header) { - c.mutex.Lock() - defer c.mutex.Unlock() - - c.logger.Debugf("<- Received Retry") - (&wire.ExtendedHeader{Header: *hdr}).Log(c.logger) - if !hdr.OrigDestConnectionID.Equal(c.destConnID) { - c.logger.Debugf("Ignoring spoofed Retry. Original Destination Connection ID: %s, expected: %s", hdr.OrigDestConnectionID, c.destConnID) - return - } - if hdr.SrcConnectionID.Equal(c.destConnID) { - c.logger.Debugf("Ignoring Retry, since the server didn't change the Source Connection ID.") - return - } - // If a token is already set, this means that we already received a Retry from the server. - // Ignore this Retry packet. - if len(c.token) > 0 { - c.logger.Debugf("Ignoring Retry, since a Retry was already received.") - return - } - c.origDestConnID = c.destConnID - c.destConnID = hdr.SrcConnectionID - c.token = hdr.Token - c.initialPacketNumber = c.session.closeForRecreating() -} - -func (c *client) createNewTLSSession(version protocol.VersionNumber) error { - params := &handshake.TransportParameters{ - InitialMaxStreamDataBidiRemote: protocol.InitialMaxStreamData, - InitialMaxStreamDataBidiLocal: protocol.InitialMaxStreamData, - InitialMaxStreamDataUni: protocol.InitialMaxStreamData, - InitialMaxData: protocol.InitialMaxData, - IdleTimeout: c.config.IdleTimeout, - MaxBidiStreams: uint64(c.config.MaxIncomingStreams), - MaxUniStreams: uint64(c.config.MaxIncomingUniStreams), - DisableMigration: true, - } - - c.mutex.Lock() - defer c.mutex.Unlock() - runner := &runner{ - onHandshakeCompleteImpl: func(_ Session) { close(c.handshakeChan) }, - retireConnectionIDImpl: c.packetHandlers.Retire, - removeConnectionIDImpl: c.packetHandlers.Remove, - } - sess, err := newClientSession( - c.conn, - runner, - c.token, - c.origDestConnID, - c.destConnID, - c.srcConnID, - c.config, - c.tlsConf, - c.initialPacketNumber, - params, - c.initialVersion, - c.logger, - c.version, - ) - if err != nil { - return err - } - c.session = sess - c.packetHandlers.Add(c.srcConnID, c) - return nil -} - -func (c *client) Close() error { - c.mutex.Lock() - defer c.mutex.Unlock() - if c.session == nil { - return nil - } - return c.session.Close() -} - -func (c *client) destroy(e error) { - c.mutex.Lock() - defer c.mutex.Unlock() - if c.session == nil { - return - } - c.session.destroy(e) -} - -func (c *client) GetVersion() protocol.VersionNumber { - c.mutex.Lock() - v := c.version - c.mutex.Unlock() - return v -} - -func (c *client) GetPerspective() protocol.Perspective { - return protocol.PerspectiveClient -} diff --git a/external/github.com/lucas-clemente/quic-go/conn.go b/external/github.com/lucas-clemente/quic-go/conn.go deleted file mode 100644 index 700c1471c..000000000 --- a/external/github.com/lucas-clemente/quic-go/conn.go +++ /dev/null @@ -1,54 +0,0 @@ -package quic - -import ( - "net" - "sync" -) - -type connection interface { - Write([]byte) error - Read([]byte) (int, net.Addr, error) - Close() error - LocalAddr() net.Addr - RemoteAddr() net.Addr - SetCurrentRemoteAddr(net.Addr) -} - -type conn struct { - mutex sync.RWMutex - - pconn net.PacketConn - currentAddr net.Addr -} - -var _ connection = &conn{} - -func (c *conn) Write(p []byte) error { - _, err := c.pconn.WriteTo(p, c.currentAddr) - return err -} - -func (c *conn) Read(p []byte) (int, net.Addr, error) { - return c.pconn.ReadFrom(p) -} - -func (c *conn) SetCurrentRemoteAddr(addr net.Addr) { - c.mutex.Lock() - c.currentAddr = addr - c.mutex.Unlock() -} - -func (c *conn) LocalAddr() net.Addr { - return c.pconn.LocalAddr() -} - -func (c *conn) RemoteAddr() net.Addr { - c.mutex.RLock() - addr := c.currentAddr - c.mutex.RUnlock() - return addr -} - -func (c *conn) Close() error { - return c.pconn.Close() -} diff --git a/external/github.com/lucas-clemente/quic-go/crypto_stream.go b/external/github.com/lucas-clemente/quic-go/crypto_stream.go deleted file mode 100644 index 806347f7d..000000000 --- a/external/github.com/lucas-clemente/quic-go/crypto_stream.go +++ /dev/null @@ -1,108 +0,0 @@ -package quic - -import ( - "errors" - "fmt" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type cryptoStream interface { - // for receiving data - HandleCryptoFrame(*wire.CryptoFrame) error - GetCryptoData() []byte - Finish() error - // for sending data - io.Writer - HasData() bool - PopCryptoFrame(protocol.ByteCount) *wire.CryptoFrame -} - -type cryptoStreamImpl struct { - queue *frameSorter - msgBuf []byte - - highestOffset protocol.ByteCount - finished bool - - writeOffset protocol.ByteCount - writeBuf []byte -} - -func newCryptoStream() cryptoStream { - return &cryptoStreamImpl{ - queue: newFrameSorter(), - } -} - -func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error { - highestOffset := f.Offset + protocol.ByteCount(len(f.Data)) - if maxOffset := highestOffset; maxOffset > protocol.MaxCryptoStreamOffset { - return fmt.Errorf("received invalid offset %d on crypto stream, maximum allowed %d", maxOffset, protocol.MaxCryptoStreamOffset) - } - if s.finished { - if highestOffset > s.highestOffset { - // reject crypto data received after this stream was already finished - return errors.New("received crypto data after change of encryption level") - } - // ignore data with a smaller offset than the highest received - // could e.g. be a retransmission - return nil - } - s.highestOffset = utils.MaxByteCount(s.highestOffset, highestOffset) - if err := s.queue.Push(f.Data, f.Offset, false); err != nil { - return err - } - for { - data, _ := s.queue.Pop() - if data == nil { - return nil - } - s.msgBuf = append(s.msgBuf, data...) - } -} - -// GetCryptoData retrieves data that was received in CRYPTO frames -func (s *cryptoStreamImpl) GetCryptoData() []byte { - if len(s.msgBuf) < 4 { - return nil - } - msgLen := 4 + int(s.msgBuf[1])<<16 + int(s.msgBuf[2])<<8 + int(s.msgBuf[3]) - if len(s.msgBuf) < msgLen { - return nil - } - msg := make([]byte, msgLen) - copy(msg, s.msgBuf[:msgLen]) - s.msgBuf = s.msgBuf[msgLen:] - return msg -} - -func (s *cryptoStreamImpl) Finish() error { - if s.queue.HasMoreData() { - return errors.New("encryption level changed, but crypto stream has more data to read") - } - s.finished = true - return nil -} - -// Writes writes data that should be sent out in CRYPTO frames -func (s *cryptoStreamImpl) Write(p []byte) (int, error) { - s.writeBuf = append(s.writeBuf, p...) - return len(p), nil -} - -func (s *cryptoStreamImpl) HasData() bool { - return len(s.writeBuf) > 0 -} - -func (s *cryptoStreamImpl) PopCryptoFrame(maxLen protocol.ByteCount) *wire.CryptoFrame { - f := &wire.CryptoFrame{Offset: s.writeOffset} - n := utils.MinByteCount(f.MaxDataLen(maxLen), protocol.ByteCount(len(s.writeBuf))) - f.Data = s.writeBuf[:n] - s.writeBuf = s.writeBuf[n:] - s.writeOffset += n - return f -} diff --git a/external/github.com/lucas-clemente/quic-go/crypto_stream_manager.go b/external/github.com/lucas-clemente/quic-go/crypto_stream_manager.go deleted file mode 100644 index 526c98aa4..000000000 --- a/external/github.com/lucas-clemente/quic-go/crypto_stream_manager.go +++ /dev/null @@ -1,55 +0,0 @@ -package quic - -import ( - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type cryptoDataHandler interface { - HandleMessage([]byte, protocol.EncryptionLevel) bool -} - -type cryptoStreamManager struct { - cryptoHandler cryptoDataHandler - - initialStream cryptoStream - handshakeStream cryptoStream -} - -func newCryptoStreamManager( - cryptoHandler cryptoDataHandler, - initialStream cryptoStream, - handshakeStream cryptoStream, -) *cryptoStreamManager { - return &cryptoStreamManager{ - cryptoHandler: cryptoHandler, - initialStream: initialStream, - handshakeStream: handshakeStream, - } -} - -func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) (bool /* encryption level changed */, error) { - var str cryptoStream - switch encLevel { - case protocol.EncryptionInitial: - str = m.initialStream - case protocol.EncryptionHandshake: - str = m.handshakeStream - default: - return false, fmt.Errorf("received CRYPTO frame with unexpected encryption level: %s", encLevel) - } - if err := str.HandleCryptoFrame(frame); err != nil { - return false, err - } - for { - data := str.GetCryptoData() - if data == nil { - return false, nil - } - if encLevelFinished := m.cryptoHandler.HandleMessage(data, encLevel); encLevelFinished { - return true, str.Finish() - } - } -} diff --git a/external/github.com/lucas-clemente/quic-go/frame_sorter.go b/external/github.com/lucas-clemente/quic-go/frame_sorter.go deleted file mode 100644 index 087265e2e..000000000 --- a/external/github.com/lucas-clemente/quic-go/frame_sorter.go +++ /dev/null @@ -1,163 +0,0 @@ -package quic - -import ( - "errors" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -type frameSorter struct { - queue map[protocol.ByteCount][]byte - readPos protocol.ByteCount - finalOffset protocol.ByteCount - gaps *utils.ByteIntervalList -} - -var errDuplicateStreamData = errors.New("Duplicate Stream Data") - -func newFrameSorter() *frameSorter { - s := frameSorter{ - gaps: utils.NewByteIntervalList(), - queue: make(map[protocol.ByteCount][]byte), - finalOffset: protocol.MaxByteCount, - } - s.gaps.PushFront(utils.ByteInterval{Start: 0, End: protocol.MaxByteCount}) - return &s -} - -func (s *frameSorter) Push(data []byte, offset protocol.ByteCount, fin bool) error { - err := s.push(data, offset, fin) - if err == errDuplicateStreamData { - return nil - } - return err -} - -func (s *frameSorter) push(data []byte, offset protocol.ByteCount, fin bool) error { - if fin { - s.finalOffset = offset + protocol.ByteCount(len(data)) - } - if len(data) == 0 { - return nil - } - - var wasCut bool - if oldData, ok := s.queue[offset]; ok { - if len(data) <= len(oldData) { - return errDuplicateStreamData - } - data = data[len(oldData):] - offset += protocol.ByteCount(len(oldData)) - wasCut = true - } - - start := offset - end := offset + protocol.ByteCount(len(data)) - - // skip all gaps that are before this stream frame - var gap *utils.ByteIntervalElement - for gap = s.gaps.Front(); gap != nil; gap = gap.Next() { - // the frame is a duplicate. Ignore it - if end <= gap.Value.Start { - return errDuplicateStreamData - } - if end > gap.Value.Start && start <= gap.Value.End { - break - } - } - - if gap == nil { - return errors.New("StreamFrameSorter BUG: no gap found") - } - - if start < gap.Value.Start { - add := gap.Value.Start - start - offset += add - start += add - data = data[add:] - wasCut = true - } - - // find the highest gaps whose Start lies before the end of the frame - endGap := gap - for end >= endGap.Value.End { - nextEndGap := endGap.Next() - if nextEndGap == nil { - return errors.New("StreamFrameSorter BUG: no end gap found") - } - if endGap != gap { - s.gaps.Remove(endGap) - } - if end <= nextEndGap.Value.Start { - break - } - // delete queued frames completely covered by the current frame - delete(s.queue, endGap.Value.End) - endGap = nextEndGap - } - - if end > endGap.Value.End { - cutLen := end - endGap.Value.End - len := protocol.ByteCount(len(data)) - cutLen - end -= cutLen - data = data[:len] - wasCut = true - } - - if start == gap.Value.Start { - if end >= gap.Value.End { - // the frame completely fills this gap - // delete the gap - s.gaps.Remove(gap) - } - if end < endGap.Value.End { - // the frame covers the beginning of the gap - // adjust the Start value to shrink the gap - endGap.Value.Start = end - } - } else if end == endGap.Value.End { - // the frame covers the end of the gap - // adjust the End value to shrink the gap - gap.Value.End = start - } else { - if gap == endGap { - // the frame lies within the current gap, splitting it into two - // insert a new gap and adjust the current one - intv := utils.ByteInterval{Start: end, End: gap.Value.End} - s.gaps.InsertAfter(intv, gap) - gap.Value.End = start - } else { - gap.Value.End = start - endGap.Value.Start = end - } - } - - if s.gaps.Len() > protocol.MaxStreamFrameSorterGaps { - return errors.New("Too many gaps in received data") - } - - if wasCut { - newData := make([]byte, len(data)) - copy(newData, data) - data = newData - } - - s.queue[offset] = data - return nil -} - -func (s *frameSorter) Pop() ([]byte /* data */, bool /* fin */) { - data, ok := s.queue[s.readPos] - if !ok { - return nil, s.readPos >= s.finalOffset - } - delete(s.queue, s.readPos) - s.readPos += protocol.ByteCount(len(data)) - return data, s.readPos >= s.finalOffset -} - -// HasMoreData says if there is any more data queued at *any* offset. -func (s *frameSorter) HasMoreData() bool { - return len(s.queue) > 0 -} diff --git a/external/github.com/lucas-clemente/quic-go/framer.go b/external/github.com/lucas-clemente/quic-go/framer.go deleted file mode 100644 index 88b14ad91..000000000 --- a/external/github.com/lucas-clemente/quic-go/framer.go +++ /dev/null @@ -1,109 +0,0 @@ -package quic - -import ( - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type framer interface { - QueueControlFrame(wire.Frame) - AppendControlFrames([]wire.Frame, protocol.ByteCount) ([]wire.Frame, protocol.ByteCount) - - AddActiveStream(protocol.StreamID) - AppendStreamFrames([]wire.Frame, protocol.ByteCount) []wire.Frame -} - -type framerI struct { - mutex sync.Mutex - - streamGetter streamGetter - version protocol.VersionNumber - - activeStreams map[protocol.StreamID]struct{} - streamQueue []protocol.StreamID - - controlFrameMutex sync.Mutex - controlFrames []wire.Frame -} - -var _ framer = &framerI{} - -func newFramer( - streamGetter streamGetter, - v protocol.VersionNumber, -) framer { - return &framerI{ - streamGetter: streamGetter, - activeStreams: make(map[protocol.StreamID]struct{}), - version: v, - } -} - -func (f *framerI) QueueControlFrame(frame wire.Frame) { - f.controlFrameMutex.Lock() - f.controlFrames = append(f.controlFrames, frame) - f.controlFrameMutex.Unlock() -} - -func (f *framerI) AppendControlFrames(frames []wire.Frame, maxLen protocol.ByteCount) ([]wire.Frame, protocol.ByteCount) { - var length protocol.ByteCount - f.controlFrameMutex.Lock() - for len(f.controlFrames) > 0 { - frame := f.controlFrames[len(f.controlFrames)-1] - frameLen := frame.Length(f.version) - if length+frameLen > maxLen { - break - } - frames = append(frames, frame) - length += frameLen - f.controlFrames = f.controlFrames[:len(f.controlFrames)-1] - } - f.controlFrameMutex.Unlock() - return frames, length -} - -func (f *framerI) AddActiveStream(id protocol.StreamID) { - f.mutex.Lock() - if _, ok := f.activeStreams[id]; !ok { - f.streamQueue = append(f.streamQueue, id) - f.activeStreams[id] = struct{}{} - } - f.mutex.Unlock() -} - -func (f *framerI) AppendStreamFrames(frames []wire.Frame, maxLen protocol.ByteCount) []wire.Frame { - var length protocol.ByteCount - f.mutex.Lock() - // pop STREAM frames, until less than MinStreamFrameSize bytes are left in the packet - numActiveStreams := len(f.streamQueue) - for i := 0; i < numActiveStreams; i++ { - if maxLen-length < protocol.MinStreamFrameSize { - break - } - id := f.streamQueue[0] - f.streamQueue = f.streamQueue[1:] - // This should never return an error. Better check it anyway. - // The stream will only be in the streamQueue, if it enqueued itself there. - str, err := f.streamGetter.GetOrOpenSendStream(id) - // The stream can be nil if it completed after it said it had data. - if str == nil || err != nil { - delete(f.activeStreams, id) - continue - } - frame, hasMoreData := str.popStreamFrame(maxLen - length) - if hasMoreData { // put the stream back in the queue (at the end) - f.streamQueue = append(f.streamQueue, id) - } else { // no more data to send. Stream is not active any more - delete(f.activeStreams, id) - } - if frame == nil { // can happen if the receiveStream was canceled after it said it had data - continue - } - frames = append(frames, frame) - length += frame.Length(f.version) - } - f.mutex.Unlock() - return frames -} diff --git a/external/github.com/lucas-clemente/quic-go/interface.go b/external/github.com/lucas-clemente/quic-go/interface.go deleted file mode 100644 index 5b52e8366..000000000 --- a/external/github.com/lucas-clemente/quic-go/interface.go +++ /dev/null @@ -1,214 +0,0 @@ -package quic - -import ( - "context" - "io" - "net" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/handshake" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// The StreamID is the ID of a QUIC stream. -type StreamID = protocol.StreamID - -// A VersionNumber is a QUIC version number. -type VersionNumber = protocol.VersionNumber - -// A Cookie can be used to verify the ownership of the client address. -type Cookie struct { - RemoteAddr string - SentTime time.Time -} - -// ConnectionState records basic details about the QUIC connection. -type ConnectionState = handshake.ConnectionState - -// An ErrorCode is an application-defined error code. -type ErrorCode = protocol.ApplicationErrorCode - -// Stream is the interface implemented by QUIC streams -type Stream interface { - // StreamID returns the stream ID. - StreamID() StreamID - // Read reads data from the stream. - // Read can be made to time out and return a net.Error with Timeout() == true - // after a fixed time limit; see SetDeadline and SetReadDeadline. - // If the stream was canceled by the peer, the error implements the StreamError - // interface, and Canceled() == true. - io.Reader - // Write writes data to the stream. - // Write can be made to time out and return a net.Error with Timeout() == true - // after a fixed time limit; see SetDeadline and SetWriteDeadline. - // If the stream was canceled by the peer, the error implements the StreamError - // interface, and Canceled() == true. - io.Writer - // Close closes the write-direction of the stream. - // Future calls to Write are not permitted after calling Close. - // It must not be called concurrently with Write. - // It must not be called after calling CancelWrite. - io.Closer - // CancelWrite aborts sending on this stream. - // It must not be called after Close. - // Data already written, but not yet delivered to the peer is not guaranteed to be delivered reliably. - // Write will unblock immediately, and future calls to Write will fail. - CancelWrite(ErrorCode) error - // CancelRead aborts receiving on this stream. - // It will ask the peer to stop transmitting stream data. - // Read will unblock immediately, and future Read calls will fail. - CancelRead(ErrorCode) error - // The context is canceled as soon as the write-side of the stream is closed. - // This happens when Close() is called, or when the stream is reset (either locally or remotely). - // Warning: This API should not be considered stable and might change soon. - Context() context.Context - // SetReadDeadline sets the deadline for future Read calls and - // any currently-blocked Read call. - // A zero value for t means Read will not time out. - SetReadDeadline(t time.Time) error - // SetWriteDeadline sets the deadline for future Write calls - // and any currently-blocked Write call. - // Even if write times out, it may return n > 0, indicating that - // some of the data was successfully written. - // A zero value for t means Write will not time out. - SetWriteDeadline(t time.Time) error - // SetDeadline sets the read and write deadlines associated - // with the connection. It is equivalent to calling both - // SetReadDeadline and SetWriteDeadline. - SetDeadline(t time.Time) error - - HasMoreData() bool -} - -// A ReceiveStream is a unidirectional Receive Stream. -type ReceiveStream interface { - // see Stream.StreamID - StreamID() StreamID - // see Stream.Read - io.Reader - // see Stream.CancelRead - CancelRead(ErrorCode) error - // see Stream.SetReadDealine - SetReadDeadline(t time.Time) error - - HasMoreData() bool -} - -// A SendStream is a unidirectional Send Stream. -type SendStream interface { - // see Stream.StreamID - StreamID() StreamID - // see Stream.Write - io.Writer - // see Stream.Close - io.Closer - // see Stream.CancelWrite - CancelWrite(ErrorCode) error - // see Stream.Context - Context() context.Context - // see Stream.SetWriteDeadline - SetWriteDeadline(t time.Time) error -} - -// StreamError is returned by Read and Write when the peer cancels the stream. -type StreamError interface { - error - Canceled() bool - ErrorCode() ErrorCode -} - -// A Session is a QUIC connection between two peers. -type Session interface { - // AcceptStream returns the next stream opened by the peer, blocking until one is available. - AcceptStream() (Stream, error) - // AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available. - AcceptUniStream() (ReceiveStream, error) - // OpenStream opens a new bidirectional QUIC stream. - // There is no signaling to the peer about new streams: - // The peer can only accept the stream after data has been sent on the stream. - // If the error is non-nil, it satisfies the net.Error interface. - // When reaching the peer's stream limit, err.Temporary() will be true. - OpenStream() (Stream, error) - // OpenStreamSync opens a new bidirectional QUIC stream. - // It blocks until a new stream can be opened. - // If the error is non-nil, it satisfies the net.Error interface. - OpenStreamSync() (Stream, error) - // OpenUniStream opens a new outgoing unidirectional QUIC stream. - // If the error is non-nil, it satisfies the net.Error interface. - // When reaching the peer's stream limit, Temporary() will be true. - OpenUniStream() (SendStream, error) - // OpenUniStreamSync opens a new outgoing unidirectional QUIC stream. - // It blocks until a new stream can be opened. - // If the error is non-nil, it satisfies the net.Error interface. - OpenUniStreamSync() (SendStream, error) - // LocalAddr returns the local address. - LocalAddr() net.Addr - // RemoteAddr returns the address of the peer. - RemoteAddr() net.Addr - // Close the connection. - io.Closer - // Close the connection with an error. - // The error must not be nil. - CloseWithError(ErrorCode, error) error - // The context is cancelled when the session is closed. - // Warning: This API should not be considered stable and might change soon. - Context() context.Context - // ConnectionState returns basic details about the QUIC connection. - // Warning: This API should not be considered stable and might change soon. - ConnectionState() ConnectionState -} - -// Config contains all configuration data needed for a QUIC server or client. -type Config struct { - // The QUIC versions that can be negotiated. - // If not set, it uses all versions available. - // Warning: This API should not be considered stable and will change soon. - Versions []VersionNumber - // The length of the connection ID in bytes. - // It can be 0, or any value between 4 and 18. - // If not set, the interpretation depends on where the Config is used: - // If used for dialing an address, a 0 byte connection ID will be used. - // If used for a server, or dialing on a packet conn, a 4 byte connection ID will be used. - // When dialing on a packet conn, the ConnectionIDLength value must be the same for every Dial call. - ConnectionIDLength int - // HandshakeTimeout is the maximum duration that the cryptographic handshake may take. - // If the timeout is exceeded, the connection is closed. - // If this value is zero, the timeout is set to 10 seconds. - HandshakeTimeout time.Duration - // IdleTimeout is the maximum duration that may pass without any incoming network activity. - // This value only applies after the handshake has completed. - // If the timeout is exceeded, the connection is closed. - // If this value is zero, the timeout is set to 30 seconds. - IdleTimeout time.Duration - // AcceptCookie determines if a Cookie is accepted. - // It is called with cookie = nil if the client didn't send an Cookie. - // If not set, it verifies that the address matches, and that the Cookie was issued within the last 24 hours. - // This option is only valid for the server. - AcceptCookie func(clientAddr net.Addr, cookie *Cookie) bool - // MaxReceiveStreamFlowControlWindow is the maximum stream-level flow control window for receiving data. - // If this value is zero, it will default to 1 MB for the server and 6 MB for the client. - MaxReceiveStreamFlowControlWindow uint64 - // MaxReceiveConnectionFlowControlWindow is the connection-level flow control window for receiving data. - // If this value is zero, it will default to 1.5 MB for the server and 15 MB for the client. - MaxReceiveConnectionFlowControlWindow uint64 - // MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open. - // If not set, it will default to 100. - // If set to a negative value, it doesn't allow any bidirectional streams. - MaxIncomingStreams int - // MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open. - // If not set, it will default to 100. - // If set to a negative value, it doesn't allow any unidirectional streams. - MaxIncomingUniStreams int - // KeepAlive defines whether this peer will periodically send PING frames to keep the connection alive. - KeepAlive bool -} - -// A Listener for incoming QUIC connections -type Listener interface { - // Close the server, sending CONNECTION_CLOSE frames to each peer. - Close() error - // Addr returns the local network addr that the server is listening on. - Addr() net.Addr - // Accept returns new sessions. It should be called in a loop. - Accept() (Session, error) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/gen.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/gen.go deleted file mode 100644 index 32235f81a..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/gen.go +++ /dev/null @@ -1,3 +0,0 @@ -package ackhandler - -//go:generate genny -pkg ackhandler -in ../utils/linkedlist/linkedlist.go -out packet_linkedlist.go gen Item=Packet diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/interfaces.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/interfaces.go deleted file mode 100644 index b839cba1a..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/interfaces.go +++ /dev/null @@ -1,49 +0,0 @@ -package ackhandler - -import ( - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -// SentPacketHandler handles ACKs received for outgoing packets -type SentPacketHandler interface { - // SentPacket may modify the packet - SentPacket(packet *Packet) - SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) - ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, recvTime time.Time) error - SetHandshakeComplete() - - // The SendMode determines if and what kind of packets can be sent. - SendMode() SendMode - // TimeUntilSend is the time when the next packet should be sent. - // It is used for pacing packets. - TimeUntilSend() time.Time - // ShouldSendNumPackets returns the number of packets that should be sent immediately. - // It always returns a number greater or equal than 1. - // A number greater than 1 is returned when the pacing delay is smaller than the minimum pacing delay. - // Note that the number of packets is only calculated based on the pacing algorithm. - // Before sending any packet, SendingAllowed() must be called to learn if we can actually send it. - ShouldSendNumPackets() int - - // only to be called once the handshake is complete - GetLowestPacketNotConfirmedAcked() protocol.PacketNumber - DequeuePacketForRetransmission() *Packet - DequeueProbePacket() (*Packet, error) - - PeekPacketNumber() (protocol.PacketNumber, protocol.PacketNumberLen) - PopPacketNumber() protocol.PacketNumber - - GetAlarmTimeout() time.Time - OnAlarm() error -} - -// ReceivedPacketHandler handles ACKs needed to send for incoming packets -type ReceivedPacketHandler interface { - ReceivedPacket(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel, rcvTime time.Time, shouldInstigateAck bool) error - IgnoreBelow(protocol.PacketNumber) - - GetAlarmTimeout() time.Time - GetAckFrame(protocol.EncryptionLevel) *wire.AckFrame -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/packet.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/packet.go deleted file mode 100644 index 53e668774..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/packet.go +++ /dev/null @@ -1,29 +0,0 @@ -package ackhandler - -import ( - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -// A Packet is a packet -type Packet struct { - PacketNumber protocol.PacketNumber - PacketType protocol.PacketType - Frames []wire.Frame - Length protocol.ByteCount - EncryptionLevel protocol.EncryptionLevel - SendTime time.Time - - largestAcked protocol.PacketNumber // if the packet contains an ACK, the LargestAcked value of that ACK - - // There are two reasons why a packet cannot be retransmitted: - // * it was already retransmitted - // * this packet is a retransmission, and we already received an ACK for the original packet - canBeRetransmitted bool - includedInBytesInFlight bool - retransmittedAs []protocol.PacketNumber - isRetransmission bool // we need a separate bool here because 0 is a valid packet number - retransmissionOf protocol.PacketNumber -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/packet_linkedlist.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/packet_linkedlist.go deleted file mode 100644 index bb74f4ef9..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/packet_linkedlist.go +++ /dev/null @@ -1,217 +0,0 @@ -// This file was automatically generated by genny. -// Any changes will be lost if this file is regenerated. -// see https://github.com/cheekybits/genny - -package ackhandler - -// Linked list implementation from the Go standard library. - -// PacketElement is an element of a linked list. -type PacketElement struct { - // Next and previous pointers in the doubly-linked list of elements. - // To simplify the implementation, internally a list l is implemented - // as a ring, such that &l.root is both the next element of the last - // list element (l.Back()) and the previous element of the first list - // element (l.Front()). - next, prev *PacketElement - - // The list to which this element belongs. - list *PacketList - - // The value stored with this element. - Value Packet -} - -// Next returns the next list element or nil. -func (e *PacketElement) Next() *PacketElement { - if p := e.next; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// Prev returns the previous list element or nil. -func (e *PacketElement) Prev() *PacketElement { - if p := e.prev; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// PacketList is a linked list of Packets. -type PacketList struct { - root PacketElement // sentinel list element, only &root, root.prev, and root.next are used - len int // current list length excluding (this) sentinel element -} - -// Init initializes or clears list l. -func (l *PacketList) Init() *PacketList { - l.root.next = &l.root - l.root.prev = &l.root - l.len = 0 - return l -} - -// NewPacketList returns an initialized list. -func NewPacketList() *PacketList { return new(PacketList).Init() } - -// Len returns the number of elements of list l. -// The complexity is O(1). -func (l *PacketList) Len() int { return l.len } - -// Front returns the first element of list l or nil if the list is empty. -func (l *PacketList) Front() *PacketElement { - if l.len == 0 { - return nil - } - return l.root.next -} - -// Back returns the last element of list l or nil if the list is empty. -func (l *PacketList) Back() *PacketElement { - if l.len == 0 { - return nil - } - return l.root.prev -} - -// lazyInit lazily initializes a zero List value. -func (l *PacketList) lazyInit() { - if l.root.next == nil { - l.Init() - } -} - -// insert inserts e after at, increments l.len, and returns e. -func (l *PacketList) insert(e, at *PacketElement) *PacketElement { - n := at.next - at.next = e - e.prev = at - e.next = n - n.prev = e - e.list = l - l.len++ - return e -} - -// insertValue is a convenience wrapper for insert(&Element{Value: v}, at). -func (l *PacketList) insertValue(v Packet, at *PacketElement) *PacketElement { - return l.insert(&PacketElement{Value: v}, at) -} - -// remove removes e from its list, decrements l.len, and returns e. -func (l *PacketList) remove(e *PacketElement) *PacketElement { - e.prev.next = e.next - e.next.prev = e.prev - e.next = nil // avoid memory leaks - e.prev = nil // avoid memory leaks - e.list = nil - l.len-- - return e -} - -// Remove removes e from l if e is an element of list l. -// It returns the element value e.Value. -// The element must not be nil. -func (l *PacketList) Remove(e *PacketElement) Packet { - if e.list == l { - // if e.list == l, l must have been initialized when e was inserted - // in l or l == nil (e is a zero Element) and l.remove will crash - l.remove(e) - } - return e.Value -} - -// PushFront inserts a new element e with value v at the front of list l and returns e. -func (l *PacketList) PushFront(v Packet) *PacketElement { - l.lazyInit() - return l.insertValue(v, &l.root) -} - -// PushBack inserts a new element e with value v at the back of list l and returns e. -func (l *PacketList) PushBack(v Packet) *PacketElement { - l.lazyInit() - return l.insertValue(v, l.root.prev) -} - -// InsertBefore inserts a new element e with value v immediately before mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *PacketList) InsertBefore(v Packet, mark *PacketElement) *PacketElement { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark.prev) -} - -// InsertAfter inserts a new element e with value v immediately after mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *PacketList) InsertAfter(v Packet, mark *PacketElement) *PacketElement { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark) -} - -// MoveToFront moves element e to the front of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *PacketList) MoveToFront(e *PacketElement) { - if e.list != l || l.root.next == e { - return - } - // see comment in List.Remove about initialization of l - l.insert(l.remove(e), &l.root) -} - -// MoveToBack moves element e to the back of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *PacketList) MoveToBack(e *PacketElement) { - if e.list != l || l.root.prev == e { - return - } - // see comment in List.Remove about initialization of l - l.insert(l.remove(e), l.root.prev) -} - -// MoveBefore moves element e to its new position before mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *PacketList) MoveBefore(e, mark *PacketElement) { - if e.list != l || e == mark || mark.list != l { - return - } - l.insert(l.remove(e), mark.prev) -} - -// MoveAfter moves element e to its new position after mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *PacketList) MoveAfter(e, mark *PacketElement) { - if e.list != l || e == mark || mark.list != l { - return - } - l.insert(l.remove(e), mark) -} - -// PushBackList inserts a copy of an other list at the back of list l. -// The lists l and other may be the same. They must not be nil. -func (l *PacketList) PushBackList(other *PacketList) { - l.lazyInit() - for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { - l.insertValue(e.Value, l.root.prev) - } -} - -// PushFrontList inserts a copy of an other list at the front of list l. -// The lists l and other may be the same. They must not be nil. -func (l *PacketList) PushFrontList(other *PacketList) { - l.lazyInit() - for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { - l.insertValue(e.Value, &l.root) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/packet_number_generator.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/packet_number_generator.go deleted file mode 100644 index 9d613792d..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/packet_number_generator.go +++ /dev/null @@ -1,78 +0,0 @@ -package ackhandler - -import ( - "crypto/rand" - "math" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -// The packetNumberGenerator generates the packet number for the next packet -// it randomly skips a packet number every averagePeriod packets (on average) -// it is guarantued to never skip two consecutive packet numbers -type packetNumberGenerator struct { - averagePeriod protocol.PacketNumber - - next protocol.PacketNumber - nextToSkip protocol.PacketNumber - - history []protocol.PacketNumber -} - -func newPacketNumberGenerator(initial, averagePeriod protocol.PacketNumber) *packetNumberGenerator { - g := &packetNumberGenerator{ - next: initial, - averagePeriod: averagePeriod, - } - g.generateNewSkip() - return g -} - -func (p *packetNumberGenerator) Peek() protocol.PacketNumber { - return p.next -} - -func (p *packetNumberGenerator) Pop() protocol.PacketNumber { - next := p.next - - // generate a new packet number for the next packet - p.next++ - - if p.next == p.nextToSkip { - if len(p.history)+1 > protocol.MaxTrackedSkippedPackets { - p.history = p.history[1:] - } - p.history = append(p.history, p.next) - p.next++ - p.generateNewSkip() - } - - return next -} - -func (p *packetNumberGenerator) generateNewSkip() { - num := p.getRandomNumber() - skip := protocol.PacketNumber(num) * (p.averagePeriod - 1) / (math.MaxUint16 / 2) - // make sure that there are never two consecutive packet numbers that are skipped - p.nextToSkip = p.next + 2 + skip -} - -// getRandomNumber() generates a cryptographically secure random number between 0 and MaxUint16 (= 65535) -// The expectation value is 65535/2 -func (p *packetNumberGenerator) getRandomNumber() uint16 { - b := make([]byte, 2) - rand.Read(b) // ignore the error here - - num := uint16(b[0])<<8 + uint16(b[1]) - return num -} - -func (p *packetNumberGenerator) Validate(ack *wire.AckFrame) bool { - for _, pn := range p.history { - if ack.AcksPacket(pn) { - return false - } - } - return true -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler.go deleted file mode 100644 index 0b1719b29..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_handler.go +++ /dev/null @@ -1,98 +0,0 @@ -package ackhandler - -import ( - "fmt" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/congestion" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -const ( - // maximum delay that can be applied to an ACK for a retransmittable packet - ackSendDelay = 25 * time.Millisecond - // initial maximum number of retransmittable packets received before sending an ack. - initialRetransmittablePacketsBeforeAck = 2 - // number of retransmittable that an ACK is sent for - retransmittablePacketsBeforeAck = 10 - // 1/5 RTT delay when doing ack decimation - ackDecimationDelay = 1.0 / 4 - // 1/8 RTT delay when doing ack decimation - shortAckDecimationDelay = 1.0 / 8 - // Minimum number of packets received before ack decimation is enabled. - // This intends to avoid the beginning of slow start, when CWNDs may be - // rapidly increasing. - minReceivedBeforeAckDecimation = 100 - // Maximum number of packets to ack immediately after a missing packet for - // fast retransmission to kick in at the sender. This limit is created to - // reduce the number of acks sent that have no benefit for fast retransmission. - // Set to the number of nacks needed for fast retransmit plus one for protection - // against an ack loss - maxPacketsAfterNewMissing = 4 -) - -type receivedPacketHandler struct { - initialPackets *receivedPacketTracker - handshakePackets *receivedPacketTracker - oneRTTPackets *receivedPacketTracker -} - -var _ ReceivedPacketHandler = &receivedPacketHandler{} - -// NewReceivedPacketHandler creates a new receivedPacketHandler -func NewReceivedPacketHandler( - rttStats *congestion.RTTStats, - logger utils.Logger, - version protocol.VersionNumber, -) ReceivedPacketHandler { - return &receivedPacketHandler{ - initialPackets: newReceivedPacketTracker(rttStats, logger, version), - handshakePackets: newReceivedPacketTracker(rttStats, logger, version), - oneRTTPackets: newReceivedPacketTracker(rttStats, logger, version), - } -} - -func (h *receivedPacketHandler) ReceivedPacket( - pn protocol.PacketNumber, - encLevel protocol.EncryptionLevel, - rcvTime time.Time, - shouldInstigateAck bool, -) error { - switch encLevel { - case protocol.EncryptionInitial: - return h.initialPackets.ReceivedPacket(pn, rcvTime, shouldInstigateAck) - case protocol.EncryptionHandshake: - return h.handshakePackets.ReceivedPacket(pn, rcvTime, shouldInstigateAck) - case protocol.Encryption1RTT: - return h.oneRTTPackets.ReceivedPacket(pn, rcvTime, shouldInstigateAck) - default: - return fmt.Errorf("received packet with unknown encryption level: %s", encLevel) - } -} - -// only to be used with 1-RTT packets -func (h *receivedPacketHandler) IgnoreBelow(pn protocol.PacketNumber) { - h.oneRTTPackets.IgnoreBelow(pn) -} - -func (h *receivedPacketHandler) GetAlarmTimeout() time.Time { - initialAlarm := h.initialPackets.GetAlarmTimeout() - handshakeAlarm := h.handshakePackets.GetAlarmTimeout() - oneRTTAlarm := h.oneRTTPackets.GetAlarmTimeout() - return utils.MinNonZeroTime(utils.MinNonZeroTime(initialAlarm, handshakeAlarm), oneRTTAlarm) -} - -func (h *receivedPacketHandler) GetAckFrame(encLevel protocol.EncryptionLevel) *wire.AckFrame { - switch encLevel { - case protocol.EncryptionInitial: - return h.initialPackets.GetAckFrame() - case protocol.EncryptionHandshake: - return h.handshakePackets.GetAckFrame() - case protocol.Encryption1RTT: - return h.oneRTTPackets.GetAckFrame() - default: - return nil - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_history.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_history.go deleted file mode 100644 index 4519a1da7..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_history.go +++ /dev/null @@ -1,122 +0,0 @@ -package ackhandler - -import ( - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -// The receivedPacketHistory stores if a packet number has already been received. -// It generates ACK ranges which can be used to assemble an ACK frame. -// It does not store packet contents. -type receivedPacketHistory struct { - ranges *utils.PacketIntervalList - - lowestInReceivedPacketNumbers protocol.PacketNumber -} - -var errTooManyOutstandingReceivedAckRanges = qerr.Error(qerr.TooManyOutstandingReceivedPackets, "Too many outstanding received ACK ranges") - -// newReceivedPacketHistory creates a new received packet history -func newReceivedPacketHistory() *receivedPacketHistory { - return &receivedPacketHistory{ - ranges: utils.NewPacketIntervalList(), - } -} - -// ReceivedPacket registers a packet with PacketNumber p and updates the ranges -func (h *receivedPacketHistory) ReceivedPacket(p protocol.PacketNumber) error { - if h.ranges.Len() >= protocol.MaxTrackedReceivedAckRanges { - return errTooManyOutstandingReceivedAckRanges - } - - if h.ranges.Len() == 0 { - h.ranges.PushBack(utils.PacketInterval{Start: p, End: p}) - return nil - } - - for el := h.ranges.Back(); el != nil; el = el.Prev() { - // p already included in an existing range. Nothing to do here - if p >= el.Value.Start && p <= el.Value.End { - return nil - } - - var rangeExtended bool - if el.Value.End == p-1 { // extend a range at the end - rangeExtended = true - el.Value.End = p - } else if el.Value.Start == p+1 { // extend a range at the beginning - rangeExtended = true - el.Value.Start = p - } - - // if a range was extended (either at the beginning or at the end, maybe it is possible to merge two ranges into one) - if rangeExtended { - prev := el.Prev() - if prev != nil && prev.Value.End+1 == el.Value.Start { // merge two ranges - prev.Value.End = el.Value.End - h.ranges.Remove(el) - return nil - } - return nil // if the two ranges were not merge, we're done here - } - - // create a new range at the end - if p > el.Value.End { - h.ranges.InsertAfter(utils.PacketInterval{Start: p, End: p}, el) - return nil - } - } - - // create a new range at the beginning - h.ranges.InsertBefore(utils.PacketInterval{Start: p, End: p}, h.ranges.Front()) - - return nil -} - -// DeleteBelow deletes all entries below (but not including) p -func (h *receivedPacketHistory) DeleteBelow(p protocol.PacketNumber) { - if p <= h.lowestInReceivedPacketNumbers { - return - } - h.lowestInReceivedPacketNumbers = p - - nextEl := h.ranges.Front() - for el := h.ranges.Front(); nextEl != nil; el = nextEl { - nextEl = el.Next() - - if p > el.Value.Start && p <= el.Value.End { - el.Value.Start = p - } else if el.Value.End < p { // delete a whole range - h.ranges.Remove(el) - } else { // no ranges affected. Nothing to do - return - } - } -} - -// GetAckRanges gets a slice of all AckRanges that can be used in an AckFrame -func (h *receivedPacketHistory) GetAckRanges() []wire.AckRange { - if h.ranges.Len() == 0 { - return nil - } - - ackRanges := make([]wire.AckRange, h.ranges.Len()) - i := 0 - for el := h.ranges.Back(); el != nil; el = el.Prev() { - ackRanges[i] = wire.AckRange{Smallest: el.Value.Start, Largest: el.Value.End} - i++ - } - return ackRanges -} - -func (h *receivedPacketHistory) GetHighestAckRange() wire.AckRange { - ackRange := wire.AckRange{} - if h.ranges.Len() > 0 { - r := h.ranges.Back().Value - ackRange.Smallest = r.Start - ackRange.Largest = r.End - } - return ackRange -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_tracker.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_tracker.go deleted file mode 100644 index 0863ab5ef..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/received_packet_tracker.go +++ /dev/null @@ -1,191 +0,0 @@ -package ackhandler - -import ( - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/congestion" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type receivedPacketTracker struct { - largestObserved protocol.PacketNumber - ignoreBelow protocol.PacketNumber - largestObservedReceivedTime time.Time - - packetHistory *receivedPacketHistory - - ackSendDelay time.Duration - rttStats *congestion.RTTStats - - packetsReceivedSinceLastAck int - retransmittablePacketsReceivedSinceLastAck int - ackQueued bool - ackAlarm time.Time - lastAck *wire.AckFrame - - logger utils.Logger - - version protocol.VersionNumber -} - -func newReceivedPacketTracker( - rttStats *congestion.RTTStats, - logger utils.Logger, - version protocol.VersionNumber, -) *receivedPacketTracker { - return &receivedPacketTracker{ - packetHistory: newReceivedPacketHistory(), - ackSendDelay: ackSendDelay, - rttStats: rttStats, - logger: logger, - version: version, - } -} - -func (h *receivedPacketTracker) ReceivedPacket(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck bool) error { - if packetNumber < h.ignoreBelow { - return nil - } - - isMissing := h.isMissing(packetNumber) - if packetNumber >= h.largestObserved { - h.largestObserved = packetNumber - h.largestObservedReceivedTime = rcvTime - } - - if err := h.packetHistory.ReceivedPacket(packetNumber); err != nil { - return err - } - h.maybeQueueAck(packetNumber, rcvTime, shouldInstigateAck, isMissing) - return nil -} - -// IgnoreBelow sets a lower limit for acking packets. -// Packets with packet numbers smaller than p will not be acked. -func (h *receivedPacketTracker) IgnoreBelow(p protocol.PacketNumber) { - if p <= h.ignoreBelow { - return - } - h.ignoreBelow = p - h.packetHistory.DeleteBelow(p) - if h.logger.Debug() { - h.logger.Debugf("\tIgnoring all packets below %#x.", p) - } -} - -// isMissing says if a packet was reported missing in the last ACK. -func (h *receivedPacketTracker) isMissing(p protocol.PacketNumber) bool { - if h.lastAck == nil || p < h.ignoreBelow { - return false - } - return p < h.lastAck.LargestAcked() && !h.lastAck.AcksPacket(p) -} - -func (h *receivedPacketTracker) hasNewMissingPackets() bool { - if h.lastAck == nil { - return false - } - highestRange := h.packetHistory.GetHighestAckRange() - return highestRange.Smallest >= h.lastAck.LargestAcked() && highestRange.Len() <= maxPacketsAfterNewMissing -} - -// maybeQueueAck queues an ACK, if necessary. -// It is implemented analogously to Chrome's QuicConnection::MaybeQueueAck() -// in ACK_DECIMATION_WITH_REORDERING mode. -func (h *receivedPacketTracker) maybeQueueAck(packetNumber protocol.PacketNumber, rcvTime time.Time, shouldInstigateAck, wasMissing bool) { - h.packetsReceivedSinceLastAck++ - - // always ack the first packet - if h.lastAck == nil { - h.logger.Debugf("\tQueueing ACK because the first packet should be acknowledged.") - h.ackQueued = true - return - } - - // Send an ACK if this packet was reported missing in an ACK sent before. - // Ack decimation with reordering relies on the timer to send an ACK, but if - // missing packets we reported in the previous ack, send an ACK immediately. - if wasMissing { - if h.logger.Debug() { - h.logger.Debugf("\tQueueing ACK because packet %#x was missing before.", packetNumber) - } - h.ackQueued = true - } - - if !h.ackQueued && shouldInstigateAck { - h.retransmittablePacketsReceivedSinceLastAck++ - - if packetNumber > minReceivedBeforeAckDecimation { - // ack up to 10 packets at once - if h.retransmittablePacketsReceivedSinceLastAck >= retransmittablePacketsBeforeAck { - h.ackQueued = true - if h.logger.Debug() { - h.logger.Debugf("\tQueueing ACK because packet %d packets were received after the last ACK (using threshold: %d).", h.retransmittablePacketsReceivedSinceLastAck, retransmittablePacketsBeforeAck) - } - } else if h.ackAlarm.IsZero() { - // wait for the minimum of the ack decimation delay or the delayed ack time before sending an ack - ackDelay := utils.MinDuration(ackSendDelay, time.Duration(float64(h.rttStats.MinRTT())*float64(ackDecimationDelay))) - h.ackAlarm = rcvTime.Add(ackDelay) - if h.logger.Debug() { - h.logger.Debugf("\tSetting ACK timer to min(1/4 min-RTT, max ack delay): %s (%s from now)", ackDelay, time.Until(h.ackAlarm)) - } - } - } else { - // send an ACK every 2 retransmittable packets - if h.retransmittablePacketsReceivedSinceLastAck >= initialRetransmittablePacketsBeforeAck { - if h.logger.Debug() { - h.logger.Debugf("\tQueueing ACK because packet %d packets were received after the last ACK (using initial threshold: %d).", h.retransmittablePacketsReceivedSinceLastAck, initialRetransmittablePacketsBeforeAck) - } - h.ackQueued = true - } else if h.ackAlarm.IsZero() { - if h.logger.Debug() { - h.logger.Debugf("\tSetting ACK timer to max ack delay: %s", ackSendDelay) - } - h.ackAlarm = rcvTime.Add(ackSendDelay) - } - } - // If there are new missing packets to report, set a short timer to send an ACK. - if h.hasNewMissingPackets() { - // wait the minimum of 1/8 min RTT and the existing ack time - ackDelay := time.Duration(float64(h.rttStats.MinRTT()) * float64(shortAckDecimationDelay)) - ackTime := rcvTime.Add(ackDelay) - if h.ackAlarm.IsZero() || h.ackAlarm.After(ackTime) { - h.ackAlarm = ackTime - if h.logger.Debug() { - h.logger.Debugf("\tSetting ACK timer to 1/8 min-RTT: %s (%s from now)", ackDelay, time.Until(h.ackAlarm)) - } - } - } - } - - if h.ackQueued { - // cancel the ack alarm - h.ackAlarm = time.Time{} - } -} - -func (h *receivedPacketTracker) GetAckFrame() *wire.AckFrame { - now := time.Now() - if !h.ackQueued && (h.ackAlarm.IsZero() || h.ackAlarm.After(now)) { - return nil - } - if h.logger.Debug() && !h.ackQueued && !h.ackAlarm.IsZero() { - h.logger.Debugf("Sending ACK because the ACK timer expired.") - } - - ack := &wire.AckFrame{ - AckRanges: h.packetHistory.GetAckRanges(), - DelayTime: now.Sub(h.largestObservedReceivedTime), - } - - h.lastAck = ack - h.ackAlarm = time.Time{} - h.ackQueued = false - h.packetsReceivedSinceLastAck = 0 - h.retransmittablePacketsReceivedSinceLastAck = 0 - return ack -} - -func (h *receivedPacketTracker) GetAlarmTimeout() time.Time { return h.ackAlarm } diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/retransmittable.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/retransmittable.go deleted file mode 100644 index 18971750b..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/retransmittable.go +++ /dev/null @@ -1,34 +0,0 @@ -package ackhandler - -import "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" - -// Returns a new slice with all non-retransmittable frames deleted. -func stripNonRetransmittableFrames(fs []wire.Frame) []wire.Frame { - res := make([]wire.Frame, 0, len(fs)) - for _, f := range fs { - if IsFrameRetransmittable(f) { - res = append(res, f) - } - } - return res -} - -// IsFrameRetransmittable returns true if the frame should be retransmitted. -func IsFrameRetransmittable(f wire.Frame) bool { - switch f.(type) { - case *wire.AckFrame: - return false - default: - return true - } -} - -// HasRetransmittableFrames returns true if at least one frame is retransmittable. -func HasRetransmittableFrames(fs []wire.Frame) bool { - for _, f := range fs { - if IsFrameRetransmittable(f) { - return true - } - } - return false -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/send_mode.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/send_mode.go deleted file mode 100644 index 8cdaa7e6b..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/send_mode.go +++ /dev/null @@ -1,36 +0,0 @@ -package ackhandler - -import "fmt" - -// The SendMode says what kind of packets can be sent. -type SendMode uint8 - -const ( - // SendNone means that no packets should be sent - SendNone SendMode = iota - // SendAck means an ACK-only packet should be sent - SendAck - // SendRetransmission means that retransmissions should be sent - SendRetransmission - // SendPTO means that a probe packet should be sent - SendPTO - // SendAny means that any packet should be sent - SendAny -) - -func (s SendMode) String() string { - switch s { - case SendNone: - return "none" - case SendAck: - return "ack" - case SendRetransmission: - return "retransmission" - case SendPTO: - return "pto" - case SendAny: - return "any" - default: - return fmt.Sprintf("invalid send mode: %d", s) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go deleted file mode 100644 index 83ddc8c99..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go +++ /dev/null @@ -1,580 +0,0 @@ -package ackhandler - -import ( - "errors" - "fmt" - "math" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/congestion" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -const ( - // Maximum reordering in time space before time based loss detection considers a packet lost. - // In fraction of an RTT. - timeReorderingFraction = 1.0 / 8 - // Timer granularity. The timer will not be set to a value smaller than granularity. - granularity = time.Millisecond -) - -type sentPacketHandler struct { - lastSentPacketNumber protocol.PacketNumber - packetNumberGenerator *packetNumberGenerator - - lastSentRetransmittablePacketTime time.Time - lastSentCryptoPacketTime time.Time - - nextPacketSendTime time.Time - - largestAcked protocol.PacketNumber - largestReceivedPacketWithAck protocol.PacketNumber - // lowestPacketNotConfirmedAcked is the lowest packet number that we sent an ACK for, but haven't received confirmation, that this ACK actually arrived - // example: we send an ACK for packets 90-100 with packet number 20 - // once we receive an ACK from the peer for packet 20, the lowestPacketNotConfirmedAcked is 101 - lowestPacketNotConfirmedAcked protocol.PacketNumber - - packetHistory *sentPacketHistory - - retransmissionQueue []*Packet - - bytesInFlight protocol.ByteCount - - congestion congestion.SendAlgorithm - rttStats *congestion.RTTStats - - handshakeComplete bool - - // The number of times the crypto packets have been retransmitted without receiving an ack. - cryptoCount uint32 - // The number of times a PTO has been sent without receiving an ack. - ptoCount uint32 - // The number of PTO probe packets that should be sent. - numProbesToSend int - - // The time at which the next packet will be considered lost based on early transmit or exceeding the reordering window in time. - lossTime time.Time - - // The alarm timeout - alarm time.Time - - logger utils.Logger -} - -// NewSentPacketHandler creates a new sentPacketHandler -func NewSentPacketHandler( - initialPacketNumber protocol.PacketNumber, - rttStats *congestion.RTTStats, - logger utils.Logger, -) SentPacketHandler { - congestion := congestion.NewCubicSender( - congestion.DefaultClock{}, - rttStats, - false, /* don't use reno since chromium doesn't (why?) */ - protocol.InitialCongestionWindow, - protocol.DefaultMaxCongestionWindow, - ) - - return &sentPacketHandler{ - packetNumberGenerator: newPacketNumberGenerator(initialPacketNumber, protocol.SkipPacketAveragePeriodLength), - packetHistory: newSentPacketHistory(), - rttStats: rttStats, - congestion: congestion, - logger: logger, - } -} - -func (h *sentPacketHandler) lowestUnacked() protocol.PacketNumber { - if p := h.packetHistory.FirstOutstanding(); p != nil { - return p.PacketNumber - } - return h.largestAcked + 1 -} - -func (h *sentPacketHandler) SetHandshakeComplete() { - h.logger.Debugf("Handshake complete. Discarding all outstanding crypto packets.") - var queue []*Packet - for _, packet := range h.retransmissionQueue { - if packet.EncryptionLevel == protocol.Encryption1RTT { - queue = append(queue, packet) - } - } - var cryptoPackets []*Packet - h.packetHistory.Iterate(func(p *Packet) (bool, error) { - if p.EncryptionLevel != protocol.Encryption1RTT { - cryptoPackets = append(cryptoPackets, p) - } - return true, nil - }) - for _, p := range cryptoPackets { - h.packetHistory.Remove(p.PacketNumber) - } - h.retransmissionQueue = queue - h.handshakeComplete = true -} - -func (h *sentPacketHandler) SentPacket(packet *Packet) { - if isRetransmittable := h.sentPacketImpl(packet); isRetransmittable { - h.packetHistory.SentPacket(packet) - h.updateLossDetectionAlarm() - } -} - -func (h *sentPacketHandler) SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) { - var p []*Packet - for _, packet := range packets { - if isRetransmittable := h.sentPacketImpl(packet); isRetransmittable { - p = append(p, packet) - } - } - h.packetHistory.SentPacketsAsRetransmission(p, retransmissionOf) - h.updateLossDetectionAlarm() -} - -func (h *sentPacketHandler) sentPacketImpl(packet *Packet) bool /* isRetransmittable */ { - if h.logger.Debug() && h.lastSentPacketNumber != 0 { - for p := h.lastSentPacketNumber + 1; p < packet.PacketNumber; p++ { - h.logger.Debugf("Skipping packet number %#x", p) - } - } - - h.lastSentPacketNumber = packet.PacketNumber - - if len(packet.Frames) > 0 { - if ackFrame, ok := packet.Frames[0].(*wire.AckFrame); ok { - packet.largestAcked = ackFrame.LargestAcked() - } - } - - packet.Frames = stripNonRetransmittableFrames(packet.Frames) - isRetransmittable := len(packet.Frames) != 0 - - if isRetransmittable { - if packet.EncryptionLevel != protocol.Encryption1RTT { - h.lastSentCryptoPacketTime = packet.SendTime - } - h.lastSentRetransmittablePacketTime = packet.SendTime - packet.includedInBytesInFlight = true - h.bytesInFlight += packet.Length - packet.canBeRetransmitted = true - if h.numProbesToSend > 0 { - h.numProbesToSend-- - } - } - h.congestion.OnPacketSent(packet.SendTime, h.bytesInFlight, packet.PacketNumber, packet.Length, isRetransmittable) - - h.nextPacketSendTime = utils.MaxTime(h.nextPacketSendTime, packet.SendTime).Add(h.congestion.TimeUntilSend(h.bytesInFlight)) - return isRetransmittable -} - -func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, rcvTime time.Time) error { - largestAcked := ackFrame.LargestAcked() - if largestAcked > h.lastSentPacketNumber { - return qerr.Error(qerr.InvalidAckData, "Received ACK for an unsent package") - } - - // duplicate or out of order ACK - if withPacketNumber != 0 && withPacketNumber < h.largestReceivedPacketWithAck { - h.logger.Debugf("Ignoring ACK frame (duplicate or out of order).") - return nil - } - h.largestReceivedPacketWithAck = withPacketNumber - h.largestAcked = utils.MaxPacketNumber(h.largestAcked, largestAcked) - - if !h.packetNumberGenerator.Validate(ackFrame) { - return qerr.Error(qerr.InvalidAckData, "Received an ACK for a skipped packet number") - } - - if rttUpdated := h.maybeUpdateRTT(largestAcked, ackFrame.DelayTime, rcvTime); rttUpdated { - h.congestion.MaybeExitSlowStart() - } - - ackedPackets, err := h.determineNewlyAckedPackets(ackFrame) - if err != nil { - return err - } - if len(ackedPackets) == 0 { - return nil - } - - priorInFlight := h.bytesInFlight - for _, p := range ackedPackets { - // TODO(#1534): check the encryption level - // if encLevel < p.EncryptionLevel { - // return fmt.Errorf("Received ACK with encryption level %s that acks a packet %d (encryption level %s)", encLevel, p.PacketNumber, p.EncryptionLevel) - // } - - // largestAcked == 0 either means that the packet didn't contain an ACK, or it just acked packet 0 - // It is safe to ignore the corner case of packets that just acked packet 0, because - // the lowestPacketNotConfirmedAcked is only used to limit the number of ACK ranges we will send. - if p.largestAcked != 0 { - h.lowestPacketNotConfirmedAcked = utils.MaxPacketNumber(h.lowestPacketNotConfirmedAcked, p.largestAcked+1) - } - if err := h.onPacketAcked(p, rcvTime); err != nil { - return err - } - if p.includedInBytesInFlight { - h.congestion.OnPacketAcked(p.PacketNumber, p.Length, priorInFlight, rcvTime) - } - } - - if err := h.detectLostPackets(rcvTime, priorInFlight); err != nil { - return err - } - - h.ptoCount = 0 - h.cryptoCount = 0 - - h.updateLossDetectionAlarm() - return nil -} - -func (h *sentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNumber { - return h.lowestPacketNotConfirmedAcked -} - -func (h *sentPacketHandler) determineNewlyAckedPackets(ackFrame *wire.AckFrame) ([]*Packet, error) { - var ackedPackets []*Packet - ackRangeIndex := 0 - lowestAcked := ackFrame.LowestAcked() - largestAcked := ackFrame.LargestAcked() - err := h.packetHistory.Iterate(func(p *Packet) (bool, error) { - // Ignore packets below the lowest acked - if p.PacketNumber < lowestAcked { - return true, nil - } - // Break after largest acked is reached - if p.PacketNumber > largestAcked { - return false, nil - } - - if ackFrame.HasMissingRanges() { - ackRange := ackFrame.AckRanges[len(ackFrame.AckRanges)-1-ackRangeIndex] - - for p.PacketNumber > ackRange.Largest && ackRangeIndex < len(ackFrame.AckRanges)-1 { - ackRangeIndex++ - ackRange = ackFrame.AckRanges[len(ackFrame.AckRanges)-1-ackRangeIndex] - } - - if p.PacketNumber >= ackRange.Smallest { // packet i contained in ACK range - if p.PacketNumber > ackRange.Largest { - return false, fmt.Errorf("BUG: ackhandler would have acked wrong packet 0x%x, while evaluating range 0x%x -> 0x%x", p.PacketNumber, ackRange.Smallest, ackRange.Largest) - } - ackedPackets = append(ackedPackets, p) - } - } else { - ackedPackets = append(ackedPackets, p) - } - return true, nil - }) - if h.logger.Debug() && len(ackedPackets) > 0 { - pns := make([]protocol.PacketNumber, len(ackedPackets)) - for i, p := range ackedPackets { - pns[i] = p.PacketNumber - } - h.logger.Debugf("\tnewly acked packets (%d): %#x", len(pns), pns) - } - return ackedPackets, err -} - -func (h *sentPacketHandler) maybeUpdateRTT(largestAcked protocol.PacketNumber, ackDelay time.Duration, rcvTime time.Time) bool { - if p := h.packetHistory.GetPacket(largestAcked); p != nil { - h.rttStats.UpdateRTT(rcvTime.Sub(p.SendTime), ackDelay, rcvTime) - if h.logger.Debug() { - h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation()) - } - return true - } - return false -} - -func (h *sentPacketHandler) updateLossDetectionAlarm() { - // Cancel the alarm if no packets are outstanding - if !h.packetHistory.HasOutstandingPackets() { - h.alarm = time.Time{} - return - } - - if h.packetHistory.HasOutstandingCryptoPackets() { - h.alarm = h.lastSentCryptoPacketTime.Add(h.computeCryptoTimeout()) - } else if !h.lossTime.IsZero() { - // Early retransmit timer or time loss detection. - h.alarm = h.lossTime - } else { // PTO alarm - h.alarm = h.lastSentRetransmittablePacketTime.Add(h.computePTOTimeout()) - } -} - -func (h *sentPacketHandler) detectLostPackets(now time.Time, priorInFlight protocol.ByteCount) error { - h.lossTime = time.Time{} - - maxRTT := float64(utils.MaxDuration(h.rttStats.LatestRTT(), h.rttStats.SmoothedRTT())) - delayUntilLost := time.Duration((1.0 + timeReorderingFraction) * maxRTT) - - var lostPackets []*Packet - h.packetHistory.Iterate(func(packet *Packet) (bool, error) { - if packet.PacketNumber > h.largestAcked { - return false, nil - } - - timeSinceSent := now.Sub(packet.SendTime) - if timeSinceSent > delayUntilLost { - lostPackets = append(lostPackets, packet) - } else if h.lossTime.IsZero() { - if h.logger.Debug() { - h.logger.Debugf("\tsetting loss timer for packet %#x to %s (in %s)", packet.PacketNumber, delayUntilLost, delayUntilLost-timeSinceSent) - } - // Note: This conditional is only entered once per call - h.lossTime = now.Add(delayUntilLost - timeSinceSent) - } - return true, nil - }) - - if h.logger.Debug() && len(lostPackets) > 0 { - pns := make([]protocol.PacketNumber, len(lostPackets)) - for i, p := range lostPackets { - pns[i] = p.PacketNumber - } - h.logger.Debugf("\tlost packets (%d): %#x", len(pns), pns) - } - - for _, p := range lostPackets { - // the bytes in flight need to be reduced no matter if this packet will be retransmitted - if p.includedInBytesInFlight { - h.bytesInFlight -= p.Length - h.congestion.OnPacketLost(p.PacketNumber, p.Length, priorInFlight) - } - if p.canBeRetransmitted { - // queue the packet for retransmission, and report the loss to the congestion controller - if err := h.queuePacketForRetransmission(p); err != nil { - return err - } - } - h.packetHistory.Remove(p.PacketNumber) - } - return nil -} - -func (h *sentPacketHandler) OnAlarm() error { - // When all outstanding are acknowledged, the alarm is canceled in - // updateLossDetectionAlarm. This doesn't reset the timer in the session though. - // When OnAlarm is called, we therefore need to make sure that there are - // actually packets outstanding. - if h.packetHistory.HasOutstandingPackets() { - if err := h.onVerifiedAlarm(); err != nil { - return err - } - } - h.updateLossDetectionAlarm() - return nil -} - -func (h *sentPacketHandler) onVerifiedAlarm() error { - var err error - if h.packetHistory.HasOutstandingCryptoPackets() { - if h.logger.Debug() { - h.logger.Debugf("Loss detection alarm fired in crypto mode. Crypto count: %d", h.cryptoCount) - } - h.cryptoCount++ - err = h.queueCryptoPacketsForRetransmission() - } else if !h.lossTime.IsZero() { - if h.logger.Debug() { - h.logger.Debugf("Loss detection alarm fired in loss timer mode. Loss time: %s", h.lossTime) - } - // Early retransmit or time loss detection - err = h.detectLostPackets(time.Now(), h.bytesInFlight) - } else { // PTO - if h.logger.Debug() { - h.logger.Debugf("Loss detection alarm fired in PTO mode. PTO count: %d", h.ptoCount) - } - h.ptoCount++ - h.numProbesToSend += 2 - } - return err -} - -func (h *sentPacketHandler) GetAlarmTimeout() time.Time { - return h.alarm -} - -func (h *sentPacketHandler) onPacketAcked(p *Packet, rcvTime time.Time) error { - // This happens if a packet and its retransmissions is acked in the same ACK. - // As soon as we process the first one, this will remove all the retransmissions, - // so we won't find the retransmitted packet number later. - if packet := h.packetHistory.GetPacket(p.PacketNumber); packet == nil { - return nil - } - - // only report the acking of this packet to the congestion controller if: - // * it is a retransmittable packet - // * this packet wasn't retransmitted yet - if p.isRetransmission { - // that the parent doesn't exist is expected to happen every time the original packet was already acked - if parent := h.packetHistory.GetPacket(p.retransmissionOf); parent != nil { - if len(parent.retransmittedAs) == 1 { - parent.retransmittedAs = nil - } else { - // remove this packet from the slice of retransmission - retransmittedAs := make([]protocol.PacketNumber, 0, len(parent.retransmittedAs)-1) - for _, pn := range parent.retransmittedAs { - if pn != p.PacketNumber { - retransmittedAs = append(retransmittedAs, pn) - } - } - parent.retransmittedAs = retransmittedAs - } - } - } - // this also applies to packets that have been retransmitted as probe packets - if p.includedInBytesInFlight { - h.bytesInFlight -= p.Length - } - if err := h.stopRetransmissionsFor(p); err != nil { - return err - } - return h.packetHistory.Remove(p.PacketNumber) -} - -func (h *sentPacketHandler) stopRetransmissionsFor(p *Packet) error { - if err := h.packetHistory.MarkCannotBeRetransmitted(p.PacketNumber); err != nil { - return err - } - for _, r := range p.retransmittedAs { - packet := h.packetHistory.GetPacket(r) - if packet == nil { - return fmt.Errorf("sent packet handler BUG: marking packet as not retransmittable %d (retransmission of %d) not found in history", r, p.PacketNumber) - } - h.stopRetransmissionsFor(packet) - } - return nil -} - -func (h *sentPacketHandler) DequeuePacketForRetransmission() *Packet { - if len(h.retransmissionQueue) == 0 { - return nil - } - packet := h.retransmissionQueue[0] - // Shift the slice and don't retain anything that isn't needed. - copy(h.retransmissionQueue, h.retransmissionQueue[1:]) - h.retransmissionQueue[len(h.retransmissionQueue)-1] = nil - h.retransmissionQueue = h.retransmissionQueue[:len(h.retransmissionQueue)-1] - return packet -} - -func (h *sentPacketHandler) DequeueProbePacket() (*Packet, error) { - if len(h.retransmissionQueue) == 0 { - p := h.packetHistory.FirstOutstanding() - if p == nil { - return nil, errors.New("cannot dequeue a probe packet. No outstanding packets") - } - if err := h.queuePacketForRetransmission(p); err != nil { - return nil, err - } - } - return h.DequeuePacketForRetransmission(), nil -} - -func (h *sentPacketHandler) PeekPacketNumber() (protocol.PacketNumber, protocol.PacketNumberLen) { - pn := h.packetNumberGenerator.Peek() - return pn, protocol.GetPacketNumberLengthForHeader(pn, h.lowestUnacked()) -} - -func (h *sentPacketHandler) PopPacketNumber() protocol.PacketNumber { - return h.packetNumberGenerator.Pop() -} - -func (h *sentPacketHandler) SendMode() SendMode { - numTrackedPackets := len(h.retransmissionQueue) + h.packetHistory.Len() - - // Don't send any packets if we're keeping track of the maximum number of packets. - // Note that since MaxOutstandingSentPackets is smaller than MaxTrackedSentPackets, - // we will stop sending out new data when reaching MaxOutstandingSentPackets, - // but still allow sending of retransmissions and ACKs. - if numTrackedPackets >= protocol.MaxTrackedSentPackets { - if h.logger.Debug() { - h.logger.Debugf("Limited by the number of tracked packets: tracking %d packets, maximum %d", numTrackedPackets, protocol.MaxTrackedSentPackets) - } - return SendNone - } - if h.numProbesToSend > 0 { - return SendPTO - } - // Only send ACKs if we're congestion limited. - if cwnd := h.congestion.GetCongestionWindow(); h.bytesInFlight > cwnd { - if h.logger.Debug() { - h.logger.Debugf("Congestion limited: bytes in flight %d, window %d", h.bytesInFlight, cwnd) - } - return SendAck - } - // Send retransmissions first, if there are any. - if len(h.retransmissionQueue) > 0 { - return SendRetransmission - } - if numTrackedPackets >= protocol.MaxOutstandingSentPackets { - if h.logger.Debug() { - h.logger.Debugf("Max outstanding limited: tracking %d packets, maximum: %d", numTrackedPackets, protocol.MaxOutstandingSentPackets) - } - return SendAck - } - return SendAny -} - -func (h *sentPacketHandler) TimeUntilSend() time.Time { - return h.nextPacketSendTime -} - -func (h *sentPacketHandler) ShouldSendNumPackets() int { - if h.numProbesToSend > 0 { - // RTO probes should not be paced, but must be sent immediately. - return h.numProbesToSend - } - delay := h.congestion.TimeUntilSend(h.bytesInFlight) - if delay == 0 || delay > protocol.MinPacingDelay { - return 1 - } - return int(math.Ceil(float64(protocol.MinPacingDelay) / float64(delay))) -} - -func (h *sentPacketHandler) queueCryptoPacketsForRetransmission() error { - var cryptoPackets []*Packet - h.packetHistory.Iterate(func(p *Packet) (bool, error) { - if p.canBeRetransmitted && p.EncryptionLevel != protocol.Encryption1RTT { - cryptoPackets = append(cryptoPackets, p) - } - return true, nil - }) - for _, p := range cryptoPackets { - h.logger.Debugf("Queueing packet %#x as a crypto retransmission", p.PacketNumber) - if err := h.queuePacketForRetransmission(p); err != nil { - return err - } - } - return nil -} - -func (h *sentPacketHandler) queuePacketForRetransmission(p *Packet) error { - if !p.canBeRetransmitted { - return fmt.Errorf("sent packet handler BUG: packet %d already queued for retransmission", p.PacketNumber) - } - if err := h.packetHistory.MarkCannotBeRetransmitted(p.PacketNumber); err != nil { - return err - } - h.retransmissionQueue = append(h.retransmissionQueue, p) - return nil -} - -func (h *sentPacketHandler) computeCryptoTimeout() time.Duration { - duration := utils.MaxDuration(2*h.rttStats.SmoothedOrInitialRTT(), granularity) - // exponential backoff - // There's an implicit limit to this set by the crypto timeout. - return duration << h.cryptoCount -} - -func (h *sentPacketHandler) computePTOTimeout() time.Duration { - // TODO(#1236): include the max_ack_delay - duration := utils.MaxDuration(h.rttStats.SmoothedOrInitialRTT()+4*h.rttStats.MeanDeviation(), granularity) - return duration << h.ptoCount -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history.go b/external/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history.go deleted file mode 100644 index 0b85993f2..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_history.go +++ /dev/null @@ -1,168 +0,0 @@ -package ackhandler - -import ( - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -type sentPacketHistory struct { - packetList *PacketList - packetMap map[protocol.PacketNumber]*PacketElement - - numOutstandingPackets int - numOutstandingCryptoPackets int - - firstOutstanding *PacketElement -} - -func newSentPacketHistory() *sentPacketHistory { - return &sentPacketHistory{ - packetList: NewPacketList(), - packetMap: make(map[protocol.PacketNumber]*PacketElement), - } -} - -func (h *sentPacketHistory) SentPacket(p *Packet) { - h.sentPacketImpl(p) -} - -func (h *sentPacketHistory) sentPacketImpl(p *Packet) *PacketElement { - el := h.packetList.PushBack(*p) - h.packetMap[p.PacketNumber] = el - if h.firstOutstanding == nil { - h.firstOutstanding = el - } - if p.canBeRetransmitted { - h.numOutstandingPackets++ - if p.EncryptionLevel != protocol.Encryption1RTT { - h.numOutstandingCryptoPackets++ - } - } - return el -} - -func (h *sentPacketHistory) SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) { - retransmission, ok := h.packetMap[retransmissionOf] - // The retransmitted packet is not present anymore. - // This can happen if it was acked in between dequeueing of the retransmission and sending. - // Just treat the retransmissions as normal packets. - // TODO: This won't happen if we clear packets queued for retransmission on new ACKs. - if !ok { - for _, packet := range packets { - h.sentPacketImpl(packet) - } - return - } - retransmission.Value.retransmittedAs = make([]protocol.PacketNumber, len(packets)) - for i, packet := range packets { - retransmission.Value.retransmittedAs[i] = packet.PacketNumber - el := h.sentPacketImpl(packet) - el.Value.isRetransmission = true - el.Value.retransmissionOf = retransmissionOf - } -} - -func (h *sentPacketHistory) GetPacket(p protocol.PacketNumber) *Packet { - if el, ok := h.packetMap[p]; ok { - return &el.Value - } - return nil -} - -// Iterate iterates through all packets. -// The callback must not modify the history. -func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) error { - cont := true - for el := h.packetList.Front(); cont && el != nil; el = el.Next() { - var err error - cont, err = cb(&el.Value) - if err != nil { - return err - } - } - return nil -} - -// FirstOutStanding returns the first outstanding packet. -// It must not be modified (e.g. retransmitted). -// Use DequeueFirstPacketForRetransmission() to retransmit it. -func (h *sentPacketHistory) FirstOutstanding() *Packet { - if h.firstOutstanding == nil { - return nil - } - return &h.firstOutstanding.Value -} - -// QueuePacketForRetransmission marks a packet for retransmission. -// A packet can only be queued once. -func (h *sentPacketHistory) MarkCannotBeRetransmitted(pn protocol.PacketNumber) error { - el, ok := h.packetMap[pn] - if !ok { - return fmt.Errorf("sent packet history: packet %d not found", pn) - } - if el.Value.canBeRetransmitted { - h.numOutstandingPackets-- - if h.numOutstandingPackets < 0 { - panic("numOutstandingHandshakePackets negative") - } - if el.Value.EncryptionLevel != protocol.Encryption1RTT { - h.numOutstandingCryptoPackets-- - if h.numOutstandingCryptoPackets < 0 { - panic("numOutstandingHandshakePackets negative") - } - } - } - el.Value.canBeRetransmitted = false - if el == h.firstOutstanding { - h.readjustFirstOutstanding() - } - return nil -} - -// readjustFirstOutstanding readjusts the pointer to the first outstanding packet. -// This is necessary every time the first outstanding packet is deleted or retransmitted. -func (h *sentPacketHistory) readjustFirstOutstanding() { - el := h.firstOutstanding.Next() - for el != nil && !el.Value.canBeRetransmitted { - el = el.Next() - } - h.firstOutstanding = el -} - -func (h *sentPacketHistory) Len() int { - return len(h.packetMap) -} - -func (h *sentPacketHistory) Remove(p protocol.PacketNumber) error { - el, ok := h.packetMap[p] - if !ok { - return fmt.Errorf("packet %d not found in sent packet history", p) - } - if el == h.firstOutstanding { - h.readjustFirstOutstanding() - } - if el.Value.canBeRetransmitted { - h.numOutstandingPackets-- - if h.numOutstandingPackets < 0 { - panic("numOutstandingHandshakePackets negative") - } - if el.Value.EncryptionLevel != protocol.Encryption1RTT { - h.numOutstandingCryptoPackets-- - if h.numOutstandingCryptoPackets < 0 { - panic("numOutstandingHandshakePackets negative") - } - } - } - h.packetList.Remove(el) - delete(h.packetMap, p) - return nil -} - -func (h *sentPacketHistory) HasOutstandingPackets() bool { - return h.numOutstandingPackets > 0 -} - -func (h *sentPacketHistory) HasOutstandingCryptoPackets() bool { - return h.numOutstandingCryptoPackets > 0 -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/congestion/bandwidth.go b/external/github.com/lucas-clemente/quic-go/internal/congestion/bandwidth.go deleted file mode 100644 index aff34ddb6..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/congestion/bandwidth.go +++ /dev/null @@ -1,22 +0,0 @@ -package congestion - -import ( - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// Bandwidth of a connection -type Bandwidth uint64 - -const ( - // BitsPerSecond is 1 bit per second - BitsPerSecond Bandwidth = 1 - // BytesPerSecond is 1 byte per second - BytesPerSecond = 8 * BitsPerSecond -) - -// BandwidthFromDelta calculates the bandwidth from a number of bytes and a time delta -func BandwidthFromDelta(bytes protocol.ByteCount, delta time.Duration) Bandwidth { - return Bandwidth(bytes) * Bandwidth(time.Second) / Bandwidth(delta) * BytesPerSecond -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/congestion/clock.go b/external/github.com/lucas-clemente/quic-go/internal/congestion/clock.go deleted file mode 100644 index 405fae70f..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/congestion/clock.go +++ /dev/null @@ -1,18 +0,0 @@ -package congestion - -import "time" - -// A Clock returns the current time -type Clock interface { - Now() time.Time -} - -// DefaultClock implements the Clock interface using the Go stdlib clock. -type DefaultClock struct{} - -var _ Clock = DefaultClock{} - -// Now gets the current time -func (DefaultClock) Now() time.Time { - return time.Now() -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/congestion/cubic.go b/external/github.com/lucas-clemente/quic-go/internal/congestion/cubic.go deleted file mode 100644 index 6b32e9bd2..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/congestion/cubic.go +++ /dev/null @@ -1,210 +0,0 @@ -package congestion - -import ( - "math" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// This cubic implementation is based on the one found in Chromiums's QUIC -// implementation, in the files net/quic/congestion_control/cubic.{hh,cc}. - -// Constants based on TCP defaults. -// The following constants are in 2^10 fractions of a second instead of ms to -// allow a 10 shift right to divide. - -// 1024*1024^3 (first 1024 is from 0.100^3) -// where 0.100 is 100 ms which is the scaling round trip time. -const cubeScale = 40 -const cubeCongestionWindowScale = 410 -const cubeFactor protocol.ByteCount = 1 << cubeScale / cubeCongestionWindowScale / protocol.DefaultTCPMSS - -const defaultNumConnections = 2 - -// Default Cubic backoff factor -const beta float32 = 0.7 - -// Additional backoff factor when loss occurs in the concave part of the Cubic -// curve. This additional backoff factor is expected to give up bandwidth to -// new concurrent flows and speed up convergence. -const betaLastMax float32 = 0.85 - -// Cubic implements the cubic algorithm from TCP -type Cubic struct { - clock Clock - - // Number of connections to simulate. - numConnections int - - // Time when this cycle started, after last loss event. - epoch time.Time - - // Max congestion window used just before last loss event. - // Note: to improve fairness to other streams an additional back off is - // applied to this value if the new value is below our latest value. - lastMaxCongestionWindow protocol.ByteCount - - // Number of acked bytes since the cycle started (epoch). - ackedBytesCount protocol.ByteCount - - // TCP Reno equivalent congestion window in packets. - estimatedTCPcongestionWindow protocol.ByteCount - - // Origin point of cubic function. - originPointCongestionWindow protocol.ByteCount - - // Time to origin point of cubic function in 2^10 fractions of a second. - timeToOriginPoint uint32 - - // Last congestion window in packets computed by cubic function. - lastTargetCongestionWindow protocol.ByteCount -} - -// NewCubic returns a new Cubic instance -func NewCubic(clock Clock) *Cubic { - c := &Cubic{ - clock: clock, - numConnections: defaultNumConnections, - } - c.Reset() - return c -} - -// Reset is called after a timeout to reset the cubic state -func (c *Cubic) Reset() { - c.epoch = time.Time{} - c.lastMaxCongestionWindow = 0 - c.ackedBytesCount = 0 - c.estimatedTCPcongestionWindow = 0 - c.originPointCongestionWindow = 0 - c.timeToOriginPoint = 0 - c.lastTargetCongestionWindow = 0 -} - -func (c *Cubic) alpha() float32 { - // TCPFriendly alpha is described in Section 3.3 of the CUBIC paper. Note that - // beta here is a cwnd multiplier, and is equal to 1-beta from the paper. - // We derive the equivalent alpha for an N-connection emulation as: - b := c.beta() - return 3 * float32(c.numConnections) * float32(c.numConnections) * (1 - b) / (1 + b) -} - -func (c *Cubic) beta() float32 { - // kNConnectionBeta is the backoff factor after loss for our N-connection - // emulation, which emulates the effective backoff of an ensemble of N - // TCP-Reno connections on a single loss event. The effective multiplier is - // computed as: - return (float32(c.numConnections) - 1 + beta) / float32(c.numConnections) -} - -func (c *Cubic) betaLastMax() float32 { - // betaLastMax is the additional backoff factor after loss for our - // N-connection emulation, which emulates the additional backoff of - // an ensemble of N TCP-Reno connections on a single loss event. The - // effective multiplier is computed as: - return (float32(c.numConnections) - 1 + betaLastMax) / float32(c.numConnections) -} - -// OnApplicationLimited is called on ack arrival when sender is unable to use -// the available congestion window. Resets Cubic state during quiescence. -func (c *Cubic) OnApplicationLimited() { - // When sender is not using the available congestion window, the window does - // not grow. But to be RTT-independent, Cubic assumes that the sender has been - // using the entire window during the time since the beginning of the current - // "epoch" (the end of the last loss recovery period). Since - // application-limited periods break this assumption, we reset the epoch when - // in such a period. This reset effectively freezes congestion window growth - // through application-limited periods and allows Cubic growth to continue - // when the entire window is being used. - c.epoch = time.Time{} -} - -// CongestionWindowAfterPacketLoss computes a new congestion window to use after -// a loss event. Returns the new congestion window in packets. The new -// congestion window is a multiplicative decrease of our current window. -func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow protocol.ByteCount) protocol.ByteCount { - if currentCongestionWindow+protocol.DefaultTCPMSS < c.lastMaxCongestionWindow { - // We never reached the old max, so assume we are competing with another - // flow. Use our extra back off factor to allow the other flow to go up. - c.lastMaxCongestionWindow = protocol.ByteCount(c.betaLastMax() * float32(currentCongestionWindow)) - } else { - c.lastMaxCongestionWindow = currentCongestionWindow - } - c.epoch = time.Time{} // Reset time. - return protocol.ByteCount(float32(currentCongestionWindow) * c.beta()) -} - -// CongestionWindowAfterAck computes a new congestion window to use after a received ACK. -// Returns the new congestion window in packets. The new congestion window -// follows a cubic function that depends on the time passed since last -// packet loss. -func (c *Cubic) CongestionWindowAfterAck( - ackedBytes protocol.ByteCount, - currentCongestionWindow protocol.ByteCount, - delayMin time.Duration, - eventTime time.Time, -) protocol.ByteCount { - c.ackedBytesCount += ackedBytes - - if c.epoch.IsZero() { - // First ACK after a loss event. - c.epoch = eventTime // Start of epoch. - c.ackedBytesCount = ackedBytes // Reset count. - // Reset estimated_tcp_congestion_window_ to be in sync with cubic. - c.estimatedTCPcongestionWindow = currentCongestionWindow - if c.lastMaxCongestionWindow <= currentCongestionWindow { - c.timeToOriginPoint = 0 - c.originPointCongestionWindow = currentCongestionWindow - } else { - c.timeToOriginPoint = uint32(math.Cbrt(float64(cubeFactor * (c.lastMaxCongestionWindow - currentCongestionWindow)))) - c.originPointCongestionWindow = c.lastMaxCongestionWindow - } - } - - // Change the time unit from microseconds to 2^10 fractions per second. Take - // the round trip time in account. This is done to allow us to use shift as a - // divide operator. - elapsedTime := int64(eventTime.Add(delayMin).Sub(c.epoch)/time.Microsecond) << 10 / (1000 * 1000) - - // Right-shifts of negative, signed numbers have implementation-dependent - // behavior, so force the offset to be positive, as is done in the kernel. - offset := int64(c.timeToOriginPoint) - elapsedTime - if offset < 0 { - offset = -offset - } - - deltaCongestionWindow := protocol.ByteCount(cubeCongestionWindowScale*offset*offset*offset) * protocol.DefaultTCPMSS >> cubeScale - var targetCongestionWindow protocol.ByteCount - if elapsedTime > int64(c.timeToOriginPoint) { - targetCongestionWindow = c.originPointCongestionWindow + deltaCongestionWindow - } else { - targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow - } - // Limit the CWND increase to half the acked bytes. - targetCongestionWindow = utils.MinByteCount(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) - - // Increase the window by approximately Alpha * 1 MSS of bytes every - // time we ack an estimated tcp window of bytes. For small - // congestion windows (less than 25), the formula below will - // increase slightly slower than linearly per estimated tcp window - // of bytes. - c.estimatedTCPcongestionWindow += protocol.ByteCount(float32(c.ackedBytesCount) * c.alpha() * float32(protocol.DefaultTCPMSS) / float32(c.estimatedTCPcongestionWindow)) - c.ackedBytesCount = 0 - - // We have a new cubic congestion window. - c.lastTargetCongestionWindow = targetCongestionWindow - - // Compute target congestion_window based on cubic target and estimated TCP - // congestion_window, use highest (fastest). - if targetCongestionWindow < c.estimatedTCPcongestionWindow { - targetCongestionWindow = c.estimatedTCPcongestionWindow - } - return targetCongestionWindow -} - -// SetNumConnections sets the number of emulated connections -func (c *Cubic) SetNumConnections(n int) { - c.numConnections = n -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/congestion/cubic_sender.go b/external/github.com/lucas-clemente/quic-go/internal/congestion/cubic_sender.go deleted file mode 100644 index 9eb898644..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/congestion/cubic_sender.go +++ /dev/null @@ -1,318 +0,0 @@ -package congestion - -import ( - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -const ( - maxBurstBytes = 3 * protocol.DefaultTCPMSS - renoBeta float32 = 0.7 // Reno backoff factor. - defaultMinimumCongestionWindow protocol.ByteCount = 2 * protocol.DefaultTCPMSS -) - -type cubicSender struct { - hybridSlowStart HybridSlowStart - prr PrrSender - rttStats *RTTStats - stats connectionStats - cubic *Cubic - - reno bool - - // Track the largest packet that has been sent. - largestSentPacketNumber protocol.PacketNumber - - // Track the largest packet that has been acked. - largestAckedPacketNumber protocol.PacketNumber - - // Track the largest packet number outstanding when a CWND cutback occurs. - largestSentAtLastCutback protocol.PacketNumber - - // Whether the last loss event caused us to exit slowstart. - // Used for stats collection of slowstartPacketsLost - lastCutbackExitedSlowstart bool - - // When true, exit slow start with large cutback of congestion window. - slowStartLargeReduction bool - - // Congestion window in packets. - congestionWindow protocol.ByteCount - - // Minimum congestion window in packets. - minCongestionWindow protocol.ByteCount - - // Maximum congestion window. - maxCongestionWindow protocol.ByteCount - - // Slow start congestion window in bytes, aka ssthresh. - slowstartThreshold protocol.ByteCount - - // Number of connections to simulate. - numConnections int - - // ACK counter for the Reno implementation. - numAckedPackets uint64 - - initialCongestionWindow protocol.ByteCount - initialMaxCongestionWindow protocol.ByteCount - - minSlowStartExitWindow protocol.ByteCount -} - -var _ SendAlgorithm = &cubicSender{} -var _ SendAlgorithmWithDebugInfo = &cubicSender{} - -// NewCubicSender makes a new cubic sender -func NewCubicSender(clock Clock, rttStats *RTTStats, reno bool, initialCongestionWindow, initialMaxCongestionWindow protocol.ByteCount) SendAlgorithmWithDebugInfo { - return &cubicSender{ - rttStats: rttStats, - initialCongestionWindow: initialCongestionWindow, - initialMaxCongestionWindow: initialMaxCongestionWindow, - congestionWindow: initialCongestionWindow, - minCongestionWindow: defaultMinimumCongestionWindow, - slowstartThreshold: initialMaxCongestionWindow, - maxCongestionWindow: initialMaxCongestionWindow, - numConnections: defaultNumConnections, - cubic: NewCubic(clock), - reno: reno, - } -} - -// TimeUntilSend returns when the next packet should be sent. -func (c *cubicSender) TimeUntilSend(bytesInFlight protocol.ByteCount) time.Duration { - if c.InRecovery() { - // PRR is used when in recovery. - if c.prr.CanSend(c.GetCongestionWindow(), bytesInFlight, c.GetSlowStartThreshold()) { - return 0 - } - } - delay := c.rttStats.SmoothedRTT() / time.Duration(2*c.GetCongestionWindow()) - if !c.InSlowStart() { // adjust delay, such that it's 1.25*cwd/rtt - delay = delay * 8 / 5 - } - return delay -} - -func (c *cubicSender) OnPacketSent( - sentTime time.Time, - bytesInFlight protocol.ByteCount, - packetNumber protocol.PacketNumber, - bytes protocol.ByteCount, - isRetransmittable bool, -) { - if !isRetransmittable { - return - } - if c.InRecovery() { - // PRR is used when in recovery. - c.prr.OnPacketSent(bytes) - } - c.largestSentPacketNumber = packetNumber - c.hybridSlowStart.OnPacketSent(packetNumber) -} - -func (c *cubicSender) InRecovery() bool { - return c.largestAckedPacketNumber <= c.largestSentAtLastCutback && c.largestAckedPacketNumber != 0 -} - -func (c *cubicSender) InSlowStart() bool { - return c.GetCongestionWindow() < c.GetSlowStartThreshold() -} - -func (c *cubicSender) GetCongestionWindow() protocol.ByteCount { - return c.congestionWindow -} - -func (c *cubicSender) GetSlowStartThreshold() protocol.ByteCount { - return c.slowstartThreshold -} - -func (c *cubicSender) ExitSlowstart() { - c.slowstartThreshold = c.congestionWindow -} - -func (c *cubicSender) SlowstartThreshold() protocol.ByteCount { - return c.slowstartThreshold -} - -func (c *cubicSender) MaybeExitSlowStart() { - if c.InSlowStart() && c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/protocol.DefaultTCPMSS) { - c.ExitSlowstart() - } -} - -func (c *cubicSender) OnPacketAcked( - ackedPacketNumber protocol.PacketNumber, - ackedBytes protocol.ByteCount, - priorInFlight protocol.ByteCount, - eventTime time.Time, -) { - c.largestAckedPacketNumber = utils.MaxPacketNumber(ackedPacketNumber, c.largestAckedPacketNumber) - if c.InRecovery() { - // PRR is used when in recovery. - c.prr.OnPacketAcked(ackedBytes) - return - } - c.maybeIncreaseCwnd(ackedPacketNumber, ackedBytes, priorInFlight, eventTime) - if c.InSlowStart() { - c.hybridSlowStart.OnPacketAcked(ackedPacketNumber) - } -} - -func (c *cubicSender) OnPacketLost( - packetNumber protocol.PacketNumber, - lostBytes protocol.ByteCount, - priorInFlight protocol.ByteCount, -) { - // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets - // already sent should be treated as a single loss event, since it's expected. - if packetNumber <= c.largestSentAtLastCutback { - if c.lastCutbackExitedSlowstart { - c.stats.slowstartPacketsLost++ - c.stats.slowstartBytesLost += lostBytes - if c.slowStartLargeReduction { - // Reduce congestion window by lost_bytes for every loss. - c.congestionWindow = utils.MaxByteCount(c.congestionWindow-lostBytes, c.minSlowStartExitWindow) - c.slowstartThreshold = c.congestionWindow - } - } - return - } - c.lastCutbackExitedSlowstart = c.InSlowStart() - if c.InSlowStart() { - c.stats.slowstartPacketsLost++ - } - - c.prr.OnPacketLost(priorInFlight) - - // TODO(chromium): Separate out all of slow start into a separate class. - if c.slowStartLargeReduction && c.InSlowStart() { - if c.congestionWindow >= 2*c.initialCongestionWindow { - c.minSlowStartExitWindow = c.congestionWindow / 2 - } - c.congestionWindow -= protocol.DefaultTCPMSS - } else if c.reno { - c.congestionWindow = protocol.ByteCount(float32(c.congestionWindow) * c.RenoBeta()) - } else { - c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow) - } - if c.congestionWindow < c.minCongestionWindow { - c.congestionWindow = c.minCongestionWindow - } - c.slowstartThreshold = c.congestionWindow - c.largestSentAtLastCutback = c.largestSentPacketNumber - // reset packet count from congestion avoidance mode. We start - // counting again when we're out of recovery. - c.numAckedPackets = 0 -} - -func (c *cubicSender) RenoBeta() float32 { - // kNConnectionBeta is the backoff factor after loss for our N-connection - // emulation, which emulates the effective backoff of an ensemble of N - // TCP-Reno connections on a single loss event. The effective multiplier is - // computed as: - return (float32(c.numConnections) - 1. + renoBeta) / float32(c.numConnections) -} - -// Called when we receive an ack. Normal TCP tracks how many packets one ack -// represents, but quic has a separate ack for each packet. -func (c *cubicSender) maybeIncreaseCwnd( - ackedPacketNumber protocol.PacketNumber, - ackedBytes protocol.ByteCount, - priorInFlight protocol.ByteCount, - eventTime time.Time, -) { - // Do not increase the congestion window unless the sender is close to using - // the current window. - if !c.isCwndLimited(priorInFlight) { - c.cubic.OnApplicationLimited() - return - } - if c.congestionWindow >= c.maxCongestionWindow { - return - } - if c.InSlowStart() { - // TCP slow start, exponential growth, increase by one for each ACK. - c.congestionWindow += protocol.DefaultTCPMSS - return - } - // Congestion avoidance - if c.reno { - // Classic Reno congestion avoidance. - c.numAckedPackets++ - // Divide by num_connections to smoothly increase the CWND at a faster - // rate than conventional Reno. - if c.numAckedPackets*uint64(c.numConnections) >= uint64(c.congestionWindow)/uint64(protocol.DefaultTCPMSS) { - c.congestionWindow += protocol.DefaultTCPMSS - c.numAckedPackets = 0 - } - } else { - c.congestionWindow = utils.MinByteCount(c.maxCongestionWindow, c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) - } -} - -func (c *cubicSender) isCwndLimited(bytesInFlight protocol.ByteCount) bool { - congestionWindow := c.GetCongestionWindow() - if bytesInFlight >= congestionWindow { - return true - } - availableBytes := congestionWindow - bytesInFlight - slowStartLimited := c.InSlowStart() && bytesInFlight > congestionWindow/2 - return slowStartLimited || availableBytes <= maxBurstBytes -} - -// BandwidthEstimate returns the current bandwidth estimate -func (c *cubicSender) BandwidthEstimate() Bandwidth { - srtt := c.rttStats.SmoothedRTT() - if srtt == 0 { - // If we haven't measured an rtt, the bandwidth estimate is unknown. - return 0 - } - return BandwidthFromDelta(c.GetCongestionWindow(), srtt) -} - -// HybridSlowStart returns the hybrid slow start instance for testing -func (c *cubicSender) HybridSlowStart() *HybridSlowStart { - return &c.hybridSlowStart -} - -// SetNumEmulatedConnections sets the number of emulated connections -func (c *cubicSender) SetNumEmulatedConnections(n int) { - c.numConnections = utils.Max(n, 1) - c.cubic.SetNumConnections(c.numConnections) -} - -// OnRetransmissionTimeout is called on an retransmission timeout -func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) { - c.largestSentAtLastCutback = 0 - if !packetsRetransmitted { - return - } - c.hybridSlowStart.Restart() - c.cubic.Reset() - c.slowstartThreshold = c.congestionWindow / 2 - c.congestionWindow = c.minCongestionWindow -} - -// OnConnectionMigration is called when the connection is migrated (?) -func (c *cubicSender) OnConnectionMigration() { - c.hybridSlowStart.Restart() - c.prr = PrrSender{} - c.largestSentPacketNumber = 0 - c.largestAckedPacketNumber = 0 - c.largestSentAtLastCutback = 0 - c.lastCutbackExitedSlowstart = false - c.cubic.Reset() - c.numAckedPackets = 0 - c.congestionWindow = c.initialCongestionWindow - c.slowstartThreshold = c.initialMaxCongestionWindow - c.maxCongestionWindow = c.initialMaxCongestionWindow -} - -// SetSlowStartLargeReduction allows enabling the SSLR experiment -func (c *cubicSender) SetSlowStartLargeReduction(enabled bool) { - c.slowStartLargeReduction = enabled -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start.go b/external/github.com/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start.go deleted file mode 100644 index 890ee4069..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/congestion/hybrid_slow_start.go +++ /dev/null @@ -1,111 +0,0 @@ -package congestion - -import ( - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// Note(pwestin): the magic clamping numbers come from the original code in -// tcp_cubic.c. -const hybridStartLowWindow = protocol.ByteCount(16) - -// Number of delay samples for detecting the increase of delay. -const hybridStartMinSamples = uint32(8) - -// Exit slow start if the min rtt has increased by more than 1/8th. -const hybridStartDelayFactorExp = 3 // 2^3 = 8 -// The original paper specifies 2 and 8ms, but those have changed over time. -const hybridStartDelayMinThresholdUs = int64(4000) -const hybridStartDelayMaxThresholdUs = int64(16000) - -// HybridSlowStart implements the TCP hybrid slow start algorithm -type HybridSlowStart struct { - endPacketNumber protocol.PacketNumber - lastSentPacketNumber protocol.PacketNumber - started bool - currentMinRTT time.Duration - rttSampleCount uint32 - hystartFound bool -} - -// StartReceiveRound is called for the start of each receive round (burst) in the slow start phase. -func (s *HybridSlowStart) StartReceiveRound(lastSent protocol.PacketNumber) { - s.endPacketNumber = lastSent - s.currentMinRTT = 0 - s.rttSampleCount = 0 - s.started = true -} - -// IsEndOfRound returns true if this ack is the last packet number of our current slow start round. -func (s *HybridSlowStart) IsEndOfRound(ack protocol.PacketNumber) bool { - return s.endPacketNumber < ack -} - -// ShouldExitSlowStart should be called on every new ack frame, since a new -// RTT measurement can be made then. -// rtt: the RTT for this ack packet. -// minRTT: is the lowest delay (RTT) we have seen during the session. -// congestionWindow: the congestion window in packets. -func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT time.Duration, congestionWindow protocol.ByteCount) bool { - if !s.started { - // Time to start the hybrid slow start. - s.StartReceiveRound(s.lastSentPacketNumber) - } - if s.hystartFound { - return true - } - // Second detection parameter - delay increase detection. - // Compare the minimum delay (s.currentMinRTT) of the current - // burst of packets relative to the minimum delay during the session. - // Note: we only look at the first few(8) packets in each burst, since we - // only want to compare the lowest RTT of the burst relative to previous - // bursts. - s.rttSampleCount++ - if s.rttSampleCount <= hybridStartMinSamples { - if s.currentMinRTT == 0 || s.currentMinRTT > latestRTT { - s.currentMinRTT = latestRTT - } - } - // We only need to check this once per round. - if s.rttSampleCount == hybridStartMinSamples { - // Divide minRTT by 8 to get a rtt increase threshold for exiting. - minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp) - // Ensure the rtt threshold is never less than 2ms or more than 16ms. - minRTTincreaseThresholdUs = utils.MinInt64(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) - minRTTincreaseThreshold := time.Duration(utils.MaxInt64(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond - - if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) { - s.hystartFound = true - } - } - // Exit from slow start if the cwnd is greater than 16 and - // increasing delay is found. - return congestionWindow >= hybridStartLowWindow && s.hystartFound -} - -// OnPacketSent is called when a packet was sent -func (s *HybridSlowStart) OnPacketSent(packetNumber protocol.PacketNumber) { - s.lastSentPacketNumber = packetNumber -} - -// OnPacketAcked gets invoked after ShouldExitSlowStart, so it's best to end -// the round when the final packet of the burst is received and start it on -// the next incoming ack. -func (s *HybridSlowStart) OnPacketAcked(ackedPacketNumber protocol.PacketNumber) { - if s.IsEndOfRound(ackedPacketNumber) { - s.started = false - } -} - -// Started returns true if started -func (s *HybridSlowStart) Started() bool { - return s.started -} - -// Restart the slow start phase -func (s *HybridSlowStart) Restart() { - s.started = false - s.hystartFound = false -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/congestion/interface.go b/external/github.com/lucas-clemente/quic-go/internal/congestion/interface.go deleted file mode 100644 index e3d80b425..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/congestion/interface.go +++ /dev/null @@ -1,36 +0,0 @@ -package congestion - -import ( - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// A SendAlgorithm performs congestion control and calculates the congestion window -type SendAlgorithm interface { - TimeUntilSend(bytesInFlight protocol.ByteCount) time.Duration - OnPacketSent(sentTime time.Time, bytesInFlight protocol.ByteCount, packetNumber protocol.PacketNumber, bytes protocol.ByteCount, isRetransmittable bool) - GetCongestionWindow() protocol.ByteCount - MaybeExitSlowStart() - OnPacketAcked(number protocol.PacketNumber, ackedBytes protocol.ByteCount, priorInFlight protocol.ByteCount, eventTime time.Time) - OnPacketLost(number protocol.PacketNumber, lostBytes protocol.ByteCount, priorInFlight protocol.ByteCount) - SetNumEmulatedConnections(n int) - OnRetransmissionTimeout(packetsRetransmitted bool) - OnConnectionMigration() - - // Experiments - SetSlowStartLargeReduction(enabled bool) -} - -// SendAlgorithmWithDebugInfo adds some debug functions to SendAlgorithm -type SendAlgorithmWithDebugInfo interface { - SendAlgorithm - BandwidthEstimate() Bandwidth - - // Stuff only used in testing - - HybridSlowStart() *HybridSlowStart - SlowstartThreshold() protocol.ByteCount - RenoBeta() float32 - InRecovery() bool -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/congestion/prr_sender.go b/external/github.com/lucas-clemente/quic-go/internal/congestion/prr_sender.go deleted file mode 100644 index 3febd7bac..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/congestion/prr_sender.go +++ /dev/null @@ -1,54 +0,0 @@ -package congestion - -import ( - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// PrrSender implements the Proportional Rate Reduction (PRR) per RFC 6937 -type PrrSender struct { - bytesSentSinceLoss protocol.ByteCount - bytesDeliveredSinceLoss protocol.ByteCount - ackCountSinceLoss protocol.ByteCount - bytesInFlightBeforeLoss protocol.ByteCount -} - -// OnPacketSent should be called after a packet was sent -func (p *PrrSender) OnPacketSent(sentBytes protocol.ByteCount) { - p.bytesSentSinceLoss += sentBytes -} - -// OnPacketLost should be called on the first loss that triggers a recovery -// period and all other methods in this class should only be called when in -// recovery. -func (p *PrrSender) OnPacketLost(priorInFlight protocol.ByteCount) { - p.bytesSentSinceLoss = 0 - p.bytesInFlightBeforeLoss = priorInFlight - p.bytesDeliveredSinceLoss = 0 - p.ackCountSinceLoss = 0 -} - -// OnPacketAcked should be called after a packet was acked -func (p *PrrSender) OnPacketAcked(ackedBytes protocol.ByteCount) { - p.bytesDeliveredSinceLoss += ackedBytes - p.ackCountSinceLoss++ -} - -// CanSend returns if packets can be sent -func (p *PrrSender) CanSend(congestionWindow, bytesInFlight, slowstartThreshold protocol.ByteCount) bool { - // Return QuicTime::Zero In order to ensure limited transmit always works. - if p.bytesSentSinceLoss == 0 || bytesInFlight < protocol.DefaultTCPMSS { - return true - } - if congestionWindow > bytesInFlight { - // During PRR-SSRB, limit outgoing packets to 1 extra MSS per ack, instead - // of sending the entire available window. This prevents burst retransmits - // when more packets are lost than the CWND reduction. - // limit = MAX(prr_delivered - prr_out, DeliveredData) + MSS - return p.bytesDeliveredSinceLoss+p.ackCountSinceLoss*protocol.DefaultTCPMSS > p.bytesSentSinceLoss - } - // Implement Proportional Rate Reduction (RFC6937). - // Checks a simplified version of the PRR formula that doesn't use division: - // AvailableSendWindow = - // CEIL(prr_delivered * ssthresh / BytesInFlightAtLoss) - prr_sent - return p.bytesDeliveredSinceLoss*slowstartThreshold > p.bytesSentSinceLoss*p.bytesInFlightBeforeLoss -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/congestion/rtt_stats.go b/external/github.com/lucas-clemente/quic-go/internal/congestion/rtt_stats.go deleted file mode 100644 index 146f03d8e..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/congestion/rtt_stats.go +++ /dev/null @@ -1,101 +0,0 @@ -package congestion - -import ( - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -const ( - rttAlpha float32 = 0.125 - oneMinusAlpha float32 = (1 - rttAlpha) - rttBeta float32 = 0.25 - oneMinusBeta float32 = (1 - rttBeta) - // The default RTT used before an RTT sample is taken. - defaultInitialRTT = 100 * time.Millisecond -) - -// RTTStats provides round-trip statistics -type RTTStats struct { - minRTT time.Duration - latestRTT time.Duration - smoothedRTT time.Duration - meanDeviation time.Duration -} - -// NewRTTStats makes a properly initialized RTTStats object -func NewRTTStats() *RTTStats { - return &RTTStats{} -} - -// MinRTT Returns the minRTT for the entire connection. -// May return Zero if no valid updates have occurred. -func (r *RTTStats) MinRTT() time.Duration { return r.minRTT } - -// LatestRTT returns the most recent rtt measurement. -// May return Zero if no valid updates have occurred. -func (r *RTTStats) LatestRTT() time.Duration { return r.latestRTT } - -// SmoothedRTT returns the EWMA smoothed RTT for the connection. -// May return Zero if no valid updates have occurred. -func (r *RTTStats) SmoothedRTT() time.Duration { return r.smoothedRTT } - -// SmoothedOrInitialRTT returns the EWMA smoothed RTT for the connection. -// If no valid updates have occurred, it returns the initial RTT. -func (r *RTTStats) SmoothedOrInitialRTT() time.Duration { - if r.smoothedRTT != 0 { - return r.smoothedRTT - } - return defaultInitialRTT -} - -// MeanDeviation gets the mean deviation -func (r *RTTStats) MeanDeviation() time.Duration { return r.meanDeviation } - -// UpdateRTT updates the RTT based on a new sample. -func (r *RTTStats) UpdateRTT(sendDelta, ackDelay time.Duration, now time.Time) { - if sendDelta == utils.InfDuration || sendDelta <= 0 { - return - } - - // Update r.minRTT first. r.minRTT does not use an rttSample corrected for - // ackDelay but the raw observed sendDelta, since poor clock granularity at - // the client may cause a high ackDelay to result in underestimation of the - // r.minRTT. - if r.minRTT == 0 || r.minRTT > sendDelta { - r.minRTT = sendDelta - } - - // Correct for ackDelay if information received from the peer results in a - // an RTT sample at least as large as minRTT. Otherwise, only use the - // sendDelta. - sample := sendDelta - if sample-r.minRTT >= ackDelay { - sample -= ackDelay - } - r.latestRTT = sample - // First time call. - if r.smoothedRTT == 0 { - r.smoothedRTT = sample - r.meanDeviation = sample / 2 - } else { - r.meanDeviation = time.Duration(oneMinusBeta*float32(r.meanDeviation/time.Microsecond)+rttBeta*float32(utils.AbsDuration(r.smoothedRTT-sample)/time.Microsecond)) * time.Microsecond - r.smoothedRTT = time.Duration((float32(r.smoothedRTT/time.Microsecond)*oneMinusAlpha)+(float32(sample/time.Microsecond)*rttAlpha)) * time.Microsecond - } -} - -// OnConnectionMigration is called when connection migrates and rtt measurement needs to be reset. -func (r *RTTStats) OnConnectionMigration() { - r.latestRTT = 0 - r.minRTT = 0 - r.smoothedRTT = 0 - r.meanDeviation = 0 -} - -// ExpireSmoothedMetrics causes the smoothed_rtt to be increased to the latest_rtt if the latest_rtt -// is larger. The mean deviation is increased to the most recent deviation if -// it's larger. -func (r *RTTStats) ExpireSmoothedMetrics() { - r.meanDeviation = utils.MaxDuration(r.meanDeviation, utils.AbsDuration(r.smoothedRTT-r.latestRTT)) - r.smoothedRTT = utils.MaxDuration(r.smoothedRTT, r.latestRTT) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/congestion/stats.go b/external/github.com/lucas-clemente/quic-go/internal/congestion/stats.go deleted file mode 100644 index 7bb1942b2..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/congestion/stats.go +++ /dev/null @@ -1,8 +0,0 @@ -package congestion - -import "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - -type connectionStats struct { - slowstartPacketsLost protocol.PacketNumber - slowstartBytesLost protocol.ByteCount -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/crypto/AEAD.go b/external/github.com/lucas-clemente/quic-go/internal/crypto/AEAD.go deleted file mode 100644 index 5c2dfd530..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/crypto/AEAD.go +++ /dev/null @@ -1,10 +0,0 @@ -package crypto - -import "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - -// An AEAD implements QUIC's authenticated encryption and associated data -type AEAD interface { - Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) - Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte - Overhead() int -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/crypto/aesgcm_aead.go b/external/github.com/lucas-clemente/quic-go/internal/crypto/aesgcm_aead.go deleted file mode 100644 index 961df50d9..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/crypto/aesgcm_aead.go +++ /dev/null @@ -1,74 +0,0 @@ -package crypto - -import ( - "crypto/aes" - "crypto/cipher" - "encoding/binary" - "errors" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -type aeadAESGCM struct { - otherIV []byte - myIV []byte - encrypter cipher.AEAD - decrypter cipher.AEAD -} - -var _ AEAD = &aeadAESGCM{} - -const ivLen = 12 - -// NewAEADAESGCM creates a AEAD using AES-GCM -func NewAEADAESGCM(otherKey []byte, myKey []byte, otherIV []byte, myIV []byte) (AEAD, error) { - // the IVs need to be at least 8 bytes long, otherwise we can't compute the nonce - if len(otherIV) != ivLen || len(myIV) != ivLen { - return nil, errors.New("AES-GCM: expected 12 byte IVs") - } - - encrypterCipher, err := aes.NewCipher(myKey) - if err != nil { - return nil, err - } - encrypter, err := cipher.NewGCM(encrypterCipher) - if err != nil { - return nil, err - } - decrypterCipher, err := aes.NewCipher(otherKey) - if err != nil { - return nil, err - } - decrypter, err := cipher.NewGCM(decrypterCipher) - if err != nil { - return nil, err - } - - return &aeadAESGCM{ - otherIV: otherIV, - myIV: myIV, - encrypter: encrypter, - decrypter: decrypter, - }, nil -} - -func (aead *aeadAESGCM) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) { - return aead.decrypter.Open(dst, aead.makeNonce(aead.otherIV, packetNumber), src, associatedData) -} - -func (aead *aeadAESGCM) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte { - return aead.encrypter.Seal(dst, aead.makeNonce(aead.myIV, packetNumber), src, associatedData) -} - -func (aead *aeadAESGCM) makeNonce(iv []byte, packetNumber protocol.PacketNumber) []byte { - nonce := make([]byte, ivLen) - binary.BigEndian.PutUint64(nonce[ivLen-8:], uint64(packetNumber)) - for i := 0; i < ivLen; i++ { - nonce[i] ^= iv[i] - } - return nonce -} - -func (aead *aeadAESGCM) Overhead() int { - return aead.encrypter.Overhead() -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/crypto/hkdf.go b/external/github.com/lucas-clemente/quic-go/internal/crypto/hkdf.go deleted file mode 100644 index d8fea7ddd..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/crypto/hkdf.go +++ /dev/null @@ -1,58 +0,0 @@ -package crypto - -import ( - "crypto" - "crypto/hmac" - "encoding/binary" -) - -// copied from https://v2ray.com/core/external/github.com/cloudflare/tls-tris/blob/master/hkdf.go -func hkdfExtract(hash crypto.Hash, secret, salt []byte) []byte { - if salt == nil { - salt = make([]byte, hash.Size()) - } - if secret == nil { - secret = make([]byte, hash.Size()) - } - extractor := hmac.New(hash.New, salt) - extractor.Write(secret) - return extractor.Sum(nil) -} - -// copied from https://v2ray.com/core/external/github.com/cloudflare/tls-tris/blob/master/hkdf.go -func hkdfExpand(hash crypto.Hash, prk, info []byte, l int) []byte { - var ( - expander = hmac.New(hash.New, prk) - res = make([]byte, l) - counter = byte(1) - prev []byte - ) - - if l > 255*expander.Size() { - panic("hkdf: requested too much output") - } - - p := res - for len(p) > 0 { - expander.Reset() - expander.Write(prev) - expander.Write(info) - expander.Write([]byte{counter}) - prev = expander.Sum(prev[:0]) - counter++ - n := copy(p, prev) - p = p[n:] - } - - return res -} - -// hkdfExpandLabel HKDF expands a label -func HkdfExpandLabel(hash crypto.Hash, secret []byte, label string, length int) []byte { - const prefix = "quic " - qlabel := make([]byte, 2 /* length */ +1 /* length of label */ +len(prefix)+len(label)+1 /* length of context (empty) */) - binary.BigEndian.PutUint16(qlabel[0:2], uint16(length)) - qlabel[2] = uint8(len(prefix) + len(label)) - copy(qlabel[3:], []byte(prefix+label)) - return hkdfExpand(hash, secret, qlabel, length) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go b/external/github.com/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go deleted file mode 100644 index 33687e312..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go +++ /dev/null @@ -1,41 +0,0 @@ -package crypto - -import ( - "crypto" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -var quicVersion1Salt = []byte{0x9c, 0x10, 0x8f, 0x98, 0x52, 0x0a, 0x5c, 0x5c, 0x32, 0x96, 0x8e, 0x95, 0x0e, 0x8a, 0x2c, 0x5f, 0xe0, 0x6d, 0x6c, 0x38} - -// NewNullAEAD creates a NullAEAD -func NewNullAEAD(connectionID protocol.ConnectionID, pers protocol.Perspective) (AEAD, error) { - clientSecret, serverSecret := computeSecrets(connectionID) - - var mySecret, otherSecret []byte - if pers == protocol.PerspectiveClient { - mySecret = clientSecret - otherSecret = serverSecret - } else { - mySecret = serverSecret - otherSecret = clientSecret - } - - myKey, myIV := computeNullAEADKeyAndIV(mySecret) - otherKey, otherIV := computeNullAEADKeyAndIV(otherSecret) - - return NewAEADAESGCM(otherKey, myKey, otherIV, myIV) -} - -func computeSecrets(connID protocol.ConnectionID) (clientSecret, serverSecret []byte) { - initialSecret := hkdfExtract(crypto.SHA256, connID, quicVersion1Salt) - clientSecret = HkdfExpandLabel(crypto.SHA256, initialSecret, "client in", crypto.SHA256.Size()) - serverSecret = HkdfExpandLabel(crypto.SHA256, initialSecret, "server in", crypto.SHA256.Size()) - return -} - -func computeNullAEADKeyAndIV(secret []byte) (key, iv []byte) { - key = HkdfExpandLabel(crypto.SHA256, secret, "key", 16) - iv = HkdfExpandLabel(crypto.SHA256, secret, "iv", 12) - return -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller.go b/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller.go deleted file mode 100644 index 0091930b5..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/base_flow_controller.go +++ /dev/null @@ -1,122 +0,0 @@ -package flowcontrol - -import ( - "sync" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/congestion" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -type baseFlowController struct { - // for sending data - bytesSent protocol.ByteCount - sendWindow protocol.ByteCount - lastBlockedAt protocol.ByteCount - - // for receiving data - mutex sync.RWMutex - bytesRead protocol.ByteCount - highestReceived protocol.ByteCount - receiveWindow protocol.ByteCount - receiveWindowSize protocol.ByteCount - maxReceiveWindowSize protocol.ByteCount - - epochStartTime time.Time - epochStartOffset protocol.ByteCount - rttStats *congestion.RTTStats - - logger utils.Logger -} - -// IsNewlyBlocked says if it is newly blocked by flow control. -// For every offset, it only returns true once. -// If it is blocked, the offset is returned. -func (c *baseFlowController) IsNewlyBlocked() (bool, protocol.ByteCount) { - if c.sendWindowSize() != 0 || c.sendWindow == c.lastBlockedAt { - return false, 0 - } - c.lastBlockedAt = c.sendWindow - return true, c.sendWindow -} - -func (c *baseFlowController) AddBytesSent(n protocol.ByteCount) { - c.bytesSent += n -} - -// UpdateSendWindow should be called after receiving a WindowUpdateFrame -// it returns true if the window was actually updated -func (c *baseFlowController) UpdateSendWindow(offset protocol.ByteCount) { - if offset > c.sendWindow { - c.sendWindow = offset - } -} - -func (c *baseFlowController) sendWindowSize() protocol.ByteCount { - // this only happens during connection establishment, when data is sent before we receive the peer's transport parameters - if c.bytesSent > c.sendWindow { - return 0 - } - return c.sendWindow - c.bytesSent -} - -func (c *baseFlowController) AddBytesRead(n protocol.ByteCount) { - c.mutex.Lock() - defer c.mutex.Unlock() - - // pretend we sent a WindowUpdate when reading the first byte - // this way auto-tuning of the window size already works for the first WindowUpdate - if c.bytesRead == 0 { - c.startNewAutoTuningEpoch() - } - c.bytesRead += n -} - -func (c *baseFlowController) hasWindowUpdate() bool { - bytesRemaining := c.receiveWindow - c.bytesRead - // update the window when more than the threshold was consumed - return bytesRemaining <= protocol.ByteCount((float64(c.receiveWindowSize) * float64((1 - protocol.WindowUpdateThreshold)))) -} - -// getWindowUpdate updates the receive window, if necessary -// it returns the new offset -func (c *baseFlowController) getWindowUpdate() protocol.ByteCount { - if !c.hasWindowUpdate() { - return 0 - } - - c.maybeAdjustWindowSize() - c.receiveWindow = c.bytesRead + c.receiveWindowSize - return c.receiveWindow -} - -// maybeAdjustWindowSize increases the receiveWindowSize if we're sending updates too often. -// For details about auto-tuning, see https://docs.google.com/document/d/1SExkMmGiz8VYzV3s9E35JQlJ73vhzCekKkDi85F1qCE/edit?usp=sharing. -func (c *baseFlowController) maybeAdjustWindowSize() { - bytesReadInEpoch := c.bytesRead - c.epochStartOffset - // don't do anything if less than half the window has been consumed - if bytesReadInEpoch <= c.receiveWindowSize/2 { - return - } - rtt := c.rttStats.SmoothedRTT() - if rtt == 0 { - return - } - - fraction := float64(bytesReadInEpoch) / float64(c.receiveWindowSize) - if time.Since(c.epochStartTime) < time.Duration(4*fraction*float64(rtt)) { - // window is consumed too fast, try to increase the window size - c.receiveWindowSize = utils.MinByteCount(2*c.receiveWindowSize, c.maxReceiveWindowSize) - } - c.startNewAutoTuningEpoch() -} - -func (c *baseFlowController) startNewAutoTuningEpoch() { - c.epochStartTime = time.Now() - c.epochStartOffset = c.bytesRead -} - -func (c *baseFlowController) checkFlowControlViolation() bool { - return c.highestReceived > c.receiveWindow -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller.go b/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller.go deleted file mode 100644 index 1dd3fb7a3..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/connection_flow_controller.go +++ /dev/null @@ -1,87 +0,0 @@ -package flowcontrol - -import ( - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/congestion" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -type connectionFlowController struct { - baseFlowController - - queueWindowUpdate func() -} - -var _ ConnectionFlowController = &connectionFlowController{} - -// NewConnectionFlowController gets a new flow controller for the connection -// It is created before we receive the peer's transport paramenters, thus it starts with a sendWindow of 0. -func NewConnectionFlowController( - receiveWindow protocol.ByteCount, - maxReceiveWindow protocol.ByteCount, - queueWindowUpdate func(), - rttStats *congestion.RTTStats, - logger utils.Logger, -) ConnectionFlowController { - return &connectionFlowController{ - baseFlowController: baseFlowController{ - rttStats: rttStats, - receiveWindow: receiveWindow, - receiveWindowSize: receiveWindow, - maxReceiveWindowSize: maxReceiveWindow, - logger: logger, - }, - queueWindowUpdate: queueWindowUpdate, - } -} - -func (c *connectionFlowController) SendWindowSize() protocol.ByteCount { - return c.baseFlowController.sendWindowSize() -} - -// IncrementHighestReceived adds an increment to the highestReceived value -func (c *connectionFlowController) IncrementHighestReceived(increment protocol.ByteCount) error { - c.mutex.Lock() - defer c.mutex.Unlock() - - c.highestReceived += increment - if c.checkFlowControlViolation() { - return qerr.Error(qerr.FlowControlReceivedTooMuchData, fmt.Sprintf("Received %d bytes for the connection, allowed %d bytes", c.highestReceived, c.receiveWindow)) - } - return nil -} - -func (c *connectionFlowController) MaybeQueueWindowUpdate() { - c.mutex.Lock() - hasWindowUpdate := c.hasWindowUpdate() - c.mutex.Unlock() - if hasWindowUpdate { - c.queueWindowUpdate() - } -} - -func (c *connectionFlowController) GetWindowUpdate() protocol.ByteCount { - c.mutex.Lock() - oldWindowSize := c.receiveWindowSize - offset := c.baseFlowController.getWindowUpdate() - if oldWindowSize < c.receiveWindowSize { - c.logger.Debugf("Increasing receive flow control window for the connection to %d kB", c.receiveWindowSize/(1<<10)) - } - c.mutex.Unlock() - return offset -} - -// EnsureMinimumWindowSize sets a minimum window size -// it should make sure that the connection-level window is increased when a stream-level window grows -func (c *connectionFlowController) EnsureMinimumWindowSize(inc protocol.ByteCount) { - c.mutex.Lock() - if inc > c.receiveWindowSize { - c.logger.Debugf("Increasing receive flow control window for the connection to %d kB, in response to stream flow control window increase", c.receiveWindowSize/(1<<10)) - c.receiveWindowSize = utils.MinByteCount(inc, c.maxReceiveWindowSize) - c.startNewAutoTuningEpoch() - } - c.mutex.Unlock() -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/interface.go b/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/interface.go deleted file mode 100644 index 5293e8771..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/interface.go +++ /dev/null @@ -1,38 +0,0 @@ -package flowcontrol - -import "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - -type flowController interface { - // for sending - SendWindowSize() protocol.ByteCount - UpdateSendWindow(protocol.ByteCount) - AddBytesSent(protocol.ByteCount) - // for receiving - AddBytesRead(protocol.ByteCount) - GetWindowUpdate() protocol.ByteCount // returns 0 if no update is necessary - MaybeQueueWindowUpdate() // queues a window update, if necessary - IsNewlyBlocked() (bool, protocol.ByteCount) -} - -// A StreamFlowController is a flow controller for a QUIC stream. -type StreamFlowController interface { - flowController - // for receiving - // UpdateHighestReceived should be called when a new highest offset is received - // final has to be to true if this is the final offset of the stream, as contained in a STREAM frame with FIN bit, and the RESET_STREAM frame - UpdateHighestReceived(offset protocol.ByteCount, final bool) error -} - -// The ConnectionFlowController is the flow controller for the connection. -type ConnectionFlowController interface { - flowController -} - -type connectionFlowControllerI interface { - ConnectionFlowController - // The following two methods are not supposed to be called from outside this packet, but are needed internally - // for sending - EnsureMinimumWindowSize(protocol.ByteCount) - // for receiving - IncrementHighestReceived(protocol.ByteCount) error -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller.go b/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller.go deleted file mode 100644 index 7ae61d983..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/flowcontrol/stream_flow_controller.go +++ /dev/null @@ -1,131 +0,0 @@ -package flowcontrol - -import ( - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/congestion" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -type streamFlowController struct { - baseFlowController - - streamID protocol.StreamID - - queueWindowUpdate func() - - connection connectionFlowControllerI - - receivedFinalOffset bool -} - -var _ StreamFlowController = &streamFlowController{} - -// NewStreamFlowController gets a new flow controller for a stream -func NewStreamFlowController( - streamID protocol.StreamID, - cfc ConnectionFlowController, - receiveWindow protocol.ByteCount, - maxReceiveWindow protocol.ByteCount, - initialSendWindow protocol.ByteCount, - queueWindowUpdate func(protocol.StreamID), - rttStats *congestion.RTTStats, - logger utils.Logger, -) StreamFlowController { - return &streamFlowController{ - streamID: streamID, - connection: cfc.(connectionFlowControllerI), - queueWindowUpdate: func() { queueWindowUpdate(streamID) }, - baseFlowController: baseFlowController{ - rttStats: rttStats, - receiveWindow: receiveWindow, - receiveWindowSize: receiveWindow, - maxReceiveWindowSize: maxReceiveWindow, - sendWindow: initialSendWindow, - logger: logger, - }, - } -} - -// UpdateHighestReceived updates the highestReceived value, if the byteOffset is higher -// it returns an ErrReceivedSmallerByteOffset if the received byteOffset is smaller than any byteOffset received before -func (c *streamFlowController) UpdateHighestReceived(byteOffset protocol.ByteCount, final bool) error { - c.mutex.Lock() - defer c.mutex.Unlock() - - // when receiving a final offset, check that this final offset is consistent with a final offset we might have received earlier - if final && c.receivedFinalOffset && byteOffset != c.highestReceived { - return qerr.Error(qerr.StreamDataAfterTermination, fmt.Sprintf("Received inconsistent final offset for stream %d (old: %d, new: %d bytes)", c.streamID, c.highestReceived, byteOffset)) - } - // if we already received a final offset, check that the offset in the STREAM frames is below the final offset - if c.receivedFinalOffset && byteOffset > c.highestReceived { - return qerr.StreamDataAfterTermination - } - if final { - c.receivedFinalOffset = true - } - if byteOffset == c.highestReceived { - return nil - } - if byteOffset <= c.highestReceived { - // a STREAM_FRAME with a higher offset was received before. - if final { - // If the current byteOffset is smaller than the offset in that STREAM_FRAME, this STREAM_FRAME contained data after the end of the stream - return qerr.StreamDataAfterTermination - } - // this is a reordered STREAM_FRAME - return nil - } - - increment := byteOffset - c.highestReceived - c.highestReceived = byteOffset - if c.checkFlowControlViolation() { - return qerr.Error(qerr.FlowControlReceivedTooMuchData, fmt.Sprintf("Received %d bytes on stream %d, allowed %d bytes", byteOffset, c.streamID, c.receiveWindow)) - } - return c.connection.IncrementHighestReceived(increment) -} - -func (c *streamFlowController) AddBytesRead(n protocol.ByteCount) { - c.baseFlowController.AddBytesRead(n) - c.connection.AddBytesRead(n) -} - -func (c *streamFlowController) AddBytesSent(n protocol.ByteCount) { - c.baseFlowController.AddBytesSent(n) - c.connection.AddBytesSent(n) -} - -func (c *streamFlowController) SendWindowSize() protocol.ByteCount { - return utils.MinByteCount(c.baseFlowController.sendWindowSize(), c.connection.SendWindowSize()) -} - -func (c *streamFlowController) MaybeQueueWindowUpdate() { - c.mutex.Lock() - hasWindowUpdate := !c.receivedFinalOffset && c.hasWindowUpdate() - c.mutex.Unlock() - if hasWindowUpdate { - c.queueWindowUpdate() - } - c.connection.MaybeQueueWindowUpdate() -} - -func (c *streamFlowController) GetWindowUpdate() protocol.ByteCount { - // don't use defer for unlocking the mutex here, GetWindowUpdate() is called frequently and defer shows up in the profiler - c.mutex.Lock() - // if we already received the final offset for this stream, the peer won't need any additional flow control credit - if c.receivedFinalOffset { - c.mutex.Unlock() - return 0 - } - - oldWindowSize := c.receiveWindowSize - offset := c.baseFlowController.getWindowUpdate() - if c.receiveWindowSize > oldWindowSize { // auto-tuning enlarged the window size - c.logger.Debugf("Increasing receive flow control window for stream %d to %d kB", c.streamID, c.receiveWindowSize/(1<<10)) - c.connection.EnsureMinimumWindowSize(protocol.ByteCount(float64(c.receiveWindowSize) * protocol.ConnectionFlowControlMultiplier)) - } - c.mutex.Unlock() - return offset -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/aead.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/aead.go deleted file mode 100644 index ba8ddbd3e..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/aead.go +++ /dev/null @@ -1,104 +0,0 @@ -package handshake - -import ( - "crypto/cipher" - "encoding/binary" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -type sealer struct { - aead cipher.AEAD - hpEncrypter cipher.Block - - // use a single slice to avoid allocations - nonceBuf []byte - hpMask []byte - - // short headers protect 5 bits in the first byte, long headers only 4 - is1RTT bool -} - -var _ Sealer = &sealer{} - -func newSealer(aead cipher.AEAD, hpEncrypter cipher.Block, is1RTT bool) Sealer { - return &sealer{ - aead: aead, - nonceBuf: make([]byte, aead.NonceSize()), - is1RTT: is1RTT, - hpEncrypter: hpEncrypter, - hpMask: make([]byte, hpEncrypter.BlockSize()), - } -} - -func (s *sealer) Seal(dst, src []byte, pn protocol.PacketNumber, ad []byte) []byte { - binary.BigEndian.PutUint64(s.nonceBuf[len(s.nonceBuf)-8:], uint64(pn)) - // The AEAD we're using here will be the qtls.aeadAESGCM13. - // It uses the nonce provided here and XOR it with the IV. - return s.aead.Seal(dst, s.nonceBuf, src, ad) -} - -func (s *sealer) EncryptHeader(sample []byte, firstByte *byte, pnBytes []byte) { - if len(sample) != s.hpEncrypter.BlockSize() { - panic("invalid sample size") - } - s.hpEncrypter.Encrypt(s.hpMask, sample) - if s.is1RTT { - *firstByte ^= s.hpMask[0] & 0x1f - } else { - *firstByte ^= s.hpMask[0] & 0xf - } - for i := range pnBytes { - pnBytes[i] ^= s.hpMask[i+1] - } -} - -func (s *sealer) Overhead() int { - return s.aead.Overhead() -} - -type opener struct { - aead cipher.AEAD - pnDecrypter cipher.Block - - // use a single slice to avoid allocations - nonceBuf []byte - hpMask []byte - - // short headers protect 5 bits in the first byte, long headers only 4 - is1RTT bool -} - -var _ Opener = &opener{} - -func newOpener(aead cipher.AEAD, pnDecrypter cipher.Block, is1RTT bool) Opener { - return &opener{ - aead: aead, - nonceBuf: make([]byte, aead.NonceSize()), - is1RTT: is1RTT, - pnDecrypter: pnDecrypter, - hpMask: make([]byte, pnDecrypter.BlockSize()), - } -} - -func (o *opener) Open(dst, src []byte, pn protocol.PacketNumber, ad []byte) ([]byte, error) { - binary.BigEndian.PutUint64(o.nonceBuf[len(o.nonceBuf)-8:], uint64(pn)) - // The AEAD we're using here will be the qtls.aeadAESGCM13. - // It uses the nonce provided here and XOR it with the IV. - return o.aead.Open(dst, o.nonceBuf, src, ad) -} - -func (o *opener) DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte) { - if len(sample) != o.pnDecrypter.BlockSize() { - panic("invalid sample size") - } - o.pnDecrypter.Encrypt(o.hpMask, sample) - if o.is1RTT { - *firstByte ^= o.hpMask[0] & 0x1f - } else { - *firstByte ^= o.hpMask[0] & 0xf - } - for i := range pnBytes { - pnBytes[i] ^= o.hpMask[i+1] - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/cookie_generator.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/cookie_generator.go deleted file mode 100644 index ae77f3568..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/cookie_generator.go +++ /dev/null @@ -1,109 +0,0 @@ -package handshake - -import ( - "encoding/asn1" - "fmt" - "net" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -const ( - cookiePrefixIP byte = iota - cookiePrefixString -) - -// A Cookie is derived from the client address and can be used to verify the ownership of this address. -type Cookie struct { - RemoteAddr string - OriginalDestConnectionID protocol.ConnectionID - // The time that the Cookie was issued (resolution 1 second) - SentTime time.Time -} - -// token is the struct that is used for ASN1 serialization and deserialization -type token struct { - RemoteAddr []byte - OriginalDestConnectionID []byte - - Timestamp int64 -} - -// A CookieGenerator generates Cookies -type CookieGenerator struct { - cookieProtector cookieProtector -} - -// NewCookieGenerator initializes a new CookieGenerator -func NewCookieGenerator() (*CookieGenerator, error) { - cookieProtector, err := newCookieProtector() - if err != nil { - return nil, err - } - return &CookieGenerator{ - cookieProtector: cookieProtector, - }, nil -} - -// NewToken generates a new Cookie for a given source address -func (g *CookieGenerator) NewToken(raddr net.Addr, origConnID protocol.ConnectionID) ([]byte, error) { - data, err := asn1.Marshal(token{ - RemoteAddr: encodeRemoteAddr(raddr), - OriginalDestConnectionID: origConnID, - Timestamp: time.Now().Unix(), - }) - if err != nil { - return nil, err - } - return g.cookieProtector.NewToken(data) -} - -// DecodeToken decodes a Cookie -func (g *CookieGenerator) DecodeToken(encrypted []byte) (*Cookie, error) { - // if the client didn't send any Cookie, DecodeToken will be called with a nil-slice - if len(encrypted) == 0 { - return nil, nil - } - - data, err := g.cookieProtector.DecodeToken(encrypted) - if err != nil { - return nil, err - } - t := &token{} - rest, err := asn1.Unmarshal(data, t) - if err != nil { - return nil, err - } - if len(rest) != 0 { - return nil, fmt.Errorf("rest when unpacking token: %d", len(rest)) - } - cookie := &Cookie{ - RemoteAddr: decodeRemoteAddr(t.RemoteAddr), - SentTime: time.Unix(t.Timestamp, 0), - } - if len(t.OriginalDestConnectionID) > 0 { - cookie.OriginalDestConnectionID = protocol.ConnectionID(t.OriginalDestConnectionID) - } - return cookie, nil -} - -// encodeRemoteAddr encodes a remote address such that it can be saved in the Cookie -func encodeRemoteAddr(remoteAddr net.Addr) []byte { - if udpAddr, ok := remoteAddr.(*net.UDPAddr); ok { - return append([]byte{cookiePrefixIP}, udpAddr.IP...) - } - return append([]byte{cookiePrefixString}, []byte(remoteAddr.String())...) -} - -// decodeRemoteAddr decodes the remote address saved in the Cookie -func decodeRemoteAddr(data []byte) string { - // data will never be empty for a Cookie that we generated. Check it to be on the safe side - if len(data) == 0 { - return "" - } - if data[0] == cookiePrefixIP { - return net.IP(data[1:]).String() - } - return string(data[1:]) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/cookie_protector.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/cookie_protector.go deleted file mode 100644 index 7ebdfa18c..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/cookie_protector.go +++ /dev/null @@ -1,86 +0,0 @@ -package handshake - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "crypto/sha256" - "fmt" - "io" - - "golang.org/x/crypto/hkdf" -) - -// CookieProtector is used to create and verify a cookie -type cookieProtector interface { - // NewToken creates a new token - NewToken([]byte) ([]byte, error) - // DecodeToken decodes a token - DecodeToken([]byte) ([]byte, error) -} - -const ( - cookieSecretSize = 32 - cookieNonceSize = 32 -) - -// cookieProtector is used to create and verify a cookie -type cookieProtectorImpl struct { - secret []byte -} - -// newCookieProtector creates a source for source address tokens -func newCookieProtector() (cookieProtector, error) { - secret := make([]byte, cookieSecretSize) - if _, err := rand.Read(secret); err != nil { - return nil, err - } - return &cookieProtectorImpl{secret: secret}, nil -} - -// NewToken encodes data into a new token. -func (s *cookieProtectorImpl) NewToken(data []byte) ([]byte, error) { - nonce := make([]byte, cookieNonceSize) - if _, err := rand.Read(nonce); err != nil { - return nil, err - } - aead, aeadNonce, err := s.createAEAD(nonce) - if err != nil { - return nil, err - } - return append(nonce, aead.Seal(nil, aeadNonce, data, nil)...), nil -} - -// DecodeToken decodes a token. -func (s *cookieProtectorImpl) DecodeToken(p []byte) ([]byte, error) { - if len(p) < cookieNonceSize { - return nil, fmt.Errorf("Token too short: %d", len(p)) - } - nonce := p[:cookieNonceSize] - aead, aeadNonce, err := s.createAEAD(nonce) - if err != nil { - return nil, err - } - return aead.Open(nil, aeadNonce, p[cookieNonceSize:], nil) -} - -func (s *cookieProtectorImpl) createAEAD(nonce []byte) (cipher.AEAD, []byte, error) { - h := hkdf.New(sha256.New, s.secret, nonce, []byte("quic-go cookie source")) - key := make([]byte, 32) // use a 32 byte key, in order to select AES-256 - if _, err := io.ReadFull(h, key); err != nil { - return nil, nil, err - } - aeadNonce := make([]byte, 12) - if _, err := io.ReadFull(h, aeadNonce); err != nil { - return nil, nil, err - } - c, err := aes.NewCipher(key) - if err != nil { - return nil, nil, err - } - aead, err := cipher.NewGCM(c) - if err != nil { - return nil, nil, err - } - return aead, aeadNonce, nil -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/crypto_setup.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/crypto_setup.go deleted file mode 100644 index bd0ef776a..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/crypto_setup.go +++ /dev/null @@ -1,537 +0,0 @@ -package handshake - -import ( - "crypto/aes" - "crypto/tls" - "errors" - "fmt" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/marten-seemann/qtls" -) - -type messageType uint8 - -// TLS handshake message types. -const ( - typeClientHello messageType = 1 - typeServerHello messageType = 2 - typeEncryptedExtensions messageType = 8 - typeCertificate messageType = 11 - typeCertificateRequest messageType = 13 - typeCertificateVerify messageType = 15 - typeFinished messageType = 20 -) - -func (m messageType) String() string { - switch m { - case typeClientHello: - return "ClientHello" - case typeServerHello: - return "ServerHello" - case typeEncryptedExtensions: - return "EncryptedExtensions" - case typeCertificate: - return "Certificate" - case typeCertificateRequest: - return "CertificateRequest" - case typeCertificateVerify: - return "CertificateVerify" - case typeFinished: - return "Finished" - default: - return fmt.Sprintf("unknown message type: %d", m) - } -} - -// ErrOpenerNotYetAvailable is returned when an opener is requested for an encryption level, -// but the corresponding opener has not yet been initialized -// This can happen when packets arrive out of order. -var ErrOpenerNotYetAvailable = errors.New("CryptoSetup: opener at this encryption level not yet available") - -type cryptoSetup struct { - tlsConf *qtls.Config - conn *qtls.Conn - - messageChan chan []byte - - readEncLevel protocol.EncryptionLevel - writeEncLevel protocol.EncryptionLevel - - handleParamsCallback func(*TransportParameters) - - // There are two ways that an error can occur during the handshake: - // 1. as a return value from qtls.Handshake() - // 2. when new data is passed to the crypto setup via HandleData() - // handshakeErrChan is closed when qtls.Handshake() errors - handshakeErrChan chan struct{} - // HandleData() sends errors on the messageErrChan - messageErrChan chan error - // handshakeDone is closed as soon as the go routine running qtls.Handshake() returns - handshakeDone chan struct{} - // transport parameters are sent on the receivedTransportParams, as soon as they are received - receivedTransportParams <-chan TransportParameters - // is closed when Close() is called - closeChan chan struct{} - - clientHelloWritten bool - clientHelloWrittenChan chan struct{} - - initialStream io.Writer - initialOpener Opener - initialSealer Sealer - - handshakeStream io.Writer - handshakeOpener Opener - handshakeSealer Sealer - - opener Opener - sealer Sealer - // TODO: add a 1-RTT stream (used for session tickets) - - receivedWriteKey chan struct{} - receivedReadKey chan struct{} - - logger utils.Logger - - perspective protocol.Perspective -} - -var _ qtls.RecordLayer = &cryptoSetup{} -var _ CryptoSetup = &cryptoSetup{} - -// NewCryptoSetupClient creates a new crypto setup for the client -func NewCryptoSetupClient( - initialStream io.Writer, - handshakeStream io.Writer, - origConnID protocol.ConnectionID, - connID protocol.ConnectionID, - params *TransportParameters, - handleParams func(*TransportParameters), - tlsConf *tls.Config, - initialVersion protocol.VersionNumber, - supportedVersions []protocol.VersionNumber, - currentVersion protocol.VersionNumber, - logger utils.Logger, - perspective protocol.Perspective, -) (CryptoSetup, <-chan struct{} /* ClientHello written */, error) { - extHandler, receivedTransportParams := newExtensionHandlerClient( - params, - origConnID, - initialVersion, - supportedVersions, - currentVersion, - logger, - ) - cs, clientHelloWritten, err := newCryptoSetup( - initialStream, - handshakeStream, - connID, - extHandler, - receivedTransportParams, - handleParams, - tlsConf, - logger, - perspective, - ) - if err != nil { - return nil, nil, err - } - cs.conn = qtls.Client(nil, cs.tlsConf) - return cs, clientHelloWritten, nil -} - -// NewCryptoSetupServer creates a new crypto setup for the server -func NewCryptoSetupServer( - initialStream io.Writer, - handshakeStream io.Writer, - connID protocol.ConnectionID, - params *TransportParameters, - handleParams func(*TransportParameters), - tlsConf *tls.Config, - supportedVersions []protocol.VersionNumber, - currentVersion protocol.VersionNumber, - logger utils.Logger, - perspective protocol.Perspective, -) (CryptoSetup, error) { - extHandler, receivedTransportParams := newExtensionHandlerServer( - params, - supportedVersions, - currentVersion, - logger, - ) - cs, _, err := newCryptoSetup( - initialStream, - handshakeStream, - connID, - extHandler, - receivedTransportParams, - handleParams, - tlsConf, - logger, - perspective, - ) - if err != nil { - return nil, err - } - cs.conn = qtls.Server(nil, cs.tlsConf) - return cs, nil -} - -func newCryptoSetup( - initialStream io.Writer, - handshakeStream io.Writer, - connID protocol.ConnectionID, - extHandler tlsExtensionHandler, - transportParamChan <-chan TransportParameters, - handleParams func(*TransportParameters), - tlsConf *tls.Config, - logger utils.Logger, - perspective protocol.Perspective, -) (*cryptoSetup, <-chan struct{} /* ClientHello written */, error) { - initialSealer, initialOpener, err := NewInitialAEAD(connID, perspective) - if err != nil { - return nil, nil, err - } - cs := &cryptoSetup{ - initialStream: initialStream, - initialSealer: initialSealer, - initialOpener: initialOpener, - handshakeStream: handshakeStream, - readEncLevel: protocol.EncryptionInitial, - writeEncLevel: protocol.EncryptionInitial, - handleParamsCallback: handleParams, - receivedTransportParams: transportParamChan, - logger: logger, - perspective: perspective, - handshakeDone: make(chan struct{}), - handshakeErrChan: make(chan struct{}), - messageErrChan: make(chan error, 1), - clientHelloWrittenChan: make(chan struct{}), - messageChan: make(chan []byte, 100), - receivedReadKey: make(chan struct{}), - receivedWriteKey: make(chan struct{}), - closeChan: make(chan struct{}), - } - qtlsConf := tlsConfigToQtlsConfig(tlsConf) - qtlsConf.AlternativeRecordLayer = cs - qtlsConf.GetExtensions = extHandler.GetExtensions - qtlsConf.ReceivedExtensions = extHandler.ReceivedExtensions - cs.tlsConf = qtlsConf - return cs, cs.clientHelloWrittenChan, nil -} - -func (h *cryptoSetup) RunHandshake() error { - // Handle errors that might occur when HandleData() is called. - handshakeErrChan := make(chan error, 1) - handshakeComplete := make(chan struct{}) - go func() { - defer close(h.handshakeDone) - if err := h.conn.Handshake(); err != nil { - handshakeErrChan <- err - return - } - close(handshakeComplete) - }() - - select { - case <-h.closeChan: - close(h.messageChan) - // wait until the Handshake() go routine has returned - <-handshakeErrChan - return errors.New("Handshake aborted") - case <-handshakeComplete: // return when the handshake is done - return nil - case err := <-handshakeErrChan: - // if handleMessageFor{server,client} are waiting for some qtls action, make them return - close(h.handshakeErrChan) - return err - case err := <-h.messageErrChan: - // If the handshake errored because of an error that occurred during HandleData(), - // that error message will be more useful than the error message generated by Handshake(). - // Close the message chan that qtls is receiving messages from. - // This will make qtls.Handshake() return. - // Thereby the go routine running qtls.Handshake() will return. - close(h.messageChan) - return err - } -} - -func (h *cryptoSetup) Close() error { - close(h.closeChan) - // wait until qtls.Handshake() actually returned - <-h.handshakeDone - return nil -} - -// handleMessage handles a TLS handshake message. -// It is called by the crypto streams when a new message is available. -// It returns if it is done with messages on the same encryption level. -func (h *cryptoSetup) HandleMessage(data []byte, encLevel protocol.EncryptionLevel) bool /* stream finished */ { - msgType := messageType(data[0]) - h.logger.Debugf("Received %s message (%d bytes, encryption level: %s)", msgType, len(data), encLevel) - if err := h.checkEncryptionLevel(msgType, encLevel); err != nil { - h.messageErrChan <- err - return false - } - h.messageChan <- data - switch h.perspective { - case protocol.PerspectiveClient: - return h.handleMessageForClient(msgType) - case protocol.PerspectiveServer: - return h.handleMessageForServer(msgType) - default: - panic("") - } -} - -func (h *cryptoSetup) checkEncryptionLevel(msgType messageType, encLevel protocol.EncryptionLevel) error { - var expected protocol.EncryptionLevel - switch msgType { - case typeClientHello, - typeServerHello: - expected = protocol.EncryptionInitial - case typeEncryptedExtensions, - typeCertificate, - typeCertificateRequest, - typeCertificateVerify, - typeFinished: - expected = protocol.EncryptionHandshake - default: - return fmt.Errorf("unexpected handshake message: %d", msgType) - } - if encLevel != expected { - return fmt.Errorf("expected handshake message %s to have encryption level %s, has %s", msgType, expected, encLevel) - } - return nil -} - -func (h *cryptoSetup) handleMessageForServer(msgType messageType) bool { - switch msgType { - case typeClientHello: - select { - case params := <-h.receivedTransportParams: - h.handleParamsCallback(¶ms) - case <-h.handshakeErrChan: - return false - } - // get the handshake write key - select { - case <-h.receivedWriteKey: - case <-h.handshakeErrChan: - return false - } - // get the 1-RTT write key - select { - case <-h.receivedWriteKey: - case <-h.handshakeErrChan: - return false - } - // get the handshake read key - select { - case <-h.receivedReadKey: - case <-h.handshakeErrChan: - return false - } - return true - case typeCertificate, typeCertificateVerify: - // nothing to do - return false - case typeFinished: - // get the 1-RTT read key - select { - case <-h.receivedReadKey: - case <-h.handshakeErrChan: - return false - } - return true - default: - panic("unexpected handshake message") - } -} - -func (h *cryptoSetup) handleMessageForClient(msgType messageType) bool { - switch msgType { - case typeServerHello: - // get the handshake read key - select { - case <-h.receivedReadKey: - case <-h.handshakeErrChan: - return false - } - // get the handshake write key - select { - case <-h.receivedWriteKey: - case <-h.handshakeErrChan: - return false - } - return true - case typeEncryptedExtensions: - select { - case params := <-h.receivedTransportParams: - h.handleParamsCallback(¶ms) - case <-h.handshakeErrChan: - return false - } - return false - case typeCertificateRequest, typeCertificate, typeCertificateVerify: - // nothing to do - return false - case typeFinished: - // While the order of these two is not defined by the TLS spec, - // we have to do it on the same order as our TLS library does it. - // get the handshake write key - select { - case <-h.receivedWriteKey: - case <-h.handshakeErrChan: - return false - } - // get the 1-RTT read key - select { - case <-h.receivedReadKey: - case <-h.handshakeErrChan: - return false - } - return true - default: - panic("unexpected handshake message: ") - } -} - -// ReadHandshakeMessage is called by TLS. -// It blocks until a new handshake message is available. -func (h *cryptoSetup) ReadHandshakeMessage() ([]byte, error) { - // TODO: add some error handling here (when the session is closed) - msg, ok := <-h.messageChan - if !ok { - return nil, errors.New("error while handling the handshake message") - } - return msg, nil -} - -func (h *cryptoSetup) SetReadKey(suite *qtls.CipherSuite, trafficSecret []byte) { - key := qtls.HkdfExpandLabel(suite.Hash(), trafficSecret, []byte{}, "quic key", suite.KeyLen()) - iv := qtls.HkdfExpandLabel(suite.Hash(), trafficSecret, []byte{}, "quic iv", suite.IVLen()) - hpKey := qtls.HkdfExpandLabel(suite.Hash(), trafficSecret, []byte{}, "quic hp", suite.KeyLen()) - hpDecrypter, err := aes.NewCipher(hpKey) - if err != nil { - panic(fmt.Sprintf("error creating new AES cipher: %s", err)) - } - - switch h.readEncLevel { - case protocol.EncryptionInitial: - h.readEncLevel = protocol.EncryptionHandshake - h.handshakeOpener = newOpener(suite.AEAD(key, iv), hpDecrypter, false) - h.logger.Debugf("Installed Handshake Read keys") - case protocol.EncryptionHandshake: - h.readEncLevel = protocol.Encryption1RTT - h.opener = newOpener(suite.AEAD(key, iv), hpDecrypter, true) - h.logger.Debugf("Installed 1-RTT Read keys") - default: - panic("unexpected read encryption level") - } - h.receivedReadKey <- struct{}{} -} - -func (h *cryptoSetup) SetWriteKey(suite *qtls.CipherSuite, trafficSecret []byte) { - key := qtls.HkdfExpandLabel(suite.Hash(), trafficSecret, []byte{}, "quic key", suite.KeyLen()) - iv := qtls.HkdfExpandLabel(suite.Hash(), trafficSecret, []byte{}, "quic iv", suite.IVLen()) - hpKey := qtls.HkdfExpandLabel(suite.Hash(), trafficSecret, []byte{}, "quic hp", suite.KeyLen()) - hpEncrypter, err := aes.NewCipher(hpKey) - if err != nil { - panic(fmt.Sprintf("error creating new AES cipher: %s", err)) - } - - switch h.writeEncLevel { - case protocol.EncryptionInitial: - h.writeEncLevel = protocol.EncryptionHandshake - h.handshakeSealer = newSealer(suite.AEAD(key, iv), hpEncrypter, false) - h.logger.Debugf("Installed Handshake Write keys") - case protocol.EncryptionHandshake: - h.writeEncLevel = protocol.Encryption1RTT - h.sealer = newSealer(suite.AEAD(key, iv), hpEncrypter, true) - h.logger.Debugf("Installed 1-RTT Write keys") - default: - panic("unexpected write encryption level") - } - h.receivedWriteKey <- struct{}{} -} - -// WriteRecord is called when TLS writes data -func (h *cryptoSetup) WriteRecord(p []byte) (int, error) { - switch h.writeEncLevel { - case protocol.EncryptionInitial: - // assume that the first WriteRecord call contains the ClientHello - n, err := h.initialStream.Write(p) - if !h.clientHelloWritten && h.perspective == protocol.PerspectiveClient { - h.clientHelloWritten = true - close(h.clientHelloWrittenChan) - } - return n, err - case protocol.EncryptionHandshake: - return h.handshakeStream.Write(p) - default: - return 0, fmt.Errorf("unexpected write encryption level: %s", h.writeEncLevel) - } -} - -func (h *cryptoSetup) GetSealer() (protocol.EncryptionLevel, Sealer) { - if h.sealer != nil { - return protocol.Encryption1RTT, h.sealer - } - if h.handshakeSealer != nil { - return protocol.EncryptionHandshake, h.handshakeSealer - } - return protocol.EncryptionInitial, h.initialSealer -} - -func (h *cryptoSetup) GetSealerWithEncryptionLevel(level protocol.EncryptionLevel) (Sealer, error) { - errNoSealer := fmt.Errorf("CryptoSetup: no sealer with encryption level %s", level.String()) - - switch level { - case protocol.EncryptionInitial: - return h.initialSealer, nil - case protocol.EncryptionHandshake: - if h.handshakeSealer == nil { - return nil, errNoSealer - } - return h.handshakeSealer, nil - case protocol.Encryption1RTT: - if h.sealer == nil { - return nil, errNoSealer - } - return h.sealer, nil - default: - return nil, errNoSealer - } -} - -func (h *cryptoSetup) GetOpener(level protocol.EncryptionLevel) (Opener, error) { - switch level { - case protocol.EncryptionInitial: - return h.initialOpener, nil - case protocol.EncryptionHandshake: - if h.handshakeOpener == nil { - return nil, ErrOpenerNotYetAvailable - } - return h.handshakeOpener, nil - case protocol.Encryption1RTT: - if h.opener == nil { - return nil, ErrOpenerNotYetAvailable - } - return h.opener, nil - default: - return nil, fmt.Errorf("CryptoSetup: no opener with encryption level %s", level) - } -} - -func (h *cryptoSetup) ConnectionState() ConnectionState { - connState := h.conn.ConnectionState() - return ConnectionState{ - HandshakeComplete: connState.HandshakeComplete, - ServerName: connState.ServerName, - PeerCertificates: connState.PeerCertificates, - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/initial_aead.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/initial_aead.go deleted file mode 100644 index 92cce873c..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/initial_aead.go +++ /dev/null @@ -1,52 +0,0 @@ -package handshake - -import ( - "crypto" - "crypto/aes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/marten-seemann/qtls" -) - -var quicVersion1Salt = []byte{0xef, 0x4f, 0xb0, 0xab, 0xb4, 0x74, 0x70, 0xc4, 0x1b, 0xef, 0xcf, 0x80, 0x31, 0x33, 0x4f, 0xae, 0x48, 0x5e, 0x09, 0xa0} - -// NewInitialAEAD creates a new AEAD for Initial encryption / decryption. -func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective) (Sealer, Opener, error) { - clientSecret, serverSecret := computeSecrets(connID) - var mySecret, otherSecret []byte - if pers == protocol.PerspectiveClient { - mySecret = clientSecret - otherSecret = serverSecret - } else { - mySecret = serverSecret - otherSecret = clientSecret - } - myKey, myHPKey, myIV := computeInitialKeyAndIV(mySecret) - otherKey, otherHPKey, otherIV := computeInitialKeyAndIV(otherSecret) - - encrypter := qtls.AEADAESGCM13(myKey, myIV) - hpEncrypter, err := aes.NewCipher(myHPKey) - if err != nil { - return nil, nil, err - } - decrypter := qtls.AEADAESGCM13(otherKey, otherIV) - hpDecrypter, err := aes.NewCipher(otherHPKey) - if err != nil { - return nil, nil, err - } - return newSealer(encrypter, hpEncrypter, false), newOpener(decrypter, hpDecrypter, false), nil -} - -func computeSecrets(connID protocol.ConnectionID) (clientSecret, serverSecret []byte) { - initialSecret := qtls.HkdfExtract(crypto.SHA256, connID, quicVersion1Salt) - clientSecret = qtls.HkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size()) - serverSecret = qtls.HkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "server in", crypto.SHA256.Size()) - return -} - -func computeInitialKeyAndIV(secret []byte) (key, hpKey, iv []byte) { - key = qtls.HkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16) - hpKey = qtls.HkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic hp", 16) - iv = qtls.HkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12) - return -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/interface.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/interface.go deleted file mode 100644 index 3f6a6f8a0..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/interface.go +++ /dev/null @@ -1,49 +0,0 @@ -package handshake - -import ( - "crypto/x509" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/marten-seemann/qtls" -) - -// Opener opens a packet -type Opener interface { - Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) - DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte) -} - -// Sealer seals a packet -type Sealer interface { - Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte - EncryptHeader(sample []byte, firstByte *byte, pnBytes []byte) - Overhead() int -} - -// A tlsExtensionHandler sends and received the QUIC TLS extension. -type tlsExtensionHandler interface { - GetExtensions(msgType uint8) []qtls.Extension - ReceivedExtensions(msgType uint8, exts []qtls.Extension) error -} - -// CryptoSetup handles the handshake and protecting / unprotecting packets -type CryptoSetup interface { - RunHandshake() error - io.Closer - - HandleMessage([]byte, protocol.EncryptionLevel) bool - ConnectionState() ConnectionState - - GetSealer() (protocol.EncryptionLevel, Sealer) - GetSealerWithEncryptionLevel(protocol.EncryptionLevel) (Sealer, error) - GetOpener(protocol.EncryptionLevel) (Opener, error) -} - -// ConnectionState records basic details about the QUIC connection. -// Warning: This API should not be considered stable and might change soon. -type ConnectionState struct { - HandshakeComplete bool // handshake is complete - ServerName string // server name requested by client, if any (server side only) - PeerCertificates []*x509.Certificate // certificate chain presented by remote peer -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/qtls.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/qtls.go deleted file mode 100644 index 23543b5c0..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/qtls.go +++ /dev/null @@ -1,50 +0,0 @@ -package handshake - -import ( - "crypto/tls" - - "v2ray.com/core/external/github.com/marten-seemann/qtls" -) - -func tlsConfigToQtlsConfig(c *tls.Config) *qtls.Config { - if c == nil { - c = &tls.Config{} - } - // QUIC requires TLS 1.3 or newer - minVersion := c.MinVersion - if minVersion < qtls.VersionTLS13 { - minVersion = qtls.VersionTLS13 - } - maxVersion := c.MaxVersion - if maxVersion < qtls.VersionTLS13 { - maxVersion = qtls.VersionTLS13 - } - return &qtls.Config{ - Rand: c.Rand, - Time: c.Time, - Certificates: c.Certificates, - NameToCertificate: c.NameToCertificate, - // TODO: make GetCertificate work - // GetCertificate: c.GetCertificate, - GetClientCertificate: c.GetClientCertificate, - // TODO: make GetConfigForClient work - // GetConfigForClient: c.GetConfigForClient, - VerifyPeerCertificate: c.VerifyPeerCertificate, - RootCAs: c.RootCAs, - NextProtos: c.NextProtos, - ServerName: c.ServerName, - ClientAuth: c.ClientAuth, - ClientCAs: c.ClientCAs, - InsecureSkipVerify: c.InsecureSkipVerify, - CipherSuites: c.CipherSuites, - PreferServerCipherSuites: c.PreferServerCipherSuites, - SessionTicketsDisabled: c.SessionTicketsDisabled, - SessionTicketKey: c.SessionTicketKey, - MinVersion: minVersion, - MaxVersion: maxVersion, - CurvePreferences: c.CurvePreferences, - DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, - Renegotiation: c.Renegotiation, - KeyLogWriter: c.KeyLogWriter, - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/tls_extension.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/tls_extension.go deleted file mode 100644 index 894ad7e4d..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/tls_extension.go +++ /dev/null @@ -1,90 +0,0 @@ -package handshake - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -const quicTLSExtensionType = 0xffa5 - -type clientHelloTransportParameters struct { - InitialVersion protocol.VersionNumber - Parameters TransportParameters -} - -func (p *clientHelloTransportParameters) Marshal() []byte { - const lenOffset = 4 - b := &bytes.Buffer{} - utils.BigEndian.WriteUint32(b, uint32(p.InitialVersion)) - b.Write([]byte{0, 0}) // length. Will be replaced later - p.Parameters.marshal(b) - data := b.Bytes() - binary.BigEndian.PutUint16(data[lenOffset:lenOffset+2], uint16(len(data)-lenOffset-2)) - return data -} - -func (p *clientHelloTransportParameters) Unmarshal(data []byte) error { - if len(data) < 6 { - return errors.New("transport parameter data too short") - } - p.InitialVersion = protocol.VersionNumber(binary.BigEndian.Uint32(data[:4])) - paramsLen := int(binary.BigEndian.Uint16(data[4:6])) - data = data[6:] - if len(data) != paramsLen { - return fmt.Errorf("expected transport parameters to be %d bytes long, have %d", paramsLen, len(data)) - } - return p.Parameters.unmarshal(data, protocol.PerspectiveClient) -} - -type encryptedExtensionsTransportParameters struct { - NegotiatedVersion protocol.VersionNumber - SupportedVersions []protocol.VersionNumber - Parameters TransportParameters -} - -func (p *encryptedExtensionsTransportParameters) Marshal() []byte { - b := &bytes.Buffer{} - utils.BigEndian.WriteUint32(b, uint32(p.NegotiatedVersion)) - b.WriteByte(uint8(4 * len(p.SupportedVersions))) - for _, v := range p.SupportedVersions { - utils.BigEndian.WriteUint32(b, uint32(v)) - } - lenOffset := b.Len() - b.Write([]byte{0, 0}) // length. Will be replaced later - p.Parameters.marshal(b) - data := b.Bytes() - binary.BigEndian.PutUint16(data[lenOffset:lenOffset+2], uint16(len(data)-lenOffset-2)) - return data -} - -func (p *encryptedExtensionsTransportParameters) Unmarshal(data []byte) error { - if len(data) < 5 { - return errors.New("transport parameter data too short") - } - p.NegotiatedVersion = protocol.VersionNumber(binary.BigEndian.Uint32(data[:4])) - numVersions := int(data[4]) - if numVersions%4 != 0 { - return fmt.Errorf("invalid length for version list: %d", numVersions) - } - numVersions /= 4 - data = data[5:] - if len(data) < 4*numVersions+2 /*length field for the parameter list */ { - return errors.New("transport parameter data too short") - } - p.SupportedVersions = make([]protocol.VersionNumber, numVersions) - for i := 0; i < numVersions; i++ { - p.SupportedVersions[i] = protocol.VersionNumber(binary.BigEndian.Uint32(data[:4])) - data = data[4:] - } - paramsLen := int(binary.BigEndian.Uint16(data[:2])) - data = data[2:] - if len(data) != paramsLen { - return fmt.Errorf("expected transport parameters to be %d bytes long, have %d", paramsLen, len(data)) - } - return p.Parameters.unmarshal(data, protocol.PerspectiveServer) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client.go deleted file mode 100644 index 8a6869594..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_client.go +++ /dev/null @@ -1,113 +0,0 @@ -package handshake - -import ( - "errors" - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/marten-seemann/qtls" -) - -type extensionHandlerClient struct { - ourParams *TransportParameters - paramsChan chan<- TransportParameters - - origConnID protocol.ConnectionID - initialVersion protocol.VersionNumber - supportedVersions []protocol.VersionNumber - version protocol.VersionNumber - - logger utils.Logger -} - -var _ tlsExtensionHandler = &extensionHandlerClient{} - -// newExtensionHandlerClient creates a new extension handler for the client. -func newExtensionHandlerClient( - params *TransportParameters, - origConnID protocol.ConnectionID, - initialVersion protocol.VersionNumber, - supportedVersions []protocol.VersionNumber, - version protocol.VersionNumber, - logger utils.Logger, -) (tlsExtensionHandler, <-chan TransportParameters) { - // The client reads the transport parameters from the Encrypted Extensions message. - // The paramsChan is used in the session's run loop's select statement. - // We have to use an unbuffered channel here to make sure that the session actually processes the transport parameters immediately. - paramsChan := make(chan TransportParameters) - return &extensionHandlerClient{ - ourParams: params, - paramsChan: paramsChan, - origConnID: origConnID, - initialVersion: initialVersion, - supportedVersions: supportedVersions, - version: version, - logger: logger, - }, paramsChan -} - -func (h *extensionHandlerClient) GetExtensions(msgType uint8) []qtls.Extension { - if messageType(msgType) != typeClientHello { - return nil - } - h.logger.Debugf("Sending Transport Parameters: %s", h.ourParams) - return []qtls.Extension{{ - Type: quicTLSExtensionType, - Data: (&clientHelloTransportParameters{ - InitialVersion: h.initialVersion, - Parameters: *h.ourParams, - }).Marshal(), - }} -} - -func (h *extensionHandlerClient) ReceivedExtensions(msgType uint8, exts []qtls.Extension) error { - if messageType(msgType) != typeEncryptedExtensions { - return nil - } - - var found bool - eetp := &encryptedExtensionsTransportParameters{} - for _, ext := range exts { - if ext.Type != quicTLSExtensionType { - continue - } - if err := eetp.Unmarshal(ext.Data); err != nil { - return err - } - found = true - } - if !found { - return errors.New("EncryptedExtensions message didn't contain a QUIC extension") - } - - // check that the negotiated_version is the current version - if eetp.NegotiatedVersion != h.version { - return qerr.Error(qerr.VersionNegotiationMismatch, "current version doesn't match negotiated_version") - } - // check that the current version is included in the supported versions - if !protocol.IsSupportedVersion(eetp.SupportedVersions, h.version) { - return qerr.Error(qerr.VersionNegotiationMismatch, "current version not included in the supported versions") - } - // if version negotiation was performed, check that we would have selected the current version based on the supported versions sent by the server - if h.version != h.initialVersion { - negotiatedVersion, ok := protocol.ChooseSupportedVersion(h.supportedVersions, eetp.SupportedVersions) - if !ok || h.version != negotiatedVersion { - return qerr.Error(qerr.VersionNegotiationMismatch, "would have picked a different version") - } - } - - params := eetp.Parameters - // check that the server sent a stateless reset token - if len(params.StatelessResetToken) == 0 { - return errors.New("server didn't sent stateless_reset_token") - } - // check the Retry token - if !h.origConnID.Equal(params.OriginalConnectionID) { - return fmt.Errorf("expected original_connection_id to equal %s, is %s", h.origConnID, params.OriginalConnectionID) - } - h.logger.Debugf("Received Transport Parameters: %s", ¶ms) - h.paramsChan <- params - return nil -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server.go deleted file mode 100644 index 7159a2ff8..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/tls_extension_handler_server.go +++ /dev/null @@ -1,86 +0,0 @@ -package handshake - -import ( - "errors" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/marten-seemann/qtls" -) - -type extensionHandlerServer struct { - ourParams *TransportParameters - paramsChan chan<- TransportParameters - - version protocol.VersionNumber - supportedVersions []protocol.VersionNumber - - logger utils.Logger -} - -var _ tlsExtensionHandler = &extensionHandlerServer{} - -// newExtensionHandlerServer creates a new extension handler for the server -func newExtensionHandlerServer( - params *TransportParameters, - supportedVersions []protocol.VersionNumber, - version protocol.VersionNumber, - logger utils.Logger, -) (tlsExtensionHandler, <-chan TransportParameters) { - // Processing the ClientHello is performed statelessly (and from a single go-routine). - // Therefore, we have to use a buffered chan to pass the transport parameters to that go routine. - paramsChan := make(chan TransportParameters) - return &extensionHandlerServer{ - ourParams: params, - paramsChan: paramsChan, - supportedVersions: supportedVersions, - version: version, - logger: logger, - }, paramsChan -} - -func (h *extensionHandlerServer) GetExtensions(msgType uint8) []qtls.Extension { - if messageType(msgType) != typeEncryptedExtensions { - return nil - } - h.logger.Debugf("Sending Transport Parameters: %s", h.ourParams) - return []qtls.Extension{{ - Type: quicTLSExtensionType, - Data: (&encryptedExtensionsTransportParameters{ - NegotiatedVersion: h.version, - SupportedVersions: protocol.GetGreasedVersions(h.supportedVersions), - Parameters: *h.ourParams, - }).Marshal(), - }} -} - -func (h *extensionHandlerServer) ReceivedExtensions(msgType uint8, exts []qtls.Extension) error { - if messageType(msgType) != typeClientHello { - return nil - } - var found bool - chtp := &clientHelloTransportParameters{} - for _, ext := range exts { - if ext.Type != quicTLSExtensionType { - continue - } - if err := chtp.Unmarshal(ext.Data); err != nil { - return err - } - found = true - } - if !found { - return errors.New("ClientHello didn't contain a QUIC extension") - } - - // perform the stateless version negotiation validation: - // make sure that we would have sent a Version Negotiation Packet if the client offered the initial version - // this is the case if and only if the initial version is not contained in the supported versions - if chtp.InitialVersion != h.version && protocol.IsSupportedVersion(h.supportedVersions, chtp.InitialVersion) { - return qerr.Error(qerr.VersionNegotiationMismatch, "Client should have used the initial version") - } - h.logger.Debugf("Received Transport Parameters: %s", &chtp.Parameters) - h.paramsChan <- chtp.Parameters - return nil -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/handshake/transport_parameters.go b/external/github.com/lucas-clemente/quic-go/internal/handshake/transport_parameters.go deleted file mode 100644 index 2477c37a0..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/handshake/transport_parameters.go +++ /dev/null @@ -1,210 +0,0 @@ -package handshake - -import ( - "bytes" - "errors" - "fmt" - "io" - "sort" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -type transportParameterID uint16 - -const ( - originalConnectionIDParameterID transportParameterID = 0x0 - idleTimeoutParameterID transportParameterID = 0x1 - statelessResetTokenParameterID transportParameterID = 0x2 - maxPacketSizeParameterID transportParameterID = 0x3 - initialMaxDataParameterID transportParameterID = 0x4 - initialMaxStreamDataBidiLocalParameterID transportParameterID = 0x5 - initialMaxStreamDataBidiRemoteParameterID transportParameterID = 0x6 - initialMaxStreamDataUniParameterID transportParameterID = 0x7 - initialMaxStreamsBidiParameterID transportParameterID = 0x8 - initialMaxStreamsUniParameterID transportParameterID = 0x9 - disableMigrationParameterID transportParameterID = 0xc -) - -// TransportParameters are parameters sent to the peer during the handshake -type TransportParameters struct { - InitialMaxStreamDataBidiLocal protocol.ByteCount - InitialMaxStreamDataBidiRemote protocol.ByteCount - InitialMaxStreamDataUni protocol.ByteCount - InitialMaxData protocol.ByteCount - - MaxPacketSize protocol.ByteCount - - MaxUniStreams uint64 - MaxBidiStreams uint64 - - IdleTimeout time.Duration - DisableMigration bool - - StatelessResetToken []byte - OriginalConnectionID protocol.ConnectionID -} - -func (p *TransportParameters) unmarshal(data []byte, sentBy protocol.Perspective) error { - // needed to check that every parameter is only sent at most once - var parameterIDs []transportParameterID - - r := bytes.NewReader(data) - for r.Len() >= 4 { - paramIDInt, _ := utils.BigEndian.ReadUint16(r) - paramID := transportParameterID(paramIDInt) - paramLen, _ := utils.BigEndian.ReadUint16(r) - parameterIDs = append(parameterIDs, paramID) - switch paramID { - case initialMaxStreamDataBidiLocalParameterID, - initialMaxStreamDataBidiRemoteParameterID, - initialMaxStreamDataUniParameterID, - initialMaxDataParameterID, - initialMaxStreamsBidiParameterID, - initialMaxStreamsUniParameterID, - idleTimeoutParameterID, - maxPacketSizeParameterID: - if err := p.readNumericTransportParameter(r, paramID, int(paramLen)); err != nil { - return err - } - default: - if r.Len() < int(paramLen) { - return fmt.Errorf("remaining length (%d) smaller than parameter length (%d)", r.Len(), paramLen) - } - switch paramID { - case disableMigrationParameterID: - if paramLen != 0 { - return fmt.Errorf("wrong length for disable_migration: %d (expected empty)", paramLen) - } - p.DisableMigration = true - case statelessResetTokenParameterID: - if sentBy == protocol.PerspectiveClient { - return errors.New("client sent a stateless_reset_token") - } - if paramLen != 16 { - return fmt.Errorf("wrong length for stateless_reset_token: %d (expected 16)", paramLen) - } - b := make([]byte, 16) - r.Read(b) - p.StatelessResetToken = b - case originalConnectionIDParameterID: - if sentBy == protocol.PerspectiveClient { - return errors.New("client sent an original_connection_id") - } - p.OriginalConnectionID, _ = protocol.ReadConnectionID(r, int(paramLen)) - default: - r.Seek(int64(paramLen), io.SeekCurrent) - } - } - } - - // check that every transport parameter was sent at most once - sort.Slice(parameterIDs, func(i, j int) bool { return parameterIDs[i] < parameterIDs[j] }) - for i := 0; i < len(parameterIDs)-1; i++ { - if parameterIDs[i] == parameterIDs[i+1] { - return fmt.Errorf("received duplicate transport parameter %#x", parameterIDs[i]) - } - } - - if r.Len() != 0 { - return fmt.Errorf("should have read all data. Still have %d bytes", r.Len()) - } - return nil -} - -func (p *TransportParameters) readNumericTransportParameter( - r *bytes.Reader, - paramID transportParameterID, - expectedLen int, -) error { - remainingLen := r.Len() - val, err := utils.ReadVarInt(r) - if err != nil { - return fmt.Errorf("error while reading transport parameter %d: %s", paramID, err) - } - if remainingLen-r.Len() != expectedLen { - return fmt.Errorf("inconsistent transport parameter length for %d", paramID) - } - switch paramID { - case initialMaxStreamDataBidiLocalParameterID: - p.InitialMaxStreamDataBidiLocal = protocol.ByteCount(val) - case initialMaxStreamDataBidiRemoteParameterID: - p.InitialMaxStreamDataBidiRemote = protocol.ByteCount(val) - case initialMaxStreamDataUniParameterID: - p.InitialMaxStreamDataUni = protocol.ByteCount(val) - case initialMaxDataParameterID: - p.InitialMaxData = protocol.ByteCount(val) - case initialMaxStreamsBidiParameterID: - p.MaxBidiStreams = val - case initialMaxStreamsUniParameterID: - p.MaxUniStreams = val - case idleTimeoutParameterID: - p.IdleTimeout = utils.MaxDuration(protocol.MinRemoteIdleTimeout, time.Duration(val)*time.Second) - case maxPacketSizeParameterID: - if val < 1200 { - return fmt.Errorf("invalid value for max_packet_size: %d (minimum 1200)", val) - } - p.MaxPacketSize = protocol.ByteCount(val) - default: - return fmt.Errorf("TransportParameter BUG: transport parameter %d not found", paramID) - } - return nil -} - -func (p *TransportParameters) marshal(b *bytes.Buffer) { - // initial_max_stream_data_bidi_local - utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID)) - utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxStreamDataBidiLocal)))) - utils.WriteVarInt(b, uint64(p.InitialMaxStreamDataBidiLocal)) - // initial_max_stream_data_bidi_remote - utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiRemoteParameterID)) - utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxStreamDataBidiRemote)))) - utils.WriteVarInt(b, uint64(p.InitialMaxStreamDataBidiRemote)) - // initial_max_stream_data_uni - utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataUniParameterID)) - utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxStreamDataUni)))) - utils.WriteVarInt(b, uint64(p.InitialMaxStreamDataUni)) - // initial_max_data - utils.BigEndian.WriteUint16(b, uint16(initialMaxDataParameterID)) - utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxData)))) - utils.WriteVarInt(b, uint64(p.InitialMaxData)) - // initial_max_bidi_streams - utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamsBidiParameterID)) - utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(p.MaxBidiStreams))) - utils.WriteVarInt(b, p.MaxBidiStreams) - // initial_max_uni_streams - utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamsUniParameterID)) - utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(p.MaxUniStreams))) - utils.WriteVarInt(b, p.MaxUniStreams) - // idle_timeout - utils.BigEndian.WriteUint16(b, uint16(idleTimeoutParameterID)) - utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.IdleTimeout/time.Second)))) - utils.WriteVarInt(b, uint64(p.IdleTimeout/time.Second)) - // max_packet_size - utils.BigEndian.WriteUint16(b, uint16(maxPacketSizeParameterID)) - utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(protocol.MaxReceivePacketSize)))) - utils.WriteVarInt(b, uint64(protocol.MaxReceivePacketSize)) - // disable_migration - if p.DisableMigration { - utils.BigEndian.WriteUint16(b, uint16(disableMigrationParameterID)) - utils.BigEndian.WriteUint16(b, 0) - } - if len(p.StatelessResetToken) > 0 { - utils.BigEndian.WriteUint16(b, uint16(statelessResetTokenParameterID)) - utils.BigEndian.WriteUint16(b, uint16(len(p.StatelessResetToken))) // should always be 16 bytes - b.Write(p.StatelessResetToken) - } - // original_connection_id - if p.OriginalConnectionID.Len() > 0 { - utils.BigEndian.WriteUint16(b, uint16(originalConnectionIDParameterID)) - utils.BigEndian.WriteUint16(b, uint16(p.OriginalConnectionID.Len())) - b.Write(p.OriginalConnectionID.Bytes()) - } -} - -// String returns a string representation, intended for logging. -func (p *TransportParameters) String() string { - return fmt.Sprintf("&handshake.TransportParameters{OriginalConnectionID: %s, InitialMaxStreamDataBidiLocal: %#x, InitialMaxStreamDataBidiRemote: %#x, InitialMaxStreamDataUni: %#x, InitialMaxData: %#x, MaxBidiStreams: %d, MaxUniStreams: %d, IdleTimeout: %s}", p.OriginalConnectionID, p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreams, p.MaxUniStreams, p.IdleTimeout) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/mockgen_internal.sh b/external/github.com/lucas-clemente/quic-go/internal/mockgen_internal.sh deleted file mode 100755 index a0f9112b7..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/mockgen_internal.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -# Mockgen refuses to generate mocks for internal packages. -# This script copies the internal directory and renames it to internalpackage. -# It also creages a public alias for private types. -# It then creates a mock for this public (alias) type. -# Afterwards, it corrects the import paths (replaces internalpackage back to internal). - -TEMP_DIR=$(mktemp -d) -mkdir -p $TEMP_DIR/src/github.com/lucas-clemente/quic-go/internalpackage - -# uppercase the name of the interface (only has an effect for private interfaces) -INTERFACE_NAME="$(tr '[:lower:]' '[:upper:]' <<< ${4:0:1})${4:1}" -PACKAGE_NAME=`echo $3 | sed 's/.*\///'` - -cp -r $GOPATH/src/github.com/lucas-clemente/quic-go/internal/* $TEMP_DIR/src/github.com/lucas-clemente/quic-go/internalpackage -find $TEMP_DIR -type f -name "*.go" -exec sed -i '' 's/internal/internalpackage/g' {} \; - -export GOPATH="$TEMP_DIR:$GOPATH" -PACKAGE_PATH=${3/internal/internalpackage} - -# if we're mocking a private interface, we need to add a public alias -if [ "$INTERFACE_NAME" != "$4" ]; then - # create a public alias for the interface, so that mockgen can process it - echo -e "package $PACKAGE_NAME\n" > $TEMP_DIR/src/$PACKAGE_PATH/mockgen_interface.go - echo "type $INTERFACE_NAME = $4" >> $TEMP_DIR/src/$PACKAGE_PATH/mockgen_interface.go -fi - -mockgen -package $1 -self_package $1 -destination $2 $PACKAGE_PATH $INTERFACE_NAME -sed -i '' 's/internalpackage/internal/g' $2 - -# mockgen imports the package we're generating a mock for -sed -i '' "s/$1\.//g" $2 -goimports -w $2 - -rm -r "$TEMP_DIR" diff --git a/external/github.com/lucas-clemente/quic-go/internal/protocol/connection_id.go b/external/github.com/lucas-clemente/quic-go/internal/protocol/connection_id.go deleted file mode 100644 index f99461b2c..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/protocol/connection_id.go +++ /dev/null @@ -1,69 +0,0 @@ -package protocol - -import ( - "bytes" - "crypto/rand" - "fmt" - "io" -) - -// A ConnectionID in QUIC -type ConnectionID []byte - -const maxConnectionIDLen = 18 - -// GenerateConnectionID generates a connection ID using cryptographic random -func GenerateConnectionID(len int) (ConnectionID, error) { - b := make([]byte, len) - if _, err := rand.Read(b); err != nil { - return nil, err - } - return ConnectionID(b), nil -} - -// GenerateConnectionIDForInitial generates a connection ID for the Initial packet. -// It uses a length randomly chosen between 8 and 18 bytes. -func GenerateConnectionIDForInitial() (ConnectionID, error) { - r := make([]byte, 1) - if _, err := rand.Read(r); err != nil { - return nil, err - } - len := MinConnectionIDLenInitial + int(r[0])%(maxConnectionIDLen-MinConnectionIDLenInitial+1) - return GenerateConnectionID(len) -} - -// ReadConnectionID reads a connection ID of length len from the given io.Reader. -// It returns io.EOF if there are not enough bytes to read. -func ReadConnectionID(r io.Reader, len int) (ConnectionID, error) { - if len == 0 { - return nil, nil - } - c := make(ConnectionID, len) - _, err := io.ReadFull(r, c) - if err == io.ErrUnexpectedEOF { - return nil, io.EOF - } - return c, err -} - -// Equal says if two connection IDs are equal -func (c ConnectionID) Equal(other ConnectionID) bool { - return bytes.Equal(c, other) -} - -// Len returns the length of the connection ID in bytes -func (c ConnectionID) Len() int { - return len(c) -} - -// Bytes returns the byte representation -func (c ConnectionID) Bytes() []byte { - return []byte(c) -} - -func (c ConnectionID) String() string { - if c.Len() == 0 { - return "(empty)" - } - return fmt.Sprintf("%#x", c.Bytes()) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/protocol/encryption_level.go b/external/github.com/lucas-clemente/quic-go/internal/protocol/encryption_level.go deleted file mode 100644 index 4b059b3a8..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/protocol/encryption_level.go +++ /dev/null @@ -1,28 +0,0 @@ -package protocol - -// EncryptionLevel is the encryption level -// Default value is Unencrypted -type EncryptionLevel int - -const ( - // EncryptionUnspecified is a not specified encryption level - EncryptionUnspecified EncryptionLevel = iota - // EncryptionInitial is the Initial encryption level - EncryptionInitial - // EncryptionHandshake is the Handshake encryption level - EncryptionHandshake - // Encryption1RTT is the 1-RTT encryption level - Encryption1RTT -) - -func (e EncryptionLevel) String() string { - switch e { - case EncryptionInitial: - return "Initial" - case EncryptionHandshake: - return "Handshake" - case Encryption1RTT: - return "1-RTT" - } - return "unknown" -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/protocol/packet_number.go b/external/github.com/lucas-clemente/quic-go/internal/protocol/packet_number.go deleted file mode 100644 index 405a07ac7..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/protocol/packet_number.go +++ /dev/null @@ -1,85 +0,0 @@ -package protocol - -// PacketNumberLen is the length of the packet number in bytes -type PacketNumberLen uint8 - -const ( - // PacketNumberLenInvalid is the default value and not a valid length for a packet number - PacketNumberLenInvalid PacketNumberLen = 0 - // PacketNumberLen1 is a packet number length of 1 byte - PacketNumberLen1 PacketNumberLen = 1 - // PacketNumberLen2 is a packet number length of 2 bytes - PacketNumberLen2 PacketNumberLen = 2 - // PacketNumberLen3 is a packet number length of 3 bytes - PacketNumberLen3 PacketNumberLen = 3 - // PacketNumberLen4 is a packet number length of 4 bytes - PacketNumberLen4 PacketNumberLen = 4 -) - -// DecodePacketNumber calculates the packet number based on the received packet number, its length and the last seen packet number -func DecodePacketNumber( - packetNumberLength PacketNumberLen, - lastPacketNumber PacketNumber, - wirePacketNumber PacketNumber, -) PacketNumber { - var epochDelta PacketNumber - switch packetNumberLength { - case PacketNumberLen1: - epochDelta = PacketNumber(1) << 8 - case PacketNumberLen2: - epochDelta = PacketNumber(1) << 16 - case PacketNumberLen3: - epochDelta = PacketNumber(1) << 24 - case PacketNumberLen4: - epochDelta = PacketNumber(1) << 32 - } - epoch := lastPacketNumber & ^(epochDelta - 1) - prevEpochBegin := epoch - epochDelta - nextEpochBegin := epoch + epochDelta - return closestTo( - lastPacketNumber+1, - epoch+wirePacketNumber, - closestTo(lastPacketNumber+1, prevEpochBegin+wirePacketNumber, nextEpochBegin+wirePacketNumber), - ) -} - -func closestTo(target, a, b PacketNumber) PacketNumber { - if delta(target, a) < delta(target, b) { - return a - } - return b -} - -func delta(a, b PacketNumber) PacketNumber { - if a < b { - return b - a - } - return a - b -} - -// GetPacketNumberLengthForHeader gets the length of the packet number for the public header -// it never chooses a PacketNumberLen of 1 byte, since this is too short under certain circumstances -func GetPacketNumberLengthForHeader(packetNumber, leastUnacked PacketNumber) PacketNumberLen { - diff := uint64(packetNumber - leastUnacked) - if diff < (1 << (16 - 1)) { - return PacketNumberLen2 - } - if diff < (1 << (24 - 1)) { - return PacketNumberLen3 - } - return PacketNumberLen4 -} - -// GetPacketNumberLength gets the minimum length needed to fully represent the packet number -func GetPacketNumberLength(packetNumber PacketNumber) PacketNumberLen { - if packetNumber < (1 << (uint8(PacketNumberLen1) * 8)) { - return PacketNumberLen1 - } - if packetNumber < (1 << (uint8(PacketNumberLen2) * 8)) { - return PacketNumberLen2 - } - if packetNumber < (1 << (uint8(PacketNumberLen3) * 8)) { - return PacketNumberLen3 - } - return PacketNumberLen4 -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/protocol/params.go b/external/github.com/lucas-clemente/quic-go/internal/protocol/params.go deleted file mode 100644 index e6f9493fa..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/protocol/params.go +++ /dev/null @@ -1,119 +0,0 @@ -package protocol - -import "time" - -// MaxPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets. -const MaxPacketSizeIPv4 = 1252 - -// MaxPacketSizeIPv6 is the maximum packet size that we use for sending IPv6 packets. -const MaxPacketSizeIPv6 = 1232 - -const defaultMaxCongestionWindowPackets = 1000 - -// DefaultMaxCongestionWindow is the default for the max congestion window -const DefaultMaxCongestionWindow ByteCount = defaultMaxCongestionWindowPackets * DefaultTCPMSS - -// InitialCongestionWindow is the initial congestion window in QUIC packets -const InitialCongestionWindow ByteCount = 32 * DefaultTCPMSS - -// MaxUndecryptablePackets limits the number of undecryptable packets that are queued in the session. -const MaxUndecryptablePackets = 10 - -// ConnectionFlowControlMultiplier determines how much larger the connection flow control windows needs to be relative to any stream's flow control window -// This is the value that Chromium is using -const ConnectionFlowControlMultiplier = 1.5 - -// InitialMaxStreamData is the stream-level flow control window for receiving data -const InitialMaxStreamData = (1 << 10) * 512 // 512 kb - -// InitialMaxData is the connection-level flow control window for receiving data -const InitialMaxData = ConnectionFlowControlMultiplier * InitialMaxStreamData - -// DefaultMaxReceiveStreamFlowControlWindow is the default maximum stream-level flow control window for receiving data, for the server -const DefaultMaxReceiveStreamFlowControlWindow = 6 * (1 << 20) // 6 MB - -// DefaultMaxReceiveConnectionFlowControlWindow is the default connection-level flow control window for receiving data, for the server -const DefaultMaxReceiveConnectionFlowControlWindow = 15 * (1 << 20) // 12 MB - -// WindowUpdateThreshold is the fraction of the receive window that has to be consumed before an higher offset is advertised to the client -const WindowUpdateThreshold = 0.25 - -// DefaultMaxIncomingStreams is the maximum number of streams that a peer may open -const DefaultMaxIncomingStreams = 100 - -// DefaultMaxIncomingUniStreams is the maximum number of unidirectional streams that a peer may open -const DefaultMaxIncomingUniStreams = 100 - -// MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed. -const MaxSessionUnprocessedPackets = defaultMaxCongestionWindowPackets - -// SkipPacketAveragePeriodLength is the average period length in which one packet number is skipped to prevent an Optimistic ACK attack -const SkipPacketAveragePeriodLength PacketNumber = 500 - -// MaxTrackedSkippedPackets is the maximum number of skipped packet numbers the SentPacketHandler keep track of for Optimistic ACK attack mitigation -const MaxTrackedSkippedPackets = 10 - -// MaxAcceptQueueSize is the maximum number of sessions that the server queues for accepting. -// If the queue is full, new connection attempts will be rejected. -const MaxAcceptQueueSize = 32 - -// CookieExpiryTime is the valid time of a cookie -const CookieExpiryTime = 24 * time.Hour - -// MaxOutstandingSentPackets is maximum number of packets saved for retransmission. -// When reached, it imposes a soft limit on sending new packets: -// Sending ACKs and retransmission is still allowed, but now new regular packets can be sent. -const MaxOutstandingSentPackets = 2 * defaultMaxCongestionWindowPackets - -// MaxTrackedSentPackets is maximum number of sent packets saved for retransmission. -// When reached, no more packets will be sent. -// This value *must* be larger than MaxOutstandingSentPackets. -const MaxTrackedSentPackets = MaxOutstandingSentPackets * 5 / 4 - -// MaxTrackedReceivedAckRanges is the maximum number of ACK ranges tracked -const MaxTrackedReceivedAckRanges = defaultMaxCongestionWindowPackets - -// MaxNonRetransmittableAcks is the maximum number of packets containing an ACK, but no retransmittable frames, that we send in a row -const MaxNonRetransmittableAcks = 19 - -// MaxStreamFrameSorterGaps is the maximum number of gaps between received StreamFrames -// prevents DoS attacks against the streamFrameSorter -const MaxStreamFrameSorterGaps = 1000 - -// MaxCryptoStreamOffset is the maximum offset allowed on any of the crypto streams. -// This limits the size of the ClientHello and Certificates that can be received. -const MaxCryptoStreamOffset = 16 * (1 << 10) - -// MinRemoteIdleTimeout is the minimum value that we accept for the remote idle timeout -const MinRemoteIdleTimeout = 5 * time.Second - -// DefaultIdleTimeout is the default idle timeout -const DefaultIdleTimeout = 30 * time.Second - -// DefaultHandshakeTimeout is the default timeout for a connection until the crypto handshake succeeds. -const DefaultHandshakeTimeout = 10 * time.Second - -// RetiredConnectionIDDeleteTimeout is the time we keep closed sessions around in order to retransmit the CONNECTION_CLOSE. -// after this time all information about the old connection will be deleted -const RetiredConnectionIDDeleteTimeout = 5 * time.Second - -// MinStreamFrameSize is the minimum size that has to be left in a packet, so that we add another STREAM frame. -// This avoids splitting up STREAM frames into small pieces, which has 2 advantages: -// 1. it reduces the framing overhead -// 2. it reduces the head-of-line blocking, when a packet is lost -const MinStreamFrameSize ByteCount = 128 - -// MaxAckFrameSize is the maximum size for an ACK frame that we write -// Due to the varint encoding, ACK frames can grow (almost) indefinitely large. -// The MaxAckFrameSize should be large enough to encode many ACK range, -// but must ensure that a maximum size ACK frame fits into one packet. -const MaxAckFrameSize ByteCount = 1000 - -// MinPacingDelay is the minimum duration that is used for packet pacing -// If the packet packing frequency is higher, multiple packets might be sent at once. -// Example: For a packet pacing delay of 20 microseconds, we would send 5 packets at once, wait for 100 microseconds, and so forth. -const MinPacingDelay time.Duration = 100 * time.Microsecond - -// DefaultConnectionIDLength is the connection ID length that is used for multiplexed connections -// if no other value is configured. -const DefaultConnectionIDLength = 4 diff --git a/external/github.com/lucas-clemente/quic-go/internal/protocol/perspective.go b/external/github.com/lucas-clemente/quic-go/internal/protocol/perspective.go deleted file mode 100644 index 43358fecb..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/protocol/perspective.go +++ /dev/null @@ -1,26 +0,0 @@ -package protocol - -// Perspective determines if we're acting as a server or a client -type Perspective int - -// the perspectives -const ( - PerspectiveServer Perspective = 1 - PerspectiveClient Perspective = 2 -) - -// Opposite returns the perspective of the peer -func (p Perspective) Opposite() Perspective { - return 3 - p -} - -func (p Perspective) String() string { - switch p { - case PerspectiveServer: - return "Server" - case PerspectiveClient: - return "Client" - default: - return "invalid perspective" - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/protocol/protocol.go b/external/github.com/lucas-clemente/quic-go/internal/protocol/protocol.go deleted file mode 100644 index 26f69fdc6..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/protocol/protocol.go +++ /dev/null @@ -1,65 +0,0 @@ -package protocol - -import ( - "fmt" -) - -// A PacketNumber in QUIC -type PacketNumber uint64 - -// The PacketType is the Long Header Type -type PacketType uint8 - -const ( - // PacketTypeInitial is the packet type of an Initial packet - PacketTypeInitial PacketType = 1 + iota - // PacketTypeRetry is the packet type of a Retry packet - PacketTypeRetry - // PacketTypeHandshake is the packet type of a Handshake packet - PacketTypeHandshake - // PacketType0RTT is the packet type of a 0-RTT packet - PacketType0RTT -) - -func (t PacketType) String() string { - switch t { - case PacketTypeInitial: - return "Initial" - case PacketTypeRetry: - return "Retry" - case PacketTypeHandshake: - return "Handshake" - case PacketType0RTT: - return "0-RTT Protected" - default: - return fmt.Sprintf("unknown packet type: %d", t) - } -} - -// A ByteCount in QUIC -type ByteCount uint64 - -// MaxByteCount is the maximum value of a ByteCount -const MaxByteCount = ByteCount(1<<62 - 1) - -// An ApplicationErrorCode is an application-defined error code. -type ApplicationErrorCode uint16 - -// MaxReceivePacketSize maximum packet size of any QUIC packet, based on -// ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header, -// UDP adds an additional 8 bytes. This is a total overhead of 48 bytes. -// Ethernet's max packet size is 1500 bytes, 1500 - 48 = 1452. -const MaxReceivePacketSize ByteCount = 1452 - 64 - -// DefaultTCPMSS is the default maximum packet size used in the Linux TCP implementation. -// Used in QUIC for congestion window computations in bytes. -const DefaultTCPMSS ByteCount = 1460 - -// MinInitialPacketSize is the minimum size an Initial packet is required to have. -const MinInitialPacketSize = 1200 - -// MinStatelessResetSize is the minimum size of a stateless reset packet -const MinStatelessResetSize = 1 /* first byte */ + 22 /* random bytes */ + 16 /* token */ - -// MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet. -const MinConnectionIDLenInitial = 8 diff --git a/external/github.com/lucas-clemente/quic-go/internal/protocol/stream_id.go b/external/github.com/lucas-clemente/quic-go/internal/protocol/stream_id.go deleted file mode 100644 index b96e0c2bc..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/protocol/stream_id.go +++ /dev/null @@ -1,67 +0,0 @@ -package protocol - -// A StreamID in QUIC -type StreamID uint64 - -// StreamType encodes if this is a unidirectional or bidirectional stream -type StreamType uint8 - -const ( - // StreamTypeUni is a unidirectional stream - StreamTypeUni StreamType = iota - // StreamTypeBidi is a bidirectional stream - StreamTypeBidi -) - -// InitiatedBy says if the stream was initiated by the client or by the server -func (s StreamID) InitiatedBy() Perspective { - if s%2 == 0 { - return PerspectiveClient - } - return PerspectiveServer -} - -//Type says if this is a unidirectional or bidirectional stream -func (s StreamID) Type() StreamType { - if s%4 >= 2 { - return StreamTypeUni - } - return StreamTypeBidi -} - -// StreamNum returns how many streams in total are below this -// Example: for stream 9 it returns 3 (i.e. streams 1, 5 and 9) -func (s StreamID) StreamNum() uint64 { - return uint64(s/4) + 1 -} - -// MaxStreamID is the highest stream ID that a peer is allowed to open, -// when it is allowed to open numStreams. -func MaxStreamID(stype StreamType, numStreams uint64, pers Perspective) StreamID { - if numStreams == 0 { - return 0 - } - var first StreamID - switch stype { - case StreamTypeBidi: - switch pers { - case PerspectiveClient: - first = 0 - case PerspectiveServer: - first = 1 - } - case StreamTypeUni: - switch pers { - case PerspectiveClient: - first = 2 - case PerspectiveServer: - first = 3 - } - } - return first + 4*StreamID(numStreams-1) -} - -// FirstStream returns the first valid stream ID -func FirstStream(stype StreamType, pers Perspective) StreamID { - return MaxStreamID(stype, 1, pers) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/protocol/version.go b/external/github.com/lucas-clemente/quic-go/internal/protocol/version.go deleted file mode 100644 index 3406cfa46..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/protocol/version.go +++ /dev/null @@ -1,117 +0,0 @@ -package protocol - -import ( - "crypto/rand" - "encoding/binary" - "fmt" - "math" -) - -// VersionNumber is a version number as int -type VersionNumber uint32 - -// gQUIC version range as defined in the wiki: https://github.com/quicwg/base-drafts/wiki/QUIC-Versions -const ( - gquicVersion0 = 0x51303030 - maxGquicVersion = 0x51303439 -) - -// The version numbers, making grepping easier -const ( - VersionTLS VersionNumber = 0x51474fff - VersionWhatever VersionNumber = 1 // for when the version doesn't matter - VersionUnknown VersionNumber = math.MaxUint32 -) - -// SupportedVersions lists the versions that the server supports -// must be in sorted descending order -var SupportedVersions = []VersionNumber{VersionTLS} - -// IsValidVersion says if the version is known to quic-go -func IsValidVersion(v VersionNumber) bool { - return v == VersionTLS || IsSupportedVersion(SupportedVersions, v) -} - -func (vn VersionNumber) String() string { - switch vn { - case VersionWhatever: - return "whatever" - case VersionUnknown: - return "unknown" - case VersionTLS: - return "TLS dev version (WIP)" - default: - if vn.isGQUIC() { - return fmt.Sprintf("gQUIC %d", vn.toGQUICVersion()) - } - return fmt.Sprintf("%#x", uint32(vn)) - } -} - -// ToAltSvc returns the representation of the version for the H2 Alt-Svc parameters -func (vn VersionNumber) ToAltSvc() string { - return fmt.Sprintf("%d", vn) -} - -func (vn VersionNumber) isGQUIC() bool { - return vn > gquicVersion0 && vn <= maxGquicVersion -} - -func (vn VersionNumber) toGQUICVersion() int { - return int(10*(vn-gquicVersion0)/0x100) + int(vn%0x10) -} - -// IsSupportedVersion returns true if the server supports this version -func IsSupportedVersion(supported []VersionNumber, v VersionNumber) bool { - for _, t := range supported { - if t == v { - return true - } - } - return false -} - -// ChooseSupportedVersion finds the best version in the overlap of ours and theirs -// ours is a slice of versions that we support, sorted by our preference (descending) -// theirs is a slice of versions offered by the peer. The order does not matter. -// The bool returned indicates if a matching version was found. -func ChooseSupportedVersion(ours, theirs []VersionNumber) (VersionNumber, bool) { - for _, ourVer := range ours { - for _, theirVer := range theirs { - if ourVer == theirVer { - return ourVer, true - } - } - } - return 0, false -} - -// generateReservedVersion generates a reserved version number (v & 0x0f0f0f0f == 0x0a0a0a0a) -func generateReservedVersion() VersionNumber { - b := make([]byte, 4) - _, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything - return VersionNumber((binary.BigEndian.Uint32(b) | 0x0a0a0a0a) & 0xfafafafa) -} - -// GetGreasedVersions adds one reserved version number to a slice of version numbers, at a random position -func GetGreasedVersions(supported []VersionNumber) []VersionNumber { - b := make([]byte, 1) - _, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything - randPos := int(b[0]) % (len(supported) + 1) - greased := make([]VersionNumber, len(supported)+1) - copy(greased, supported[:randPos]) - greased[randPos] = generateReservedVersion() - copy(greased[randPos+1:], supported[randPos:]) - return greased -} - -// StripGreasedVersions strips all greased versions from a slice of versions -func StripGreasedVersions(versions []VersionNumber) []VersionNumber { - realVersions := make([]VersionNumber, 0, len(versions)) - for _, v := range versions { - if v&0x0f0f0f0f != 0x0a0a0a0a { - realVersions = append(realVersions, v) - } - } - return realVersions -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/qerr/error_codes.go b/external/github.com/lucas-clemente/quic-go/internal/qerr/error_codes.go deleted file mode 100644 index f3e6dd9cb..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/qerr/error_codes.go +++ /dev/null @@ -1,193 +0,0 @@ -package qerr - -// The error codes defined by QUIC -// Remember to run `go generate ./...` whenever the error codes change. -//go:generate stringer -type=ErrorCode -const ( - InternalError ErrorCode = 1 - // There were data frames after the a fin or reset. - StreamDataAfterTermination ErrorCode = 2 - // Control frame is malformed. - InvalidPacketHeader ErrorCode = 3 - // Frame data is malformed. - InvalidFrameData ErrorCode = 4 - // The packet contained no payload. - MissingPayload ErrorCode = 48 - // FEC data is malformed. - InvalidFecData ErrorCode = 5 - // STREAM frame data is malformed. - InvalidStreamData ErrorCode = 46 - // STREAM frame data overlaps with buffered data. - OverlappingStreamData ErrorCode = 87 - // Received STREAM frame data is not encrypted. - UnencryptedStreamData ErrorCode = 61 - // Attempt to send unencrypted STREAM frame. - AttemptToSendUnencryptedStreamData ErrorCode = 88 - // FEC frame data is not encrypted. - UnencryptedFecData ErrorCode = 77 - // RST_STREAM frame data is malformed. - InvalidRstStreamData ErrorCode = 6 - // CONNECTION_CLOSE frame data is malformed. - InvalidConnectionCloseData ErrorCode = 7 - // GOAWAY frame data is malformed. - InvalidGoawayData ErrorCode = 8 - // WINDOW_UPDATE frame data is malformed. - InvalidWindowUpdateData ErrorCode = 57 - // BLOCKED frame data is malformed. - InvalidBlockedData ErrorCode = 58 - // STOP_WAITING frame data is malformed. - InvalidStopWaitingData ErrorCode = 60 - // PATH_CLOSE frame data is malformed. - InvalidPathCloseData ErrorCode = 78 - // ACK frame data is malformed. - InvalidAckData ErrorCode = 9 - - // Version negotiation packet is malformed. - InvalidVersionNegotiationPacket ErrorCode = 10 - // Public RST packet is malformed. - InvalidPublicRstPacket ErrorCode = 11 - // There was an error decrypting. - DecryptionFailure ErrorCode = 12 - // There was an error encrypting. - EncryptionFailure ErrorCode = 13 - // The packet exceeded kMaxPacketSize. - PacketTooLarge ErrorCode = 14 - // The peer is going away. May be a client or server. - PeerGoingAway ErrorCode = 16 - // A stream ID was invalid. - InvalidStreamID ErrorCode = 17 - // A priority was invalid. - InvalidPriority ErrorCode = 49 - // Too many streams already open. - TooManyOpenStreams ErrorCode = 18 - // The peer created too many available streams. - TooManyAvailableStreams ErrorCode = 76 - // Received public reset for this connection. - PublicReset ErrorCode = 19 - // Invalid protocol version. - InvalidVersion ErrorCode = 20 - - // The Header ID for a stream was too far from the previous. - InvalidHeaderID ErrorCode = 22 - // Negotiable parameter received during handshake had invalid value. - InvalidNegotiatedValue ErrorCode = 23 - // There was an error decompressing data. - DecompressionFailure ErrorCode = 24 - // The connection timed out due to no network activity. - NetworkIdleTimeout ErrorCode = 25 - // The connection timed out waiting for the handshake to complete. - HandshakeTimeout ErrorCode = 67 - // There was an error encountered migrating addresses. - ErrorMigratingAddress ErrorCode = 26 - // There was an error encountered migrating port only. - ErrorMigratingPort ErrorCode = 86 - // There was an error while writing to the socket. - PacketWriteError ErrorCode = 27 - // There was an error while reading from the socket. - PacketReadError ErrorCode = 51 - // We received a STREAM_FRAME with no data and no fin flag set. - EmptyStreamFrameNoFin ErrorCode = 50 - // We received invalid data on the headers stream. - InvalidHeadersStreamData ErrorCode = 56 - // Invalid data on the headers stream received because of decompression - // failure. - HeadersStreamDataDecompressFailure ErrorCode = 97 - // The peer received too much data, violating flow control. - FlowControlReceivedTooMuchData ErrorCode = 59 - // The peer sent too much data, violating flow control. - FlowControlSentTooMuchData ErrorCode = 63 - // The peer received an invalid flow control window. - FlowControlInvalidWindow ErrorCode = 64 - // The connection has been IP pooled into an existing connection. - ConnectionIPPooled ErrorCode = 62 - // The connection has too many outstanding sent packets. - TooManyOutstandingSentPackets ErrorCode = 68 - // The connection has too many outstanding received packets. - TooManyOutstandingReceivedPackets ErrorCode = 69 - // The quic connection has been cancelled. - ConnectionCancelled ErrorCode = 70 - // Disabled QUIC because of high packet loss rate. - BadPacketLossRate ErrorCode = 71 - // Disabled QUIC because of too many PUBLIC_RESETs post handshake. - PublicResetsPostHandshake ErrorCode = 73 - // Disabled QUIC because of too many timeouts with streams open. - TimeoutsWithOpenStreams ErrorCode = 74 - // Closed because we failed to serialize a packet. - FailedToSerializePacket ErrorCode = 75 - // QUIC timed out after too many RTOs. - TooManyRtos ErrorCode = 85 - - // Crypto errors. - - // Hanshake failed. - HandshakeFailed ErrorCode = 28 - // Handshake message contained out of order tags. - CryptoTagsOutOfOrder ErrorCode = 29 - // Handshake message contained too many entries. - CryptoTooManyEntries ErrorCode = 30 - // Handshake message contained an invalid value length. - CryptoInvalidValueLength ErrorCode = 31 - // A crypto message was received after the handshake was complete. - CryptoMessageAfterHandshakeComplete ErrorCode = 32 - // A crypto message was received with an illegal message tag. - InvalidCryptoMessageType ErrorCode = 33 - // A crypto message was received with an illegal parameter. - InvalidCryptoMessageParameter ErrorCode = 34 - // An invalid channel id signature was supplied. - InvalidChannelIDSignature ErrorCode = 52 - // A crypto message was received with a mandatory parameter missing. - CryptoMessageParameterNotFound ErrorCode = 35 - // A crypto message was received with a parameter that has no overlap - // with the local parameter. - CryptoMessageParameterNoOverlap ErrorCode = 36 - // A crypto message was received that contained a parameter with too few - // values. - CryptoMessageIndexNotFound ErrorCode = 37 - // An internal error occurred in crypto processing. - CryptoInternalError ErrorCode = 38 - // A crypto handshake message specified an unsupported version. - CryptoVersionNotSupported ErrorCode = 39 - // A crypto handshake message resulted in a stateless reject. - CryptoHandshakeStatelessReject ErrorCode = 72 - // There was no intersection between the crypto primitives supported by the - // peer and ourselves. - CryptoNoSupport ErrorCode = 40 - // The server rejected our client hello messages too many times. - CryptoTooManyRejects ErrorCode = 41 - // The client rejected the server's certificate chain or signature. - ProofInvalid ErrorCode = 42 - // A crypto message was received with a duplicate tag. - CryptoDuplicateTag ErrorCode = 43 - // A crypto message was received with the wrong encryption level (i.e. it - // should have been encrypted but was not.) - CryptoEncryptionLevelIncorrect ErrorCode = 44 - // The server config for a server has expired. - CryptoServerConfigExpired ErrorCode = 45 - // We failed to setup the symmetric keys for a connection. - CryptoSymmetricKeySetupFailed ErrorCode = 53 - // A handshake message arrived, but we are still validating the - // previous handshake message. - CryptoMessageWhileValidatingClientHello ErrorCode = 54 - // A server config update arrived before the handshake is complete. - CryptoUpdateBeforeHandshakeComplete ErrorCode = 65 - // This connection involved a version negotiation which appears to have been - // tampered with. - VersionNegotiationMismatch ErrorCode = 55 - - // Multipath is not enabled, but a packet with multipath flag on is received. - BadMultipathFlag ErrorCode = 79 - - // IP address changed causing connection close. - IPAddressChanged ErrorCode = 80 - - // Connection migration errors. - // Network changed, but connection had no migratable streams. - ConnectionMigrationNoMigratableStreams ErrorCode = 81 - // Connection changed networks too many times. - ConnectionMigrationTooManyChanges ErrorCode = 82 - // Connection migration was attempted, but there was no new network to - // migrate to. - ConnectionMigrationNoNewNetwork ErrorCode = 83 - // Network changed, but connection had one or more non-migratable streams. - ConnectionMigrationNonMigratableStream ErrorCode = 84 -) diff --git a/external/github.com/lucas-clemente/quic-go/internal/qerr/errorcode_string.go b/external/github.com/lucas-clemente/quic-go/internal/qerr/errorcode_string.go deleted file mode 100644 index 22d0c85a7..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/qerr/errorcode_string.go +++ /dev/null @@ -1,46 +0,0 @@ -// Code generated by "stringer -type=ErrorCode"; DO NOT EDIT. - -package qerr - -import "strconv" - -const ( - _ErrorCode_name_0 = "InternalErrorStreamDataAfterTerminationInvalidPacketHeaderInvalidFrameDataInvalidFecDataInvalidRstStreamDataInvalidConnectionCloseDataInvalidGoawayDataInvalidAckDataInvalidVersionNegotiationPacketInvalidPublicRstPacketDecryptionFailureEncryptionFailurePacketTooLarge" - _ErrorCode_name_1 = "PeerGoingAwayInvalidStreamIDTooManyOpenStreamsPublicResetInvalidVersion" - _ErrorCode_name_2 = "InvalidHeaderIDInvalidNegotiatedValueDecompressionFailureNetworkIdleTimeoutErrorMigratingAddressPacketWriteErrorHandshakeFailedCryptoTagsOutOfOrderCryptoTooManyEntriesCryptoInvalidValueLengthCryptoMessageAfterHandshakeCompleteInvalidCryptoMessageTypeInvalidCryptoMessageParameterCryptoMessageParameterNotFoundCryptoMessageParameterNoOverlapCryptoMessageIndexNotFoundCryptoInternalErrorCryptoVersionNotSupportedCryptoNoSupportCryptoTooManyRejectsProofInvalidCryptoDuplicateTagCryptoEncryptionLevelIncorrectCryptoServerConfigExpiredInvalidStreamData" - _ErrorCode_name_3 = "MissingPayloadInvalidPriorityEmptyStreamFrameNoFinPacketReadErrorInvalidChannelIDSignatureCryptoSymmetricKeySetupFailedCryptoMessageWhileValidatingClientHelloVersionNegotiationMismatchInvalidHeadersStreamDataInvalidWindowUpdateDataInvalidBlockedDataFlowControlReceivedTooMuchDataInvalidStopWaitingDataUnencryptedStreamDataConnectionIPPooledFlowControlSentTooMuchDataFlowControlInvalidWindowCryptoUpdateBeforeHandshakeComplete" - _ErrorCode_name_4 = "HandshakeTimeoutTooManyOutstandingSentPacketsTooManyOutstandingReceivedPacketsConnectionCancelledBadPacketLossRateCryptoHandshakeStatelessRejectPublicResetsPostHandshakeTimeoutsWithOpenStreamsFailedToSerializePacketTooManyAvailableStreamsUnencryptedFecDataInvalidPathCloseDataBadMultipathFlagIPAddressChangedConnectionMigrationNoMigratableStreamsConnectionMigrationTooManyChangesConnectionMigrationNoNewNetworkConnectionMigrationNonMigratableStreamTooManyRtosErrorMigratingPortOverlappingStreamDataAttemptToSendUnencryptedStreamData" - _ErrorCode_name_5 = "HeadersStreamDataDecompressFailure" -) - -var ( - _ErrorCode_index_0 = [...]uint16{0, 13, 39, 58, 74, 88, 108, 134, 151, 165, 196, 218, 235, 252, 266} - _ErrorCode_index_1 = [...]uint8{0, 13, 28, 46, 57, 71} - _ErrorCode_index_2 = [...]uint16{0, 15, 37, 57, 75, 96, 112, 127, 147, 167, 191, 226, 250, 279, 309, 340, 366, 385, 410, 425, 445, 457, 475, 505, 530, 547} - _ErrorCode_index_3 = [...]uint16{0, 14, 29, 50, 65, 90, 119, 158, 184, 208, 231, 249, 279, 301, 322, 340, 366, 390, 425} - _ErrorCode_index_4 = [...]uint16{0, 16, 45, 78, 97, 114, 144, 169, 192, 215, 238, 256, 276, 292, 308, 346, 379, 410, 448, 459, 477, 498, 532} -) - -func (i ErrorCode) String() string { - switch { - case 1 <= i && i <= 14: - i -= 1 - return _ErrorCode_name_0[_ErrorCode_index_0[i]:_ErrorCode_index_0[i+1]] - case 16 <= i && i <= 20: - i -= 16 - return _ErrorCode_name_1[_ErrorCode_index_1[i]:_ErrorCode_index_1[i+1]] - case 22 <= i && i <= 46: - i -= 22 - return _ErrorCode_name_2[_ErrorCode_index_2[i]:_ErrorCode_index_2[i+1]] - case 48 <= i && i <= 65: - i -= 48 - return _ErrorCode_name_3[_ErrorCode_index_3[i]:_ErrorCode_index_3[i+1]] - case 67 <= i && i <= 88: - i -= 67 - return _ErrorCode_name_4[_ErrorCode_index_4[i]:_ErrorCode_index_4[i+1]] - case i == 97: - return _ErrorCode_name_5 - default: - return "ErrorCode(" + strconv.FormatInt(int64(i), 10) + ")" - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/qerr/quic_error.go b/external/github.com/lucas-clemente/quic-go/internal/qerr/quic_error.go deleted file mode 100644 index 4a90b5784..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/qerr/quic_error.go +++ /dev/null @@ -1,53 +0,0 @@ -package qerr - -import ( - "fmt" -) - -// ErrorCode can be used as a normal error without reason. -type ErrorCode uint16 - -func (e ErrorCode) Error() string { - return e.String() -} - -// A QuicError consists of an error code plus a error reason -type QuicError struct { - ErrorCode ErrorCode - ErrorMessage string -} - -// Error creates a new QuicError instance -func Error(errorCode ErrorCode, errorMessage string) *QuicError { - return &QuicError{ - ErrorCode: errorCode, - ErrorMessage: errorMessage, - } -} - -func (e *QuicError) Error() string { - return fmt.Sprintf("%s: %s", e.ErrorCode.String(), e.ErrorMessage) -} - -// Timeout says if this error is a timeout. -func (e *QuicError) Timeout() bool { - switch e.ErrorCode { - case NetworkIdleTimeout, - HandshakeTimeout, - TimeoutsWithOpenStreams: - return true - } - return false -} - -// ToQuicError converts an arbitrary error to a QuicError. It leaves QuicErrors -// unchanged, and properly handles `ErrorCode`s. -func ToQuicError(err error) *QuicError { - switch e := err.(type) { - case *QuicError: - return e - case ErrorCode: - return Error(e, "") - } - return Error(InternalError, err.Error()) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/testdata/ca.pem b/external/github.com/lucas-clemente/quic-go/internal/testdata/ca.pem deleted file mode 100644 index 1118b05b8..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/testdata/ca.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC0DCCAbgCCQCmiwJpSoekpDANBgkqhkiG9w0BAQsFADAqMRMwEQYDVQQKDApx -dWljLWdvIENBMRMwEQYDVQQLDApxdWljLWdvIENBMB4XDTE4MTIwODA2NDIyMVoX -DTI4MTIwNTA2NDIyMVowKjETMBEGA1UECgwKcXVpYy1nbyBDQTETMBEGA1UECwwK -cXVpYy1nbyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN5MxI09 -i01xRON732BFIuxO2SGjA9jYkvUvNXK886gifp2BfWLcOW1DHkXxBnhWMqfpcIWM -GviF4G2Mp0HEJDMe+4LBxje/1e2WA+nzQlIZD6LaDi98nXJaAcCMM4a64Vm0i8Z3 -+4c+O93+5TekPn507nl7QA1IaEEtoek7w7wDw4ZF3ET+nns2HwVpV/ugfuYOQbTJ -8Np+zO8EfPMTUjEpKdl4bp/yqcouWD+oIhoxmx1V+LxshcpSwtzHIAi6gjHUDCEe -bk5Y2GBT4VR5WKmNGvlfe9L0Gn0ZLJoeXDshrunF0xEmSv8MxlHcKH/u4IHiO+6x -+5sdslqY7uEPEhkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAhvXUMiatkgsnoRHc -UobKraGttETivxvtKpc48o1TSkR+kCKbMnygmrvc5niEqc9iDg8JI6HjBKJ3/hfA -uKdyiR8cQNcQRgJ/3FVx0n3KGDUbHJSuIQzFvXom2ZPdlAHFqAT+8AVrz42v8gct -gyiGdFCSNisDbevOiRHuJtZ0m8YsGgtfU48wqGOaSSsRz4mYD6kqBFd0+Ja3/EGv -vl24L5xMCy1zGGl6wKPa7TT7ok4TfD1YmIXOfmWYop6cTLwePLj1nHrLi0AlsSn1 -2pFlosc9/qEbO5drqNoxUZfeF0L9RUSuArHRSO779dW/AmOtFdK3yaBGqflg0r7p -lYombA== ------END CERTIFICATE----- diff --git a/external/github.com/lucas-clemente/quic-go/internal/testdata/cert.go b/external/github.com/lucas-clemente/quic-go/internal/testdata/cert.go deleted file mode 100644 index 0f67e0759..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/testdata/cert.go +++ /dev/null @@ -1,57 +0,0 @@ -package testdata - -import ( - "crypto/tls" - "crypto/x509" - "encoding/pem" - "io/ioutil" - "path" - "runtime" -) - -var certPath string - -func init() { - _, filename, _, ok := runtime.Caller(0) - if !ok { - panic("Failed to get current frame") - } - - certPath = path.Dir(filename) -} - -// GetCertificatePaths returns the paths to certificate and key -func GetCertificatePaths() (string, string) { - return path.Join(certPath, "cert.pem"), path.Join(certPath, "priv.key") -} - -// GetTLSConfig returns a tls config for quic.clemente.io -func GetTLSConfig() *tls.Config { - cert, err := tls.LoadX509KeyPair(GetCertificatePaths()) - if err != nil { - panic(err) - } - return &tls.Config{ - Certificates: []tls.Certificate{cert}, - } -} - -// GetRootCA returns an x509.CertPool containing the CA certificate -func GetRootCA() *x509.CertPool { - caCertPath := path.Join(certPath, "ca.pem") - caCertRaw, err := ioutil.ReadFile(caCertPath) - if err != nil { - panic(err) - } - p, _ := pem.Decode(caCertRaw) - if p.Type != "CERTIFICATE" { - panic("expected a certificate") - } - caCert, err := x509.ParseCertificate(p.Bytes) - if err != nil { - panic(err) - } - certPool := x509.NewCertPool() - certPool.AddCert(caCert) - return certPool -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/testdata/cert.pem b/external/github.com/lucas-clemente/quic-go/internal/testdata/cert.pem deleted file mode 100644 index 28e66b707..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/testdata/cert.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC3jCCAcYCCQCV4BOv+SRo4zANBgkqhkiG9w0BAQUFADAqMRMwEQYDVQQKDApx -dWljLWdvIENBMRMwEQYDVQQLDApxdWljLWdvIENBMB4XDTE4MTIwODA2NDMwMloX -DTI4MTIwNTA2NDMwMlowODEQMA4GA1UECgwHcXVpYy1nbzEQMA4GA1UECwwHcXVp -Yy1nbzESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAyc/hS8XHkOJaLrdPOSTZFUBVyHNSfQUX/3dEpmccPlLQLgopYZZO -W/cVhkxAfQ3e68xKkuZKfZN5Hytn5V/AOSk281BqxFxpfCcKVYqVpDZH99+jaVfG -ImPp5Y22qCnbSEwYrMTcLiK8PVa4MkpKf1KNacVlqawU+ZWI5fevAFGTtmrMJ4S+ -qZY7tAaVkax+OiKWWfhLQjJCsN3IIDysTfbWao6cYKgtTfqVChEddzS7LRJVRaB+ -+huUbB87tRBJbCuJX65yB7Fw77YiKoFjc5r2845fcS2Ew4+w29mbXoj7M7g6eup5 -SnCydsCvyNy6VkgaSlWS0DXvxuzWshwUrwIDAQABMA0GCSqGSIb3DQEBBQUAA4IB -AQBWgmFunf44X3/NIjNvVLeQsfGW+4L/lCi2F5tqa70Hkda+xhKACnQQGB2qCSCF -Jfxj4iKrFJ7+JB8GnribWthLuDq49PQrTI+1wKFd9c2b8DXzJLz4Onw+mPX97pZm -TflQSIxXRaFAIQuUWNTArZZEe1ESSlnaBuE5w77LMf4GMFD3P3jzSHKUyM1sF97j -gRbIt8Jw7Uyd8vlXk6m2wvO5H3hZrrhJUJH3WW13a7wLJRnff2meKU90hkLQwuxO -kyh0k/h158/r2ibiahTmQEgHs9vQaCM+HXuk5P+Tzq5Zl/n0dMFZMfkqNkD4nym/ -nu7zfdwMlcBjKt9g3BGw+KE3 ------END CERTIFICATE----- diff --git a/external/github.com/lucas-clemente/quic-go/internal/testdata/priv.key b/external/github.com/lucas-clemente/quic-go/internal/testdata/priv.key deleted file mode 100644 index cd3dd0cfc..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/testdata/priv.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAyc/hS8XHkOJaLrdPOSTZFUBVyHNSfQUX/3dEpmccPlLQLgop -YZZOW/cVhkxAfQ3e68xKkuZKfZN5Hytn5V/AOSk281BqxFxpfCcKVYqVpDZH99+j -aVfGImPp5Y22qCnbSEwYrMTcLiK8PVa4MkpKf1KNacVlqawU+ZWI5fevAFGTtmrM -J4S+qZY7tAaVkax+OiKWWfhLQjJCsN3IIDysTfbWao6cYKgtTfqVChEddzS7LRJV -RaB++huUbB87tRBJbCuJX65yB7Fw77YiKoFjc5r2845fcS2Ew4+w29mbXoj7M7g6 -eup5SnCydsCvyNy6VkgaSlWS0DXvxuzWshwUrwIDAQABAoIBADunQwVO1Qqync2p -SbWueqyZc8HotL1XwBw3eQdm+yZA/GBfiJPcBhWRF7+20mkkrHwuyuxZPjOYX/ki -r3dRslQzJpcNckHQvy1/rMJUUJ9VnDhc1sTQuTR5LC46kX9rv/HC7JhFKIBKrDHF -bHURGKxCDqLxQnfA8gJEfU7cw9HnxMxmKv7qJ3O7EHYMuTQstkYsGOr60zX/C+Zm -7YA+d7nx1LpL0m2lKs70iz5MzGg+KgKyrkMWQ30gpxILBxNzzuQr7Kv/+63/3+G9 -nfCGeLmwGakPFpm6/GwiABE0yGa71YNAQs18iUTZwP/ZEDw3KB2SoG8wcqWjNAd+ -cUF2PgECgYEA5Xe/OZouw9h0NBo0Zut+HC0YOuUfY72Ug9Fm8bAS6wDuPiO3jIvK -J40d+ZHNp4AakfTuugiqEDJRlV7T/F2K/KHDWvXTg5ZpAC8dsZKJMxyyAp8EniYQ -vsoFWeHBfsD83rCVKLcjDB3hbQH+MSoT3lsqjZRNiNUMK13gyuX7k28CgYEA4SWF -ySRXUqUezX5D8kV5rQVYLcw6WVB3czYd7cKf8zHy4xJX0ZicyZjohknMmKCkdx+M -1mrxlqUO7EBGokM8vs87m/4rz6bjgZffpWzUmP/x1+3f3j/wIZeqNilW8NqY5nLi -tj3JxMwaesU86rOekSy27BlX4sjQ8NRs7Z2d8sECgYBKAD8kBWwVbqWy88x4cHOA -BK7ut1tTIB1YEVzgjobbULaERaJ46c/sx16mUHYBEZf///xI9Ghbxs52nFlC5qve -4xAMMoDey8/a5lbuIDKs0BE8NSoZEm+OB7qIDP0IspYZ/tprgfwEeVJshBsEoew8 -Ziwn8m66tPIyvhizdk2WcwKBgH2M8RgDffaGQbESEk3N1FZZvpx7YKZhqtrCeNoX -SB7T4cAigHpPAk+hRzlref46xrvvChiftmztSm8QQNNHb15wLauFh2Taic/Ao2Sa -VcukHnbtHYPQX9Y7vx1I3ESfgdgwhKBfwF5P+wwvZRL0ax5FsxPh5hJ/LZS+wKeY -13WBAoGAXSqG3ANmCyvSLVmAXGIbr0Tuixf/a25sPrlq7Im1H1OnqLrcyxWCLV3E -6gprhG5An0Zlr/FFRxVojf0TKmtJZs9B70/6WPwVvFtBduCM1zuUuCQYU9opTJQL -ElMIP4VfjABm4tm1fqGIy1PQP0Osb6/qb2DPPJqsFiW0oRByyMA= ------END RSA PRIVATE KEY----- diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/atomic_bool.go b/external/github.com/lucas-clemente/quic-go/internal/utils/atomic_bool.go deleted file mode 100644 index cf4642504..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/atomic_bool.go +++ /dev/null @@ -1,22 +0,0 @@ -package utils - -import "sync/atomic" - -// An AtomicBool is an atomic bool -type AtomicBool struct { - v int32 -} - -// Set sets the value -func (a *AtomicBool) Set(value bool) { - var n int32 - if value { - n = 1 - } - atomic.StoreInt32(&a.v, n) -} - -// Get gets the value -func (a *AtomicBool) Get() bool { - return atomic.LoadInt32(&a.v) != 0 -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/byteinterval_linkedlist.go b/external/github.com/lucas-clemente/quic-go/internal/utils/byteinterval_linkedlist.go deleted file mode 100644 index 096023ef2..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/byteinterval_linkedlist.go +++ /dev/null @@ -1,217 +0,0 @@ -// This file was automatically generated by genny. -// Any changes will be lost if this file is regenerated. -// see https://github.com/cheekybits/genny - -package utils - -// Linked list implementation from the Go standard library. - -// ByteIntervalElement is an element of a linked list. -type ByteIntervalElement struct { - // Next and previous pointers in the doubly-linked list of elements. - // To simplify the implementation, internally a list l is implemented - // as a ring, such that &l.root is both the next element of the last - // list element (l.Back()) and the previous element of the first list - // element (l.Front()). - next, prev *ByteIntervalElement - - // The list to which this element belongs. - list *ByteIntervalList - - // The value stored with this element. - Value ByteInterval -} - -// Next returns the next list element or nil. -func (e *ByteIntervalElement) Next() *ByteIntervalElement { - if p := e.next; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// Prev returns the previous list element or nil. -func (e *ByteIntervalElement) Prev() *ByteIntervalElement { - if p := e.prev; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// ByteIntervalList is a linked list of ByteIntervals. -type ByteIntervalList struct { - root ByteIntervalElement // sentinel list element, only &root, root.prev, and root.next are used - len int // current list length excluding (this) sentinel element -} - -// Init initializes or clears list l. -func (l *ByteIntervalList) Init() *ByteIntervalList { - l.root.next = &l.root - l.root.prev = &l.root - l.len = 0 - return l -} - -// NewByteIntervalList returns an initialized list. -func NewByteIntervalList() *ByteIntervalList { return new(ByteIntervalList).Init() } - -// Len returns the number of elements of list l. -// The complexity is O(1). -func (l *ByteIntervalList) Len() int { return l.len } - -// Front returns the first element of list l or nil if the list is empty. -func (l *ByteIntervalList) Front() *ByteIntervalElement { - if l.len == 0 { - return nil - } - return l.root.next -} - -// Back returns the last element of list l or nil if the list is empty. -func (l *ByteIntervalList) Back() *ByteIntervalElement { - if l.len == 0 { - return nil - } - return l.root.prev -} - -// lazyInit lazily initializes a zero List value. -func (l *ByteIntervalList) lazyInit() { - if l.root.next == nil { - l.Init() - } -} - -// insert inserts e after at, increments l.len, and returns e. -func (l *ByteIntervalList) insert(e, at *ByteIntervalElement) *ByteIntervalElement { - n := at.next - at.next = e - e.prev = at - e.next = n - n.prev = e - e.list = l - l.len++ - return e -} - -// insertValue is a convenience wrapper for insert(&Element{Value: v}, at). -func (l *ByteIntervalList) insertValue(v ByteInterval, at *ByteIntervalElement) *ByteIntervalElement { - return l.insert(&ByteIntervalElement{Value: v}, at) -} - -// remove removes e from its list, decrements l.len, and returns e. -func (l *ByteIntervalList) remove(e *ByteIntervalElement) *ByteIntervalElement { - e.prev.next = e.next - e.next.prev = e.prev - e.next = nil // avoid memory leaks - e.prev = nil // avoid memory leaks - e.list = nil - l.len-- - return e -} - -// Remove removes e from l if e is an element of list l. -// It returns the element value e.Value. -// The element must not be nil. -func (l *ByteIntervalList) Remove(e *ByteIntervalElement) ByteInterval { - if e.list == l { - // if e.list == l, l must have been initialized when e was inserted - // in l or l == nil (e is a zero Element) and l.remove will crash - l.remove(e) - } - return e.Value -} - -// PushFront inserts a new element e with value v at the front of list l and returns e. -func (l *ByteIntervalList) PushFront(v ByteInterval) *ByteIntervalElement { - l.lazyInit() - return l.insertValue(v, &l.root) -} - -// PushBack inserts a new element e with value v at the back of list l and returns e. -func (l *ByteIntervalList) PushBack(v ByteInterval) *ByteIntervalElement { - l.lazyInit() - return l.insertValue(v, l.root.prev) -} - -// InsertBefore inserts a new element e with value v immediately before mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *ByteIntervalList) InsertBefore(v ByteInterval, mark *ByteIntervalElement) *ByteIntervalElement { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark.prev) -} - -// InsertAfter inserts a new element e with value v immediately after mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *ByteIntervalList) InsertAfter(v ByteInterval, mark *ByteIntervalElement) *ByteIntervalElement { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark) -} - -// MoveToFront moves element e to the front of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *ByteIntervalList) MoveToFront(e *ByteIntervalElement) { - if e.list != l || l.root.next == e { - return - } - // see comment in List.Remove about initialization of l - l.insert(l.remove(e), &l.root) -} - -// MoveToBack moves element e to the back of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *ByteIntervalList) MoveToBack(e *ByteIntervalElement) { - if e.list != l || l.root.prev == e { - return - } - // see comment in List.Remove about initialization of l - l.insert(l.remove(e), l.root.prev) -} - -// MoveBefore moves element e to its new position before mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *ByteIntervalList) MoveBefore(e, mark *ByteIntervalElement) { - if e.list != l || e == mark || mark.list != l { - return - } - l.insert(l.remove(e), mark.prev) -} - -// MoveAfter moves element e to its new position after mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *ByteIntervalList) MoveAfter(e, mark *ByteIntervalElement) { - if e.list != l || e == mark || mark.list != l { - return - } - l.insert(l.remove(e), mark) -} - -// PushBackList inserts a copy of an other list at the back of list l. -// The lists l and other may be the same. They must not be nil. -func (l *ByteIntervalList) PushBackList(other *ByteIntervalList) { - l.lazyInit() - for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { - l.insertValue(e.Value, l.root.prev) - } -} - -// PushFrontList inserts a copy of an other list at the front of list l. -// The lists l and other may be the same. They must not be nil. -func (l *ByteIntervalList) PushFrontList(other *ByteIntervalList) { - l.lazyInit() - for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { - l.insertValue(e.Value, &l.root) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/byteorder.go b/external/github.com/lucas-clemente/quic-go/internal/utils/byteorder.go deleted file mode 100644 index 6b92cfa26..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/byteorder.go +++ /dev/null @@ -1,17 +0,0 @@ -package utils - -import ( - "bytes" - "io" -) - -// A ByteOrder specifies how to convert byte sequences into 16-, 32-, or 64-bit unsigned integers. -type ByteOrder interface { - ReadUintN(b io.ByteReader, length uint8) (uint64, error) - ReadUint32(io.ByteReader) (uint32, error) - ReadUint16(io.ByteReader) (uint16, error) - - WriteUintN(b *bytes.Buffer, length uint8, value uint64) - WriteUint32(*bytes.Buffer, uint32) - WriteUint16(*bytes.Buffer, uint16) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/byteorder_big_endian.go b/external/github.com/lucas-clemente/quic-go/internal/utils/byteorder_big_endian.go deleted file mode 100644 index eede9cd72..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/byteorder_big_endian.go +++ /dev/null @@ -1,74 +0,0 @@ -package utils - -import ( - "bytes" - "io" -) - -// BigEndian is the big-endian implementation of ByteOrder. -var BigEndian ByteOrder = bigEndian{} - -type bigEndian struct{} - -var _ ByteOrder = &bigEndian{} - -// ReadUintN reads N bytes -func (bigEndian) ReadUintN(b io.ByteReader, length uint8) (uint64, error) { - var res uint64 - for i := uint8(0); i < length; i++ { - bt, err := b.ReadByte() - if err != nil { - return 0, err - } - res ^= uint64(bt) << ((length - 1 - i) * 8) - } - return res, nil -} - -// ReadUint32 reads a uint32 -func (bigEndian) ReadUint32(b io.ByteReader) (uint32, error) { - var b1, b2, b3, b4 uint8 - var err error - if b4, err = b.ReadByte(); err != nil { - return 0, err - } - if b3, err = b.ReadByte(); err != nil { - return 0, err - } - if b2, err = b.ReadByte(); err != nil { - return 0, err - } - if b1, err = b.ReadByte(); err != nil { - return 0, err - } - return uint32(b1) + uint32(b2)<<8 + uint32(b3)<<16 + uint32(b4)<<24, nil -} - -// ReadUint16 reads a uint16 -func (bigEndian) ReadUint16(b io.ByteReader) (uint16, error) { - var b1, b2 uint8 - var err error - if b2, err = b.ReadByte(); err != nil { - return 0, err - } - if b1, err = b.ReadByte(); err != nil { - return 0, err - } - return uint16(b1) + uint16(b2)<<8, nil -} - -func (bigEndian) WriteUintN(b *bytes.Buffer, length uint8, i uint64) { - for j := length; j > 0; j-- { - b.WriteByte(uint8(i >> (8 * (j - 1)))) - } -} - -// WriteUint32 writes a uint32 -func (bigEndian) WriteUint32(b *bytes.Buffer, i uint32) { - b.Write([]byte{uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i)}) -} - -// WriteUint16 writes a uint16 -func (bigEndian) WriteUint16(b *bytes.Buffer, i uint16) { - b.Write([]byte{uint8(i >> 8), uint8(i)}) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/gen.go b/external/github.com/lucas-clemente/quic-go/internal/utils/gen.go deleted file mode 100644 index bb839be66..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/gen.go +++ /dev/null @@ -1,4 +0,0 @@ -package utils - -//go:generate genny -pkg utils -in linkedlist/linkedlist.go -out byteinterval_linkedlist.go gen Item=ByteInterval -//go:generate genny -pkg utils -in linkedlist/linkedlist.go -out packetinterval_linkedlist.go gen Item=PacketInterval diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/host.go b/external/github.com/lucas-clemente/quic-go/internal/utils/host.go deleted file mode 100644 index a1d6453b0..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/host.go +++ /dev/null @@ -1,27 +0,0 @@ -package utils - -import ( - "net/url" - "strings" -) - -// HostnameFromAddr determines the hostname in an address string -func HostnameFromAddr(addr string) (string, error) { - p, err := url.Parse(addr) - if err != nil { - return "", err - } - h := p.Host - - // copied from https://golang.org/src/net/http/transport.go - if hasPort(h) { - h = h[:strings.LastIndex(h, ":")] - } - - return h, nil -} - -// copied from https://golang.org/src/net/http/http.go -func hasPort(s string) bool { - return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/linkedlist/README.md b/external/github.com/lucas-clemente/quic-go/internal/utils/linkedlist/README.md deleted file mode 100644 index 15b46dce5..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/linkedlist/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Usage - -This is the Go standard library implementation of a linked list -(https://golang.org/src/container/list/list.go), modified such that genny -(https://github.com/cheekybits/genny) can be used to generate a typed linked -list. - -To generate, run -``` -genny -pkg $PACKAGE -in linkedlist.go -out $OUTFILE gen Item=$TYPE -``` diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/linkedlist/linkedlist.go b/external/github.com/lucas-clemente/quic-go/internal/utils/linkedlist/linkedlist.go deleted file mode 100644 index 06d32959c..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/linkedlist/linkedlist.go +++ /dev/null @@ -1,218 +0,0 @@ -package linkedlist - -import "v2ray.com/core/external/github.com/cheekybits/genny/generic" - -// Linked list implementation from the Go standard library. - -// Item is a generic type. -type Item generic.Type - -// ItemElement is an element of a linked list. -type ItemElement struct { - // Next and previous pointers in the doubly-linked list of elements. - // To simplify the implementation, internally a list l is implemented - // as a ring, such that &l.root is both the next element of the last - // list element (l.Back()) and the previous element of the first list - // element (l.Front()). - next, prev *ItemElement - - // The list to which this element belongs. - list *ItemList - - // The value stored with this element. - Value Item -} - -// Next returns the next list element or nil. -func (e *ItemElement) Next() *ItemElement { - if p := e.next; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// Prev returns the previous list element or nil. -func (e *ItemElement) Prev() *ItemElement { - if p := e.prev; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// ItemList is a linked list of Items. -type ItemList struct { - root ItemElement // sentinel list element, only &root, root.prev, and root.next are used - len int // current list length excluding (this) sentinel element -} - -// Init initializes or clears list l. -func (l *ItemList) Init() *ItemList { - l.root.next = &l.root - l.root.prev = &l.root - l.len = 0 - return l -} - -// NewItemList returns an initialized list. -func NewItemList() *ItemList { return new(ItemList).Init() } - -// Len returns the number of elements of list l. -// The complexity is O(1). -func (l *ItemList) Len() int { return l.len } - -// Front returns the first element of list l or nil if the list is empty. -func (l *ItemList) Front() *ItemElement { - if l.len == 0 { - return nil - } - return l.root.next -} - -// Back returns the last element of list l or nil if the list is empty. -func (l *ItemList) Back() *ItemElement { - if l.len == 0 { - return nil - } - return l.root.prev -} - -// lazyInit lazily initializes a zero List value. -func (l *ItemList) lazyInit() { - if l.root.next == nil { - l.Init() - } -} - -// insert inserts e after at, increments l.len, and returns e. -func (l *ItemList) insert(e, at *ItemElement) *ItemElement { - n := at.next - at.next = e - e.prev = at - e.next = n - n.prev = e - e.list = l - l.len++ - return e -} - -// insertValue is a convenience wrapper for insert(&Element{Value: v}, at). -func (l *ItemList) insertValue(v Item, at *ItemElement) *ItemElement { - return l.insert(&ItemElement{Value: v}, at) -} - -// remove removes e from its list, decrements l.len, and returns e. -func (l *ItemList) remove(e *ItemElement) *ItemElement { - e.prev.next = e.next - e.next.prev = e.prev - e.next = nil // avoid memory leaks - e.prev = nil // avoid memory leaks - e.list = nil - l.len-- - return e -} - -// Remove removes e from l if e is an element of list l. -// It returns the element value e.Value. -// The element must not be nil. -func (l *ItemList) Remove(e *ItemElement) Item { - if e.list == l { - // if e.list == l, l must have been initialized when e was inserted - // in l or l == nil (e is a zero Element) and l.remove will crash - l.remove(e) - } - return e.Value -} - -// PushFront inserts a new element e with value v at the front of list l and returns e. -func (l *ItemList) PushFront(v Item) *ItemElement { - l.lazyInit() - return l.insertValue(v, &l.root) -} - -// PushBack inserts a new element e with value v at the back of list l and returns e. -func (l *ItemList) PushBack(v Item) *ItemElement { - l.lazyInit() - return l.insertValue(v, l.root.prev) -} - -// InsertBefore inserts a new element e with value v immediately before mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *ItemList) InsertBefore(v Item, mark *ItemElement) *ItemElement { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark.prev) -} - -// InsertAfter inserts a new element e with value v immediately after mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *ItemList) InsertAfter(v Item, mark *ItemElement) *ItemElement { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark) -} - -// MoveToFront moves element e to the front of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *ItemList) MoveToFront(e *ItemElement) { - if e.list != l || l.root.next == e { - return - } - // see comment in List.Remove about initialization of l - l.insert(l.remove(e), &l.root) -} - -// MoveToBack moves element e to the back of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *ItemList) MoveToBack(e *ItemElement) { - if e.list != l || l.root.prev == e { - return - } - // see comment in List.Remove about initialization of l - l.insert(l.remove(e), l.root.prev) -} - -// MoveBefore moves element e to its new position before mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *ItemList) MoveBefore(e, mark *ItemElement) { - if e.list != l || e == mark || mark.list != l { - return - } - l.insert(l.remove(e), mark.prev) -} - -// MoveAfter moves element e to its new position after mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *ItemList) MoveAfter(e, mark *ItemElement) { - if e.list != l || e == mark || mark.list != l { - return - } - l.insert(l.remove(e), mark) -} - -// PushBackList inserts a copy of an other list at the back of list l. -// The lists l and other may be the same. They must not be nil. -func (l *ItemList) PushBackList(other *ItemList) { - l.lazyInit() - for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { - l.insertValue(e.Value, l.root.prev) - } -} - -// PushFrontList inserts a copy of an other list at the front of list l. -// The lists l and other may be the same. They must not be nil. -func (l *ItemList) PushFrontList(other *ItemList) { - l.lazyInit() - for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { - l.insertValue(e.Value, &l.root) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/log.go b/external/github.com/lucas-clemente/quic-go/internal/utils/log.go deleted file mode 100644 index 63d5e23d7..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/log.go +++ /dev/null @@ -1,64 +0,0 @@ -package utils - -// LogLevel of quic-go -type LogLevel uint8 - -const ( - // LogLevelNothing disables - LogLevelNothing LogLevel = iota - // LogLevelError enables err logs - LogLevelError - // LogLevelInfo enables info logs (e.g. packets) - LogLevelInfo - // LogLevelDebug enables debug logs (e.g. packet contents) - LogLevelDebug -) - -// A Logger logs. -type Logger interface { - SetLogLevel(LogLevel) - SetLogTimeFormat(format string) - WithPrefix(prefix string) Logger - Debug() bool - - Errorf(format string, args ...interface{}) - Infof(format string, args ...interface{}) - Debugf(format string, args ...interface{}) -} - -// DefaultLogger is used by quic-go for logging. -var DefaultLogger Logger - -type defaultLogger struct{} - -var _ Logger = &defaultLogger{} - -// SetLogLevel sets the log level -func (l *defaultLogger) SetLogLevel(level LogLevel) { -} - -// SetLogTimeFormat sets the format of the timestamp -// an empty string disables the logging of timestamps -func (l *defaultLogger) SetLogTimeFormat(format string) {} - -// Debugf logs something -func (l *defaultLogger) Debugf(format string, args ...interface{}) {} - -// Infof logs something -func (l *defaultLogger) Infof(format string, args ...interface{}) {} - -// Errorf logs something -func (l *defaultLogger) Errorf(format string, args ...interface{}) {} - -func (l *defaultLogger) WithPrefix(prefix string) Logger { - return l -} - -// Debug returns true if the log level is LogLevelDebug -func (l *defaultLogger) Debug() bool { - return false -} - -func init() { - DefaultLogger = &defaultLogger{} -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/minmax.go b/external/github.com/lucas-clemente/quic-go/internal/utils/minmax.go deleted file mode 100644 index d245ea7d3..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/minmax.go +++ /dev/null @@ -1,159 +0,0 @@ -package utils - -import ( - "math" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// InfDuration is a duration of infinite length -const InfDuration = time.Duration(math.MaxInt64) - -// Max returns the maximum of two Ints -func Max(a, b int) int { - if a < b { - return b - } - return a -} - -// MaxUint32 returns the maximum of two uint32 -func MaxUint32(a, b uint32) uint32 { - if a < b { - return b - } - return a -} - -// MaxUint64 returns the maximum of two uint64 -func MaxUint64(a, b uint64) uint64 { - if a < b { - return b - } - return a -} - -// MinUint64 returns the maximum of two uint64 -func MinUint64(a, b uint64) uint64 { - if a < b { - return a - } - return b -} - -// Min returns the minimum of two Ints -func Min(a, b int) int { - if a < b { - return a - } - return b -} - -// MinUint32 returns the maximum of two uint32 -func MinUint32(a, b uint32) uint32 { - if a < b { - return a - } - return b -} - -// MinInt64 returns the minimum of two int64 -func MinInt64(a, b int64) int64 { - if a < b { - return a - } - return b -} - -// MaxInt64 returns the minimum of two int64 -func MaxInt64(a, b int64) int64 { - if a > b { - return a - } - return b -} - -// MinByteCount returns the minimum of two ByteCounts -func MinByteCount(a, b protocol.ByteCount) protocol.ByteCount { - if a < b { - return a - } - return b -} - -// MaxByteCount returns the maximum of two ByteCounts -func MaxByteCount(a, b protocol.ByteCount) protocol.ByteCount { - if a < b { - return b - } - return a -} - -// MaxDuration returns the max duration -func MaxDuration(a, b time.Duration) time.Duration { - if a > b { - return a - } - return b -} - -// MinDuration returns the minimum duration -func MinDuration(a, b time.Duration) time.Duration { - if a > b { - return b - } - return a -} - -// AbsDuration returns the absolute value of a time duration -func AbsDuration(d time.Duration) time.Duration { - if d >= 0 { - return d - } - return -d -} - -// MinTime returns the earlier time -func MinTime(a, b time.Time) time.Time { - if a.After(b) { - return b - } - return a -} - -// MinNonZeroTime returns the earlist time that is not time.Time{} -// If both a and b are time.Time{}, it returns time.Time{} -func MinNonZeroTime(a, b time.Time) time.Time { - if a.IsZero() { - return b - } - if b.IsZero() { - return a - } - return MinTime(a, b) -} - -// MaxTime returns the later time -func MaxTime(a, b time.Time) time.Time { - if a.After(b) { - return a - } - return b -} - -// MaxPacketNumber returns the max packet number -func MaxPacketNumber(a, b protocol.PacketNumber) protocol.PacketNumber { - if a > b { - return a - } - return b -} - -// MinPacketNumber returns the min packet number -func MinPacketNumber(a, b protocol.PacketNumber) protocol.PacketNumber { - if a < b { - return a - } - return b -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/packet_interval.go b/external/github.com/lucas-clemente/quic-go/internal/utils/packet_interval.go deleted file mode 100644 index 7e5707dcf..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/packet_interval.go +++ /dev/null @@ -1,9 +0,0 @@ -package utils - -import "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - -// PacketInterval is an interval from one PacketNumber to the other -type PacketInterval struct { - Start protocol.PacketNumber - End protocol.PacketNumber -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/packetinterval_linkedlist.go b/external/github.com/lucas-clemente/quic-go/internal/utils/packetinterval_linkedlist.go deleted file mode 100644 index b461e85a9..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/packetinterval_linkedlist.go +++ /dev/null @@ -1,217 +0,0 @@ -// This file was automatically generated by genny. -// Any changes will be lost if this file is regenerated. -// see https://github.com/cheekybits/genny - -package utils - -// Linked list implementation from the Go standard library. - -// PacketIntervalElement is an element of a linked list. -type PacketIntervalElement struct { - // Next and previous pointers in the doubly-linked list of elements. - // To simplify the implementation, internally a list l is implemented - // as a ring, such that &l.root is both the next element of the last - // list element (l.Back()) and the previous element of the first list - // element (l.Front()). - next, prev *PacketIntervalElement - - // The list to which this element belongs. - list *PacketIntervalList - - // The value stored with this element. - Value PacketInterval -} - -// Next returns the next list element or nil. -func (e *PacketIntervalElement) Next() *PacketIntervalElement { - if p := e.next; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// Prev returns the previous list element or nil. -func (e *PacketIntervalElement) Prev() *PacketIntervalElement { - if p := e.prev; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// PacketIntervalList is a linked list of PacketIntervals. -type PacketIntervalList struct { - root PacketIntervalElement // sentinel list element, only &root, root.prev, and root.next are used - len int // current list length excluding (this) sentinel element -} - -// Init initializes or clears list l. -func (l *PacketIntervalList) Init() *PacketIntervalList { - l.root.next = &l.root - l.root.prev = &l.root - l.len = 0 - return l -} - -// NewPacketIntervalList returns an initialized list. -func NewPacketIntervalList() *PacketIntervalList { return new(PacketIntervalList).Init() } - -// Len returns the number of elements of list l. -// The complexity is O(1). -func (l *PacketIntervalList) Len() int { return l.len } - -// Front returns the first element of list l or nil if the list is empty. -func (l *PacketIntervalList) Front() *PacketIntervalElement { - if l.len == 0 { - return nil - } - return l.root.next -} - -// Back returns the last element of list l or nil if the list is empty. -func (l *PacketIntervalList) Back() *PacketIntervalElement { - if l.len == 0 { - return nil - } - return l.root.prev -} - -// lazyInit lazily initializes a zero List value. -func (l *PacketIntervalList) lazyInit() { - if l.root.next == nil { - l.Init() - } -} - -// insert inserts e after at, increments l.len, and returns e. -func (l *PacketIntervalList) insert(e, at *PacketIntervalElement) *PacketIntervalElement { - n := at.next - at.next = e - e.prev = at - e.next = n - n.prev = e - e.list = l - l.len++ - return e -} - -// insertValue is a convenience wrapper for insert(&Element{Value: v}, at). -func (l *PacketIntervalList) insertValue(v PacketInterval, at *PacketIntervalElement) *PacketIntervalElement { - return l.insert(&PacketIntervalElement{Value: v}, at) -} - -// remove removes e from its list, decrements l.len, and returns e. -func (l *PacketIntervalList) remove(e *PacketIntervalElement) *PacketIntervalElement { - e.prev.next = e.next - e.next.prev = e.prev - e.next = nil // avoid memory leaks - e.prev = nil // avoid memory leaks - e.list = nil - l.len-- - return e -} - -// Remove removes e from l if e is an element of list l. -// It returns the element value e.Value. -// The element must not be nil. -func (l *PacketIntervalList) Remove(e *PacketIntervalElement) PacketInterval { - if e.list == l { - // if e.list == l, l must have been initialized when e was inserted - // in l or l == nil (e is a zero Element) and l.remove will crash - l.remove(e) - } - return e.Value -} - -// PushFront inserts a new element e with value v at the front of list l and returns e. -func (l *PacketIntervalList) PushFront(v PacketInterval) *PacketIntervalElement { - l.lazyInit() - return l.insertValue(v, &l.root) -} - -// PushBack inserts a new element e with value v at the back of list l and returns e. -func (l *PacketIntervalList) PushBack(v PacketInterval) *PacketIntervalElement { - l.lazyInit() - return l.insertValue(v, l.root.prev) -} - -// InsertBefore inserts a new element e with value v immediately before mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *PacketIntervalList) InsertBefore(v PacketInterval, mark *PacketIntervalElement) *PacketIntervalElement { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark.prev) -} - -// InsertAfter inserts a new element e with value v immediately after mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *PacketIntervalList) InsertAfter(v PacketInterval, mark *PacketIntervalElement) *PacketIntervalElement { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark) -} - -// MoveToFront moves element e to the front of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *PacketIntervalList) MoveToFront(e *PacketIntervalElement) { - if e.list != l || l.root.next == e { - return - } - // see comment in List.Remove about initialization of l - l.insert(l.remove(e), &l.root) -} - -// MoveToBack moves element e to the back of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *PacketIntervalList) MoveToBack(e *PacketIntervalElement) { - if e.list != l || l.root.prev == e { - return - } - // see comment in List.Remove about initialization of l - l.insert(l.remove(e), l.root.prev) -} - -// MoveBefore moves element e to its new position before mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *PacketIntervalList) MoveBefore(e, mark *PacketIntervalElement) { - if e.list != l || e == mark || mark.list != l { - return - } - l.insert(l.remove(e), mark.prev) -} - -// MoveAfter moves element e to its new position after mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *PacketIntervalList) MoveAfter(e, mark *PacketIntervalElement) { - if e.list != l || e == mark || mark.list != l { - return - } - l.insert(l.remove(e), mark) -} - -// PushBackList inserts a copy of an other list at the back of list l. -// The lists l and other may be the same. They must not be nil. -func (l *PacketIntervalList) PushBackList(other *PacketIntervalList) { - l.lazyInit() - for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { - l.insertValue(e.Value, l.root.prev) - } -} - -// PushFrontList inserts a copy of an other list at the front of list l. -// The lists l and other may be the same. They must not be nil. -func (l *PacketIntervalList) PushFrontList(other *PacketIntervalList) { - l.lazyInit() - for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { - l.insertValue(e.Value, &l.root) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/streamframe_interval.go b/external/github.com/lucas-clemente/quic-go/internal/utils/streamframe_interval.go deleted file mode 100644 index b1bc82b5f..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/streamframe_interval.go +++ /dev/null @@ -1,9 +0,0 @@ -package utils - -import "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - -// ByteInterval is an interval from one ByteCount to the other -type ByteInterval struct { - Start protocol.ByteCount - End protocol.ByteCount -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/timer.go b/external/github.com/lucas-clemente/quic-go/internal/utils/timer.go deleted file mode 100644 index 1fefc6ec8..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/timer.go +++ /dev/null @@ -1,48 +0,0 @@ -package utils - -import ( - "math" - "time" -) - -// A Timer wrapper that behaves correctly when resetting -type Timer struct { - t *time.Timer - read bool - deadline time.Time -} - -// NewTimer creates a new timer that is not set -func NewTimer() *Timer { - return &Timer{t: time.NewTimer(time.Duration(math.MaxInt64))} -} - -// Chan returns the channel of the wrapped timer -func (t *Timer) Chan() <-chan time.Time { - return t.t.C -} - -// Reset the timer, no matter whether the value was read or not -func (t *Timer) Reset(deadline time.Time) { - if deadline.Equal(t.deadline) && !t.read { - // No need to reset the timer - return - } - - // We need to drain the timer if the value from its channel was not read yet. - // See https://groups.google.com/forum/#!topic/golang-dev/c9UUfASVPoU - if !t.t.Stop() && !t.read { - <-t.t.C - } - if !deadline.IsZero() { - t.t.Reset(time.Until(deadline)) - } - - t.read = false - t.deadline = deadline -} - -// SetRead should be called after the value from the chan was read -func (t *Timer) SetRead() { - t.read = true -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/varint.go b/external/github.com/lucas-clemente/quic-go/internal/utils/varint.go deleted file mode 100644 index 2cf839298..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/varint.go +++ /dev/null @@ -1,101 +0,0 @@ -package utils - -import ( - "bytes" - "fmt" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// taken from the QUIC draft -const ( - maxVarInt1 = 63 - maxVarInt2 = 16383 - maxVarInt4 = 1073741823 - maxVarInt8 = 4611686018427387903 -) - -// ReadVarInt reads a number in the QUIC varint format -func ReadVarInt(b io.ByteReader) (uint64, error) { - firstByte, err := b.ReadByte() - if err != nil { - return 0, err - } - // the first two bits of the first byte encode the length - len := 1 << ((firstByte & 0xc0) >> 6) - b1 := firstByte & (0xff - 0xc0) - if len == 1 { - return uint64(b1), nil - } - b2, err := b.ReadByte() - if err != nil { - return 0, err - } - if len == 2 { - return uint64(b2) + uint64(b1)<<8, nil - } - b3, err := b.ReadByte() - if err != nil { - return 0, err - } - b4, err := b.ReadByte() - if err != nil { - return 0, err - } - if len == 4 { - return uint64(b4) + uint64(b3)<<8 + uint64(b2)<<16 + uint64(b1)<<24, nil - } - b5, err := b.ReadByte() - if err != nil { - return 0, err - } - b6, err := b.ReadByte() - if err != nil { - return 0, err - } - b7, err := b.ReadByte() - if err != nil { - return 0, err - } - b8, err := b.ReadByte() - if err != nil { - return 0, err - } - return uint64(b8) + uint64(b7)<<8 + uint64(b6)<<16 + uint64(b5)<<24 + uint64(b4)<<32 + uint64(b3)<<40 + uint64(b2)<<48 + uint64(b1)<<56, nil -} - -// WriteVarInt writes a number in the QUIC varint format -func WriteVarInt(b *bytes.Buffer, i uint64) { - if i <= maxVarInt1 { - b.WriteByte(uint8(i)) - } else if i <= maxVarInt2 { - b.Write([]byte{uint8(i>>8) | 0x40, uint8(i)}) - } else if i <= maxVarInt4 { - b.Write([]byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)}) - } else if i <= maxVarInt8 { - b.Write([]byte{ - uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32), - uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i), - }) - } else { - panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i)) - } -} - -// VarIntLen determines the number of bytes that will be needed to write a number -func VarIntLen(i uint64) protocol.ByteCount { - if i <= maxVarInt1 { - return 1 - } - if i <= maxVarInt2 { - return 2 - } - if i <= maxVarInt4 { - return 4 - } - if i <= maxVarInt8 { - return 8 - } - panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i)) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/utils/varint_packetnumber.go b/external/github.com/lucas-clemente/quic-go/internal/utils/varint_packetnumber.go deleted file mode 100644 index b220b4a24..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/utils/varint_packetnumber.go +++ /dev/null @@ -1,50 +0,0 @@ -package utils - -import ( - "bytes" - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// ReadVarIntPacketNumber reads a number in the QUIC varint packet number format -func ReadVarIntPacketNumber(b *bytes.Reader) (protocol.PacketNumber, protocol.PacketNumberLen, error) { - b1, err := b.ReadByte() - if err != nil { - return 0, 0, err - } - if b1&0x80 == 0 { - return protocol.PacketNumber(b1), protocol.PacketNumberLen1, nil - } - b2, err := b.ReadByte() - if err != nil { - return 0, 0, err - } - if b1&0x40 == 0 { - return protocol.PacketNumber(uint64(b1&0x3f)<<8 + uint64(b2)), protocol.PacketNumberLen2, nil - } - b3, err := b.ReadByte() - if err != nil { - return 0, 0, err - } - b4, err := b.ReadByte() - if err != nil { - return 0, 0, err - } - return protocol.PacketNumber(uint64(b1&0x3f)<<24 + uint64(b2)<<16 + uint64(b3)<<8 + uint64(b4)), protocol.PacketNumberLen4, nil -} - -// WriteVarIntPacketNumber writes a packet number in the QUIC varint packet number format -func WriteVarIntPacketNumber(b *bytes.Buffer, i protocol.PacketNumber, len protocol.PacketNumberLen) error { - switch len { - case protocol.PacketNumberLen1: - b.WriteByte(uint8(i & 0x7f)) - case protocol.PacketNumberLen2: - b.Write([]byte{(uint8(i>>8) & 0x3f) | 0x80, uint8(i)}) - case protocol.PacketNumberLen4: - b.Write([]byte{(uint8(i>>24) & 0x3f) | 0xc0, uint8(i >> 16), uint8(i >> 8), uint8(i)}) - default: - return fmt.Errorf("invalid packet number length: %d", len) - } - return nil -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/ack_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/ack_frame.go deleted file mode 100644 index 4af3de98e..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/ack_frame.go +++ /dev/null @@ -1,229 +0,0 @@ -package wire - -import ( - "bytes" - "errors" - "sort" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// TODO: use the value sent in the transport parameters -const ackDelayExponent = 3 - -var errInvalidAckRanges = errors.New("AckFrame: ACK frame contains invalid ACK ranges") - -// An AckFrame is an ACK frame -type AckFrame struct { - AckRanges []AckRange // has to be ordered. The highest ACK range goes first, the lowest ACK range goes last - DelayTime time.Duration -} - -// parseAckFrame reads an ACK frame -func parseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) { - typeByte, err := r.ReadByte() - if err != nil { - return nil, err - } - ecn := typeByte&0x1 > 0 - - frame := &AckFrame{} - - la, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - largestAcked := protocol.PacketNumber(la) - delay, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - frame.DelayTime = time.Duration(delay*1< largestAcked { - return nil, errors.New("invalid first ACK range") - } - smallest := largestAcked - ackBlock - - // read all the other ACK ranges - frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largestAcked}) - for i := uint64(0); i < numBlocks; i++ { - g, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - gap := protocol.PacketNumber(g) - if smallest < gap+2 { - return nil, errInvalidAckRanges - } - largest := smallest - gap - 2 - - ab, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - ackBlock := protocol.PacketNumber(ab) - - if ackBlock > largest { - return nil, errInvalidAckRanges - } - smallest = largest - ackBlock - frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largest}) - } - - if !frame.validateAckRanges() { - return nil, errInvalidAckRanges - } - - // parse (and skip) the ECN section - if ecn { - for i := 0; i < 3; i++ { - if _, err := utils.ReadVarInt(r); err != nil { - return nil, err - } - } - } - - return frame, nil -} - -// Write writes an ACK frame. -func (f *AckFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - b.WriteByte(0x2) - utils.WriteVarInt(b, uint64(f.LargestAcked())) - utils.WriteVarInt(b, encodeAckDelay(f.DelayTime)) - - numRanges := f.numEncodableAckRanges() - utils.WriteVarInt(b, uint64(numRanges-1)) - - // write the first range - _, firstRange := f.encodeAckRange(0) - utils.WriteVarInt(b, firstRange) - - // write all the other range - for i := 1; i < numRanges; i++ { - gap, len := f.encodeAckRange(i) - utils.WriteVarInt(b, gap) - utils.WriteVarInt(b, len) - } - return nil -} - -// Length of a written frame -func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount { - largestAcked := f.AckRanges[0].Largest - numRanges := f.numEncodableAckRanges() - - length := 1 + utils.VarIntLen(uint64(largestAcked)) + utils.VarIntLen(encodeAckDelay(f.DelayTime)) - - length += utils.VarIntLen(uint64(numRanges - 1)) - lowestInFirstRange := f.AckRanges[0].Smallest - length += utils.VarIntLen(uint64(largestAcked - lowestInFirstRange)) - - for i := 1; i < numRanges; i++ { - gap, len := f.encodeAckRange(i) - length += utils.VarIntLen(gap) - length += utils.VarIntLen(len) - } - return length -} - -// gets the number of ACK ranges that can be encoded -// such that the resulting frame is smaller than the maximum ACK frame size -func (f *AckFrame) numEncodableAckRanges() int { - length := 1 + utils.VarIntLen(uint64(f.LargestAcked())) + utils.VarIntLen(encodeAckDelay(f.DelayTime)) - length += 2 // assume that the number of ranges will consume 2 bytes - for i := 1; i < len(f.AckRanges); i++ { - gap, len := f.encodeAckRange(i) - rangeLen := utils.VarIntLen(gap) + utils.VarIntLen(len) - if length+rangeLen > protocol.MaxAckFrameSize { - // Writing range i would exceed the MaxAckFrameSize. - // So encode one range less than that. - return i - 1 - } - length += rangeLen - } - return len(f.AckRanges) -} - -func (f *AckFrame) encodeAckRange(i int) (uint64 /* gap */, uint64 /* length */) { - if i == 0 { - return 0, uint64(f.AckRanges[0].Largest - f.AckRanges[0].Smallest) - } - return uint64(f.AckRanges[i-1].Smallest - f.AckRanges[i].Largest - 2), - uint64(f.AckRanges[i].Largest - f.AckRanges[i].Smallest) -} - -// HasMissingRanges returns if this frame reports any missing packets -func (f *AckFrame) HasMissingRanges() bool { - return len(f.AckRanges) > 1 -} - -func (f *AckFrame) validateAckRanges() bool { - if len(f.AckRanges) == 0 { - return false - } - - // check the validity of every single ACK range - for _, ackRange := range f.AckRanges { - if ackRange.Smallest > ackRange.Largest { - return false - } - } - - // check the consistency for ACK with multiple NACK ranges - for i, ackRange := range f.AckRanges { - if i == 0 { - continue - } - lastAckRange := f.AckRanges[i-1] - if lastAckRange.Smallest <= ackRange.Smallest { - return false - } - if lastAckRange.Smallest <= ackRange.Largest+1 { - return false - } - } - - return true -} - -// LargestAcked is the largest acked packet number -func (f *AckFrame) LargestAcked() protocol.PacketNumber { - return f.AckRanges[0].Largest -} - -// LowestAcked is the lowest acked packet number -func (f *AckFrame) LowestAcked() protocol.PacketNumber { - return f.AckRanges[len(f.AckRanges)-1].Smallest -} - -// AcksPacket determines if this ACK frame acks a certain packet number -func (f *AckFrame) AcksPacket(p protocol.PacketNumber) bool { - if p < f.LowestAcked() || p > f.LargestAcked() { - return false - } - - i := sort.Search(len(f.AckRanges), func(i int) bool { - return p >= f.AckRanges[i].Smallest - }) - // i will always be < len(f.AckRanges), since we checked above that p is not bigger than the largest acked - return p <= f.AckRanges[i].Largest -} - -func encodeAckDelay(delay time.Duration) uint64 { - return uint64(delay.Nanoseconds() / (1000 * (1 << ackDelayExponent))) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/ack_range.go b/external/github.com/lucas-clemente/quic-go/internal/wire/ack_range.go deleted file mode 100644 index a4d3dff6b..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/ack_range.go +++ /dev/null @@ -1,14 +0,0 @@ -package wire - -import "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - -// AckRange is an ACK range -type AckRange struct { - Smallest protocol.PacketNumber - Largest protocol.PacketNumber -} - -// Len returns the number of packets contained in this ACK range -func (r AckRange) Len() protocol.PacketNumber { - return r.Largest - r.Smallest + 1 -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/connection_close_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/connection_close_frame.go deleted file mode 100644 index 624f066d5..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/connection_close_frame.go +++ /dev/null @@ -1,81 +0,0 @@ -package wire - -import ( - "bytes" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A ConnectionCloseFrame is a CONNECTION_CLOSE frame -type ConnectionCloseFrame struct { - IsApplicationError bool - ErrorCode qerr.ErrorCode - ReasonPhrase string -} - -func parseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber) (*ConnectionCloseFrame, error) { - typeByte, err := r.ReadByte() - if err != nil { - return nil, err - } - - f := &ConnectionCloseFrame{IsApplicationError: typeByte == 0x1d} - ec, err := utils.BigEndian.ReadUint16(r) - if err != nil { - return nil, err - } - f.ErrorCode = qerr.ErrorCode(ec) - // read the Frame Type, if this is not an application error - if !f.IsApplicationError { - if _, err := utils.ReadVarInt(r); err != nil { - return nil, err - } - } - var reasonPhraseLen uint64 - reasonPhraseLen, err = utils.ReadVarInt(r) - if err != nil { - return nil, err - } - // shortcut to prevent the unnecessary allocation of dataLen bytes - // if the dataLen is larger than the remaining length of the packet - // reading the whole reason phrase would result in EOF when attempting to READ - if int(reasonPhraseLen) > r.Len() { - return nil, io.EOF - } - - reasonPhrase := make([]byte, reasonPhraseLen) - if _, err := io.ReadFull(r, reasonPhrase); err != nil { - // this should never happen, since we already checked the reasonPhraseLen earlier - return nil, err - } - f.ReasonPhrase = string(reasonPhrase) - return f, nil -} - -// Length of a written frame -func (f *ConnectionCloseFrame) Length(version protocol.VersionNumber) protocol.ByteCount { - length := 1 + 2 + utils.VarIntLen(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase)) - if !f.IsApplicationError { - length++ // for the frame type - } - return length -} - -func (f *ConnectionCloseFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - if f.IsApplicationError { - b.WriteByte(0x1d) - } else { - b.WriteByte(0x1c) - } - - utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode)) - if !f.IsApplicationError { - utils.WriteVarInt(b, 0) - } - utils.WriteVarInt(b, uint64(len(f.ReasonPhrase))) - b.WriteString(f.ReasonPhrase) - return nil -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/crypto_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/crypto_frame.go deleted file mode 100644 index c3aacb728..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/crypto_frame.go +++ /dev/null @@ -1,71 +0,0 @@ -package wire - -import ( - "bytes" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A CryptoFrame is a CRYPTO frame -type CryptoFrame struct { - Offset protocol.ByteCount - Data []byte -} - -func parseCryptoFrame(r *bytes.Reader, _ protocol.VersionNumber) (*CryptoFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - - frame := &CryptoFrame{} - offset, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - frame.Offset = protocol.ByteCount(offset) - dataLen, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - if dataLen > uint64(r.Len()) { - return nil, io.EOF - } - if dataLen != 0 { - frame.Data = make([]byte, dataLen) - if _, err := io.ReadFull(r, frame.Data); err != nil { - // this should never happen, since we already checked the dataLen earlier - return nil, err - } - } - return frame, nil -} - -func (f *CryptoFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { - b.WriteByte(0x6) - utils.WriteVarInt(b, uint64(f.Offset)) - utils.WriteVarInt(b, uint64(len(f.Data))) - b.Write(f.Data) - return nil -} - -// Length of a written frame -func (f *CryptoFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(uint64(f.Offset)) + utils.VarIntLen(uint64(len(f.Data))) + protocol.ByteCount(len(f.Data)) -} - -// MaxDataLen returns the maximum data length -func (f *CryptoFrame) MaxDataLen(maxSize protocol.ByteCount) protocol.ByteCount { - // pretend that the data size will be 1 bytes - // if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards - headerLen := 1 + utils.VarIntLen(uint64(f.Offset)) + 1 - if headerLen > maxSize { - return 0 - } - maxDataLen := maxSize - headerLen - if utils.VarIntLen(uint64(maxDataLen)) != 1 { - maxDataLen-- - } - return maxDataLen -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/data_blocked_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/data_blocked_frame.go deleted file mode 100644 index 66b7760c6..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/data_blocked_frame.go +++ /dev/null @@ -1,38 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A DataBlockedFrame is a DATA_BLOCKED frame -type DataBlockedFrame struct { - DataLimit protocol.ByteCount -} - -func parseDataBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*DataBlockedFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - offset, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - return &DataBlockedFrame{ - DataLimit: protocol.ByteCount(offset), - }, nil -} - -func (f *DataBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - typeByte := uint8(0x14) - b.WriteByte(typeByte) - utils.WriteVarInt(b, uint64(f.DataLimit)) - return nil -} - -// Length of a written frame -func (f *DataBlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(uint64(f.DataLimit)) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/extended_header.go b/external/github.com/lucas-clemente/quic-go/internal/wire/extended_header.go deleted file mode 100644 index 814ddd280..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/extended_header.go +++ /dev/null @@ -1,204 +0,0 @@ -package wire - -import ( - "bytes" - "errors" - "fmt" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// ExtendedHeader is the header of a QUIC packet. -type ExtendedHeader struct { - Header - - typeByte byte - - PacketNumberLen protocol.PacketNumberLen - PacketNumber protocol.PacketNumber - - KeyPhase int -} - -func (h *ExtendedHeader) parse(b *bytes.Reader, v protocol.VersionNumber) (*ExtendedHeader, error) { - // read the (now unencrypted) first byte - var err error - h.typeByte, err = b.ReadByte() - if err != nil { - return nil, err - } - if _, err := b.Seek(int64(h.ParsedLen())-1, io.SeekCurrent); err != nil { - return nil, err - } - if h.IsLongHeader { - return h.parseLongHeader(b, v) - } - return h.parseShortHeader(b, v) -} - -func (h *ExtendedHeader) parseLongHeader(b *bytes.Reader, v protocol.VersionNumber) (*ExtendedHeader, error) { - if h.typeByte&0xc != 0 { - return nil, errors.New("5th and 6th bit must be 0") - } - if err := h.readPacketNumber(b); err != nil { - return nil, err - } - return h, nil -} - -func (h *ExtendedHeader) parseShortHeader(b *bytes.Reader, v protocol.VersionNumber) (*ExtendedHeader, error) { - if h.typeByte&0x18 != 0 { - return nil, errors.New("4th and 5th bit must be 0") - } - - h.KeyPhase = int(h.typeByte&0x4) >> 2 - - if err := h.readPacketNumber(b); err != nil { - return nil, err - } - return h, nil -} - -func (h *ExtendedHeader) readPacketNumber(b *bytes.Reader) error { - h.PacketNumberLen = protocol.PacketNumberLen(h.typeByte&0x3) + 1 - pn, err := utils.BigEndian.ReadUintN(b, uint8(h.PacketNumberLen)) - if err != nil { - return err - } - h.PacketNumber = protocol.PacketNumber(pn) - return nil -} - -// Write writes the Header. -func (h *ExtendedHeader) Write(b *bytes.Buffer, ver protocol.VersionNumber) error { - if h.IsLongHeader { - return h.writeLongHeader(b, ver) - } - return h.writeShortHeader(b, ver) -} - -func (h *ExtendedHeader) writeLongHeader(b *bytes.Buffer, v protocol.VersionNumber) error { - var packetType uint8 - switch h.Type { - case protocol.PacketTypeInitial: - packetType = 0x0 - case protocol.PacketType0RTT: - packetType = 0x1 - case protocol.PacketTypeHandshake: - packetType = 0x2 - case protocol.PacketTypeRetry: - packetType = 0x3 - } - firstByte := 0xc0 | packetType<<4 - if h.Type == protocol.PacketTypeRetry { - odcil, err := encodeSingleConnIDLen(h.OrigDestConnectionID) - if err != nil { - return err - } - firstByte |= odcil - } else { // Retry packets don't have a packet number - firstByte |= uint8(h.PacketNumberLen - 1) - } - - b.WriteByte(firstByte) - utils.BigEndian.WriteUint32(b, uint32(h.Version)) - connIDLen, err := encodeConnIDLen(h.DestConnectionID, h.SrcConnectionID) - if err != nil { - return err - } - b.WriteByte(connIDLen) - b.Write(h.DestConnectionID.Bytes()) - b.Write(h.SrcConnectionID.Bytes()) - - switch h.Type { - case protocol.PacketTypeRetry: - b.Write(h.OrigDestConnectionID.Bytes()) - b.Write(h.Token) - return nil - case protocol.PacketTypeInitial: - utils.WriteVarInt(b, uint64(len(h.Token))) - b.Write(h.Token) - } - - utils.WriteVarInt(b, uint64(h.Length)) - return h.writePacketNumber(b) -} - -// TODO: add support for the key phase -func (h *ExtendedHeader) writeShortHeader(b *bytes.Buffer, v protocol.VersionNumber) error { - typeByte := 0x40 | uint8(h.PacketNumberLen-1) - typeByte |= byte(h.KeyPhase << 2) - - b.WriteByte(typeByte) - b.Write(h.DestConnectionID.Bytes()) - return h.writePacketNumber(b) -} - -func (h *ExtendedHeader) writePacketNumber(b *bytes.Buffer) error { - if h.PacketNumberLen == protocol.PacketNumberLenInvalid || h.PacketNumberLen > protocol.PacketNumberLen4 { - return fmt.Errorf("invalid packet number length: %d", h.PacketNumberLen) - } - utils.BigEndian.WriteUintN(b, uint8(h.PacketNumberLen), uint64(h.PacketNumber)) - return nil -} - -// GetLength determines the length of the Header. -func (h *ExtendedHeader) GetLength(v protocol.VersionNumber) protocol.ByteCount { - if h.IsLongHeader { - length := 1 /* type byte */ + 4 /* version */ + 1 /* conn id len byte */ + protocol.ByteCount(h.DestConnectionID.Len()+h.SrcConnectionID.Len()) + protocol.ByteCount(h.PacketNumberLen) + utils.VarIntLen(uint64(h.Length)) - if h.Type == protocol.PacketTypeInitial { - length += utils.VarIntLen(uint64(len(h.Token))) + protocol.ByteCount(len(h.Token)) - } - return length - } - - length := protocol.ByteCount(1 /* type byte */ + h.DestConnectionID.Len()) - length += protocol.ByteCount(h.PacketNumberLen) - return length -} - -// Log logs the Header -func (h *ExtendedHeader) Log(logger utils.Logger) { - if h.IsLongHeader { - var token string - if h.Type == protocol.PacketTypeInitial || h.Type == protocol.PacketTypeRetry { - if len(h.Token) == 0 { - token = "Token: (empty), " - } else { - token = fmt.Sprintf("Token: %#x, ", h.Token) - } - if h.Type == protocol.PacketTypeRetry { - logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sOrigDestConnectionID: %s, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.OrigDestConnectionID, h.Version) - return - } - } - logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sPacketNumber: %#x, PacketNumberLen: %d, Length: %d, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.PacketNumber, h.PacketNumberLen, h.Length, h.Version) - } else { - logger.Debugf("\tShort Header{DestConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, KeyPhase: %d}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, h.KeyPhase) - } -} - -func encodeConnIDLen(dest, src protocol.ConnectionID) (byte, error) { - dcil, err := encodeSingleConnIDLen(dest) - if err != nil { - return 0, err - } - scil, err := encodeSingleConnIDLen(src) - if err != nil { - return 0, err - } - return scil | dcil<<4, nil -} - -func encodeSingleConnIDLen(id protocol.ConnectionID) (byte, error) { - len := id.Len() - if len == 0 { - return 0, nil - } - if len < 4 || len > 18 { - return 0, fmt.Errorf("invalid connection ID length: %d bytes", len) - } - return byte(len - 3), nil -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/frame.go deleted file mode 100644 index 4e2050071..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/frame.go +++ /dev/null @@ -1,13 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// A Frame in QUIC -type Frame interface { - Write(b *bytes.Buffer, version protocol.VersionNumber) error - Length(version protocol.VersionNumber) protocol.ByteCount -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/frame_parser.go b/external/github.com/lucas-clemente/quic-go/internal/wire/frame_parser.go deleted file mode 100644 index 3762a3392..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/frame_parser.go +++ /dev/null @@ -1,78 +0,0 @@ -package wire - -import ( - "bytes" - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" -) - -// ParseNextFrame parses the next frame -// It skips PADDING frames. -func ParseNextFrame(r *bytes.Reader, v protocol.VersionNumber) (Frame, error) { - for r.Len() != 0 { - typeByte, _ := r.ReadByte() - if typeByte == 0x0 { // PADDING frame - continue - } - r.UnreadByte() - - return parseFrame(r, typeByte, v) - } - return nil, nil -} - -func parseFrame(r *bytes.Reader, typeByte byte, v protocol.VersionNumber) (Frame, error) { - var frame Frame - var err error - if typeByte&0xf8 == 0x8 { - frame, err = parseStreamFrame(r, v) - if err != nil { - return nil, qerr.Error(qerr.InvalidFrameData, err.Error()) - } - return frame, nil - } - switch typeByte { - case 0x1: - frame, err = parsePingFrame(r, v) - case 0x2, 0x3: - frame, err = parseAckFrame(r, v) - case 0x4: - frame, err = parseResetStreamFrame(r, v) - case 0x5: - frame, err = parseStopSendingFrame(r, v) - case 0x6: - frame, err = parseCryptoFrame(r, v) - case 0x7: - frame, err = parseNewTokenFrame(r, v) - case 0x10: - frame, err = parseMaxDataFrame(r, v) - case 0x11: - frame, err = parseMaxStreamDataFrame(r, v) - case 0x12, 0x13: - frame, err = parseMaxStreamsFrame(r, v) - case 0x14: - frame, err = parseDataBlockedFrame(r, v) - case 0x15: - frame, err = parseStreamDataBlockedFrame(r, v) - case 0x16, 0x17: - frame, err = parseStreamsBlockedFrame(r, v) - case 0x18: - frame, err = parseNewConnectionIDFrame(r, v) - case 0x19: - frame, err = parseRetireConnectionIDFrame(r, v) - case 0x1a: - frame, err = parsePathChallengeFrame(r, v) - case 0x1b: - frame, err = parsePathResponseFrame(r, v) - case 0x1c, 0x1d: - frame, err = parseConnectionCloseFrame(r, v) - default: - err = fmt.Errorf("unknown type byte 0x%x", typeByte) - } - if err != nil { - return nil, qerr.Error(qerr.InvalidFrameData, err.Error()) - } - return frame, nil -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/header.go b/external/github.com/lucas-clemente/quic-go/internal/wire/header.go deleted file mode 100644 index 68f652ab8..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/header.go +++ /dev/null @@ -1,198 +0,0 @@ -package wire - -import ( - "bytes" - "errors" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// The Header is the version independent part of the header -type Header struct { - Version protocol.VersionNumber - SrcConnectionID protocol.ConnectionID - DestConnectionID protocol.ConnectionID - - IsLongHeader bool - Type protocol.PacketType - Length protocol.ByteCount - - Token []byte - SupportedVersions []protocol.VersionNumber // sent in a Version Negotiation Packet - OrigDestConnectionID protocol.ConnectionID // sent in the Retry packet - - typeByte byte - parsedLen protocol.ByteCount // how many bytes were read while parsing this header -} - -// ParseHeader parses the header. -// For short header packets: up to the packet number. -// For long header packets: -// * if we understand the version: up to the packet number -// * if not, only the invariant part of the header -func ParseHeader(b *bytes.Reader, shortHeaderConnIDLen int) (*Header, error) { - startLen := b.Len() - h, err := parseHeaderImpl(b, shortHeaderConnIDLen) - if err != nil { - return nil, err - } - h.parsedLen = protocol.ByteCount(startLen - b.Len()) - return h, nil -} - -func parseHeaderImpl(b *bytes.Reader, shortHeaderConnIDLen int) (*Header, error) { - typeByte, err := b.ReadByte() - if err != nil { - return nil, err - } - - h := &Header{ - typeByte: typeByte, - IsLongHeader: typeByte&0x80 > 0, - } - - if !h.IsLongHeader { - if h.typeByte&0x40 == 0 { - return nil, errors.New("not a QUIC packet") - } - if err := h.parseShortHeader(b, shortHeaderConnIDLen); err != nil { - return nil, err - } - return h, nil - } - if err := h.parseLongHeader(b); err != nil { - return nil, err - } - return h, nil -} - -func (h *Header) parseShortHeader(b *bytes.Reader, shortHeaderConnIDLen int) error { - var err error - h.DestConnectionID, err = protocol.ReadConnectionID(b, shortHeaderConnIDLen) - return err -} - -func (h *Header) parseLongHeader(b *bytes.Reader) error { - v, err := utils.BigEndian.ReadUint32(b) - if err != nil { - return err - } - h.Version = protocol.VersionNumber(v) - if !h.IsVersionNegotiation() && h.typeByte&0x40 == 0 { - return errors.New("not a QUIC packet") - } - connIDLenByte, err := b.ReadByte() - if err != nil { - return err - } - dcil, scil := decodeConnIDLen(connIDLenByte) - h.DestConnectionID, err = protocol.ReadConnectionID(b, dcil) - if err != nil { - return err - } - h.SrcConnectionID, err = protocol.ReadConnectionID(b, scil) - if err != nil { - return err - } - if h.Version == 0 { - return h.parseVersionNegotiationPacket(b) - } - // If we don't understand the version, we have no idea how to interpret the rest of the bytes - if !protocol.IsSupportedVersion(protocol.SupportedVersions, h.Version) { - return nil - } - - switch (h.typeByte & 0x30) >> 4 { - case 0x0: - h.Type = protocol.PacketTypeInitial - case 0x1: - h.Type = protocol.PacketType0RTT - case 0x2: - h.Type = protocol.PacketTypeHandshake - case 0x3: - h.Type = protocol.PacketTypeRetry - } - - if h.Type == protocol.PacketTypeRetry { - odcil := decodeSingleConnIDLen(h.typeByte & 0xf) - h.OrigDestConnectionID, err = protocol.ReadConnectionID(b, odcil) - if err != nil { - return err - } - h.Token = make([]byte, b.Len()) - if _, err := io.ReadFull(b, h.Token); err != nil { - return err - } - return nil - } - - if h.Type == protocol.PacketTypeInitial { - tokenLen, err := utils.ReadVarInt(b) - if err != nil { - return err - } - if tokenLen > uint64(b.Len()) { - return io.EOF - } - h.Token = make([]byte, tokenLen) - if _, err := io.ReadFull(b, h.Token); err != nil { - return err - } - } - - pl, err := utils.ReadVarInt(b) - if err != nil { - return err - } - h.Length = protocol.ByteCount(pl) - return nil -} - -func (h *Header) parseVersionNegotiationPacket(b *bytes.Reader) error { - if b.Len() == 0 { - return qerr.Error(qerr.InvalidVersionNegotiationPacket, "empty version list") - } - h.SupportedVersions = make([]protocol.VersionNumber, b.Len()/4) - for i := 0; b.Len() > 0; i++ { - v, err := utils.BigEndian.ReadUint32(b) - if err != nil { - return qerr.InvalidVersionNegotiationPacket - } - h.SupportedVersions[i] = protocol.VersionNumber(v) - } - return nil -} - -// IsVersionNegotiation says if this a version negotiation packet -func (h *Header) IsVersionNegotiation() bool { - return h.IsLongHeader && h.Version == 0 -} - -// ParsedLen returns the number of bytes that were consumed when parsing the header -func (h *Header) ParsedLen() protocol.ByteCount { - return h.parsedLen -} - -// ParseExtended parses the version dependent part of the header. -// The Reader has to be set such that it points to the first byte of the header. -func (h *Header) ParseExtended(b *bytes.Reader, ver protocol.VersionNumber) (*ExtendedHeader, error) { - return h.toExtendedHeader().parse(b, ver) -} - -func (h *Header) toExtendedHeader() *ExtendedHeader { - return &ExtendedHeader{Header: *h} -} - -func decodeConnIDLen(enc byte) (int /*dest conn id len*/, int /*src conn id len*/) { - return decodeSingleConnIDLen(enc >> 4), decodeSingleConnIDLen(enc & 0xf) -} - -func decodeSingleConnIDLen(enc uint8) int { - if enc == 0 { - return 0 - } - return int(enc) + 3 -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/log.go b/external/github.com/lucas-clemente/quic-go/internal/wire/log.go deleted file mode 100644 index 8a72410bd..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/log.go +++ /dev/null @@ -1,39 +0,0 @@ -package wire - -import ( - "fmt" - "strings" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// LogFrame logs a frame, either sent or received -func LogFrame(logger utils.Logger, frame Frame, sent bool) { - if !logger.Debug() { - return - } - dir := "<-" - if sent { - dir = "->" - } - switch f := frame.(type) { - case *CryptoFrame: - dataLen := protocol.ByteCount(len(f.Data)) - logger.Debugf("\t%s &wire.CryptoFrame{Offset: 0x%x, Data length: 0x%x, Offset + Data length: 0x%x}", dir, f.Offset, dataLen, f.Offset+dataLen) - case *StreamFrame: - logger.Debugf("\t%s &wire.StreamFrame{StreamID: %d, FinBit: %t, Offset: 0x%x, Data length: 0x%x, Offset + Data length: 0x%x}", dir, f.StreamID, f.FinBit, f.Offset, f.DataLen(), f.Offset+f.DataLen()) - case *AckFrame: - if len(f.AckRanges) > 1 { - ackRanges := make([]string, len(f.AckRanges)) - for i, r := range f.AckRanges { - ackRanges[i] = fmt.Sprintf("{Largest: %#x, Smallest: %#x}", r.Largest, r.Smallest) - } - logger.Debugf("\t%s &wire.AckFrame{LargestAcked: %#x, LowestAcked: %#x, AckRanges: {%s}, DelayTime: %s}", dir, f.LargestAcked(), f.LowestAcked(), strings.Join(ackRanges, ", "), f.DelayTime.String()) - } else { - logger.Debugf("\t%s &wire.AckFrame{LargestAcked: %#x, LowestAcked: %#x, DelayTime: %s}", dir, f.LargestAcked(), f.LowestAcked(), f.DelayTime.String()) - } - default: - logger.Debugf("\t%s %#v", dir, frame) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/max_data_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/max_data_frame.go deleted file mode 100644 index ba0a3a25f..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/max_data_frame.go +++ /dev/null @@ -1,40 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A MaxDataFrame carries flow control information for the connection -type MaxDataFrame struct { - ByteOffset protocol.ByteCount -} - -// parseMaxDataFrame parses a MAX_DATA frame -func parseMaxDataFrame(r *bytes.Reader, version protocol.VersionNumber) (*MaxDataFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - - frame := &MaxDataFrame{} - byteOffset, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - frame.ByteOffset = protocol.ByteCount(byteOffset) - return frame, nil -} - -//Write writes a MAX_STREAM_DATA frame -func (f *MaxDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - b.WriteByte(0x10) - utils.WriteVarInt(b, uint64(f.ByteOffset)) - return nil -} - -// Length of a written frame -func (f *MaxDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(uint64(f.ByteOffset)) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/max_stream_data_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/max_stream_data_frame.go deleted file mode 100644 index b13944e45..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/max_stream_data_frame.go +++ /dev/null @@ -1,46 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A MaxStreamDataFrame is a MAX_STREAM_DATA frame -type MaxStreamDataFrame struct { - StreamID protocol.StreamID - ByteOffset protocol.ByteCount -} - -func parseMaxStreamDataFrame(r *bytes.Reader, version protocol.VersionNumber) (*MaxStreamDataFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - - sid, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - offset, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - - return &MaxStreamDataFrame{ - StreamID: protocol.StreamID(sid), - ByteOffset: protocol.ByteCount(offset), - }, nil -} - -func (f *MaxStreamDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - b.WriteByte(0x11) - utils.WriteVarInt(b, uint64(f.StreamID)) - utils.WriteVarInt(b, uint64(f.ByteOffset)) - return nil -} - -// Length of a written frame -func (f *MaxStreamDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.ByteOffset)) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/max_streams_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/max_streams_frame.go deleted file mode 100644 index 63cfae257..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/max_streams_frame.go +++ /dev/null @@ -1,51 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A MaxStreamsFrame is a MAX_STREAMS frame -type MaxStreamsFrame struct { - Type protocol.StreamType - MaxStreams uint64 -} - -func parseMaxStreamsFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxStreamsFrame, error) { - typeByte, err := r.ReadByte() - if err != nil { - return nil, err - } - - f := &MaxStreamsFrame{} - switch typeByte { - case 0x12: - f.Type = protocol.StreamTypeBidi - case 0x13: - f.Type = protocol.StreamTypeUni - } - streamID, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - f.MaxStreams = streamID - return f, nil -} - -func (f *MaxStreamsFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { - switch f.Type { - case protocol.StreamTypeBidi: - b.WriteByte(0x12) - case protocol.StreamTypeUni: - b.WriteByte(0x13) - } - utils.WriteVarInt(b, f.MaxStreams) - return nil -} - -// Length of a written frame -func (f *MaxStreamsFrame) Length(protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(f.MaxStreams) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/new_connection_id_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/new_connection_id_frame.go deleted file mode 100644 index 73893438c..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/new_connection_id_frame.go +++ /dev/null @@ -1,70 +0,0 @@ -package wire - -import ( - "bytes" - "fmt" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// A NewConnectionIDFrame is a NEW_CONNECTION_ID frame -type NewConnectionIDFrame struct { - SequenceNumber uint64 - ConnectionID protocol.ConnectionID - StatelessResetToken [16]byte -} - -func parseNewConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewConnectionIDFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - - seq, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - connIDLen, err := r.ReadByte() - if err != nil { - return nil, err - } - if connIDLen < 4 || connIDLen > 18 { - return nil, fmt.Errorf("invalid connection ID length: %d", connIDLen) - } - connID, err := protocol.ReadConnectionID(r, int(connIDLen)) - if err != nil { - return nil, err - } - frame := &NewConnectionIDFrame{ - SequenceNumber: seq, - ConnectionID: connID, - } - if _, err := io.ReadFull(r, frame.StatelessResetToken[:]); err != nil { - if err == io.ErrUnexpectedEOF { - return nil, io.EOF - } - return nil, err - } - - return frame, nil -} - -func (f *NewConnectionIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { - b.WriteByte(0x18) - utils.WriteVarInt(b, f.SequenceNumber) - connIDLen := f.ConnectionID.Len() - if connIDLen < 4 || connIDLen > 18 { - return fmt.Errorf("invalid connection ID length: %d", connIDLen) - } - b.WriteByte(uint8(connIDLen)) - b.Write(f.ConnectionID.Bytes()) - b.Write(f.StatelessResetToken[:]) - return nil -} - -// Length of a written frame -func (f *NewConnectionIDFrame) Length(protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(f.SequenceNumber) + 1 /* connection ID length */ + protocol.ByteCount(f.ConnectionID.Len()) + 16 -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/new_token_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/new_token_frame.go deleted file mode 100644 index 2cf4db636..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/new_token_frame.go +++ /dev/null @@ -1,44 +0,0 @@ -package wire - -import ( - "bytes" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A NewTokenFrame is a NEW_TOKEN frame -type NewTokenFrame struct { - Token []byte -} - -func parseNewTokenFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewTokenFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - tokenLen, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - if uint64(r.Len()) < tokenLen { - return nil, io.EOF - } - token := make([]byte, int(tokenLen)) - if _, err := io.ReadFull(r, token); err != nil { - return nil, err - } - return &NewTokenFrame{Token: token}, nil -} - -func (f *NewTokenFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { - b.WriteByte(0x7) - utils.WriteVarInt(b, uint64(len(f.Token))) - b.Write(f.Token) - return nil -} - -// Length of a written frame -func (f *NewTokenFrame) Length(protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(uint64(len(f.Token))) + protocol.ByteCount(len(f.Token)) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/path_challenge_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/path_challenge_frame.go deleted file mode 100644 index 074cc053c..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/path_challenge_frame.go +++ /dev/null @@ -1,38 +0,0 @@ -package wire - -import ( - "bytes" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// A PathChallengeFrame is a PATH_CHALLENGE frame -type PathChallengeFrame struct { - Data [8]byte -} - -func parsePathChallengeFrame(r *bytes.Reader, version protocol.VersionNumber) (*PathChallengeFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - frame := &PathChallengeFrame{} - if _, err := io.ReadFull(r, frame.Data[:]); err != nil { - if err == io.ErrUnexpectedEOF { - return nil, io.EOF - } - return nil, err - } - return frame, nil -} - -func (f *PathChallengeFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { - b.WriteByte(0x1a) - b.Write(f.Data[:]) - return nil -} - -// Length of a written frame -func (f *PathChallengeFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { - return 1 + 8 -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/path_response_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/path_response_frame.go deleted file mode 100644 index 2b385bc7d..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/path_response_frame.go +++ /dev/null @@ -1,38 +0,0 @@ -package wire - -import ( - "bytes" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// A PathResponseFrame is a PATH_RESPONSE frame -type PathResponseFrame struct { - Data [8]byte -} - -func parsePathResponseFrame(r *bytes.Reader, version protocol.VersionNumber) (*PathResponseFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - frame := &PathResponseFrame{} - if _, err := io.ReadFull(r, frame.Data[:]); err != nil { - if err == io.ErrUnexpectedEOF { - return nil, io.EOF - } - return nil, err - } - return frame, nil -} - -func (f *PathResponseFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { - b.WriteByte(0x1b) - b.Write(f.Data[:]) - return nil -} - -// Length of a written frame -func (f *PathResponseFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { - return 1 + 8 -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/ping_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/ping_frame.go deleted file mode 100644 index f9b0bfcd1..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/ping_frame.go +++ /dev/null @@ -1,27 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// A PingFrame is a PING frame -type PingFrame struct{} - -func parsePingFrame(r *bytes.Reader, version protocol.VersionNumber) (*PingFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - return &PingFrame{}, nil -} - -func (f *PingFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - b.WriteByte(0x1) - return nil -} - -// Length of a written frame -func (f *PingFrame) Length(version protocol.VersionNumber) protocol.ByteCount { - return 1 -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/reset_stream_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/reset_stream_frame.go deleted file mode 100644 index b1ed65e05..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/reset_stream_frame.go +++ /dev/null @@ -1,58 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A ResetStreamFrame is a RESET_STREAM frame in QUIC -type ResetStreamFrame struct { - StreamID protocol.StreamID - ErrorCode protocol.ApplicationErrorCode - ByteOffset protocol.ByteCount -} - -func parseResetStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*ResetStreamFrame, error) { - if _, err := r.ReadByte(); err != nil { // read the TypeByte - return nil, err - } - - var streamID protocol.StreamID - var errorCode uint16 - var byteOffset protocol.ByteCount - sid, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - streamID = protocol.StreamID(sid) - errorCode, err = utils.BigEndian.ReadUint16(r) - if err != nil { - return nil, err - } - bo, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - byteOffset = protocol.ByteCount(bo) - - return &ResetStreamFrame{ - StreamID: streamID, - ErrorCode: protocol.ApplicationErrorCode(errorCode), - ByteOffset: byteOffset, - }, nil -} - -func (f *ResetStreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - b.WriteByte(0x4) - utils.WriteVarInt(b, uint64(f.StreamID)) - utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode)) - utils.WriteVarInt(b, uint64(f.ByteOffset)) - return nil -} - -// Length of a written frame -func (f *ResetStreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(uint64(f.StreamID)) + 2 + utils.VarIntLen(uint64(f.ByteOffset)) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/retire_connection_id_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/retire_connection_id_frame.go deleted file mode 100644 index 50230f6d7..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/retire_connection_id_frame.go +++ /dev/null @@ -1,36 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A RetireConnectionIDFrame is a RETIRE_CONNECTION_ID frame -type RetireConnectionIDFrame struct { - SequenceNumber uint64 -} - -func parseRetireConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*RetireConnectionIDFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - - seq, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - return &RetireConnectionIDFrame{SequenceNumber: seq}, nil -} - -func (f *RetireConnectionIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { - b.WriteByte(0x19) - utils.WriteVarInt(b, f.SequenceNumber) - return nil -} - -// Length of a written frame -func (f *RetireConnectionIDFrame) Length(protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(f.SequenceNumber) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/stop_sending_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/stop_sending_frame.go deleted file mode 100644 index f71a476c1..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/stop_sending_frame.go +++ /dev/null @@ -1,47 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A StopSendingFrame is a STOP_SENDING frame -type StopSendingFrame struct { - StreamID protocol.StreamID - ErrorCode protocol.ApplicationErrorCode -} - -// parseStopSendingFrame parses a STOP_SENDING frame -func parseStopSendingFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StopSendingFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - - streamID, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - errorCode, err := utils.BigEndian.ReadUint16(r) - if err != nil { - return nil, err - } - - return &StopSendingFrame{ - StreamID: protocol.StreamID(streamID), - ErrorCode: protocol.ApplicationErrorCode(errorCode), - }, nil -} - -// Length of a written frame -func (f *StopSendingFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(uint64(f.StreamID)) + 2 -} - -func (f *StopSendingFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { - b.WriteByte(0x5) - utils.WriteVarInt(b, uint64(f.StreamID)) - utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode)) - return nil -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/stream_data_blocked_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/stream_data_blocked_frame.go deleted file mode 100644 index 4c6e58058..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/stream_data_blocked_frame.go +++ /dev/null @@ -1,46 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A StreamDataBlockedFrame is a STREAM_DATA_BLOCKED frame -type StreamDataBlockedFrame struct { - StreamID protocol.StreamID - DataLimit protocol.ByteCount -} - -func parseStreamDataBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamDataBlockedFrame, error) { - if _, err := r.ReadByte(); err != nil { - return nil, err - } - - sid, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - offset, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - - return &StreamDataBlockedFrame{ - StreamID: protocol.StreamID(sid), - DataLimit: protocol.ByteCount(offset), - }, nil -} - -func (f *StreamDataBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - b.WriteByte(0x15) - utils.WriteVarInt(b, uint64(f.StreamID)) - utils.WriteVarInt(b, uint64(f.DataLimit)) - return nil -} - -// Length of a written frame -func (f *StreamDataBlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.DataLimit)) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/stream_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/stream_frame.go deleted file mode 100644 index 2f5900ce8..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/stream_frame.go +++ /dev/null @@ -1,168 +0,0 @@ -package wire - -import ( - "bytes" - "errors" - "io" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A StreamFrame of QUIC -type StreamFrame struct { - StreamID protocol.StreamID - FinBit bool - DataLenPresent bool - Offset protocol.ByteCount - Data []byte -} - -func parseStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*StreamFrame, error) { - typeByte, err := r.ReadByte() - if err != nil { - return nil, err - } - - hasOffset := typeByte&0x4 > 0 - frame := &StreamFrame{ - FinBit: typeByte&0x1 > 0, - DataLenPresent: typeByte&0x2 > 0, - } - - streamID, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - frame.StreamID = protocol.StreamID(streamID) - if hasOffset { - offset, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - frame.Offset = protocol.ByteCount(offset) - } - - var dataLen uint64 - if frame.DataLenPresent { - var err error - dataLen, err = utils.ReadVarInt(r) - if err != nil { - return nil, err - } - // shortcut to prevent the unnecessary allocation of dataLen bytes - // if the dataLen is larger than the remaining length of the packet - // reading the packet contents would result in EOF when attempting to READ - if dataLen > uint64(r.Len()) { - return nil, io.EOF - } - } else { - // The rest of the packet is data - dataLen = uint64(r.Len()) - } - if dataLen != 0 { - frame.Data = make([]byte, dataLen) - if _, err := io.ReadFull(r, frame.Data); err != nil { - // this should never happen, since we already checked the dataLen earlier - return nil, err - } - } - if frame.Offset+frame.DataLen() > protocol.MaxByteCount { - return nil, qerr.Error(qerr.InvalidStreamData, "data overflows maximum offset") - } - return frame, nil -} - -// Write writes a STREAM frame -func (f *StreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - if len(f.Data) == 0 && !f.FinBit { - return errors.New("StreamFrame: attempting to write empty frame without FIN") - } - - typeByte := byte(0x8) - if f.FinBit { - typeByte ^= 0x1 - } - hasOffset := f.Offset != 0 - if f.DataLenPresent { - typeByte ^= 0x2 - } - if hasOffset { - typeByte ^= 0x4 - } - b.WriteByte(typeByte) - utils.WriteVarInt(b, uint64(f.StreamID)) - if hasOffset { - utils.WriteVarInt(b, uint64(f.Offset)) - } - if f.DataLenPresent { - utils.WriteVarInt(b, uint64(f.DataLen())) - } - b.Write(f.Data) - return nil -} - -// Length returns the total length of the STREAM frame -func (f *StreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount { - length := 1 + utils.VarIntLen(uint64(f.StreamID)) - if f.Offset != 0 { - length += utils.VarIntLen(uint64(f.Offset)) - } - if f.DataLenPresent { - length += utils.VarIntLen(uint64(f.DataLen())) - } - return length + f.DataLen() -} - -// DataLen gives the length of data in bytes -func (f *StreamFrame) DataLen() protocol.ByteCount { - return protocol.ByteCount(len(f.Data)) -} - -// MaxDataLen returns the maximum data length -// If 0 is returned, writing will fail (a STREAM frame must contain at least 1 byte of data). -func (f *StreamFrame) MaxDataLen(maxSize protocol.ByteCount, version protocol.VersionNumber) protocol.ByteCount { - headerLen := 1 + utils.VarIntLen(uint64(f.StreamID)) - if f.Offset != 0 { - headerLen += utils.VarIntLen(uint64(f.Offset)) - } - if f.DataLenPresent { - // pretend that the data size will be 1 bytes - // if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards - headerLen++ - } - if headerLen > maxSize { - return 0 - } - maxDataLen := maxSize - headerLen - if f.DataLenPresent && utils.VarIntLen(uint64(maxDataLen)) != 1 { - maxDataLen-- - } - return maxDataLen -} - -// MaybeSplitOffFrame splits a frame such that it is not bigger than n bytes. -// If n >= len(frame), nil is returned and nothing is modified. -func (f *StreamFrame) MaybeSplitOffFrame(maxSize protocol.ByteCount, version protocol.VersionNumber) (*StreamFrame, error) { - if maxSize >= f.Length(version) { - return nil, nil - } - - n := f.MaxDataLen(maxSize, version) - if n == 0 { - return nil, errors.New("too small") - } - newFrame := &StreamFrame{ - FinBit: false, - StreamID: f.StreamID, - Offset: f.Offset, - Data: f.Data[:n], - DataLenPresent: f.DataLenPresent, - } - - f.Data = f.Data[n:] - f.Offset += n - - return newFrame, nil -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/streams_blocked_frame.go b/external/github.com/lucas-clemente/quic-go/internal/wire/streams_blocked_frame.go deleted file mode 100644 index 516706af3..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/streams_blocked_frame.go +++ /dev/null @@ -1,52 +0,0 @@ -package wire - -import ( - "bytes" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// A StreamsBlockedFrame is a STREAMS_BLOCKED frame -type StreamsBlockedFrame struct { - Type protocol.StreamType - StreamLimit uint64 -} - -func parseStreamsBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamsBlockedFrame, error) { - typeByte, err := r.ReadByte() - if err != nil { - return nil, err - } - - f := &StreamsBlockedFrame{} - switch typeByte { - case 0x16: - f.Type = protocol.StreamTypeBidi - case 0x17: - f.Type = protocol.StreamTypeUni - } - streamLimit, err := utils.ReadVarInt(r) - if err != nil { - return nil, err - } - f.StreamLimit = streamLimit - - return f, nil -} - -func (f *StreamsBlockedFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error { - switch f.Type { - case protocol.StreamTypeBidi: - b.WriteByte(0x16) - case protocol.StreamTypeUni: - b.WriteByte(0x17) - } - utils.WriteVarInt(b, f.StreamLimit) - return nil -} - -// Length of a written frame -func (f *StreamsBlockedFrame) Length(_ protocol.VersionNumber) protocol.ByteCount { - return 1 + utils.VarIntLen(f.StreamLimit) -} diff --git a/external/github.com/lucas-clemente/quic-go/internal/wire/version_negotiation.go b/external/github.com/lucas-clemente/quic-go/internal/wire/version_negotiation.go deleted file mode 100644 index e09ebf758..000000000 --- a/external/github.com/lucas-clemente/quic-go/internal/wire/version_negotiation.go +++ /dev/null @@ -1,31 +0,0 @@ -package wire - -import ( - "bytes" - "crypto/rand" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -// ComposeVersionNegotiation composes a Version Negotiation -func ComposeVersionNegotiation(destConnID, srcConnID protocol.ConnectionID, versions []protocol.VersionNumber) ([]byte, error) { - greasedVersions := protocol.GetGreasedVersions(versions) - expectedLen := 1 /* type byte */ + 4 /* version field */ + 1 /* connection ID length field */ + destConnID.Len() + srcConnID.Len() + len(greasedVersions)*4 - buf := bytes.NewBuffer(make([]byte, 0, expectedLen)) - r := make([]byte, 1) - _, _ = rand.Read(r) // ignore the error here. It is not critical to have perfect random here. - buf.WriteByte(r[0] | 0x80) - utils.BigEndian.WriteUint32(buf, 0) // version 0 - connIDLen, err := encodeConnIDLen(destConnID, srcConnID) - if err != nil { - return nil, err - } - buf.WriteByte(connIDLen) - buf.Write(destConnID) - buf.Write(srcConnID) - for _, v := range greasedVersions { - utils.BigEndian.WriteUint32(buf, uint32(v)) - } - return buf.Bytes(), nil -} diff --git a/external/github.com/lucas-clemente/quic-go/mockgen.go b/external/github.com/lucas-clemente/quic-go/mockgen.go deleted file mode 100644 index 1a882c358..000000000 --- a/external/github.com/lucas-clemente/quic-go/mockgen.go +++ /dev/null @@ -1,21 +0,0 @@ -package quic - -//go:generate sh -c "./mockgen_private.sh quic mock_stream_internal_test.go github.com/lucas-clemente/quic-go streamI" -//go:generate sh -c "./mockgen_private.sh quic mock_crypto_stream_test.go github.com/lucas-clemente/quic-go cryptoStream" -//go:generate sh -c "./mockgen_private.sh quic mock_receive_stream_internal_test.go github.com/lucas-clemente/quic-go receiveStreamI" -//go:generate sh -c "./mockgen_private.sh quic mock_send_stream_internal_test.go github.com/lucas-clemente/quic-go sendStreamI" -//go:generate sh -c "./mockgen_private.sh quic mock_stream_sender_test.go github.com/lucas-clemente/quic-go streamSender" -//go:generate sh -c "./mockgen_private.sh quic mock_stream_getter_test.go github.com/lucas-clemente/quic-go streamGetter" -//go:generate sh -c "./mockgen_private.sh quic mock_crypto_data_handler_test.go github.com/lucas-clemente/quic-go cryptoDataHandler" -//go:generate sh -c "./mockgen_private.sh quic mock_frame_source_test.go github.com/lucas-clemente/quic-go frameSource" -//go:generate sh -c "./mockgen_private.sh quic mock_ack_frame_source_test.go github.com/lucas-clemente/quic-go ackFrameSource" -//go:generate sh -c "./mockgen_private.sh quic mock_stream_manager_test.go github.com/lucas-clemente/quic-go streamManager" -//go:generate sh -c "./mockgen_private.sh quic mock_sealing_manager_test.go github.com/lucas-clemente/quic-go sealingManager" -//go:generate sh -c "./mockgen_private.sh quic mock_unpacker_test.go github.com/lucas-clemente/quic-go unpacker" -//go:generate sh -c "./mockgen_private.sh quic mock_packer_test.go github.com/lucas-clemente/quic-go packer" -//go:generate sh -c "./mockgen_private.sh quic mock_session_runner_test.go github.com/lucas-clemente/quic-go sessionRunner" -//go:generate sh -c "./mockgen_private.sh quic mock_quic_session_test.go github.com/lucas-clemente/quic-go quicSession" -//go:generate sh -c "./mockgen_private.sh quic mock_packet_handler_test.go github.com/lucas-clemente/quic-go packetHandler" -//go:generate sh -c "./mockgen_private.sh quic mock_unknown_packet_handler_test.go github.com/lucas-clemente/quic-go unknownPacketHandler" -//go:generate sh -c "./mockgen_private.sh quic mock_packet_handler_manager_test.go github.com/lucas-clemente/quic-go packetHandlerManager" -//go:generate sh -c "./mockgen_private.sh quic mock_multiplexer_test.go github.com/lucas-clemente/quic-go multiplexer" diff --git a/external/github.com/lucas-clemente/quic-go/mockgen_private.sh b/external/github.com/lucas-clemente/quic-go/mockgen_private.sh deleted file mode 100755 index 0ba5f64ef..000000000 --- a/external/github.com/lucas-clemente/quic-go/mockgen_private.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -# Mockgen refuses to generate mocks private types. -# This script copies the quic package to a temporary directory, and adds an public alias for the private type. -# It then creates a mock for this public (alias) type. - -TEMP_DIR=$(mktemp -d) -mkdir -p $TEMP_DIR/src/github.com/lucas-clemente/quic-go/ - -# uppercase the name of the interface -INTERFACE_NAME="$(tr '[:lower:]' '[:upper:]' <<< ${4:0:1})${4:1}" - -# copy all .go files to a temporary directory -rsync -r --exclude 'vendor' --include='*.go' --include '*/' --exclude '*' $GOPATH/src/github.com/lucas-clemente/quic-go/ $TEMP_DIR/src/github.com/lucas-clemente/quic-go/ - -# create a public alias for the interface, so that mockgen can process it -echo -e "package $1\n" > $TEMP_DIR/src/github.com/lucas-clemente/quic-go/mockgen_interface.go -echo "type $INTERFACE_NAME = $4" >> $TEMP_DIR/src/github.com/lucas-clemente/quic-go/mockgen_interface.go - -export GOPATH="$TEMP_DIR:$GOPATH" - -mockgen -package $1 -self_package $1 -destination $2 $3 $INTERFACE_NAME - -# mockgen imports quic-go as 'import quic_go github.com/lucas_clemente/quic-go' -sed -i '' 's/quic_go.//g' $2 -goimports -w $2 - -rm -r "$TEMP_DIR" diff --git a/external/github.com/lucas-clemente/quic-go/multiplexer.go b/external/github.com/lucas-clemente/quic-go/multiplexer.go deleted file mode 100644 index 3d5e2372e..000000000 --- a/external/github.com/lucas-clemente/quic-go/multiplexer.go +++ /dev/null @@ -1,76 +0,0 @@ -package quic - -import ( - "fmt" - "net" - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -var ( - connMuxerOnce sync.Once - connMuxer multiplexer -) - -type multiplexer interface { - AddConn(net.PacketConn, int) (packetHandlerManager, error) - RemoveConn(net.PacketConn) error -} - -type connManager struct { - connIDLen int - manager packetHandlerManager -} - -// The connMultiplexer listens on multiple net.PacketConns and dispatches -// incoming packets to the session handler. -type connMultiplexer struct { - mutex sync.Mutex - - conns map[net.PacketConn]connManager - newPacketHandlerManager func(net.PacketConn, int, utils.Logger) packetHandlerManager // so it can be replaced in the tests - - logger utils.Logger -} - -var _ multiplexer = &connMultiplexer{} - -func getMultiplexer() multiplexer { - connMuxerOnce.Do(func() { - connMuxer = &connMultiplexer{ - conns: make(map[net.PacketConn]connManager), - logger: utils.DefaultLogger.WithPrefix("muxer"), - newPacketHandlerManager: newPacketHandlerMap, - } - }) - return connMuxer -} - -func (m *connMultiplexer) AddConn(c net.PacketConn, connIDLen int) (packetHandlerManager, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - p, ok := m.conns[c] - if !ok { - manager := m.newPacketHandlerManager(c, connIDLen, m.logger) - p = connManager{connIDLen: connIDLen, manager: manager} - m.conns[c] = p - } - if p.connIDLen != connIDLen { - return nil, fmt.Errorf("cannot use %d byte connection IDs on a connection that is already using %d byte connction IDs", connIDLen, p.connIDLen) - } - return p.manager, nil -} - -func (m *connMultiplexer) RemoveConn(c net.PacketConn) error { - m.mutex.Lock() - defer m.mutex.Unlock() - - if _, ok := m.conns[c]; !ok { - return fmt.Errorf("cannote remove connection, connection is unknown") - } - - delete(m.conns, c) - return nil -} diff --git a/external/github.com/lucas-clemente/quic-go/packet_handler_map.go b/external/github.com/lucas-clemente/quic-go/packet_handler_map.go deleted file mode 100644 index 3ea76d6ed..000000000 --- a/external/github.com/lucas-clemente/quic-go/packet_handler_map.go +++ /dev/null @@ -1,264 +0,0 @@ -package quic - -import ( - "bytes" - "errors" - "fmt" - "net" - "sync" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type packetHandlerEntry struct { - handler packetHandler - resetToken *[16]byte -} - -// The packetHandlerMap stores packetHandlers, identified by connection ID. -// It is used: -// * by the server to store sessions -// * when multiplexing outgoing connections to store clients -type packetHandlerMap struct { - mutex sync.RWMutex - - conn net.PacketConn - connIDLen int - - handlers map[string] /* string(ConnectionID)*/ packetHandlerEntry - resetTokens map[[16]byte] /* stateless reset token */ packetHandler - server unknownPacketHandler - closed bool - - deleteRetiredSessionsAfter time.Duration - - logger utils.Logger -} - -var _ packetHandlerManager = &packetHandlerMap{} - -func newPacketHandlerMap(conn net.PacketConn, connIDLen int, logger utils.Logger) packetHandlerManager { - m := &packetHandlerMap{ - conn: conn, - connIDLen: connIDLen, - handlers: make(map[string]packetHandlerEntry), - resetTokens: make(map[[16]byte]packetHandler), - deleteRetiredSessionsAfter: protocol.RetiredConnectionIDDeleteTimeout, - logger: logger, - } - go m.listen() - return m -} - -func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler) { - h.mutex.Lock() - h.handlers[string(id)] = packetHandlerEntry{handler: handler} - h.mutex.Unlock() -} - -func (h *packetHandlerMap) AddWithResetToken(id protocol.ConnectionID, handler packetHandler, token [16]byte) { - h.mutex.Lock() - h.handlers[string(id)] = packetHandlerEntry{handler: handler, resetToken: &token} - h.resetTokens[token] = handler - h.mutex.Unlock() -} - -func (h *packetHandlerMap) Remove(id protocol.ConnectionID) { - h.removeByConnectionIDAsString(string(id)) -} - -func (h *packetHandlerMap) removeByConnectionIDAsString(id string) { - h.mutex.Lock() - if handlerEntry, ok := h.handlers[id]; ok { - if token := handlerEntry.resetToken; token != nil { - delete(h.resetTokens, *token) - } - delete(h.handlers, id) - } - h.mutex.Unlock() -} - -func (h *packetHandlerMap) Retire(id protocol.ConnectionID) { - h.retireByConnectionIDAsString(string(id)) -} - -func (h *packetHandlerMap) retireByConnectionIDAsString(id string) { - time.AfterFunc(h.deleteRetiredSessionsAfter, func() { - h.removeByConnectionIDAsString(id) - }) -} - -func (h *packetHandlerMap) SetServer(s unknownPacketHandler) { - h.mutex.Lock() - h.server = s - h.mutex.Unlock() -} - -func (h *packetHandlerMap) CloseServer() { - h.mutex.Lock() - h.server = nil - var wg sync.WaitGroup - for id, handlerEntry := range h.handlers { - handler := handlerEntry.handler - if handler.GetPerspective() == protocol.PerspectiveServer { - wg.Add(1) - go func(id string, handler packetHandler) { - // session.Close() blocks until the CONNECTION_CLOSE has been sent and the run-loop has stopped - _ = handler.Close() - h.retireByConnectionIDAsString(id) - wg.Done() - }(id, handler) - } - } - h.mutex.Unlock() - wg.Wait() -} - -func (h *packetHandlerMap) close(e error) error { - h.mutex.Lock() - if h.closed { - h.mutex.Unlock() - return nil - } - h.closed = true - - var wg sync.WaitGroup - for _, handlerEntry := range h.handlers { - wg.Add(1) - go func(handlerEntry packetHandlerEntry) { - handlerEntry.handler.destroy(e) - wg.Done() - }(handlerEntry) - } - - if h.server != nil { - h.server.closeWithError(e) - } - h.mutex.Unlock() - wg.Wait() - return getMultiplexer().RemoveConn(h.conn) -} - -func (h *packetHandlerMap) listen() { - for { - buffer := getPacketBuffer() - data := buffer.Slice - // The packet size should not exceed protocol.MaxReceivePacketSize bytes - // If it does, we only read a truncated packet, which will then end up undecryptable - n, addr, err := h.conn.ReadFrom(data) - if err != nil { - h.close(err) - return - } - h.handlePacket(addr, buffer, data[:n]) - } -} - -func (h *packetHandlerMap) handlePacket( - addr net.Addr, - buffer *packetBuffer, - data []byte, -) { - packets, err := h.parsePacket(addr, buffer, data) - if err != nil { - h.logger.Debugf("error parsing packets from %s: %s", addr, err) - // This is just the error from parsing the last packet. - // We still need to process the packets that were successfully parsed before. - } - if len(packets) == 0 { - buffer.Release() - return - } - h.handleParsedPackets(packets) -} - -func (h *packetHandlerMap) parsePacket( - addr net.Addr, - buffer *packetBuffer, - data []byte, -) ([]*receivedPacket, error) { - rcvTime := time.Now() - packets := make([]*receivedPacket, 0, 1) - - var counter int - var lastConnID protocol.ConnectionID - for len(data) > 0 { - hdr, err := wire.ParseHeader(bytes.NewReader(data), h.connIDLen) - // drop the packet if we can't parse the header - if err != nil { - return packets, fmt.Errorf("error parsing header: %s", err) - } - if counter > 0 && !hdr.DestConnectionID.Equal(lastConnID) { - return packets, fmt.Errorf("coalesced packet has different destination connection ID: %s, expected %s", hdr.DestConnectionID, lastConnID) - } - lastConnID = hdr.DestConnectionID - - var rest []byte - if hdr.IsLongHeader { - if protocol.ByteCount(len(data)) < hdr.ParsedLen()+hdr.Length { - return packets, fmt.Errorf("packet length (%d bytes) is smaller than the expected length (%d bytes)", len(data)-int(hdr.ParsedLen()), hdr.Length) - } - packetLen := int(hdr.ParsedLen() + hdr.Length) - rest = data[packetLen:] - data = data[:packetLen] - } - - if counter > 0 { - buffer.Split() - } - counter++ - packets = append(packets, &receivedPacket{ - remoteAddr: addr, - hdr: hdr, - rcvTime: rcvTime, - data: data, - buffer: buffer, - }) - - // only log if this actually a coalesced packet - if h.logger.Debug() && (counter > 1 || len(rest) > 0) { - h.logger.Debugf("Parsed a coalesced packet. Part %d: %d bytes. Remaining: %d bytes.", counter, len(packets[counter-1].data), len(rest)) - } - - data = rest - } - return packets, nil -} - -func (h *packetHandlerMap) handleParsedPackets(packets []*receivedPacket) { - h.mutex.RLock() - defer h.mutex.RUnlock() - - // coalesced packets all have the same destination connection ID - handlerEntry, handlerFound := h.handlers[string(packets[0].hdr.DestConnectionID)] - - for _, p := range packets { - if handlerFound { // existing session - handlerEntry.handler.handlePacket(p) - continue - } - // No session found. - // This might be a stateless reset. - if !p.hdr.IsLongHeader { - if len(p.data) >= protocol.MinStatelessResetSize { - var token [16]byte - copy(token[:], p.data[len(p.data)-16:]) - if sess, ok := h.resetTokens[token]; ok { - sess.destroy(errors.New("received a stateless reset")) - continue - } - } - // TODO(#943): send a stateless reset - h.logger.Debugf("received a short header packet with an unexpected connection ID %s", p.hdr.DestConnectionID) - break // a short header packet is always the last in a coalesced packet - } - if h.server == nil { // no server set - h.logger.Debugf("received a packet with an unexpected connection ID %s", p.hdr.DestConnectionID) - continue - } - h.server.handlePacket(p) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/packet_packer.go b/external/github.com/lucas-clemente/quic-go/packet_packer.go deleted file mode 100644 index 406f54871..000000000 --- a/external/github.com/lucas-clemente/quic-go/packet_packer.go +++ /dev/null @@ -1,483 +0,0 @@ -package quic - -import ( - "bytes" - "errors" - "fmt" - "net" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/ackhandler" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/handshake" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type packer interface { - PackPacket() (*packedPacket, error) - MaybePackAckPacket() (*packedPacket, error) - PackRetransmission(packet *ackhandler.Packet) ([]*packedPacket, error) - PackConnectionClose(*wire.ConnectionCloseFrame) (*packedPacket, error) - - HandleTransportParameters(*handshake.TransportParameters) - ChangeDestConnectionID(protocol.ConnectionID) -} - -type packedPacket struct { - header *wire.ExtendedHeader - raw []byte - frames []wire.Frame - - buffer *packetBuffer -} - -func (p *packedPacket) EncryptionLevel() protocol.EncryptionLevel { - if !p.header.IsLongHeader { - return protocol.Encryption1RTT - } - switch p.header.Type { - case protocol.PacketTypeInitial: - return protocol.EncryptionInitial - case protocol.PacketTypeHandshake: - return protocol.EncryptionHandshake - default: - return protocol.EncryptionUnspecified - } -} - -func (p *packedPacket) ToAckHandlerPacket() *ackhandler.Packet { - return &ackhandler.Packet{ - PacketNumber: p.header.PacketNumber, - PacketType: p.header.Type, - Frames: p.frames, - Length: protocol.ByteCount(len(p.raw)), - EncryptionLevel: p.EncryptionLevel(), - SendTime: time.Now(), - } -} - -func getMaxPacketSize(addr net.Addr) protocol.ByteCount { - maxSize := protocol.ByteCount(protocol.MinInitialPacketSize) - // If this is not a UDP address, we don't know anything about the MTU. - // Use the minimum size of an Initial packet as the max packet size. - if udpAddr, ok := addr.(*net.UDPAddr); ok { - // If ip is not an IPv4 address, To4 returns nil. - // Note that there might be some corner cases, where this is not correct. - // See https://stackoverflow.com/questions/22751035/golang-distinguish-ipv4-ipv6. - if udpAddr.IP.To4() == nil { - maxSize = protocol.MaxPacketSizeIPv6 - } else { - maxSize = protocol.MaxPacketSizeIPv4 - } - } - return maxSize -} - -type packetNumberManager interface { - PeekPacketNumber() (protocol.PacketNumber, protocol.PacketNumberLen) - PopPacketNumber() protocol.PacketNumber -} - -type sealingManager interface { - GetSealer() (protocol.EncryptionLevel, handshake.Sealer) - GetSealerWithEncryptionLevel(protocol.EncryptionLevel) (handshake.Sealer, error) -} - -type frameSource interface { - AppendStreamFrames([]wire.Frame, protocol.ByteCount) []wire.Frame - AppendControlFrames([]wire.Frame, protocol.ByteCount) ([]wire.Frame, protocol.ByteCount) -} - -type ackFrameSource interface { - GetAckFrame(protocol.EncryptionLevel) *wire.AckFrame -} - -type packetPacker struct { - destConnID protocol.ConnectionID - srcConnID protocol.ConnectionID - - perspective protocol.Perspective - version protocol.VersionNumber - cryptoSetup sealingManager - - initialStream cryptoStream - handshakeStream cryptoStream - - token []byte - - pnManager packetNumberManager - framer frameSource - acks ackFrameSource - - maxPacketSize protocol.ByteCount - numNonRetransmittableAcks int -} - -var _ packer = &packetPacker{} - -func newPacketPacker( - destConnID protocol.ConnectionID, - srcConnID protocol.ConnectionID, - initialStream cryptoStream, - handshakeStream cryptoStream, - packetNumberManager packetNumberManager, - remoteAddr net.Addr, // only used for determining the max packet size - token []byte, - cryptoSetup sealingManager, - framer frameSource, - acks ackFrameSource, - perspective protocol.Perspective, - version protocol.VersionNumber, -) *packetPacker { - return &packetPacker{ - cryptoSetup: cryptoSetup, - token: token, - destConnID: destConnID, - srcConnID: srcConnID, - initialStream: initialStream, - handshakeStream: handshakeStream, - perspective: perspective, - version: version, - framer: framer, - acks: acks, - pnManager: packetNumberManager, - maxPacketSize: getMaxPacketSize(remoteAddr), - } -} - -// PackConnectionClose packs a packet that ONLY contains a ConnectionCloseFrame -func (p *packetPacker) PackConnectionClose(ccf *wire.ConnectionCloseFrame) (*packedPacket, error) { - frames := []wire.Frame{ccf} - encLevel, sealer := p.cryptoSetup.GetSealer() - header := p.getHeader(encLevel) - return p.writeAndSealPacket(header, frames, sealer) -} - -func (p *packetPacker) MaybePackAckPacket() (*packedPacket, error) { - ack := p.acks.GetAckFrame(protocol.Encryption1RTT) - if ack == nil { - return nil, nil - } - // TODO(#1534): only pack ACKs with the right encryption level - encLevel, sealer := p.cryptoSetup.GetSealer() - header := p.getHeader(encLevel) - frames := []wire.Frame{ack} - return p.writeAndSealPacket(header, frames, sealer) -} - -// PackRetransmission packs a retransmission -// For packets sent after completion of the handshake, it might happen that 2 packets have to be sent. -// This can happen e.g. when a longer packet number is used in the header. -func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedPacket, error) { - var controlFrames []wire.Frame - var streamFrames []*wire.StreamFrame - for _, f := range packet.Frames { - // CRYPTO frames are treated as control frames here. - // Since we're making sure that the header can never be larger for a retransmission, - // we never have to split CRYPTO frames. - if sf, ok := f.(*wire.StreamFrame); ok { - sf.DataLenPresent = true - streamFrames = append(streamFrames, sf) - } else { - controlFrames = append(controlFrames, f) - } - } - - var packets []*packedPacket - encLevel := packet.EncryptionLevel - sealer, err := p.cryptoSetup.GetSealerWithEncryptionLevel(encLevel) - if err != nil { - return nil, err - } - for len(controlFrames) > 0 || len(streamFrames) > 0 { - var frames []wire.Frame - var length protocol.ByteCount - - header := p.getHeader(encLevel) - headerLen := header.GetLength(p.version) - maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLen - - for len(controlFrames) > 0 { - frame := controlFrames[0] - frameLen := frame.Length(p.version) - if length+frameLen > maxSize { - break - } - length += frameLen - frames = append(frames, frame) - controlFrames = controlFrames[1:] - } - - for len(streamFrames) > 0 && length+protocol.MinStreamFrameSize < maxSize { - frame := streamFrames[0] - frame.DataLenPresent = false - frameToAdd := frame - - sf, err := frame.MaybeSplitOffFrame(maxSize-length, p.version) - if err != nil { - return nil, err - } - if sf != nil { - frameToAdd = sf - } else { - streamFrames = streamFrames[1:] - } - frame.DataLenPresent = true - length += frameToAdd.Length(p.version) - frames = append(frames, frameToAdd) - } - if sf, ok := frames[len(frames)-1].(*wire.StreamFrame); ok { - sf.DataLenPresent = false - } - p, err := p.writeAndSealPacket(header, frames, sealer) - if err != nil { - return nil, err - } - packets = append(packets, p) - } - return packets, nil -} - -// PackPacket packs a new packet -// the other controlFrames are sent in the next packet, but might be queued and sent in the next packet if the packet would overflow MaxPacketSize otherwise -func (p *packetPacker) PackPacket() (*packedPacket, error) { - packet, err := p.maybePackCryptoPacket() - if err != nil { - return nil, err - } - if packet != nil { - return packet, nil - } - - encLevel, sealer := p.cryptoSetup.GetSealer() - header := p.getHeader(encLevel) - headerLen := header.GetLength(p.version) - if err != nil { - return nil, err - } - - maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLen - frames, err := p.composeNextPacket(maxSize) - if err != nil { - return nil, err - } - - // Check if we have enough frames to send - if len(frames) == 0 { - return nil, nil - } - // check if this packet only contains an ACK - if !ackhandler.HasRetransmittableFrames(frames) { - if p.numNonRetransmittableAcks >= protocol.MaxNonRetransmittableAcks { - frames = append(frames, &wire.PingFrame{}) - p.numNonRetransmittableAcks = 0 - } else { - p.numNonRetransmittableAcks++ - } - } else { - p.numNonRetransmittableAcks = 0 - } - - return p.writeAndSealPacket(header, frames, sealer) -} - -func (p *packetPacker) maybePackCryptoPacket() (*packedPacket, error) { - var s cryptoStream - var encLevel protocol.EncryptionLevel - - hasData := p.initialStream.HasData() - ack := p.acks.GetAckFrame(protocol.EncryptionInitial) - if hasData || ack != nil { - s = p.initialStream - encLevel = protocol.EncryptionInitial - } else { - hasData = p.handshakeStream.HasData() - ack = p.acks.GetAckFrame(protocol.EncryptionHandshake) - if hasData || ack != nil { - s = p.handshakeStream - encLevel = protocol.EncryptionHandshake - } - } - if s == nil { - return nil, nil - } - sealer, err := p.cryptoSetup.GetSealerWithEncryptionLevel(encLevel) - if err != nil { - // The sealer - return nil, err - } - - hdr := p.getHeader(encLevel) - hdrLen := hdr.GetLength(p.version) - var length protocol.ByteCount - frames := make([]wire.Frame, 0, 2) - if ack != nil { - frames = append(frames, ack) - length += ack.Length(p.version) - } - if hasData { - cf := s.PopCryptoFrame(p.maxPacketSize - hdrLen - protocol.ByteCount(sealer.Overhead()) - length) - frames = append(frames, cf) - } - return p.writeAndSealPacket(hdr, frames, sealer) -} - -func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount) ([]wire.Frame, error) { - var length protocol.ByteCount - var frames []wire.Frame - - // ACKs need to go first, so that the sentPacketHandler will recognize them - if ack := p.acks.GetAckFrame(protocol.Encryption1RTT); ack != nil { - frames = append(frames, ack) - length += ack.Length(p.version) - } - - var lengthAdded protocol.ByteCount - frames, lengthAdded = p.framer.AppendControlFrames(frames, maxFrameSize-length) - length += lengthAdded - - // temporarily increase the maxFrameSize by the (minimum) length of the DataLen field - // this leads to a properly sized packet in all cases, since we do all the packet length calculations with STREAM frames that have the DataLen set - // however, for the last STREAM frame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size - // the length is encoded to either 1 or 2 bytes - maxFrameSize++ - - frames = p.framer.AppendStreamFrames(frames, maxFrameSize-length) - if len(frames) > 0 { - lastFrame := frames[len(frames)-1] - if sf, ok := lastFrame.(*wire.StreamFrame); ok { - sf.DataLenPresent = false - } - } - return frames, nil -} - -func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.ExtendedHeader { - pn, pnLen := p.pnManager.PeekPacketNumber() - header := &wire.ExtendedHeader{} - header.PacketNumber = pn - header.PacketNumberLen = pnLen - header.Version = p.version - header.DestConnectionID = p.destConnID - - if encLevel != protocol.Encryption1RTT { - header.IsLongHeader = true - // Always send Initial and Handshake packets with the maximum packet number length. - // This simplifies retransmissions: Since the header can't get any larger, - // we don't need to split CRYPTO frames. - header.PacketNumberLen = protocol.PacketNumberLen4 - header.SrcConnectionID = p.srcConnID - // Set the length to the maximum packet size. - // Since it is encoded as a varint, this guarantees us that the header will end up at most as big as GetLength() returns. - header.Length = p.maxPacketSize - switch encLevel { - case protocol.EncryptionInitial: - header.Type = protocol.PacketTypeInitial - case protocol.EncryptionHandshake: - header.Type = protocol.PacketTypeHandshake - } - } - - return header -} - -func (p *packetPacker) writeAndSealPacket( - header *wire.ExtendedHeader, - frames []wire.Frame, - sealer handshake.Sealer, -) (*packedPacket, error) { - packetBuffer := getPacketBuffer() - buffer := bytes.NewBuffer(packetBuffer.Slice[:0]) - - addPaddingForInitial := p.perspective == protocol.PerspectiveClient && header.Type == protocol.PacketTypeInitial - - if header.IsLongHeader { - if p.perspective == protocol.PerspectiveClient && header.Type == protocol.PacketTypeInitial { - header.Token = p.token - } - if addPaddingForInitial { - headerLen := header.GetLength(p.version) - header.Length = protocol.ByteCount(header.PacketNumberLen) + protocol.MinInitialPacketSize - headerLen - } else { - // long header packets always use 4 byte packet number, so we never need to pad short payloads - length := protocol.ByteCount(sealer.Overhead()) + protocol.ByteCount(header.PacketNumberLen) - for _, frame := range frames { - length += frame.Length(p.version) - } - header.Length = length - } - } - - if err := header.Write(buffer, p.version); err != nil { - return nil, err - } - payloadOffset := buffer.Len() - - // write all frames but the last one - for _, frame := range frames[:len(frames)-1] { - if err := frame.Write(buffer, p.version); err != nil { - return nil, err - } - } - lastFrame := frames[len(frames)-1] - if addPaddingForInitial { - // when appending padding, we need to make sure that the last STREAM frames has the data length set - if sf, ok := lastFrame.(*wire.StreamFrame); ok { - sf.DataLenPresent = true - } - } else { - payloadLen := buffer.Len() - payloadOffset + int(lastFrame.Length(p.version)) - if paddingLen := 4 - int(header.PacketNumberLen) - payloadLen; paddingLen > 0 { - // Pad the packet such that packet number length + payload length is 4 bytes. - // This is needed to enable the peer to get a 16 byte sample for header protection. - buffer.Write(bytes.Repeat([]byte{0}, paddingLen)) - } - } - if err := lastFrame.Write(buffer, p.version); err != nil { - return nil, err - } - - if addPaddingForInitial { - paddingLen := protocol.MinInitialPacketSize - sealer.Overhead() - buffer.Len() - if paddingLen > 0 { - buffer.Write(bytes.Repeat([]byte{0}, paddingLen)) - } - } - - if size := protocol.ByteCount(buffer.Len() + sealer.Overhead()); size > p.maxPacketSize { - return nil, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, p.maxPacketSize) - } - - raw := buffer.Bytes() - _ = sealer.Seal(raw[payloadOffset:payloadOffset], raw[payloadOffset:], header.PacketNumber, raw[:payloadOffset]) - raw = raw[0 : buffer.Len()+sealer.Overhead()] - - pnOffset := payloadOffset - int(header.PacketNumberLen) - sealer.EncryptHeader( - raw[pnOffset+4:pnOffset+4+16], - &raw[0], - raw[pnOffset:payloadOffset], - ) - - num := p.pnManager.PopPacketNumber() - if num != header.PacketNumber { - return nil, errors.New("packetPacker BUG: Peeked and Popped packet numbers do not match") - } - return &packedPacket{ - header: header, - raw: raw, - frames: frames, - buffer: packetBuffer, - }, nil -} - -func (p *packetPacker) ChangeDestConnectionID(connID protocol.ConnectionID) { - p.destConnID = connID -} - -func (p *packetPacker) HandleTransportParameters(params *handshake.TransportParameters) { - if params.MaxPacketSize != 0 { - p.maxPacketSize = utils.MinByteCount(p.maxPacketSize, params.MaxPacketSize) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/packet_unpacker.go b/external/github.com/lucas-clemente/quic-go/packet_unpacker.go deleted file mode 100644 index 2257503aa..000000000 --- a/external/github.com/lucas-clemente/quic-go/packet_unpacker.go +++ /dev/null @@ -1,102 +0,0 @@ -package quic - -import ( - "bytes" - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/handshake" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type unpackedPacket struct { - packetNumber protocol.PacketNumber // the decoded packet number - hdr *wire.ExtendedHeader - encryptionLevel protocol.EncryptionLevel - data []byte -} - -// The packetUnpacker unpacks QUIC packets. -type packetUnpacker struct { - cs handshake.CryptoSetup - - largestRcvdPacketNumber protocol.PacketNumber - - version protocol.VersionNumber -} - -var _ unpacker = &packetUnpacker{} - -func newPacketUnpacker(cs handshake.CryptoSetup, version protocol.VersionNumber) unpacker { - return &packetUnpacker{ - cs: cs, - version: version, - } -} - -func (u *packetUnpacker) Unpack(hdr *wire.Header, data []byte) (*unpackedPacket, error) { - r := bytes.NewReader(data) - - var encLevel protocol.EncryptionLevel - switch hdr.Type { - case protocol.PacketTypeInitial: - encLevel = protocol.EncryptionInitial - case protocol.PacketTypeHandshake: - encLevel = protocol.EncryptionHandshake - default: - if hdr.IsLongHeader { - return nil, fmt.Errorf("unknown packet type: %s", hdr.Type) - } - encLevel = protocol.Encryption1RTT - } - opener, err := u.cs.GetOpener(encLevel) - if err != nil { - return nil, err - } - hdrLen := int(hdr.ParsedLen()) - if len(data) < hdrLen+4+16 { - return nil, fmt.Errorf("Packet too small. Expected at least 20 bytes after the header, got %d", len(data)-hdrLen) - } - // The packet number can be up to 4 bytes long, but we won't know the length until we decrypt it. - // 1. save a copy of the 4 bytes - origPNBytes := make([]byte, 4) - copy(origPNBytes, data[hdrLen:hdrLen+4]) - // 2. decrypt the header, assuming a 4 byte packet number - opener.DecryptHeader( - data[hdrLen+4:hdrLen+4+16], - &data[0], - data[hdrLen:hdrLen+4], - ) - // 3. parse the header (and learn the actual length of the packet number) - extHdr, err := hdr.ParseExtended(r, u.version) - if err != nil { - return nil, fmt.Errorf("error parsing extended header: %s", err) - } - extHdrLen := hdrLen + int(extHdr.PacketNumberLen) - // 4. if the packet number is shorter than 4 bytes, replace the remaining bytes with the copy we saved earlier - if extHdr.PacketNumberLen != protocol.PacketNumberLen4 { - copy(data[extHdrLen:hdrLen+4], origPNBytes[int(extHdr.PacketNumberLen):]) - } - - pn := protocol.DecodePacketNumber( - extHdr.PacketNumberLen, - u.largestRcvdPacketNumber, - extHdr.PacketNumber, - ) - - decrypted, err := opener.Open(data[extHdrLen:extHdrLen], data[extHdrLen:], pn, data[:extHdrLen]) - if err != nil { - return nil, err - } - - // Only do this after decrypting, so we are sure the packet is not attacker-controlled - u.largestRcvdPacketNumber = utils.MaxPacketNumber(u.largestRcvdPacketNumber, pn) - - return &unpackedPacket{ - hdr: extHdr, - packetNumber: pn, - encryptionLevel: encLevel, - data: decrypted, - }, nil -} diff --git a/external/github.com/lucas-clemente/quic-go/receive_stream.go b/external/github.com/lucas-clemente/quic-go/receive_stream.go deleted file mode 100644 index 5d1999c91..000000000 --- a/external/github.com/lucas-clemente/quic-go/receive_stream.go +++ /dev/null @@ -1,298 +0,0 @@ -package quic - -import ( - "fmt" - "io" - "sync" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/flowcontrol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type receiveStreamI interface { - ReceiveStream - - handleStreamFrame(*wire.StreamFrame) error - handleResetStreamFrame(*wire.ResetStreamFrame) error - closeForShutdown(error) - getWindowUpdate() protocol.ByteCount -} - -type receiveStream struct { - mutex sync.Mutex - - streamID protocol.StreamID - - sender streamSender - - frameQueue *frameSorter - readOffset protocol.ByteCount - - currentFrame []byte - currentFrameIsLast bool // is the currentFrame the last frame on this stream - readPosInFrame int - - closeForShutdownErr error - cancelReadErr error - resetRemotelyErr StreamError - - closedForShutdown bool // set when CloseForShutdown() is called - finRead bool // set once we read a frame with a FinBit - canceledRead bool // set when CancelRead() is called - resetRemotely bool // set when HandleResetStreamFrame() is called - - readChan chan struct{} - deadline time.Time - - flowController flowcontrol.StreamFlowController - version protocol.VersionNumber -} - -var _ ReceiveStream = &receiveStream{} -var _ receiveStreamI = &receiveStream{} - -func newReceiveStream( - streamID protocol.StreamID, - sender streamSender, - flowController flowcontrol.StreamFlowController, - version protocol.VersionNumber, -) *receiveStream { - return &receiveStream{ - streamID: streamID, - sender: sender, - flowController: flowController, - frameQueue: newFrameSorter(), - readChan: make(chan struct{}, 1), - version: version, - } -} - -func (s *receiveStream) StreamID() protocol.StreamID { - return s.streamID -} - -// Read implements io.Reader. It is not thread safe! -func (s *receiveStream) Read(p []byte) (int, error) { - completed, n, err := s.readImpl(p) - if completed { - s.sender.onStreamCompleted(s.streamID) - } - return n, err -} - -func (s *receiveStream) HasMoreData() bool { - s.mutex.Lock() - defer s.mutex.Unlock() - - return s.currentFrame != nil -} - -func (s *receiveStream) readImpl(p []byte) (bool /*stream completed */, int, error) { - s.mutex.Lock() - defer s.mutex.Unlock() - - if s.finRead { - return false, 0, io.EOF - } - if s.canceledRead { - return false, 0, s.cancelReadErr - } - if s.resetRemotely { - return false, 0, s.resetRemotelyErr - } - if s.closedForShutdown { - return false, 0, s.closeForShutdownErr - } - - bytesRead := 0 - for bytesRead < len(p) { - if s.currentFrame == nil || s.readPosInFrame >= len(s.currentFrame) { - s.dequeueNextFrame() - } - if s.currentFrame == nil && bytesRead > 0 { - return false, bytesRead, s.closeForShutdownErr - } - - var deadlineTimer *utils.Timer - for { - // Stop waiting on errors - if s.closedForShutdown { - return false, bytesRead, s.closeForShutdownErr - } - if s.canceledRead { - return false, bytesRead, s.cancelReadErr - } - if s.resetRemotely { - return false, bytesRead, s.resetRemotelyErr - } - - deadline := s.deadline - if !deadline.IsZero() { - if !time.Now().Before(deadline) { - return false, bytesRead, errDeadline - } - if deadlineTimer == nil { - deadlineTimer = utils.NewTimer() - } - deadlineTimer.Reset(deadline) - } - - if s.currentFrame != nil || s.currentFrameIsLast { - break - } - - s.mutex.Unlock() - if deadline.IsZero() { - <-s.readChan - } else { - select { - case <-s.readChan: - case <-deadlineTimer.Chan(): - deadlineTimer.SetRead() - } - } - s.mutex.Lock() - if s.currentFrame == nil { - s.dequeueNextFrame() - } - } - - if bytesRead > len(p) { - return false, bytesRead, fmt.Errorf("BUG: bytesRead (%d) > len(p) (%d) in stream.Read", bytesRead, len(p)) - } - if s.readPosInFrame > len(s.currentFrame) { - return false, bytesRead, fmt.Errorf("BUG: readPosInFrame (%d) > frame.DataLen (%d) in stream.Read", s.readPosInFrame, len(s.currentFrame)) - } - - s.mutex.Unlock() - - m := copy(p[bytesRead:], s.currentFrame[s.readPosInFrame:]) - s.readPosInFrame += m - bytesRead += m - s.readOffset += protocol.ByteCount(m) - - s.mutex.Lock() - // when a RESET_STREAM was received, the was already informed about the final byteOffset for this stream - if !s.resetRemotely { - s.flowController.AddBytesRead(protocol.ByteCount(m)) - } - // increase the flow control window, if necessary - s.flowController.MaybeQueueWindowUpdate() - - if s.readPosInFrame >= len(s.currentFrame) && s.currentFrameIsLast { - s.finRead = true - return true, bytesRead, io.EOF - } - } - return false, bytesRead, nil -} - -func (s *receiveStream) dequeueNextFrame() { - s.currentFrame, s.currentFrameIsLast = s.frameQueue.Pop() - s.readPosInFrame = 0 -} - -func (s *receiveStream) CancelRead(errorCode protocol.ApplicationErrorCode) error { - s.mutex.Lock() - defer s.mutex.Unlock() - - if s.finRead { - return nil - } - if s.canceledRead { - return nil - } - s.canceledRead = true - s.cancelReadErr = fmt.Errorf("Read on stream %d canceled with error code %d", s.streamID, errorCode) - s.signalRead() - s.sender.queueControlFrame(&wire.StopSendingFrame{ - StreamID: s.streamID, - ErrorCode: errorCode, - }) - return nil -} - -func (s *receiveStream) handleStreamFrame(frame *wire.StreamFrame) error { - maxOffset := frame.Offset + frame.DataLen() - if err := s.flowController.UpdateHighestReceived(maxOffset, frame.FinBit); err != nil { - return err - } - - s.mutex.Lock() - defer s.mutex.Unlock() - if err := s.frameQueue.Push(frame.Data, frame.Offset, frame.FinBit); err != nil { - return err - } - s.signalRead() - return nil -} - -func (s *receiveStream) handleResetStreamFrame(frame *wire.ResetStreamFrame) error { - completed, err := s.handleResetStreamFrameImpl(frame) - if completed { - s.sender.onStreamCompleted(s.streamID) - } - return err -} - -func (s *receiveStream) handleResetStreamFrameImpl(frame *wire.ResetStreamFrame) (bool /*completed */, error) { - s.mutex.Lock() - defer s.mutex.Unlock() - - if s.closedForShutdown { - return false, nil - } - if err := s.flowController.UpdateHighestReceived(frame.ByteOffset, true); err != nil { - return false, err - } - - // ignore duplicate RESET_STREAM frames for this stream (after checking their final offset) - if s.resetRemotely { - return false, nil - } - s.resetRemotely = true - s.resetRemotelyErr = streamCanceledError{ - errorCode: frame.ErrorCode, - error: fmt.Errorf("Stream %d was reset with error code %d", s.streamID, frame.ErrorCode), - } - s.signalRead() - return true, nil -} - -func (s *receiveStream) CloseRemote(offset protocol.ByteCount) { - s.handleStreamFrame(&wire.StreamFrame{FinBit: true, Offset: offset}) -} - -func (s *receiveStream) SetReadDeadline(t time.Time) error { - s.mutex.Lock() - s.deadline = t - s.mutex.Unlock() - s.signalRead() - return nil -} - -// CloseForShutdown closes a stream abruptly. -// It makes Read unblock (and return the error) immediately. -// The peer will NOT be informed about this: the stream is closed without sending a FIN or RESET. -func (s *receiveStream) closeForShutdown(err error) { - s.mutex.Lock() - s.closedForShutdown = true - s.closeForShutdownErr = err - s.mutex.Unlock() - s.signalRead() -} - -func (s *receiveStream) getWindowUpdate() protocol.ByteCount { - return s.flowController.GetWindowUpdate() -} - -// signalRead performs a non-blocking send on the readChan -func (s *receiveStream) signalRead() { - select { - case s.readChan <- struct{}{}: - default: - } -} diff --git a/external/github.com/lucas-clemente/quic-go/send_stream.go b/external/github.com/lucas-clemente/quic-go/send_stream.go deleted file mode 100644 index 97849b1cf..000000000 --- a/external/github.com/lucas-clemente/quic-go/send_stream.go +++ /dev/null @@ -1,340 +0,0 @@ -package quic - -import ( - "context" - "fmt" - "sync" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/flowcontrol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type sendStreamI interface { - SendStream - handleStopSendingFrame(*wire.StopSendingFrame) - hasData() bool - popStreamFrame(maxBytes protocol.ByteCount) (*wire.StreamFrame, bool) - closeForShutdown(error) - handleMaxStreamDataFrame(*wire.MaxStreamDataFrame) -} - -type sendStream struct { - mutex sync.Mutex - - ctx context.Context - ctxCancel context.CancelFunc - - streamID protocol.StreamID - sender streamSender - - writeOffset protocol.ByteCount - - cancelWriteErr error - closeForShutdownErr error - - closedForShutdown bool // set when CloseForShutdown() is called - finishedWriting bool // set once Close() is called - canceledWrite bool // set when CancelWrite() is called, or a STOP_SENDING frame is received - finSent bool // set when a STREAM_FRAME with FIN bit has b - - dataForWriting []byte - - writeChan chan struct{} - deadline time.Time - - flowController flowcontrol.StreamFlowController - - version protocol.VersionNumber -} - -var _ SendStream = &sendStream{} -var _ sendStreamI = &sendStream{} - -func newSendStream( - streamID protocol.StreamID, - sender streamSender, - flowController flowcontrol.StreamFlowController, - version protocol.VersionNumber, -) *sendStream { - s := &sendStream{ - streamID: streamID, - sender: sender, - flowController: flowController, - writeChan: make(chan struct{}, 1), - version: version, - } - s.ctx, s.ctxCancel = context.WithCancel(context.Background()) - return s -} - -func (s *sendStream) StreamID() protocol.StreamID { - return s.streamID // same for receiveStream and sendStream -} - -func (s *sendStream) Write(p []byte) (int, error) { - s.mutex.Lock() - defer s.mutex.Unlock() - - if s.finishedWriting { - return 0, fmt.Errorf("write on closed stream %d", s.streamID) - } - if s.canceledWrite { - return 0, s.cancelWriteErr - } - if s.closeForShutdownErr != nil { - return 0, s.closeForShutdownErr - } - if !s.deadline.IsZero() && !time.Now().Before(s.deadline) { - return 0, errDeadline - } - if len(p) == 0 { - return 0, nil - } - - s.dataForWriting = p - - var ( - deadlineTimer *utils.Timer - bytesWritten int - notifiedSender bool - ) - for { - bytesWritten = len(p) - len(s.dataForWriting) - deadline := s.deadline - if !deadline.IsZero() { - if !time.Now().Before(deadline) { - s.dataForWriting = nil - return bytesWritten, errDeadline - } - if deadlineTimer == nil { - deadlineTimer = utils.NewTimer() - } - deadlineTimer.Reset(deadline) - } - if s.dataForWriting == nil || s.canceledWrite || s.closedForShutdown { - break - } - - s.mutex.Unlock() - if !notifiedSender { - s.sender.onHasStreamData(s.streamID) // must be called without holding the mutex - notifiedSender = true - } - if deadline.IsZero() { - <-s.writeChan - } else { - select { - case <-s.writeChan: - case <-deadlineTimer.Chan(): - deadlineTimer.SetRead() - } - } - s.mutex.Lock() - } - - if s.closeForShutdownErr != nil { - return bytesWritten, s.closeForShutdownErr - } else if s.cancelWriteErr != nil { - return bytesWritten, s.cancelWriteErr - } - return bytesWritten, nil -} - -// popStreamFrame returns the next STREAM frame that is supposed to be sent on this stream -// maxBytes is the maximum length this frame (including frame header) will have. -func (s *sendStream) popStreamFrame(maxBytes protocol.ByteCount) (*wire.StreamFrame, bool /* has more data to send */) { - completed, frame, hasMoreData := s.popStreamFrameImpl(maxBytes) - if completed { - s.sender.onStreamCompleted(s.streamID) - } - return frame, hasMoreData -} - -func (s *sendStream) popStreamFrameImpl(maxBytes protocol.ByteCount) (bool /* completed */, *wire.StreamFrame, bool /* has more data to send */) { - s.mutex.Lock() - defer s.mutex.Unlock() - - if s.closeForShutdownErr != nil { - return false, nil, false - } - - frame := &wire.StreamFrame{ - StreamID: s.streamID, - Offset: s.writeOffset, - DataLenPresent: true, - } - maxDataLen := frame.MaxDataLen(maxBytes, s.version) - if maxDataLen == 0 { // a STREAM frame must have at least one byte of data - return false, nil, s.dataForWriting != nil - } - frame.Data, frame.FinBit = s.getDataForWriting(maxDataLen) - if len(frame.Data) == 0 && !frame.FinBit { - // this can happen if: - // - popStreamFrame is called but there's no data for writing - // - there's data for writing, but the stream is stream-level flow control blocked - // - there's data for writing, but the stream is connection-level flow control blocked - if s.dataForWriting == nil { - return false, nil, false - } - if isBlocked, offset := s.flowController.IsNewlyBlocked(); isBlocked { - s.sender.queueControlFrame(&wire.StreamDataBlockedFrame{ - StreamID: s.streamID, - DataLimit: offset, - }) - return false, nil, false - } - return false, nil, true - } - if frame.FinBit { - s.finSent = true - } - return frame.FinBit, frame, s.dataForWriting != nil -} - -func (s *sendStream) hasData() bool { - s.mutex.Lock() - hasData := len(s.dataForWriting) > 0 - s.mutex.Unlock() - return hasData -} - -func (s *sendStream) getDataForWriting(maxBytes protocol.ByteCount) ([]byte, bool /* should send FIN */) { - if s.dataForWriting == nil { - return nil, s.finishedWriting && !s.finSent - } - - maxBytes = utils.MinByteCount(maxBytes, s.flowController.SendWindowSize()) - if maxBytes == 0 { - return nil, false - } - - var ret []byte - if protocol.ByteCount(len(s.dataForWriting)) > maxBytes { - ret = make([]byte, int(maxBytes)) - copy(ret, s.dataForWriting[:maxBytes]) - s.dataForWriting = s.dataForWriting[maxBytes:] - } else { - ret = make([]byte, len(s.dataForWriting)) - copy(ret, s.dataForWriting) - s.dataForWriting = nil - s.signalWrite() - } - s.writeOffset += protocol.ByteCount(len(ret)) - s.flowController.AddBytesSent(protocol.ByteCount(len(ret))) - return ret, s.finishedWriting && s.dataForWriting == nil && !s.finSent -} - -func (s *sendStream) Close() error { - s.mutex.Lock() - if s.canceledWrite { - s.mutex.Unlock() - return fmt.Errorf("Close called for canceled stream %d", s.streamID) - } - s.finishedWriting = true - s.mutex.Unlock() - - s.sender.onHasStreamData(s.streamID) // need to send the FIN, must be called without holding the mutex - s.ctxCancel() - return nil -} - -func (s *sendStream) CancelWrite(errorCode protocol.ApplicationErrorCode) error { - s.mutex.Lock() - completed, err := s.cancelWriteImpl(errorCode, fmt.Errorf("Write on stream %d canceled with error code %d", s.streamID, errorCode)) - s.mutex.Unlock() - - if completed { - s.sender.onStreamCompleted(s.streamID) // must be called without holding the mutex - } - return err -} - -// must be called after locking the mutex -func (s *sendStream) cancelWriteImpl(errorCode protocol.ApplicationErrorCode, writeErr error) (bool /*completed */, error) { - if s.canceledWrite { - return false, nil - } - if s.finishedWriting { - return false, fmt.Errorf("CancelWrite for closed stream %d", s.streamID) - } - s.canceledWrite = true - s.cancelWriteErr = writeErr - s.signalWrite() - s.sender.queueControlFrame(&wire.ResetStreamFrame{ - StreamID: s.streamID, - ByteOffset: s.writeOffset, - ErrorCode: errorCode, - }) - // TODO(#991): cancel retransmissions for this stream - s.ctxCancel() - return true, nil -} - -func (s *sendStream) handleStopSendingFrame(frame *wire.StopSendingFrame) { - if completed := s.handleStopSendingFrameImpl(frame); completed { - s.sender.onStreamCompleted(s.streamID) - } -} - -func (s *sendStream) handleMaxStreamDataFrame(frame *wire.MaxStreamDataFrame) { - s.mutex.Lock() - hasStreamData := s.dataForWriting != nil - s.mutex.Unlock() - s.flowController.UpdateSendWindow(frame.ByteOffset) - if hasStreamData { - s.sender.onHasStreamData(s.streamID) - } -} - -// must be called after locking the mutex -func (s *sendStream) handleStopSendingFrameImpl(frame *wire.StopSendingFrame) bool /*completed*/ { - s.mutex.Lock() - defer s.mutex.Unlock() - - writeErr := streamCanceledError{ - errorCode: frame.ErrorCode, - error: fmt.Errorf("Stream %d was reset with error code %d", s.streamID, frame.ErrorCode), - } - errorCode := errorCodeStopping - completed, _ := s.cancelWriteImpl(errorCode, writeErr) - return completed -} - -func (s *sendStream) Context() context.Context { - return s.ctx -} - -func (s *sendStream) SetWriteDeadline(t time.Time) error { - s.mutex.Lock() - s.deadline = t - s.mutex.Unlock() - s.signalWrite() - return nil -} - -// CloseForShutdown closes a stream abruptly. -// It makes Write unblock (and return the error) immediately. -// The peer will NOT be informed about this: the stream is closed without sending a FIN or RST. -func (s *sendStream) closeForShutdown(err error) { - s.mutex.Lock() - s.closedForShutdown = true - s.closeForShutdownErr = err - s.mutex.Unlock() - s.signalWrite() - s.ctxCancel() -} - -func (s *sendStream) getWriteOffset() protocol.ByteCount { - return s.writeOffset -} - -// signalWrite performs a non-blocking send on the writeChan -func (s *sendStream) signalWrite() { - select { - case s.writeChan <- struct{}{}: - default: - } -} diff --git a/external/github.com/lucas-clemente/quic-go/server.go b/external/github.com/lucas-clemente/quic-go/server.go deleted file mode 100644 index 8ee500145..000000000 --- a/external/github.com/lucas-clemente/quic-go/server.go +++ /dev/null @@ -1,542 +0,0 @@ -package quic - -import ( - "bytes" - "crypto/tls" - "errors" - "fmt" - "io" - "net" - "sync" - "sync/atomic" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/handshake" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -// packetHandler handles packets -type packetHandler interface { - handlePacket(*receivedPacket) - io.Closer - destroy(error) - GetPerspective() protocol.Perspective -} - -type unknownPacketHandler interface { - handlePacket(*receivedPacket) - closeWithError(error) error -} - -type packetHandlerManager interface { - Add(protocol.ConnectionID, packetHandler) - Retire(protocol.ConnectionID) - Remove(protocol.ConnectionID) - SetServer(unknownPacketHandler) - CloseServer() -} - -type quicSession interface { - Session - handlePacket(*receivedPacket) - GetVersion() protocol.VersionNumber - run() error - destroy(error) - closeForRecreating() protocol.PacketNumber - closeRemote(error) -} - -type sessionRunner interface { - onHandshakeComplete(Session) - retireConnectionID(protocol.ConnectionID) - removeConnectionID(protocol.ConnectionID) -} - -type runner struct { - onHandshakeCompleteImpl func(Session) - retireConnectionIDImpl func(protocol.ConnectionID) - removeConnectionIDImpl func(protocol.ConnectionID) -} - -func (r *runner) onHandshakeComplete(s Session) { r.onHandshakeCompleteImpl(s) } -func (r *runner) retireConnectionID(c protocol.ConnectionID) { r.retireConnectionIDImpl(c) } -func (r *runner) removeConnectionID(c protocol.ConnectionID) { r.removeConnectionIDImpl(c) } - -var _ sessionRunner = &runner{} - -// A Listener of QUIC -type server struct { - mutex sync.Mutex - - tlsConf *tls.Config - config *Config - - conn net.PacketConn - // If the server is started with ListenAddr, we create a packet conn. - // If it is started with Listen, we take a packet conn as a parameter. - createdPacketConn bool - - cookieGenerator *handshake.CookieGenerator - - sessionHandler packetHandlerManager - - // set as a member, so they can be set in the tests - newSession func(connection, sessionRunner, protocol.ConnectionID /* original connection ID */, protocol.ConnectionID /* destination connection ID */, protocol.ConnectionID /* source connection ID */, *Config, *tls.Config, *handshake.TransportParameters, utils.Logger, protocol.VersionNumber) (quicSession, error) - - serverError error - errorChan chan struct{} - closed bool - - sessionQueue chan Session - sessionQueueLen int32 // to be used as an atomic - - sessionRunner sessionRunner - - logger utils.Logger -} - -var _ Listener = &server{} -var _ unknownPacketHandler = &server{} - -// ListenAddr creates a QUIC server listening on a given address. -// The tls.Config must not be nil and must contain a certificate configuration. -// The quic.Config may be nil, in that case the default values will be used. -func ListenAddr(addr string, tlsConf *tls.Config, config *Config) (Listener, error) { - udpAddr, err := net.ResolveUDPAddr("udp", addr) - if err != nil { - return nil, err - } - conn, err := net.ListenUDP("udp", udpAddr) - if err != nil { - return nil, err - } - serv, err := listen(conn, tlsConf, config) - if err != nil { - return nil, err - } - serv.createdPacketConn = true - return serv, nil -} - -// Listen listens for QUIC connections on a given net.PacketConn. -// A single PacketConn only be used for a single call to Listen. -// The PacketConn can be used for simultaneous calls to Dial. -// QUIC connection IDs are used for demultiplexing the different connections. -// The tls.Config must not be nil and must contain a certificate configuration. -// The quic.Config may be nil, in that case the default values will be used. -func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (Listener, error) { - return listen(conn, tlsConf, config) -} - -func listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*server, error) { - // TODO(#1655): only require that tls.Config.Certificates or tls.Config.GetCertificate is set - if tlsConf == nil || len(tlsConf.Certificates) == 0 { - return nil, errors.New("quic: Certificates not set in tls.Config") - } - config = populateServerConfig(config) - for _, v := range config.Versions { - if !protocol.IsValidVersion(v) { - return nil, fmt.Errorf("%s is not a valid QUIC version", v) - } - } - - sessionHandler, err := getMultiplexer().AddConn(conn, config.ConnectionIDLength) - if err != nil { - return nil, err - } - s := &server{ - conn: conn, - tlsConf: tlsConf, - config: config, - sessionHandler: sessionHandler, - sessionQueue: make(chan Session), - errorChan: make(chan struct{}), - newSession: newSession, - logger: utils.DefaultLogger.WithPrefix("server"), - } - if err := s.setup(); err != nil { - return nil, err - } - sessionHandler.SetServer(s) - s.logger.Debugf("Listening for %s connections on %s", conn.LocalAddr().Network(), conn.LocalAddr().String()) - return s, nil -} - -func (s *server) setup() error { - s.sessionRunner = &runner{ - onHandshakeCompleteImpl: func(sess Session) { - go func() { - atomic.AddInt32(&s.sessionQueueLen, 1) - defer atomic.AddInt32(&s.sessionQueueLen, -1) - select { - case s.sessionQueue <- sess: - // blocks until the session is accepted - case <-sess.Context().Done(): - // don't pass sessions that were already closed to Accept() - } - }() - }, - retireConnectionIDImpl: s.sessionHandler.Retire, - removeConnectionIDImpl: s.sessionHandler.Remove, - } - cookieGenerator, err := handshake.NewCookieGenerator() - if err != nil { - return err - } - s.cookieGenerator = cookieGenerator - return nil -} - -var defaultAcceptCookie = func(clientAddr net.Addr, cookie *Cookie) bool { - if cookie == nil { - return false - } - if time.Now().After(cookie.SentTime.Add(protocol.CookieExpiryTime)) { - return false - } - var sourceAddr string - if udpAddr, ok := clientAddr.(*net.UDPAddr); ok { - sourceAddr = udpAddr.IP.String() - } else { - sourceAddr = clientAddr.String() - } - return sourceAddr == cookie.RemoteAddr -} - -// populateServerConfig populates fields in the quic.Config with their default values, if none are set -// it may be called with nil -func populateServerConfig(config *Config) *Config { - if config == nil { - config = &Config{} - } - versions := config.Versions - if len(versions) == 0 { - versions = protocol.SupportedVersions - } - - vsa := defaultAcceptCookie - if config.AcceptCookie != nil { - vsa = config.AcceptCookie - } - - handshakeTimeout := protocol.DefaultHandshakeTimeout - if config.HandshakeTimeout != 0 { - handshakeTimeout = config.HandshakeTimeout - } - idleTimeout := protocol.DefaultIdleTimeout - if config.IdleTimeout != 0 { - idleTimeout = config.IdleTimeout - } - - maxReceiveStreamFlowControlWindow := config.MaxReceiveStreamFlowControlWindow - if maxReceiveStreamFlowControlWindow == 0 { - maxReceiveStreamFlowControlWindow = protocol.DefaultMaxReceiveStreamFlowControlWindow - } - maxReceiveConnectionFlowControlWindow := config.MaxReceiveConnectionFlowControlWindow - if maxReceiveConnectionFlowControlWindow == 0 { - maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindow - } - maxIncomingStreams := config.MaxIncomingStreams - if maxIncomingStreams == 0 { - maxIncomingStreams = protocol.DefaultMaxIncomingStreams - } else if maxIncomingStreams < 0 { - maxIncomingStreams = 0 - } - maxIncomingUniStreams := config.MaxIncomingUniStreams - if maxIncomingUniStreams == 0 { - maxIncomingUniStreams = protocol.DefaultMaxIncomingUniStreams - } else if maxIncomingUniStreams < 0 { - maxIncomingUniStreams = 0 - } - connIDLen := config.ConnectionIDLength - if connIDLen == 0 { - connIDLen = protocol.DefaultConnectionIDLength - } - - return &Config{ - Versions: versions, - HandshakeTimeout: handshakeTimeout, - IdleTimeout: idleTimeout, - AcceptCookie: vsa, - KeepAlive: config.KeepAlive, - MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow, - MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow, - MaxIncomingStreams: maxIncomingStreams, - MaxIncomingUniStreams: maxIncomingUniStreams, - ConnectionIDLength: connIDLen, - } -} - -// Accept returns newly openend sessions -func (s *server) Accept() (Session, error) { - var sess Session - select { - case sess = <-s.sessionQueue: - return sess, nil - case <-s.errorChan: - return nil, s.serverError - } -} - -// Close the server -func (s *server) Close() error { - s.mutex.Lock() - defer s.mutex.Unlock() - if s.closed { - return nil - } - return s.closeWithMutex() -} - -func (s *server) closeWithMutex() error { - s.sessionHandler.CloseServer() - if s.serverError == nil { - s.serverError = errors.New("server closed") - } - var err error - // If the server was started with ListenAddr, we created the packet conn. - // We need to close it in order to make the go routine reading from that conn return. - if s.createdPacketConn { - err = s.conn.Close() - } - s.closed = true - close(s.errorChan) - return err -} - -func (s *server) closeWithError(e error) error { - s.mutex.Lock() - defer s.mutex.Unlock() - if s.closed { - return nil - } - s.serverError = e - return s.closeWithMutex() -} - -// Addr returns the server's network address -func (s *server) Addr() net.Addr { - return s.conn.LocalAddr() -} - -func (s *server) handlePacket(p *receivedPacket) { - hdr := p.hdr - - // send a Version Negotiation Packet if the client is speaking a different protocol version - if !protocol.IsSupportedVersion(s.config.Versions, hdr.Version) { - go s.sendVersionNegotiationPacket(p) - return - } - if hdr.Type == protocol.PacketTypeInitial { - go s.handleInitial(p) - return - } - - // TODO(#943): send Stateless Reset - p.buffer.Release() -} - -func (s *server) handleInitial(p *receivedPacket) { - s.logger.Debugf("<- Received Initial packet.") - sess, connID, err := s.handleInitialImpl(p) - if err != nil { - p.buffer.Release() - s.logger.Errorf("Error occurred handling initial packet: %s", err) - return - } - if sess == nil { // a retry was done, or the connection attempt was rejected - p.buffer.Release() - return - } - // Don't put the packet buffer back if a new session was created. - // The session will handle the packet and take of that. - serverSession := newServerSession(sess, s.config, s.logger) - s.sessionHandler.Add(connID, serverSession) -} - -func (s *server) handleInitialImpl(p *receivedPacket) (quicSession, protocol.ConnectionID, error) { - hdr := p.hdr - if len(hdr.Token) == 0 && hdr.DestConnectionID.Len() < protocol.MinConnectionIDLenInitial { - return nil, nil, errors.New("dropping Initial packet with too short connection ID") - } - if len(p.data) < protocol.MinInitialPacketSize { - return nil, nil, errors.New("dropping too small Initial packet") - } - - var cookie *Cookie - var origDestConnectionID protocol.ConnectionID - if len(hdr.Token) > 0 { - c, err := s.cookieGenerator.DecodeToken(hdr.Token) - if err == nil { - cookie = &Cookie{ - RemoteAddr: c.RemoteAddr, - SentTime: c.SentTime, - } - origDestConnectionID = c.OriginalDestConnectionID - } - } - if !s.config.AcceptCookie(p.remoteAddr, cookie) { - // Log the Initial packet now. - // If no Retry is sent, the packet will be logged by the session. - (&wire.ExtendedHeader{Header: *p.hdr}).Log(s.logger) - return nil, nil, s.sendRetry(p.remoteAddr, hdr) - } - - if queueLen := atomic.LoadInt32(&s.sessionQueueLen); queueLen >= protocol.MaxAcceptQueueSize { - s.logger.Debugf("Rejecting new connection. Server currently busy. Accept queue length: %d (max %d)", queueLen, protocol.MaxAcceptQueueSize) - return nil, nil, s.sendServerBusy(p.remoteAddr, hdr) - } - - connID, err := protocol.GenerateConnectionID(s.config.ConnectionIDLength) - if err != nil { - return nil, nil, err - } - s.logger.Debugf("Changing connection ID to %s.", connID) - sess, err := s.createNewSession( - p.remoteAddr, - origDestConnectionID, - hdr.DestConnectionID, - hdr.SrcConnectionID, - connID, - hdr.Version, - ) - if err != nil { - return nil, nil, err - } - sess.handlePacket(p) - return sess, connID, nil -} - -func (s *server) createNewSession( - remoteAddr net.Addr, - origDestConnID protocol.ConnectionID, - clientDestConnID protocol.ConnectionID, - destConnID protocol.ConnectionID, - srcConnID protocol.ConnectionID, - version protocol.VersionNumber, -) (quicSession, error) { - params := &handshake.TransportParameters{ - InitialMaxStreamDataBidiLocal: protocol.InitialMaxStreamData, - InitialMaxStreamDataBidiRemote: protocol.InitialMaxStreamData, - InitialMaxStreamDataUni: protocol.InitialMaxStreamData, - InitialMaxData: protocol.InitialMaxData, - IdleTimeout: s.config.IdleTimeout, - MaxBidiStreams: uint64(s.config.MaxIncomingStreams), - MaxUniStreams: uint64(s.config.MaxIncomingUniStreams), - DisableMigration: true, - // TODO(#855): generate a real token - StatelessResetToken: bytes.Repeat([]byte{42}, 16), - OriginalConnectionID: origDestConnID, - } - sess, err := s.newSession( - &conn{pconn: s.conn, currentAddr: remoteAddr}, - s.sessionRunner, - clientDestConnID, - destConnID, - srcConnID, - s.config, - s.tlsConf, - params, - s.logger, - version, - ) - if err != nil { - return nil, err - } - go sess.run() - return sess, nil -} - -func (s *server) sendRetry(remoteAddr net.Addr, hdr *wire.Header) error { - token, err := s.cookieGenerator.NewToken(remoteAddr, hdr.DestConnectionID) - if err != nil { - return err - } - connID, err := protocol.GenerateConnectionID(s.config.ConnectionIDLength) - if err != nil { - return err - } - replyHdr := &wire.ExtendedHeader{} - replyHdr.IsLongHeader = true - replyHdr.Type = protocol.PacketTypeRetry - replyHdr.Version = hdr.Version - replyHdr.SrcConnectionID = connID - replyHdr.DestConnectionID = hdr.SrcConnectionID - replyHdr.OrigDestConnectionID = hdr.DestConnectionID - replyHdr.Token = token - s.logger.Debugf("Changing connection ID to %s.\n-> Sending Retry", connID) - replyHdr.Log(s.logger) - buf := &bytes.Buffer{} - if err := replyHdr.Write(buf, hdr.Version); err != nil { - return err - } - if _, err := s.conn.WriteTo(buf.Bytes(), remoteAddr); err != nil { - s.logger.Debugf("Error sending Retry: %s", err) - } - return nil -} - -func (s *server) sendServerBusy(remoteAddr net.Addr, hdr *wire.Header) error { - sealer, _, err := handshake.NewInitialAEAD(hdr.DestConnectionID, protocol.PerspectiveServer) - if err != nil { - return err - } - packetBuffer := getPacketBuffer() - defer packetBuffer.Release() - buf := bytes.NewBuffer(packetBuffer.Slice[:0]) - - // TODO(#1567): use the SERVER_BUSY error code - ccf := &wire.ConnectionCloseFrame{ErrorCode: qerr.PeerGoingAway} - - replyHdr := &wire.ExtendedHeader{} - replyHdr.IsLongHeader = true - replyHdr.Type = protocol.PacketTypeInitial - replyHdr.Version = hdr.Version - replyHdr.SrcConnectionID = hdr.DestConnectionID - replyHdr.DestConnectionID = hdr.SrcConnectionID - replyHdr.PacketNumberLen = protocol.PacketNumberLen4 - replyHdr.Length = 4 /* packet number len */ + ccf.Length(hdr.Version) + protocol.ByteCount(sealer.Overhead()) - if err := replyHdr.Write(buf, hdr.Version); err != nil { - return err - } - payloadOffset := buf.Len() - - if err := ccf.Write(buf, hdr.Version); err != nil { - return err - } - - raw := buf.Bytes() - _ = sealer.Seal(raw[payloadOffset:payloadOffset], raw[payloadOffset:], replyHdr.PacketNumber, raw[:payloadOffset]) - raw = raw[0 : buf.Len()+sealer.Overhead()] - - pnOffset := payloadOffset - int(replyHdr.PacketNumberLen) - sealer.EncryptHeader( - raw[pnOffset+4:pnOffset+4+16], - &raw[0], - raw[pnOffset:payloadOffset], - ) - - replyHdr.Log(s.logger) - wire.LogFrame(s.logger, ccf, true) - if _, err := s.conn.WriteTo(raw, remoteAddr); err != nil { - s.logger.Debugf("Error rejecting connection: %s", err) - } - return nil -} - -func (s *server) sendVersionNegotiationPacket(p *receivedPacket) { - defer p.buffer.Release() - hdr := p.hdr - s.logger.Debugf("Client offered version %s, sending Version Negotiation", hdr.Version) - data, err := wire.ComposeVersionNegotiation(hdr.SrcConnectionID, hdr.DestConnectionID, s.config.Versions) - if err != nil { - s.logger.Debugf("Error composing Version Negotiation: %s", err) - return - } - if _, err := s.conn.WriteTo(data, p.remoteAddr); err != nil { - s.logger.Debugf("Error sending Version Negotiation: %s", err) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/server_session.go b/external/github.com/lucas-clemente/quic-go/server_session.go deleted file mode 100644 index 2c1fd4028..000000000 --- a/external/github.com/lucas-clemente/quic-go/server_session.go +++ /dev/null @@ -1,59 +0,0 @@ -package quic - -import ( - "fmt" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" -) - -type serverSession struct { - quicSession - - config *Config - - logger utils.Logger -} - -var _ packetHandler = &serverSession{} - -func newServerSession(sess quicSession, config *Config, logger utils.Logger) packetHandler { - return &serverSession{ - quicSession: sess, - config: config, - logger: logger, - } -} - -func (s *serverSession) handlePacket(p *receivedPacket) { - if err := s.handlePacketImpl(p); err != nil { - s.logger.Debugf("error handling packet from %s: %s", p.remoteAddr, err) - } -} - -func (s *serverSession) handlePacketImpl(p *receivedPacket) error { - hdr := p.hdr - - // Probably an old packet that was sent by the client before the version was negotiated. - // It is safe to drop it. - if hdr.IsLongHeader && hdr.Version != s.quicSession.GetVersion() { - return nil - } - - if hdr.IsLongHeader { - switch hdr.Type { - case protocol.PacketTypeInitial, protocol.PacketTypeHandshake: - // nothing to do here. Packet will be passed to the session. - default: - // Note that this also drops 0-RTT packets. - return fmt.Errorf("Received unsupported packet type: %s", hdr.Type) - } - } - - s.quicSession.handlePacket(p) - return nil -} - -func (s *serverSession) GetPerspective() protocol.Perspective { - return protocol.PerspectiveServer -} diff --git a/external/github.com/lucas-clemente/quic-go/session.go b/external/github.com/lucas-clemente/quic-go/session.go deleted file mode 100644 index dc75628ef..000000000 --- a/external/github.com/lucas-clemente/quic-go/session.go +++ /dev/null @@ -1,1143 +0,0 @@ -package quic - -import ( - "bytes" - "context" - "crypto/tls" - "errors" - "fmt" - "io" - "net" - "reflect" - "sync" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/ackhandler" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/congestion" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/flowcontrol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/handshake" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type unpacker interface { - Unpack(hdr *wire.Header, data []byte) (*unpackedPacket, error) -} - -type streamGetter interface { - GetOrOpenReceiveStream(protocol.StreamID) (receiveStreamI, error) - GetOrOpenSendStream(protocol.StreamID) (sendStreamI, error) -} - -type streamManager interface { - GetOrOpenSendStream(protocol.StreamID) (sendStreamI, error) - GetOrOpenReceiveStream(protocol.StreamID) (receiveStreamI, error) - OpenStream() (Stream, error) - OpenUniStream() (SendStream, error) - OpenStreamSync() (Stream, error) - OpenUniStreamSync() (SendStream, error) - AcceptStream() (Stream, error) - AcceptUniStream() (ReceiveStream, error) - DeleteStream(protocol.StreamID) error - UpdateLimits(*handshake.TransportParameters) - HandleMaxStreamsFrame(*wire.MaxStreamsFrame) error - CloseWithError(error) -} - -type cryptoStreamHandler interface { - RunHandshake() error - io.Closer - ConnectionState() handshake.ConnectionState -} - -type receivedPacket struct { - remoteAddr net.Addr - hdr *wire.Header - rcvTime time.Time - data []byte - - buffer *packetBuffer -} - -type closeError struct { - err error - remote bool - sendClose bool -} - -var errCloseForRecreating = errors.New("closing session in order to recreate it") - -// A Session is a QUIC session -type session struct { - sessionRunner sessionRunner - - destConnID protocol.ConnectionID - srcConnID protocol.ConnectionID - - perspective protocol.Perspective - version protocol.VersionNumber - config *Config - - conn connection - - streamsMap streamManager - - rttStats *congestion.RTTStats - - cryptoStreamManager *cryptoStreamManager - sentPacketHandler ackhandler.SentPacketHandler - receivedPacketHandler ackhandler.ReceivedPacketHandler - framer framer - windowUpdateQueue *windowUpdateQueue - connFlowController flowcontrol.ConnectionFlowController - - unpacker unpacker - packer packer - - cryptoStreamHandler cryptoStreamHandler - - receivedPackets chan *receivedPacket - sendingScheduled chan struct{} - - closeOnce sync.Once - closed utils.AtomicBool - // closeChan is used to notify the run loop that it should terminate - closeChan chan closeError - connectionClosePacket *packedPacket - packetsReceivedAfterClose int - - ctx context.Context - ctxCancel context.CancelFunc - - undecryptablePackets []*receivedPacket - - clientHelloWritten <-chan struct{} - handshakeCompleteChan chan struct{} // is closed when the handshake completes - handshakeComplete bool - - receivedFirstPacket bool - receivedFirstForwardSecurePacket bool - - sessionCreationTime time.Time - lastNetworkActivityTime time.Time - // pacingDeadline is the time when the next packet should be sent - pacingDeadline time.Time - - peerParams *handshake.TransportParameters - - timer *utils.Timer - // keepAlivePingSent stores whether a Ping frame was sent to the peer or not - // it is reset as soon as we receive a packet from the peer - keepAlivePingSent bool - - logger utils.Logger -} - -var _ Session = &session{} -var _ streamSender = &session{} - -var newSession = func( - conn connection, - runner sessionRunner, - clientDestConnID protocol.ConnectionID, - destConnID protocol.ConnectionID, - srcConnID protocol.ConnectionID, - conf *Config, - tlsConf *tls.Config, - params *handshake.TransportParameters, - logger utils.Logger, - v protocol.VersionNumber, -) (quicSession, error) { - s := &session{ - conn: conn, - sessionRunner: runner, - config: conf, - srcConnID: srcConnID, - destConnID: destConnID, - perspective: protocol.PerspectiveServer, - handshakeCompleteChan: make(chan struct{}), - logger: logger, - version: v, - } - s.preSetup() - s.sentPacketHandler = ackhandler.NewSentPacketHandler(0, s.rttStats, s.logger) - initialStream := newCryptoStream() - handshakeStream := newCryptoStream() - s.streamsMap = newStreamsMap( - s, - s.newFlowController, - uint64(s.config.MaxIncomingStreams), - uint64(s.config.MaxIncomingUniStreams), - s.perspective, - s.version, - ) - s.framer = newFramer(s.streamsMap, s.version) - cs, err := handshake.NewCryptoSetupServer( - initialStream, - handshakeStream, - clientDestConnID, - params, - s.processTransportParameters, - tlsConf, - conf.Versions, - v, - logger, - protocol.PerspectiveServer, - ) - if err != nil { - return nil, err - } - s.cryptoStreamHandler = cs - s.packer = newPacketPacker( - s.destConnID, - s.srcConnID, - initialStream, - handshakeStream, - s.sentPacketHandler, - s.RemoteAddr(), - nil, // no token - cs, - s.framer, - s.receivedPacketHandler, - s.perspective, - s.version, - ) - s.cryptoStreamManager = newCryptoStreamManager(cs, initialStream, handshakeStream) - - if err := s.postSetup(); err != nil { - return nil, err - } - s.unpacker = newPacketUnpacker(cs, s.version) - return s, nil -} - -// declare this as a variable, such that we can it mock it in the tests -var newClientSession = func( - conn connection, - runner sessionRunner, - token []byte, - origDestConnID protocol.ConnectionID, - destConnID protocol.ConnectionID, - srcConnID protocol.ConnectionID, - conf *Config, - tlsConf *tls.Config, - initialPacketNumber protocol.PacketNumber, - params *handshake.TransportParameters, - initialVersion protocol.VersionNumber, - logger utils.Logger, - v protocol.VersionNumber, -) (quicSession, error) { - s := &session{ - conn: conn, - sessionRunner: runner, - config: conf, - srcConnID: srcConnID, - destConnID: destConnID, - perspective: protocol.PerspectiveClient, - handshakeCompleteChan: make(chan struct{}), - logger: logger, - version: v, - } - s.preSetup() - s.sentPacketHandler = ackhandler.NewSentPacketHandler(initialPacketNumber, s.rttStats, s.logger) - initialStream := newCryptoStream() - handshakeStream := newCryptoStream() - cs, clientHelloWritten, err := handshake.NewCryptoSetupClient( - initialStream, - handshakeStream, - origDestConnID, - s.destConnID, - params, - s.processTransportParameters, - tlsConf, - initialVersion, - conf.Versions, - v, - logger, - protocol.PerspectiveClient, - ) - if err != nil { - return nil, err - } - s.clientHelloWritten = clientHelloWritten - s.cryptoStreamHandler = cs - s.cryptoStreamManager = newCryptoStreamManager(cs, initialStream, handshakeStream) - s.unpacker = newPacketUnpacker(cs, s.version) - s.streamsMap = newStreamsMap( - s, - s.newFlowController, - uint64(s.config.MaxIncomingStreams), - uint64(s.config.MaxIncomingUniStreams), - s.perspective, - s.version, - ) - s.framer = newFramer(s.streamsMap, s.version) - s.packer = newPacketPacker( - s.destConnID, - s.srcConnID, - initialStream, - handshakeStream, - s.sentPacketHandler, - s.RemoteAddr(), - token, - cs, - s.framer, - s.receivedPacketHandler, - s.perspective, - s.version, - ) - return s, s.postSetup() -} - -func (s *session) preSetup() { - s.rttStats = &congestion.RTTStats{} - s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.rttStats, s.logger, s.version) - s.connFlowController = flowcontrol.NewConnectionFlowController( - protocol.InitialMaxData, - protocol.ByteCount(s.config.MaxReceiveConnectionFlowControlWindow), - s.onHasConnectionWindowUpdate, - s.rttStats, - s.logger, - ) -} - -func (s *session) postSetup() error { - s.receivedPackets = make(chan *receivedPacket, protocol.MaxSessionUnprocessedPackets) - s.closeChan = make(chan closeError, 1) - s.sendingScheduled = make(chan struct{}, 1) - s.undecryptablePackets = make([]*receivedPacket, 0, protocol.MaxUndecryptablePackets) - s.ctx, s.ctxCancel = context.WithCancel(context.Background()) - - s.timer = utils.NewTimer() - now := time.Now() - s.lastNetworkActivityTime = now - s.sessionCreationTime = now - - s.windowUpdateQueue = newWindowUpdateQueue(s.streamsMap, s.connFlowController, s.framer.QueueControlFrame) - return nil -} - -// run the session main loop -func (s *session) run() error { - defer s.ctxCancel() - - go func() { - if err := s.cryptoStreamHandler.RunHandshake(); err != nil { - s.closeLocal(err) - return - } - close(s.handshakeCompleteChan) - }() - if s.perspective == protocol.PerspectiveClient { - select { - case <-s.clientHelloWritten: - s.scheduleSending() - case closeErr := <-s.closeChan: - // put the close error back into the channel, so that the run loop can receive it - s.closeChan <- closeErr - } - } - - var closeErr closeError - -runLoop: - for { - // Close immediately if requested - select { - case closeErr = <-s.closeChan: - break runLoop - case <-s.handshakeCompleteChan: - s.handleHandshakeComplete() - default: - } - - s.maybeResetTimer() - - select { - case closeErr = <-s.closeChan: - break runLoop - case <-s.timer.Chan(): - s.timer.SetRead() - // We do all the interesting stuff after the switch statement, so - // nothing to see here. - case <-s.sendingScheduled: - // We do all the interesting stuff after the switch statement, so - // nothing to see here. - case p := <-s.receivedPackets: - // Only reset the timers if this packet was actually processed. - // This avoids modifying any state when handling undecryptable packets, - // which could be injected by an attacker. - if wasProcessed := s.handlePacketImpl(p); !wasProcessed { - continue - } - case <-s.handshakeCompleteChan: - s.handleHandshakeComplete() - } - - now := time.Now() - if timeout := s.sentPacketHandler.GetAlarmTimeout(); !timeout.IsZero() && timeout.Before(now) { - // This could cause packets to be retransmitted. - // Check it before trying to send packets. - if err := s.sentPacketHandler.OnAlarm(); err != nil { - s.closeLocal(err) - } - } - - var pacingDeadline time.Time - if s.pacingDeadline.IsZero() { // the timer didn't have a pacing deadline set - pacingDeadline = s.sentPacketHandler.TimeUntilSend() - } - if s.config.KeepAlive && !s.keepAlivePingSent && s.handshakeComplete && time.Since(s.lastNetworkActivityTime) >= s.peerParams.IdleTimeout/2 { - // send a PING frame since there is no activity in the session - s.logger.Debugf("Sending a keep-alive ping to keep the connection alive.") - s.framer.QueueControlFrame(&wire.PingFrame{}) - s.keepAlivePingSent = true - } else if !pacingDeadline.IsZero() && now.Before(pacingDeadline) { - // If we get to this point before the pacing deadline, we should wait until that deadline. - // This can happen when scheduleSending is called, or a packet is received. - // Set the timer and restart the run loop. - s.pacingDeadline = pacingDeadline - continue - } - - if !s.handshakeComplete && now.Sub(s.sessionCreationTime) >= s.config.HandshakeTimeout { - s.closeLocal(qerr.Error(qerr.HandshakeTimeout, "Crypto handshake did not complete in time.")) - continue - } - if s.handshakeComplete && now.Sub(s.lastNetworkActivityTime) >= s.config.IdleTimeout { - s.closeLocal(qerr.Error(qerr.NetworkIdleTimeout, "No recent network activity.")) - continue - } - - if err := s.sendPackets(); err != nil { - s.closeLocal(err) - } - } - - if err := s.handleCloseError(closeErr); err != nil { - s.logger.Infof("Handling close error failed: %s", err) - } - s.closed.Set(true) - s.logger.Infof("Connection %s closed.", s.srcConnID) - s.cryptoStreamHandler.Close() - return closeErr.err -} - -func (s *session) Context() context.Context { - return s.ctx -} - -func (s *session) ConnectionState() ConnectionState { - return s.cryptoStreamHandler.ConnectionState() -} - -func (s *session) maybeResetTimer() { - var deadline time.Time - if s.config.KeepAlive && s.handshakeComplete && !s.keepAlivePingSent { - deadline = s.lastNetworkActivityTime.Add(s.peerParams.IdleTimeout / 2) - } else { - deadline = s.lastNetworkActivityTime.Add(s.config.IdleTimeout) - } - - if ackAlarm := s.receivedPacketHandler.GetAlarmTimeout(); !ackAlarm.IsZero() { - deadline = utils.MinTime(deadline, ackAlarm) - } - if lossTime := s.sentPacketHandler.GetAlarmTimeout(); !lossTime.IsZero() { - deadline = utils.MinTime(deadline, lossTime) - } - if !s.handshakeComplete { - handshakeDeadline := s.sessionCreationTime.Add(s.config.HandshakeTimeout) - deadline = utils.MinTime(deadline, handshakeDeadline) - } - if !s.pacingDeadline.IsZero() { - deadline = utils.MinTime(deadline, s.pacingDeadline) - } - - s.timer.Reset(deadline) -} - -func (s *session) handleHandshakeComplete() { - s.handshakeComplete = true - s.handshakeCompleteChan = nil // prevent this case from ever being selected again - s.sessionRunner.onHandshakeComplete(s) - - // The client completes the handshake first (after sending the CFIN). - // We need to make sure they learn about the peer completing the handshake, - // in order to stop retransmitting handshake packets. - // They will stop retransmitting handshake packets when receiving the first forward-secure packet. - // We need to make sure that a retransmittable forward-secure packet is sent, - // independent from the application protocol. - if s.perspective == protocol.PerspectiveServer { - s.queueControlFrame(&wire.PingFrame{}) - s.sentPacketHandler.SetHandshakeComplete() - } -} - -func (s *session) handlePacketImpl(p *receivedPacket) bool /* was the packet successfully processed */ { - var wasQueued bool - - defer func() { - // Put back the packet buffer if the packet wasn't queued for later decryption. - if !wasQueued { - p.buffer.Release() - } - }() - - // The server can change the source connection ID with the first Handshake packet. - // After this, all packets with a different source connection have to be ignored. - if s.receivedFirstPacket && p.hdr.IsLongHeader && !p.hdr.SrcConnectionID.Equal(s.destConnID) { - s.logger.Debugf("Dropping packet with unexpected source connection ID: %s (expected %s)", p.hdr.SrcConnectionID, s.destConnID) - return false - } - // drop 0-RTT packets - if p.hdr.Type == protocol.PacketType0RTT { - return false - } - - packet, err := s.unpacker.Unpack(p.hdr, p.data) - if err != nil { - if err == handshake.ErrOpenerNotYetAvailable { - // Sealer for this encryption level not yet available. - // Try again later. - wasQueued = true - s.tryQueueingUndecryptablePacket(p) - return false - } - // This might be a packet injected by an attacker. - // Drop it. - s.logger.Debugf("Dropping packet that could not be unpacked. Unpack error: %s", err) - return false - } - - if s.logger.Debug() { - s.logger.Debugf("<- Reading packet %#x (%d bytes) for connection %s, %s", packet.packetNumber, len(p.data), p.hdr.DestConnectionID, packet.encryptionLevel) - packet.hdr.Log(s.logger) - } - - if err := s.handleUnpackedPacket(packet, p.rcvTime); err != nil { - s.closeLocal(err) - return false - } - return true -} - -func (s *session) handleUnpackedPacket(packet *unpackedPacket, rcvTime time.Time) error { - if len(packet.data) == 0 { - return qerr.MissingPayload - } - - // The server can change the source connection ID with the first Handshake packet. - if s.perspective == protocol.PerspectiveClient && !s.receivedFirstPacket && packet.hdr.IsLongHeader && !packet.hdr.SrcConnectionID.Equal(s.destConnID) { - s.logger.Debugf("Received first packet. Switching destination connection ID to: %s", packet.hdr.SrcConnectionID) - s.destConnID = packet.hdr.SrcConnectionID - s.packer.ChangeDestConnectionID(s.destConnID) - } - - s.receivedFirstPacket = true - s.lastNetworkActivityTime = rcvTime - s.keepAlivePingSent = false - - // The client completes the handshake first (after sending the CFIN). - // We know that the server completed the handshake as soon as we receive a forward-secure packet. - if s.perspective == protocol.PerspectiveClient { - if !s.receivedFirstForwardSecurePacket && packet.encryptionLevel == protocol.Encryption1RTT { - s.receivedFirstForwardSecurePacket = true - s.sentPacketHandler.SetHandshakeComplete() - } - } - - r := bytes.NewReader(packet.data) - var isRetransmittable bool - for { - frame, err := wire.ParseNextFrame(r, s.version) - if err != nil { - return err - } - if frame == nil { - break - } - if ackhandler.IsFrameRetransmittable(frame) { - isRetransmittable = true - } - if err := s.handleFrame(frame, packet.packetNumber, packet.encryptionLevel); err != nil { - return err - } - } - - if err := s.receivedPacketHandler.ReceivedPacket(packet.packetNumber, packet.encryptionLevel, rcvTime, isRetransmittable); err != nil { - return err - } - return nil -} - -func (s *session) handleFrame(f wire.Frame, pn protocol.PacketNumber, encLevel protocol.EncryptionLevel) error { - var err error - wire.LogFrame(s.logger, f, false) - switch frame := f.(type) { - case *wire.CryptoFrame: - err = s.handleCryptoFrame(frame, encLevel) - case *wire.StreamFrame: - err = s.handleStreamFrame(frame, encLevel) - case *wire.AckFrame: - err = s.handleAckFrame(frame, pn, encLevel) - case *wire.ConnectionCloseFrame: - s.closeRemote(qerr.Error(frame.ErrorCode, frame.ReasonPhrase)) - case *wire.ResetStreamFrame: - err = s.handleResetStreamFrame(frame) - case *wire.MaxDataFrame: - s.handleMaxDataFrame(frame) - case *wire.MaxStreamDataFrame: - err = s.handleMaxStreamDataFrame(frame) - case *wire.MaxStreamsFrame: - err = s.handleMaxStreamsFrame(frame) - case *wire.DataBlockedFrame: - case *wire.StreamDataBlockedFrame: - case *wire.StreamsBlockedFrame: - case *wire.StopSendingFrame: - err = s.handleStopSendingFrame(frame) - case *wire.PingFrame: - case *wire.PathChallengeFrame: - s.handlePathChallengeFrame(frame) - case *wire.PathResponseFrame: - // since we don't send PATH_CHALLENGEs, we don't expect PATH_RESPONSEs - err = errors.New("unexpected PATH_RESPONSE frame") - case *wire.NewTokenFrame: - case *wire.NewConnectionIDFrame: - case *wire.RetireConnectionIDFrame: - // since we don't send new connection IDs, we don't expect retirements - err = errors.New("unexpected RETIRE_CONNECTION_ID frame") - default: - err = fmt.Errorf("unexpected frame type: %s", reflect.ValueOf(&frame).Elem().Type().Name()) - } - return err -} - -// handlePacket is called by the server with a new packet -func (s *session) handlePacket(p *receivedPacket) { - if s.closed.Get() { - s.handlePacketAfterClosed(p) - } - // Discard packets once the amount of queued packets is larger than - // the channel size, protocol.MaxSessionUnprocessedPackets - select { - case s.receivedPackets <- p: - default: - } -} - -func (s *session) handlePacketAfterClosed(p *receivedPacket) { - s.packetsReceivedAfterClose++ - if s.connectionClosePacket == nil { - return - } - // exponential backoff - // only send a CONNECTION_CLOSE for the 1st, 2nd, 4th, 8th, 16th, ... packet arriving - for n := s.packetsReceivedAfterClose; n > 1; n = n / 2 { - if n%2 != 0 { - return - } - } - s.logger.Debugf("Received %d packets after sending CONNECTION_CLOSE. Retransmitting.", s.packetsReceivedAfterClose) - if err := s.conn.Write(s.connectionClosePacket.raw); err != nil { - s.logger.Debugf("Error retransmitting CONNECTION_CLOSE: %s", err) - } -} - -func (s *session) handleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) error { - encLevelChanged, err := s.cryptoStreamManager.HandleCryptoFrame(frame, encLevel) - if err != nil { - return err - } - if encLevelChanged { - s.tryDecryptingQueuedPackets() - } - return nil -} - -func (s *session) handleStreamFrame(frame *wire.StreamFrame, encLevel protocol.EncryptionLevel) error { - if encLevel < protocol.Encryption1RTT { - return qerr.Error(qerr.UnencryptedStreamData, fmt.Sprintf("received unencrypted stream data on stream %d", frame.StreamID)) - } - str, err := s.streamsMap.GetOrOpenReceiveStream(frame.StreamID) - if err != nil { - return err - } - if str == nil { - // Stream is closed and already garbage collected - // ignore this StreamFrame - return nil - } - return str.handleStreamFrame(frame) -} - -func (s *session) handleMaxDataFrame(frame *wire.MaxDataFrame) { - s.connFlowController.UpdateSendWindow(frame.ByteOffset) -} - -func (s *session) handleMaxStreamDataFrame(frame *wire.MaxStreamDataFrame) error { - str, err := s.streamsMap.GetOrOpenSendStream(frame.StreamID) - if err != nil { - return err - } - if str == nil { - // stream is closed and already garbage collected - return nil - } - str.handleMaxStreamDataFrame(frame) - return nil -} - -func (s *session) handleMaxStreamsFrame(frame *wire.MaxStreamsFrame) error { - return s.streamsMap.HandleMaxStreamsFrame(frame) -} - -func (s *session) handleResetStreamFrame(frame *wire.ResetStreamFrame) error { - str, err := s.streamsMap.GetOrOpenReceiveStream(frame.StreamID) - if err != nil { - return err - } - if str == nil { - // stream is closed and already garbage collected - return nil - } - return str.handleResetStreamFrame(frame) -} - -func (s *session) handleStopSendingFrame(frame *wire.StopSendingFrame) error { - str, err := s.streamsMap.GetOrOpenSendStream(frame.StreamID) - if err != nil { - return err - } - if str == nil { - // stream is closed and already garbage collected - return nil - } - str.handleStopSendingFrame(frame) - return nil -} - -func (s *session) handlePathChallengeFrame(frame *wire.PathChallengeFrame) { - s.queueControlFrame(&wire.PathResponseFrame{Data: frame.Data}) -} - -func (s *session) handleAckFrame(frame *wire.AckFrame, pn protocol.PacketNumber, encLevel protocol.EncryptionLevel) error { - if err := s.sentPacketHandler.ReceivedAck(frame, pn, encLevel, s.lastNetworkActivityTime); err != nil { - return err - } - if encLevel == protocol.Encryption1RTT { - s.receivedPacketHandler.IgnoreBelow(s.sentPacketHandler.GetLowestPacketNotConfirmedAcked()) - } - return nil -} - -// closeLocal closes the session and send a CONNECTION_CLOSE containing the error -func (s *session) closeLocal(e error) { - s.closeOnce.Do(func() { - s.sessionRunner.retireConnectionID(s.srcConnID) - s.closeChan <- closeError{err: e, sendClose: true, remote: false} - }) -} - -// destroy closes the session without sending the error on the wire -func (s *session) destroy(e error) { - s.closeOnce.Do(func() { - s.sessionRunner.removeConnectionID(s.srcConnID) - s.closeChan <- closeError{err: e, sendClose: false, remote: false} - }) -} - -// closeForRecreating closes the session in order to recreate it immediately afterwards -// It returns the first packet number that should be used in the new session. -func (s *session) closeForRecreating() protocol.PacketNumber { - s.destroy(errCloseForRecreating) - nextPN, _ := s.sentPacketHandler.PeekPacketNumber() - return nextPN -} - -func (s *session) closeRemote(e error) { - s.closeOnce.Do(func() { - s.sessionRunner.removeConnectionID(s.srcConnID) - s.closeChan <- closeError{err: e, remote: true} - }) -} - -// Close the connection. It sends a qerr.PeerGoingAway. -// It waits until the run loop has stopped before returning -func (s *session) Close() error { - s.closeLocal(nil) - <-s.ctx.Done() - return nil -} - -func (s *session) CloseWithError(code protocol.ApplicationErrorCode, e error) error { - s.closeLocal(qerr.Error(qerr.ErrorCode(code), e.Error())) - <-s.ctx.Done() - return nil -} - -func (s *session) handleCloseError(closeErr closeError) error { - if closeErr.err == nil { - closeErr.err = qerr.PeerGoingAway - } - - var quicErr *qerr.QuicError - var ok bool - if quicErr, ok = closeErr.err.(*qerr.QuicError); !ok { - quicErr = qerr.ToQuicError(closeErr.err) - } - // Don't log 'normal' reasons - if quicErr.ErrorCode == qerr.PeerGoingAway || quicErr.ErrorCode == qerr.NetworkIdleTimeout { - s.logger.Infof("Closing connection %s.", s.srcConnID) - } else { - s.logger.Errorf("Closing session with error: %s", closeErr.err.Error()) - } - - s.streamsMap.CloseWithError(quicErr) - - if !closeErr.sendClose { - return nil - } - - // If this is a remote close we're done here - if closeErr.remote { - return nil - } - // otherwise send a CONNECTION_CLOSE - return s.sendConnectionClose(quicErr) -} - -func (s *session) processTransportParameters(params *handshake.TransportParameters) { - s.peerParams = params - s.streamsMap.UpdateLimits(params) - s.packer.HandleTransportParameters(params) - s.connFlowController.UpdateSendWindow(params.InitialMaxData) - // the crypto stream is the only open stream at this moment - // so we don't need to update stream flow control windows -} - -func (s *session) sendPackets() error { - s.pacingDeadline = time.Time{} - - sendMode := s.sentPacketHandler.SendMode() - if sendMode == ackhandler.SendNone { // shortcut: return immediately if there's nothing to send - return nil - } - - numPackets := s.sentPacketHandler.ShouldSendNumPackets() - var numPacketsSent int -sendLoop: - for { - switch sendMode { - case ackhandler.SendNone: - break sendLoop - case ackhandler.SendAck: - // If we already sent packets, and the send mode switches to SendAck, - // we've just become congestion limited. - // There's no need to try to send an ACK at this moment. - if numPacketsSent > 0 { - return nil - } - // We can at most send a single ACK only packet. - // There will only be a new ACK after receiving new packets. - // SendAck is only returned when we're congestion limited, so we don't need to set the pacingt timer. - return s.maybeSendAckOnlyPacket() - case ackhandler.SendPTO: - if err := s.sendProbePacket(); err != nil { - return err - } - numPacketsSent++ - case ackhandler.SendRetransmission: - sentPacket, err := s.maybeSendRetransmission() - if err != nil { - return err - } - if sentPacket { - numPacketsSent++ - // This can happen if a retransmission queued, but it wasn't necessary to send it. - // e.g. when an Initial is queued, but we already received a packet from the server. - } - case ackhandler.SendAny: - sentPacket, err := s.sendPacket() - if err != nil { - return err - } - if !sentPacket { - break sendLoop - } - numPacketsSent++ - default: - return fmt.Errorf("BUG: invalid send mode %d", sendMode) - } - if numPacketsSent >= numPackets { - break - } - sendMode = s.sentPacketHandler.SendMode() - } - // Only start the pacing timer if we sent as many packets as we were allowed. - // There will probably be more to send when calling sendPacket again. - if numPacketsSent == numPackets { - s.pacingDeadline = s.sentPacketHandler.TimeUntilSend() - } - return nil -} - -func (s *session) maybeSendAckOnlyPacket() error { - packet, err := s.packer.MaybePackAckPacket() - if err != nil { - return err - } - if packet == nil { - return nil - } - s.sentPacketHandler.SentPacket(packet.ToAckHandlerPacket()) - return s.sendPackedPacket(packet) -} - -// maybeSendRetransmission sends retransmissions for at most one packet. -// It takes care that Initials aren't retransmitted, if a packet from the server was already received. -func (s *session) maybeSendRetransmission() (bool, error) { - var retransmitPacket *ackhandler.Packet - for { - retransmitPacket = s.sentPacketHandler.DequeuePacketForRetransmission() - if retransmitPacket == nil { - return false, nil - } - - // Don't retransmit Initial packets if we already received a response. - // An Initial might have been retransmitted multiple times before we receive a response. - // As soon as we receive one response, we don't need to send any more Initials. - if s.perspective == protocol.PerspectiveClient && s.receivedFirstPacket && retransmitPacket.PacketType == protocol.PacketTypeInitial { - s.logger.Debugf("Skipping retransmission of packet %d. Already received a response to an Initial.", retransmitPacket.PacketNumber) - continue - } - break - } - - s.logger.Debugf("Dequeueing retransmission for packet 0x%x", retransmitPacket.PacketNumber) - packets, err := s.packer.PackRetransmission(retransmitPacket) - if err != nil { - return false, err - } - ackhandlerPackets := make([]*ackhandler.Packet, len(packets)) - for i, packet := range packets { - ackhandlerPackets[i] = packet.ToAckHandlerPacket() - } - s.sentPacketHandler.SentPacketsAsRetransmission(ackhandlerPackets, retransmitPacket.PacketNumber) - for _, packet := range packets { - if err := s.sendPackedPacket(packet); err != nil { - return false, err - } - } - return true, nil -} - -func (s *session) sendProbePacket() error { - p, err := s.sentPacketHandler.DequeueProbePacket() - if err != nil { - return err - } - s.logger.Debugf("Sending a retransmission for %#x as a probe packet.", p.PacketNumber) - - packets, err := s.packer.PackRetransmission(p) - if err != nil { - return err - } - ackhandlerPackets := make([]*ackhandler.Packet, len(packets)) - for i, packet := range packets { - ackhandlerPackets[i] = packet.ToAckHandlerPacket() - } - s.sentPacketHandler.SentPacketsAsRetransmission(ackhandlerPackets, p.PacketNumber) - for _, packet := range packets { - if err := s.sendPackedPacket(packet); err != nil { - return err - } - } - return nil -} - -func (s *session) sendPacket() (bool, error) { - if isBlocked, offset := s.connFlowController.IsNewlyBlocked(); isBlocked { - s.framer.QueueControlFrame(&wire.DataBlockedFrame{DataLimit: offset}) - } - s.windowUpdateQueue.QueueAll() - - packet, err := s.packer.PackPacket() - if err != nil || packet == nil { - return false, err - } - s.sentPacketHandler.SentPacket(packet.ToAckHandlerPacket()) - if err := s.sendPackedPacket(packet); err != nil { - return false, err - } - return true, nil -} - -func (s *session) sendPackedPacket(packet *packedPacket) error { - defer packet.buffer.Release() - s.logPacket(packet) - return s.conn.Write(packet.raw) -} - -func (s *session) sendConnectionClose(quicErr *qerr.QuicError) error { - packet, err := s.packer.PackConnectionClose(&wire.ConnectionCloseFrame{ - ErrorCode: quicErr.ErrorCode, - ReasonPhrase: quicErr.ErrorMessage, - }) - if err != nil { - return err - } - s.connectionClosePacket = packet - s.logPacket(packet) - return s.conn.Write(packet.raw) -} - -func (s *session) logPacket(packet *packedPacket) { - if !s.logger.Debug() { - // We don't need to allocate the slices for calling the format functions - return - } - s.logger.Debugf("-> Sending packet 0x%x (%d bytes) for connection %s, %s", packet.header.PacketNumber, len(packet.raw), s.srcConnID, packet.EncryptionLevel()) - packet.header.Log(s.logger) - for _, frame := range packet.frames { - wire.LogFrame(s.logger, frame, true) - } -} - -// GetOrOpenStream either returns an existing stream, a newly opened stream, or nil if a stream with the provided ID is already closed. -// It is *only* needed for gQUIC's H2. -// It will be removed as soon as gQUIC moves towards the IETF H2/QUIC stream mapping. -func (s *session) GetOrOpenStream(id protocol.StreamID) (Stream, error) { - str, err := s.streamsMap.GetOrOpenSendStream(id) - if str != nil { - if bstr, ok := str.(Stream); ok { - return bstr, err - } - return nil, fmt.Errorf("Stream %d is not a bidirectional stream", id) - } - // make sure to return an actual nil value here, not an Stream with value nil - return nil, err -} - -// AcceptStream returns the next stream openend by the peer -func (s *session) AcceptStream() (Stream, error) { - return s.streamsMap.AcceptStream() -} - -func (s *session) AcceptUniStream() (ReceiveStream, error) { - return s.streamsMap.AcceptUniStream() -} - -// OpenStream opens a stream -func (s *session) OpenStream() (Stream, error) { - return s.streamsMap.OpenStream() -} - -func (s *session) OpenStreamSync() (Stream, error) { - return s.streamsMap.OpenStreamSync() -} - -func (s *session) OpenUniStream() (SendStream, error) { - return s.streamsMap.OpenUniStream() -} - -func (s *session) OpenUniStreamSync() (SendStream, error) { - return s.streamsMap.OpenUniStreamSync() -} - -func (s *session) newStream(id protocol.StreamID) streamI { - flowController := s.newFlowController(id) - return newStream(id, s, flowController, s.version) -} - -func (s *session) newFlowController(id protocol.StreamID) flowcontrol.StreamFlowController { - var initialSendWindow protocol.ByteCount - if s.peerParams != nil { - if id.Type() == protocol.StreamTypeUni { - initialSendWindow = s.peerParams.InitialMaxStreamDataUni - } else { - if id.InitiatedBy() == s.perspective { - initialSendWindow = s.peerParams.InitialMaxStreamDataBidiLocal - } else { - initialSendWindow = s.peerParams.InitialMaxStreamDataBidiRemote - } - } - } - return flowcontrol.NewStreamFlowController( - id, - s.connFlowController, - protocol.InitialMaxStreamData, - protocol.ByteCount(s.config.MaxReceiveStreamFlowControlWindow), - initialSendWindow, - s.onHasStreamWindowUpdate, - s.rttStats, - s.logger, - ) -} - -// scheduleSending signals that we have data for sending -func (s *session) scheduleSending() { - select { - case s.sendingScheduled <- struct{}{}: - default: - } -} - -func (s *session) tryQueueingUndecryptablePacket(p *receivedPacket) { - if s.handshakeComplete { - s.logger.Debugf("Received undecryptable packet from %s after the handshake (%d bytes)", p.remoteAddr.String(), len(p.data)) - return - } - if len(s.undecryptablePackets)+1 > protocol.MaxUndecryptablePackets { - s.logger.Infof("Dropping undecrytable packet (%d bytes). Undecryptable packet queue full.", len(p.data)) - return - } - s.logger.Infof("Queueing packet (%d bytes) for later decryption", len(p.data)) - s.undecryptablePackets = append(s.undecryptablePackets, p) -} - -func (s *session) tryDecryptingQueuedPackets() { - for _, p := range s.undecryptablePackets { - s.handlePacket(p) - } - s.undecryptablePackets = s.undecryptablePackets[:0] -} - -func (s *session) queueControlFrame(f wire.Frame) { - s.framer.QueueControlFrame(f) - s.scheduleSending() -} - -func (s *session) onHasStreamWindowUpdate(id protocol.StreamID) { - s.windowUpdateQueue.AddStream(id) - s.scheduleSending() -} - -func (s *session) onHasConnectionWindowUpdate() { - s.windowUpdateQueue.AddConnection() - s.scheduleSending() -} - -func (s *session) onHasStreamData(id protocol.StreamID) { - s.framer.AddActiveStream(id) - s.scheduleSending() -} - -func (s *session) onStreamCompleted(id protocol.StreamID) { - if err := s.streamsMap.DeleteStream(id); err != nil { - s.closeLocal(err) - } -} - -func (s *session) LocalAddr() net.Addr { - return s.conn.LocalAddr() -} - -func (s *session) RemoteAddr() net.Addr { - return s.conn.RemoteAddr() -} - -func (s *session) GetVersion() protocol.VersionNumber { - return s.version -} diff --git a/external/github.com/lucas-clemente/quic-go/stream.go b/external/github.com/lucas-clemente/quic-go/stream.go deleted file mode 100644 index 80d2d9b39..000000000 --- a/external/github.com/lucas-clemente/quic-go/stream.go +++ /dev/null @@ -1,163 +0,0 @@ -package quic - -import ( - "net" - "sync" - "time" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/flowcontrol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -const errorCodeStopping protocol.ApplicationErrorCode = 0 - -// The streamSender is notified by the stream about various events. -type streamSender interface { - queueControlFrame(wire.Frame) - onHasStreamData(protocol.StreamID) - // must be called without holding the mutex that is acquired by closeForShutdown - onStreamCompleted(protocol.StreamID) -} - -// Each of the both stream halves gets its own uniStreamSender. -// This is necessary in order to keep track when both halves have been completed. -type uniStreamSender struct { - streamSender - onStreamCompletedImpl func() -} - -func (s *uniStreamSender) queueControlFrame(f wire.Frame) { - s.streamSender.queueControlFrame(f) -} - -func (s *uniStreamSender) onHasStreamData(id protocol.StreamID) { - s.streamSender.onHasStreamData(id) -} - -func (s *uniStreamSender) onStreamCompleted(protocol.StreamID) { - s.onStreamCompletedImpl() -} - -var _ streamSender = &uniStreamSender{} - -type streamI interface { - Stream - closeForShutdown(error) - // for receiving - handleStreamFrame(*wire.StreamFrame) error - handleResetStreamFrame(*wire.ResetStreamFrame) error - getWindowUpdate() protocol.ByteCount - // for sending - hasData() bool - handleStopSendingFrame(*wire.StopSendingFrame) - popStreamFrame(maxBytes protocol.ByteCount) (*wire.StreamFrame, bool) - handleMaxStreamDataFrame(*wire.MaxStreamDataFrame) -} - -var _ receiveStreamI = (streamI)(nil) -var _ sendStreamI = (streamI)(nil) - -// A Stream assembles the data from StreamFrames and provides a super-convenient Read-Interface -// -// Read() and Write() may be called concurrently, but multiple calls to Read() or Write() individually must be synchronized manually. -type stream struct { - receiveStream - sendStream - - completedMutex sync.Mutex - sender streamSender - receiveStreamCompleted bool - sendStreamCompleted bool - - version protocol.VersionNumber -} - -var _ Stream = &stream{} - -type deadlineError struct{} - -func (deadlineError) Error() string { return "deadline exceeded" } -func (deadlineError) Temporary() bool { return true } -func (deadlineError) Timeout() bool { return true } - -var errDeadline net.Error = &deadlineError{} - -type streamCanceledError struct { - error - errorCode protocol.ApplicationErrorCode -} - -func (streamCanceledError) Canceled() bool { return true } -func (e streamCanceledError) ErrorCode() protocol.ApplicationErrorCode { return e.errorCode } - -var _ StreamError = &streamCanceledError{} - -// newStream creates a new Stream -func newStream(streamID protocol.StreamID, - sender streamSender, - flowController flowcontrol.StreamFlowController, - version protocol.VersionNumber, -) *stream { - s := &stream{sender: sender, version: version} - senderForSendStream := &uniStreamSender{ - streamSender: sender, - onStreamCompletedImpl: func() { - s.completedMutex.Lock() - s.sendStreamCompleted = true - s.checkIfCompleted() - s.completedMutex.Unlock() - }, - } - s.sendStream = *newSendStream(streamID, senderForSendStream, flowController, version) - senderForReceiveStream := &uniStreamSender{ - streamSender: sender, - onStreamCompletedImpl: func() { - s.completedMutex.Lock() - s.receiveStreamCompleted = true - s.checkIfCompleted() - s.completedMutex.Unlock() - }, - } - s.receiveStream = *newReceiveStream(streamID, senderForReceiveStream, flowController, version) - return s -} - -// need to define StreamID() here, since both receiveStream and readStream have a StreamID() -func (s *stream) StreamID() protocol.StreamID { - // the result is same for receiveStream and sendStream - return s.sendStream.StreamID() -} - -func (s *stream) Close() error { - if err := s.sendStream.Close(); err != nil { - return err - } - return nil -} - -func (s *stream) SetDeadline(t time.Time) error { - _ = s.SetReadDeadline(t) // SetReadDeadline never errors - _ = s.SetWriteDeadline(t) // SetWriteDeadline never errors - return nil -} - -// CloseForShutdown closes a stream abruptly. -// It makes Read and Write unblock (and return the error) immediately. -// The peer will NOT be informed about this: the stream is closed without sending a FIN or RST. -func (s *stream) closeForShutdown(err error) { - s.sendStream.closeForShutdown(err) - s.receiveStream.closeForShutdown(err) -} - -func (s *stream) handleResetStreamFrame(frame *wire.ResetStreamFrame) error { - return s.receiveStream.handleResetStreamFrame(frame) -} - -// checkIfCompleted is called from the uniStreamSender, when one of the stream halves is completed. -// It makes sure that the onStreamCompleted callback is only called if both receive and send side have completed. -func (s *stream) checkIfCompleted() { - if s.sendStreamCompleted && s.receiveStreamCompleted { - s.sender.onStreamCompleted(s.StreamID()) - } -} diff --git a/external/github.com/lucas-clemente/quic-go/streams_map.go b/external/github.com/lucas-clemente/quic-go/streams_map.go deleted file mode 100644 index ceffbd17b..000000000 --- a/external/github.com/lucas-clemente/quic-go/streams_map.go +++ /dev/null @@ -1,184 +0,0 @@ -package quic - -import ( - "errors" - "fmt" - "net" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/flowcontrol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/handshake" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type streamOpenErr struct{ error } - -var _ net.Error = &streamOpenErr{} - -func (e streamOpenErr) Temporary() bool { return e.error == errTooManyOpenStreams } -func (streamOpenErr) Timeout() bool { return false } - -// errTooManyOpenStreams is used internally by the outgoing streams maps. -var errTooManyOpenStreams = errors.New("too many open streams") - -type streamsMap struct { - perspective protocol.Perspective - - sender streamSender - newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController - - outgoingBidiStreams *outgoingBidiStreamsMap - outgoingUniStreams *outgoingUniStreamsMap - incomingBidiStreams *incomingBidiStreamsMap - incomingUniStreams *incomingUniStreamsMap -} - -var _ streamManager = &streamsMap{} - -func newStreamsMap( - sender streamSender, - newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController, - maxIncomingStreams uint64, - maxIncomingUniStreams uint64, - perspective protocol.Perspective, - version protocol.VersionNumber, -) streamManager { - m := &streamsMap{ - perspective: perspective, - newFlowController: newFlowController, - sender: sender, - } - newBidiStream := func(id protocol.StreamID) streamI { - return newStream(id, m.sender, m.newFlowController(id), version) - } - newUniSendStream := func(id protocol.StreamID) sendStreamI { - return newSendStream(id, m.sender, m.newFlowController(id), version) - } - newUniReceiveStream := func(id protocol.StreamID) receiveStreamI { - return newReceiveStream(id, m.sender, m.newFlowController(id), version) - } - m.outgoingBidiStreams = newOutgoingBidiStreamsMap( - protocol.FirstStream(protocol.StreamTypeBidi, perspective), - newBidiStream, - sender.queueControlFrame, - ) - m.incomingBidiStreams = newIncomingBidiStreamsMap( - protocol.FirstStream(protocol.StreamTypeBidi, perspective.Opposite()), - protocol.MaxStreamID(protocol.StreamTypeBidi, maxIncomingStreams, perspective.Opposite()), - maxIncomingStreams, - sender.queueControlFrame, - newBidiStream, - ) - m.outgoingUniStreams = newOutgoingUniStreamsMap( - protocol.FirstStream(protocol.StreamTypeUni, perspective), - newUniSendStream, - sender.queueControlFrame, - ) - m.incomingUniStreams = newIncomingUniStreamsMap( - protocol.FirstStream(protocol.StreamTypeUni, perspective.Opposite()), - protocol.MaxStreamID(protocol.StreamTypeUni, maxIncomingUniStreams, perspective.Opposite()), - maxIncomingUniStreams, - sender.queueControlFrame, - newUniReceiveStream, - ) - return m -} - -func (m *streamsMap) OpenStream() (Stream, error) { - return m.outgoingBidiStreams.OpenStream() -} - -func (m *streamsMap) OpenStreamSync() (Stream, error) { - return m.outgoingBidiStreams.OpenStreamSync() -} - -func (m *streamsMap) OpenUniStream() (SendStream, error) { - return m.outgoingUniStreams.OpenStream() -} - -func (m *streamsMap) OpenUniStreamSync() (SendStream, error) { - return m.outgoingUniStreams.OpenStreamSync() -} - -func (m *streamsMap) AcceptStream() (Stream, error) { - return m.incomingBidiStreams.AcceptStream() -} - -func (m *streamsMap) AcceptUniStream() (ReceiveStream, error) { - return m.incomingUniStreams.AcceptStream() -} - -func (m *streamsMap) DeleteStream(id protocol.StreamID) error { - switch id.Type() { - case protocol.StreamTypeUni: - if id.InitiatedBy() == m.perspective { - return m.outgoingUniStreams.DeleteStream(id) - } - return m.incomingUniStreams.DeleteStream(id) - case protocol.StreamTypeBidi: - if id.InitiatedBy() == m.perspective { - return m.outgoingBidiStreams.DeleteStream(id) - } - return m.incomingBidiStreams.DeleteStream(id) - } - panic("") -} - -func (m *streamsMap) GetOrOpenReceiveStream(id protocol.StreamID) (receiveStreamI, error) { - switch id.Type() { - case protocol.StreamTypeUni: - if id.InitiatedBy() == m.perspective { - // an outgoing unidirectional stream is a send stream, not a receive stream - return nil, fmt.Errorf("peer attempted to open receive stream %d", id) - } - return m.incomingUniStreams.GetOrOpenStream(id) - case protocol.StreamTypeBidi: - if id.InitiatedBy() == m.perspective { - return m.outgoingBidiStreams.GetStream(id) - } - return m.incomingBidiStreams.GetOrOpenStream(id) - } - panic("") -} - -func (m *streamsMap) GetOrOpenSendStream(id protocol.StreamID) (sendStreamI, error) { - switch id.Type() { - case protocol.StreamTypeUni: - if id.InitiatedBy() == m.perspective { - return m.outgoingUniStreams.GetStream(id) - } - // an incoming unidirectional stream is a receive stream, not a send stream - return nil, fmt.Errorf("peer attempted to open send stream %d", id) - case protocol.StreamTypeBidi: - if id.InitiatedBy() == m.perspective { - return m.outgoingBidiStreams.GetStream(id) - } - return m.incomingBidiStreams.GetOrOpenStream(id) - } - panic("") -} - -func (m *streamsMap) HandleMaxStreamsFrame(f *wire.MaxStreamsFrame) error { - id := protocol.MaxStreamID(f.Type, f.MaxStreams, m.perspective) - switch id.Type() { - case protocol.StreamTypeUni: - m.outgoingUniStreams.SetMaxStream(id) - case protocol.StreamTypeBidi: - fmt.Printf("") - m.outgoingBidiStreams.SetMaxStream(id) - } - return nil -} - -func (m *streamsMap) UpdateLimits(p *handshake.TransportParameters) { - // Max{Uni,Bidi}StreamID returns the highest stream ID that the peer is allowed to open. - m.outgoingBidiStreams.SetMaxStream(protocol.MaxStreamID(protocol.StreamTypeBidi, p.MaxBidiStreams, m.perspective)) - m.outgoingUniStreams.SetMaxStream(protocol.MaxStreamID(protocol.StreamTypeUni, p.MaxUniStreams, m.perspective)) -} - -func (m *streamsMap) CloseWithError(err error) { - m.outgoingBidiStreams.CloseWithError(err) - m.outgoingUniStreams.CloseWithError(err) - m.incomingBidiStreams.CloseWithError(err) - m.incomingUniStreams.CloseWithError(err) -} diff --git a/external/github.com/lucas-clemente/quic-go/streams_map_generic_helper.go b/external/github.com/lucas-clemente/quic-go/streams_map_generic_helper.go deleted file mode 100644 index b7235022c..000000000 --- a/external/github.com/lucas-clemente/quic-go/streams_map_generic_helper.go +++ /dev/null @@ -1,17 +0,0 @@ -package quic - -import ( - "v2ray.com/core/external/github.com/cheekybits/genny/generic" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" -) - -// In the auto-generated streams maps, we need to be able to close the streams. -// Therefore, extend the generic.Type with the stream close method. -// This definition must be in a file that Genny doesn't process. -type item interface { - generic.Type - closeForShutdown(error) -} - -const streamTypeGeneric protocol.StreamType = protocol.StreamTypeUni diff --git a/external/github.com/lucas-clemente/quic-go/streams_map_incoming_bidi.go b/external/github.com/lucas-clemente/quic-go/streams_map_incoming_bidi.go deleted file mode 100644 index 74880798d..000000000 --- a/external/github.com/lucas-clemente/quic-go/streams_map_incoming_bidi.go +++ /dev/null @@ -1,130 +0,0 @@ -// This file was automatically generated by genny. -// Any changes will be lost if this file is regenerated. -// see https://github.com/cheekybits/genny - -package quic - -import ( - "fmt" - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type incomingBidiStreamsMap struct { - mutex sync.RWMutex - cond sync.Cond - - streams map[protocol.StreamID]streamI - - nextStreamToAccept protocol.StreamID // the next stream that will be returned by AcceptStream() - nextStreamToOpen protocol.StreamID // the highest stream that the peer openend - maxStream protocol.StreamID // the highest stream that the peer is allowed to open - maxNumStreams uint64 // maximum number of streams - - newStream func(protocol.StreamID) streamI - queueMaxStreamID func(*wire.MaxStreamsFrame) - - closeErr error -} - -func newIncomingBidiStreamsMap( - nextStreamToAccept protocol.StreamID, - initialMaxStreamID protocol.StreamID, - maxNumStreams uint64, - queueControlFrame func(wire.Frame), - newStream func(protocol.StreamID) streamI, -) *incomingBidiStreamsMap { - m := &incomingBidiStreamsMap{ - streams: make(map[protocol.StreamID]streamI), - nextStreamToAccept: nextStreamToAccept, - nextStreamToOpen: nextStreamToAccept, - maxStream: initialMaxStreamID, - maxNumStreams: maxNumStreams, - newStream: newStream, - queueMaxStreamID: func(f *wire.MaxStreamsFrame) { queueControlFrame(f) }, - } - m.cond.L = &m.mutex - return m -} - -func (m *incomingBidiStreamsMap) AcceptStream() (streamI, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - var str streamI - for { - var ok bool - if m.closeErr != nil { - return nil, m.closeErr - } - str, ok = m.streams[m.nextStreamToAccept] - if ok { - break - } - m.cond.Wait() - } - m.nextStreamToAccept += 4 - return str, nil -} - -func (m *incomingBidiStreamsMap) GetOrOpenStream(id protocol.StreamID) (streamI, error) { - m.mutex.RLock() - if id > m.maxStream { - m.mutex.RUnlock() - return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) - } - // if the id is smaller than the highest we accepted - // * this stream exists in the map, and we can return it, or - // * this stream was already closed, then we can return the nil - if id < m.nextStreamToOpen { - s := m.streams[id] - m.mutex.RUnlock() - return s, nil - } - m.mutex.RUnlock() - - m.mutex.Lock() - // no need to check the two error conditions from above again - // * maxStream can only increase, so if the id was valid before, it definitely is valid now - // * highestStream is only modified by this function - for newID := m.nextStreamToOpen; newID <= id; newID += 4 { - m.streams[newID] = m.newStream(newID) - m.cond.Signal() - } - m.nextStreamToOpen = id + 4 - s := m.streams[id] - m.mutex.Unlock() - return s, nil -} - -func (m *incomingBidiStreamsMap) DeleteStream(id protocol.StreamID) error { - m.mutex.Lock() - defer m.mutex.Unlock() - - if _, ok := m.streams[id]; !ok { - return fmt.Errorf("Tried to delete unknown stream %d", id) - } - delete(m.streams, id) - // queue a MAX_STREAM_ID frame, giving the peer the option to open a new stream - if m.maxNumStreams > uint64(len(m.streams)) { - numNewStreams := m.maxNumStreams - uint64(len(m.streams)) - m.maxStream = m.nextStreamToOpen + protocol.StreamID((numNewStreams-1)*4) - m.queueMaxStreamID(&wire.MaxStreamsFrame{ - Type: protocol.StreamTypeBidi, - MaxStreams: m.maxStream.StreamNum(), - }) - } - return nil -} - -func (m *incomingBidiStreamsMap) CloseWithError(err error) { - m.mutex.Lock() - m.closeErr = err - for _, str := range m.streams { - str.closeForShutdown(err) - } - m.mutex.Unlock() - m.cond.Broadcast() -} diff --git a/external/github.com/lucas-clemente/quic-go/streams_map_incoming_generic.go b/external/github.com/lucas-clemente/quic-go/streams_map_incoming_generic.go deleted file mode 100644 index 3ab5a6cf8..000000000 --- a/external/github.com/lucas-clemente/quic-go/streams_map_incoming_generic.go +++ /dev/null @@ -1,128 +0,0 @@ -package quic - -import ( - "fmt" - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -//go:generate genny -in $GOFILE -out streams_map_incoming_bidi.go gen "item=streamI Item=BidiStream streamTypeGeneric=protocol.StreamTypeBidi" -//go:generate genny -in $GOFILE -out streams_map_incoming_uni.go gen "item=receiveStreamI Item=UniStream streamTypeGeneric=protocol.StreamTypeUni" -type incomingItemsMap struct { - mutex sync.RWMutex - cond sync.Cond - - streams map[protocol.StreamID]item - - nextStreamToAccept protocol.StreamID // the next stream that will be returned by AcceptStream() - nextStreamToOpen protocol.StreamID // the highest stream that the peer openend - maxStream protocol.StreamID // the highest stream that the peer is allowed to open - maxNumStreams uint64 // maximum number of streams - - newStream func(protocol.StreamID) item - queueMaxStreamID func(*wire.MaxStreamsFrame) - - closeErr error -} - -func newIncomingItemsMap( - nextStreamToAccept protocol.StreamID, - initialMaxStreamID protocol.StreamID, - maxNumStreams uint64, - queueControlFrame func(wire.Frame), - newStream func(protocol.StreamID) item, -) *incomingItemsMap { - m := &incomingItemsMap{ - streams: make(map[protocol.StreamID]item), - nextStreamToAccept: nextStreamToAccept, - nextStreamToOpen: nextStreamToAccept, - maxStream: initialMaxStreamID, - maxNumStreams: maxNumStreams, - newStream: newStream, - queueMaxStreamID: func(f *wire.MaxStreamsFrame) { queueControlFrame(f) }, - } - m.cond.L = &m.mutex - return m -} - -func (m *incomingItemsMap) AcceptStream() (item, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - var str item - for { - var ok bool - if m.closeErr != nil { - return nil, m.closeErr - } - str, ok = m.streams[m.nextStreamToAccept] - if ok { - break - } - m.cond.Wait() - } - m.nextStreamToAccept += 4 - return str, nil -} - -func (m *incomingItemsMap) GetOrOpenStream(id protocol.StreamID) (item, error) { - m.mutex.RLock() - if id > m.maxStream { - m.mutex.RUnlock() - return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) - } - // if the id is smaller than the highest we accepted - // * this stream exists in the map, and we can return it, or - // * this stream was already closed, then we can return the nil - if id < m.nextStreamToOpen { - s := m.streams[id] - m.mutex.RUnlock() - return s, nil - } - m.mutex.RUnlock() - - m.mutex.Lock() - // no need to check the two error conditions from above again - // * maxStream can only increase, so if the id was valid before, it definitely is valid now - // * highestStream is only modified by this function - for newID := m.nextStreamToOpen; newID <= id; newID += 4 { - m.streams[newID] = m.newStream(newID) - m.cond.Signal() - } - m.nextStreamToOpen = id + 4 - s := m.streams[id] - m.mutex.Unlock() - return s, nil -} - -func (m *incomingItemsMap) DeleteStream(id protocol.StreamID) error { - m.mutex.Lock() - defer m.mutex.Unlock() - - if _, ok := m.streams[id]; !ok { - return fmt.Errorf("Tried to delete unknown stream %d", id) - } - delete(m.streams, id) - // queue a MAX_STREAM_ID frame, giving the peer the option to open a new stream - if m.maxNumStreams > uint64(len(m.streams)) { - numNewStreams := m.maxNumStreams - uint64(len(m.streams)) - m.maxStream = m.nextStreamToOpen + protocol.StreamID((numNewStreams-1)*4) - m.queueMaxStreamID(&wire.MaxStreamsFrame{ - Type: streamTypeGeneric, - MaxStreams: m.maxStream.StreamNum(), - }) - } - return nil -} - -func (m *incomingItemsMap) CloseWithError(err error) { - m.mutex.Lock() - m.closeErr = err - for _, str := range m.streams { - str.closeForShutdown(err) - } - m.mutex.Unlock() - m.cond.Broadcast() -} diff --git a/external/github.com/lucas-clemente/quic-go/streams_map_incoming_uni.go b/external/github.com/lucas-clemente/quic-go/streams_map_incoming_uni.go deleted file mode 100644 index 28a0b0ddc..000000000 --- a/external/github.com/lucas-clemente/quic-go/streams_map_incoming_uni.go +++ /dev/null @@ -1,130 +0,0 @@ -// This file was automatically generated by genny. -// Any changes will be lost if this file is regenerated. -// see https://github.com/cheekybits/genny - -package quic - -import ( - "fmt" - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type incomingUniStreamsMap struct { - mutex sync.RWMutex - cond sync.Cond - - streams map[protocol.StreamID]receiveStreamI - - nextStreamToAccept protocol.StreamID // the next stream that will be returned by AcceptStream() - nextStreamToOpen protocol.StreamID // the highest stream that the peer openend - maxStream protocol.StreamID // the highest stream that the peer is allowed to open - maxNumStreams uint64 // maximum number of streams - - newStream func(protocol.StreamID) receiveStreamI - queueMaxStreamID func(*wire.MaxStreamsFrame) - - closeErr error -} - -func newIncomingUniStreamsMap( - nextStreamToAccept protocol.StreamID, - initialMaxStreamID protocol.StreamID, - maxNumStreams uint64, - queueControlFrame func(wire.Frame), - newStream func(protocol.StreamID) receiveStreamI, -) *incomingUniStreamsMap { - m := &incomingUniStreamsMap{ - streams: make(map[protocol.StreamID]receiveStreamI), - nextStreamToAccept: nextStreamToAccept, - nextStreamToOpen: nextStreamToAccept, - maxStream: initialMaxStreamID, - maxNumStreams: maxNumStreams, - newStream: newStream, - queueMaxStreamID: func(f *wire.MaxStreamsFrame) { queueControlFrame(f) }, - } - m.cond.L = &m.mutex - return m -} - -func (m *incomingUniStreamsMap) AcceptStream() (receiveStreamI, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - var str receiveStreamI - for { - var ok bool - if m.closeErr != nil { - return nil, m.closeErr - } - str, ok = m.streams[m.nextStreamToAccept] - if ok { - break - } - m.cond.Wait() - } - m.nextStreamToAccept += 4 - return str, nil -} - -func (m *incomingUniStreamsMap) GetOrOpenStream(id protocol.StreamID) (receiveStreamI, error) { - m.mutex.RLock() - if id > m.maxStream { - m.mutex.RUnlock() - return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) - } - // if the id is smaller than the highest we accepted - // * this stream exists in the map, and we can return it, or - // * this stream was already closed, then we can return the nil - if id < m.nextStreamToOpen { - s := m.streams[id] - m.mutex.RUnlock() - return s, nil - } - m.mutex.RUnlock() - - m.mutex.Lock() - // no need to check the two error conditions from above again - // * maxStream can only increase, so if the id was valid before, it definitely is valid now - // * highestStream is only modified by this function - for newID := m.nextStreamToOpen; newID <= id; newID += 4 { - m.streams[newID] = m.newStream(newID) - m.cond.Signal() - } - m.nextStreamToOpen = id + 4 - s := m.streams[id] - m.mutex.Unlock() - return s, nil -} - -func (m *incomingUniStreamsMap) DeleteStream(id protocol.StreamID) error { - m.mutex.Lock() - defer m.mutex.Unlock() - - if _, ok := m.streams[id]; !ok { - return fmt.Errorf("Tried to delete unknown stream %d", id) - } - delete(m.streams, id) - // queue a MAX_STREAM_ID frame, giving the peer the option to open a new stream - if m.maxNumStreams > uint64(len(m.streams)) { - numNewStreams := m.maxNumStreams - uint64(len(m.streams)) - m.maxStream = m.nextStreamToOpen + protocol.StreamID((numNewStreams-1)*4) - m.queueMaxStreamID(&wire.MaxStreamsFrame{ - Type: protocol.StreamTypeUni, - MaxStreams: m.maxStream.StreamNum(), - }) - } - return nil -} - -func (m *incomingUniStreamsMap) CloseWithError(err error) { - m.mutex.Lock() - m.closeErr = err - for _, str := range m.streams { - str.closeForShutdown(err) - } - m.mutex.Unlock() - m.cond.Broadcast() -} diff --git a/external/github.com/lucas-clemente/quic-go/streams_map_outgoing_bidi.go b/external/github.com/lucas-clemente/quic-go/streams_map_outgoing_bidi.go deleted file mode 100644 index ac602190a..000000000 --- a/external/github.com/lucas-clemente/quic-go/streams_map_outgoing_bidi.go +++ /dev/null @@ -1,143 +0,0 @@ -// This file was automatically generated by genny. -// Any changes will be lost if this file is regenerated. -// see https://github.com/cheekybits/genny - -package quic - -import ( - "fmt" - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type outgoingBidiStreamsMap struct { - mutex sync.RWMutex - cond sync.Cond - - streams map[protocol.StreamID]streamI - - nextStream protocol.StreamID // stream ID of the stream returned by OpenStream(Sync) - maxStream protocol.StreamID // the maximum stream ID we're allowed to open - maxStreamSet bool // was maxStream set. If not, it's not possible to any stream (also works for stream 0) - blockedSent bool // was a STREAMS_BLOCKED sent for the current maxStream - - newStream func(protocol.StreamID) streamI - queueStreamIDBlocked func(*wire.StreamsBlockedFrame) - - closeErr error -} - -func newOutgoingBidiStreamsMap( - nextStream protocol.StreamID, - newStream func(protocol.StreamID) streamI, - queueControlFrame func(wire.Frame), -) *outgoingBidiStreamsMap { - m := &outgoingBidiStreamsMap{ - streams: make(map[protocol.StreamID]streamI), - nextStream: nextStream, - newStream: newStream, - queueStreamIDBlocked: func(f *wire.StreamsBlockedFrame) { queueControlFrame(f) }, - } - m.cond.L = &m.mutex - return m -} - -func (m *outgoingBidiStreamsMap) OpenStream() (streamI, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - str, err := m.openStreamImpl() - if err != nil { - return nil, streamOpenErr{err} - } - return str, nil -} - -func (m *outgoingBidiStreamsMap) OpenStreamSync() (streamI, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - for { - str, err := m.openStreamImpl() - if err == nil { - return str, nil - } - if err != nil && err != errTooManyOpenStreams { - return nil, streamOpenErr{err} - } - m.cond.Wait() - } -} - -func (m *outgoingBidiStreamsMap) openStreamImpl() (streamI, error) { - if m.closeErr != nil { - return nil, m.closeErr - } - if !m.maxStreamSet || m.nextStream > m.maxStream { - if !m.blockedSent { - if m.maxStreamSet { - m.queueStreamIDBlocked(&wire.StreamsBlockedFrame{ - Type: protocol.StreamTypeBidi, - StreamLimit: m.maxStream.StreamNum(), - }) - } else { - m.queueStreamIDBlocked(&wire.StreamsBlockedFrame{ - Type: protocol.StreamTypeBidi, - StreamLimit: 0, - }) - } - m.blockedSent = true - } - return nil, errTooManyOpenStreams - } - s := m.newStream(m.nextStream) - m.streams[m.nextStream] = s - m.nextStream += 4 - return s, nil -} - -func (m *outgoingBidiStreamsMap) GetStream(id protocol.StreamID) (streamI, error) { - m.mutex.RLock() - if id >= m.nextStream { - m.mutex.RUnlock() - return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) - } - s := m.streams[id] - m.mutex.RUnlock() - return s, nil -} - -func (m *outgoingBidiStreamsMap) DeleteStream(id protocol.StreamID) error { - m.mutex.Lock() - defer m.mutex.Unlock() - - if _, ok := m.streams[id]; !ok { - return fmt.Errorf("Tried to delete unknown stream %d", id) - } - delete(m.streams, id) - return nil -} - -func (m *outgoingBidiStreamsMap) SetMaxStream(id protocol.StreamID) { - m.mutex.Lock() - if !m.maxStreamSet || id > m.maxStream { - m.maxStream = id - m.maxStreamSet = true - m.blockedSent = false - m.cond.Broadcast() - } - m.mutex.Unlock() -} - -func (m *outgoingBidiStreamsMap) CloseWithError(err error) { - m.mutex.Lock() - m.closeErr = err - for _, str := range m.streams { - str.closeForShutdown(err) - } - m.cond.Broadcast() - m.mutex.Unlock() -} diff --git a/external/github.com/lucas-clemente/quic-go/streams_map_outgoing_generic.go b/external/github.com/lucas-clemente/quic-go/streams_map_outgoing_generic.go deleted file mode 100644 index 0ac554793..000000000 --- a/external/github.com/lucas-clemente/quic-go/streams_map_outgoing_generic.go +++ /dev/null @@ -1,141 +0,0 @@ -package quic - -import ( - "fmt" - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -//go:generate genny -in $GOFILE -out streams_map_outgoing_bidi.go gen "item=streamI Item=BidiStream streamTypeGeneric=protocol.StreamTypeBidi" -//go:generate genny -in $GOFILE -out streams_map_outgoing_uni.go gen "item=sendStreamI Item=UniStream streamTypeGeneric=protocol.StreamTypeUni" -type outgoingItemsMap struct { - mutex sync.RWMutex - cond sync.Cond - - streams map[protocol.StreamID]item - - nextStream protocol.StreamID // stream ID of the stream returned by OpenStream(Sync) - maxStream protocol.StreamID // the maximum stream ID we're allowed to open - maxStreamSet bool // was maxStream set. If not, it's not possible to any stream (also works for stream 0) - blockedSent bool // was a STREAMS_BLOCKED sent for the current maxStream - - newStream func(protocol.StreamID) item - queueStreamIDBlocked func(*wire.StreamsBlockedFrame) - - closeErr error -} - -func newOutgoingItemsMap( - nextStream protocol.StreamID, - newStream func(protocol.StreamID) item, - queueControlFrame func(wire.Frame), -) *outgoingItemsMap { - m := &outgoingItemsMap{ - streams: make(map[protocol.StreamID]item), - nextStream: nextStream, - newStream: newStream, - queueStreamIDBlocked: func(f *wire.StreamsBlockedFrame) { queueControlFrame(f) }, - } - m.cond.L = &m.mutex - return m -} - -func (m *outgoingItemsMap) OpenStream() (item, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - str, err := m.openStreamImpl() - if err != nil { - return nil, streamOpenErr{err} - } - return str, nil -} - -func (m *outgoingItemsMap) OpenStreamSync() (item, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - for { - str, err := m.openStreamImpl() - if err == nil { - return str, nil - } - if err != nil && err != errTooManyOpenStreams { - return nil, streamOpenErr{err} - } - m.cond.Wait() - } -} - -func (m *outgoingItemsMap) openStreamImpl() (item, error) { - if m.closeErr != nil { - return nil, m.closeErr - } - if !m.maxStreamSet || m.nextStream > m.maxStream { - if !m.blockedSent { - if m.maxStreamSet { - m.queueStreamIDBlocked(&wire.StreamsBlockedFrame{ - Type: streamTypeGeneric, - StreamLimit: m.maxStream.StreamNum(), - }) - } else { - m.queueStreamIDBlocked(&wire.StreamsBlockedFrame{ - Type: streamTypeGeneric, - StreamLimit: 0, - }) - } - m.blockedSent = true - } - return nil, errTooManyOpenStreams - } - s := m.newStream(m.nextStream) - m.streams[m.nextStream] = s - m.nextStream += 4 - return s, nil -} - -func (m *outgoingItemsMap) GetStream(id protocol.StreamID) (item, error) { - m.mutex.RLock() - if id >= m.nextStream { - m.mutex.RUnlock() - return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) - } - s := m.streams[id] - m.mutex.RUnlock() - return s, nil -} - -func (m *outgoingItemsMap) DeleteStream(id protocol.StreamID) error { - m.mutex.Lock() - defer m.mutex.Unlock() - - if _, ok := m.streams[id]; !ok { - return fmt.Errorf("Tried to delete unknown stream %d", id) - } - delete(m.streams, id) - return nil -} - -func (m *outgoingItemsMap) SetMaxStream(id protocol.StreamID) { - m.mutex.Lock() - if !m.maxStreamSet || id > m.maxStream { - m.maxStream = id - m.maxStreamSet = true - m.blockedSent = false - m.cond.Broadcast() - } - m.mutex.Unlock() -} - -func (m *outgoingItemsMap) CloseWithError(err error) { - m.mutex.Lock() - m.closeErr = err - for _, str := range m.streams { - str.closeForShutdown(err) - } - m.cond.Broadcast() - m.mutex.Unlock() -} diff --git a/external/github.com/lucas-clemente/quic-go/streams_map_outgoing_uni.go b/external/github.com/lucas-clemente/quic-go/streams_map_outgoing_uni.go deleted file mode 100644 index a6f1feb40..000000000 --- a/external/github.com/lucas-clemente/quic-go/streams_map_outgoing_uni.go +++ /dev/null @@ -1,143 +0,0 @@ -// This file was automatically generated by genny. -// Any changes will be lost if this file is regenerated. -// see https://github.com/cheekybits/genny - -package quic - -import ( - "fmt" - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type outgoingUniStreamsMap struct { - mutex sync.RWMutex - cond sync.Cond - - streams map[protocol.StreamID]sendStreamI - - nextStream protocol.StreamID // stream ID of the stream returned by OpenStream(Sync) - maxStream protocol.StreamID // the maximum stream ID we're allowed to open - maxStreamSet bool // was maxStream set. If not, it's not possible to any stream (also works for stream 0) - blockedSent bool // was a STREAMS_BLOCKED sent for the current maxStream - - newStream func(protocol.StreamID) sendStreamI - queueStreamIDBlocked func(*wire.StreamsBlockedFrame) - - closeErr error -} - -func newOutgoingUniStreamsMap( - nextStream protocol.StreamID, - newStream func(protocol.StreamID) sendStreamI, - queueControlFrame func(wire.Frame), -) *outgoingUniStreamsMap { - m := &outgoingUniStreamsMap{ - streams: make(map[protocol.StreamID]sendStreamI), - nextStream: nextStream, - newStream: newStream, - queueStreamIDBlocked: func(f *wire.StreamsBlockedFrame) { queueControlFrame(f) }, - } - m.cond.L = &m.mutex - return m -} - -func (m *outgoingUniStreamsMap) OpenStream() (sendStreamI, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - str, err := m.openStreamImpl() - if err != nil { - return nil, streamOpenErr{err} - } - return str, nil -} - -func (m *outgoingUniStreamsMap) OpenStreamSync() (sendStreamI, error) { - m.mutex.Lock() - defer m.mutex.Unlock() - - for { - str, err := m.openStreamImpl() - if err == nil { - return str, nil - } - if err != nil && err != errTooManyOpenStreams { - return nil, streamOpenErr{err} - } - m.cond.Wait() - } -} - -func (m *outgoingUniStreamsMap) openStreamImpl() (sendStreamI, error) { - if m.closeErr != nil { - return nil, m.closeErr - } - if !m.maxStreamSet || m.nextStream > m.maxStream { - if !m.blockedSent { - if m.maxStreamSet { - m.queueStreamIDBlocked(&wire.StreamsBlockedFrame{ - Type: protocol.StreamTypeUni, - StreamLimit: m.maxStream.StreamNum(), - }) - } else { - m.queueStreamIDBlocked(&wire.StreamsBlockedFrame{ - Type: protocol.StreamTypeUni, - StreamLimit: 0, - }) - } - m.blockedSent = true - } - return nil, errTooManyOpenStreams - } - s := m.newStream(m.nextStream) - m.streams[m.nextStream] = s - m.nextStream += 4 - return s, nil -} - -func (m *outgoingUniStreamsMap) GetStream(id protocol.StreamID) (sendStreamI, error) { - m.mutex.RLock() - if id >= m.nextStream { - m.mutex.RUnlock() - return nil, qerr.Error(qerr.InvalidStreamID, fmt.Sprintf("peer attempted to open stream %d", id)) - } - s := m.streams[id] - m.mutex.RUnlock() - return s, nil -} - -func (m *outgoingUniStreamsMap) DeleteStream(id protocol.StreamID) error { - m.mutex.Lock() - defer m.mutex.Unlock() - - if _, ok := m.streams[id]; !ok { - return fmt.Errorf("Tried to delete unknown stream %d", id) - } - delete(m.streams, id) - return nil -} - -func (m *outgoingUniStreamsMap) SetMaxStream(id protocol.StreamID) { - m.mutex.Lock() - if !m.maxStreamSet || id > m.maxStream { - m.maxStream = id - m.maxStreamSet = true - m.blockedSent = false - m.cond.Broadcast() - } - m.mutex.Unlock() -} - -func (m *outgoingUniStreamsMap) CloseWithError(err error) { - m.mutex.Lock() - m.closeErr = err - for _, str := range m.streams { - str.closeForShutdown(err) - } - m.cond.Broadcast() - m.mutex.Unlock() -} diff --git a/external/github.com/lucas-clemente/quic-go/window_update_queue.go b/external/github.com/lucas-clemente/quic-go/window_update_queue.go deleted file mode 100644 index 808d6048f..000000000 --- a/external/github.com/lucas-clemente/quic-go/window_update_queue.go +++ /dev/null @@ -1,71 +0,0 @@ -package quic - -import ( - "sync" - - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/flowcontrol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" - "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire" -) - -type windowUpdateQueue struct { - mutex sync.Mutex - - queue map[protocol.StreamID]bool // used as a set - queuedConn bool // connection-level window update - - streamGetter streamGetter - connFlowController flowcontrol.ConnectionFlowController - callback func(wire.Frame) -} - -func newWindowUpdateQueue( - streamGetter streamGetter, - connFC flowcontrol.ConnectionFlowController, - cb func(wire.Frame), -) *windowUpdateQueue { - return &windowUpdateQueue{ - queue: make(map[protocol.StreamID]bool), - streamGetter: streamGetter, - connFlowController: connFC, - callback: cb, - } -} - -func (q *windowUpdateQueue) AddStream(id protocol.StreamID) { - q.mutex.Lock() - q.queue[id] = true - q.mutex.Unlock() -} - -func (q *windowUpdateQueue) AddConnection() { - q.mutex.Lock() - q.queuedConn = true - q.mutex.Unlock() -} - -func (q *windowUpdateQueue) QueueAll() { - q.mutex.Lock() - // queue a connection-level window update - if q.queuedConn { - q.callback(&wire.MaxDataFrame{ByteOffset: q.connFlowController.GetWindowUpdate()}) - q.queuedConn = false - } - // queue all stream-level window updates - for id := range q.queue { - str, err := q.streamGetter.GetOrOpenReceiveStream(id) - if err != nil || str == nil { // the stream can be nil if it was completed before dequeing the window update - continue - } - offset := str.getWindowUpdate() - if offset == 0 { // can happen if we received a final offset, right after queueing the window update - continue - } - q.callback(&wire.MaxStreamDataFrame{ - StreamID: id, - ByteOffset: offset, - }) - delete(q.queue, id) - } - q.mutex.Unlock() -} diff --git a/external/github.com/marten-seemann/qtls/13.go b/external/github.com/marten-seemann/qtls/13.go deleted file mode 100644 index bde8eec04..000000000 --- a/external/github.com/marten-seemann/qtls/13.go +++ /dev/null @@ -1,1328 +0,0 @@ -package qtls - -import ( - "bytes" - "crypto" - "crypto/cipher" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/hmac" - "crypto/rsa" - "crypto/subtle" - "encoding/hex" - "errors" - "fmt" - "hash" - "io" - "log" - "os" - "runtime" - "runtime/debug" - "strings" - "sync/atomic" - "time" - - "golang.org/x/crypto/curve25519" - "v2ray.com/core/external/github.com/cloudflare/sidh/sidh" -) - -// numSessionTickets is the number of different session tickets the -// server sends to a TLS 1.3 client, who will use each only once. -const numSessionTickets = 2 - -type secretLabel int - -const ( - x25519SharedSecretSz = 32 - - P503PubKeySz = 378 - P503PrvKeySz = 32 - P503SharedSecretSz = 126 - SIDHp503Curve25519PubKeySz = x25519SharedSecretSz + P503PubKeySz - SIDHp503Curve25519PrvKeySz = x25519SharedSecretSz + P503PrvKeySz - SIDHp503Curve25519SharedKeySz = x25519SharedSecretSz + P503SharedSecretSz -) - -const ( - secretResumptionPskBinder secretLabel = iota - secretEarlyClient - secretHandshakeClient - secretHandshakeServer - secretApplicationClient - secretApplicationServer - secretResumption -) - -type keySchedule13 struct { - suite *cipherSuite - transcriptHash hash.Hash // uses the cipher suite hash algo - secret []byte // Current secret as used for Derive-Secret - handshakeCtx []byte // cached handshake context, invalidated on updates. - clientRandom []byte // Used for keylogging, nil if keylogging is disabled. - config *Config // Used for KeyLogWriter callback, nil if keylogging is disabled. -} - -// Interface implemented by DH key exchange strategies -type dhKex interface { - // c - context of current TLS handshake, groupId - ID of an algorithm - // (curve/field) being chosen for key agreement. Methods implmenting an - // interface always assume that provided groupId is correct. - // - // In case of success, function returns secret key and ephemeral key. Otherwise - // error is set. - generate(c *Conn, groupId CurveID) ([]byte, keyShare, error) - // c - context of current TLS handshake, ks - public key received - // from the other side of the connection, secretKey - is a private key - // used for DH key agreement. Function returns shared secret in case - // of success or empty slice otherwise. - derive(c *Conn, ks keyShare, secretKey []byte) []byte -} - -// Key Exchange strategies per curve type -type kexNist struct{} // Used by NIST curves; P-256, P-384, P-512 -type kexX25519 struct{} // Used by X25519 -type kexSIDHp503 struct{} // Used by SIDH/P503 -type kexHybridSIDHp503X25519 struct { - classicKEX kexX25519 - pqKEX kexSIDHp503 -} // Used by SIDH-ECDH hybrid scheme - -// Routing map for key exchange strategies -var dhKexStrat = map[CurveID]dhKex{ - CurveP256: &kexNist{}, - CurveP384: &kexNist{}, - CurveP521: &kexNist{}, - X25519: &kexX25519{}, - HybridSIDHp503Curve25519: &kexHybridSIDHp503X25519{}, -} - -func newKeySchedule13(suite *cipherSuite, config *Config, clientRandom []byte) *keySchedule13 { - if config.KeyLogWriter == nil { - clientRandom = nil - config = nil - } - return &keySchedule13{ - suite: suite, - transcriptHash: hashForSuite(suite).New(), - clientRandom: clientRandom, - config: config, - } -} - -// setSecret sets the early/handshake/master secret based on the given secret -// (IKM). The salt is based on previous secrets (nil for the early secret). -func (ks *keySchedule13) setSecret(secret []byte) { - hash := hashForSuite(ks.suite) - salt := ks.secret - if salt != nil { - h0 := hash.New().Sum(nil) - salt = hkdfExpandLabel(hash, salt, h0, "derived", hash.Size()) - } - ks.secret = hkdfExtract(hash, secret, salt) -} - -// Depending on role returns pair of key variant to be used by -// local and remote process. -func getSidhKeyVariant(isClient bool) (sidh.KeyVariant, sidh.KeyVariant) { - if isClient { - return sidh.KeyVariant_SIDH_A, sidh.KeyVariant_SIDH_B - } - return sidh.KeyVariant_SIDH_B, sidh.KeyVariant_SIDH_A -} - -// write appends the data to the transcript hash context. -func (ks *keySchedule13) write(data []byte) { - ks.handshakeCtx = nil - ks.transcriptHash.Write(data) -} - -func (ks *keySchedule13) getLabel(secretLabel secretLabel) (label, keylogType string) { - switch secretLabel { - case secretResumptionPskBinder: - label = "res binder" - case secretEarlyClient: - label = "c e traffic" - keylogType = "CLIENT_EARLY_TRAFFIC_SECRET" - case secretHandshakeClient: - label = "c hs traffic" - keylogType = "CLIENT_HANDSHAKE_TRAFFIC_SECRET" - case secretHandshakeServer: - label = "s hs traffic" - keylogType = "SERVER_HANDSHAKE_TRAFFIC_SECRET" - case secretApplicationClient: - label = "c ap traffic" - keylogType = "CLIENT_TRAFFIC_SECRET_0" - case secretApplicationServer: - label = "s ap traffic" - keylogType = "SERVER_TRAFFIC_SECRET_0" - case secretResumption: - label = "res master" - } - return -} - -// deriveSecret returns the secret derived from the handshake context and label. -func (ks *keySchedule13) deriveSecret(secretLabel secretLabel) []byte { - label, keylogType := ks.getLabel(secretLabel) - if ks.handshakeCtx == nil { - ks.handshakeCtx = ks.transcriptHash.Sum(nil) - } - hash := hashForSuite(ks.suite) - secret := hkdfExpandLabel(hash, ks.secret, ks.handshakeCtx, label, hash.Size()) - if keylogType != "" && ks.config != nil { - ks.config.writeKeyLog(keylogType, ks.clientRandom, secret) - } - return secret -} - -func (ks *keySchedule13) prepareCipher(trafficSecret []byte) cipher.AEAD { - hash := hashForSuite(ks.suite) - key := hkdfExpandLabel(hash, trafficSecret, nil, "key", ks.suite.keyLen) - iv := hkdfExpandLabel(hash, trafficSecret, nil, "iv", ks.suite.ivLen) - return ks.suite.aead(key, iv) -} - -func (hs *serverHandshakeState) doTLS13Handshake() error { - config := hs.c.config - c := hs.c - - hs.c.cipherSuite, hs.hello.cipherSuite = hs.suite.id, hs.suite.id - hs.c.clientHello = hs.clientHello.marshal() - - // When picking the group for the handshake, priority is given to groups - // that the client provided a keyShare for, so to avoid a round-trip. - // After that the order of CurvePreferences is respected. - var ks keyShare -CurvePreferenceLoop: - for _, curveID := range config.curvePreferences() { - for _, keyShare := range hs.clientHello.keyShares { - if curveID == keyShare.group { - ks = keyShare - break CurvePreferenceLoop - } - } - } - if ks.group == 0 { - c.sendAlert(alertInternalError) - return errors.New("tls: HelloRetryRequest not implemented") // TODO(filippo) - } - - privateKey, serverKS, err := c.generateKeyShare(ks.group) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - hs.hello.keyShare = serverKS - - hash := hashForSuite(hs.suite) - hashSize := hash.Size() - hs.keySchedule = newKeySchedule13(hs.suite, config, hs.clientHello.random) - - // Check for PSK and update key schedule with new early secret key - isResumed, pskAlert := hs.checkPSK() - switch { - case pskAlert != alertSuccess: - c.sendAlert(pskAlert) - return errors.New("tls: invalid client PSK") - case !isResumed: - // apply an empty PSK if not resumed. - hs.keySchedule.setSecret(nil) - case isResumed: - c.didResume = true - } - - hs.keySchedule.write(hs.clientHello.marshal()) - - earlyClientTrafficSecret := hs.keySchedule.deriveSecret(secretEarlyClient) - - ecdheSecret := c.deriveDHESecret(ks, privateKey) - if ecdheSecret == nil { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: bad ECDHE client share") - } - - hs.keySchedule.write(hs.hello.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { - return err - } - - // middlebox compatibility mode: send CCS after first handshake message - if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { - return err - } - - hs.keySchedule.setSecret(ecdheSecret) - hs.hsClientTrafficSecret = hs.keySchedule.deriveSecret(secretHandshakeClient) - hsServerTrafficSecret := hs.keySchedule.deriveSecret(secretHandshakeServer) - c.out.exportKey(hs.keySchedule.suite, hsServerTrafficSecret) - c.out.setKey(c.vers, hs.keySchedule.suite, hsServerTrafficSecret) - - serverFinishedKey := hkdfExpandLabel(hash, hsServerTrafficSecret, nil, "finished", hashSize) - hs.clientFinishedKey = hkdfExpandLabel(hash, hs.hsClientTrafficSecret, nil, "finished", hashSize) - - // EncryptedExtensions - hs.keySchedule.write(hs.hello13Enc.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, hs.hello13Enc.marshal()); err != nil { - return err - } - - // TODO: we should have 2 separated methods - one for full-handshake and the other for PSK-handshake - if !c.didResume { - // Server MUST NOT send CertificateRequest if authenticating with PSK - if c.config.ClientAuth >= RequestClientCert { - - certReq := new(certificateRequestMsg13) - // extension 'signature_algorithms' MUST be specified - certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms13 - certReq.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13) - hs.keySchedule.write(certReq.marshal()) - if _, err := hs.c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil { - return err - } - } - - if err := hs.sendCertificate13(); err != nil { - return err - } - } - - verifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, serverFinishedKey) - serverFinished := &finishedMsg{ - verifyData: verifyData, - } - hs.keySchedule.write(serverFinished.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, serverFinished.marshal()); err != nil { - return err - } - - hs.keySchedule.setSecret(nil) // derive master secret - serverAppTrafficSecret := hs.keySchedule.deriveSecret(secretApplicationServer) - c.out.exportKey(hs.keySchedule.suite, serverAppTrafficSecret) - c.out.setKey(c.vers, hs.keySchedule.suite, serverAppTrafficSecret) - - if c.hand.Len() > 0 { - return c.sendAlert(alertUnexpectedMessage) - } - hs.appClientTrafficSecret = hs.keySchedule.deriveSecret(secretApplicationClient) - if hs.hello13Enc.earlyData { - c.in.exportKey(hs.keySchedule.suite, earlyClientTrafficSecret) - c.in.setKey(c.vers, hs.keySchedule.suite, earlyClientTrafficSecret) - c.phase = readingEarlyData - } else { - c.in.exportKey(hs.keySchedule.suite, hs.hsClientTrafficSecret) - c.in.setKey(c.vers, hs.keySchedule.suite, hs.hsClientTrafficSecret) - if hs.clientHello.earlyData { - c.phase = discardingEarlyData - } else { - c.phase = waitingClientFinished - } - } - - return nil -} - -// readClientFinished13 is called during the server handshake (when no early -// data it available) or after reading all early data. It discards early data if -// the server did not accept it and then verifies the Finished message. Once -// done it sends the session tickets. Under c.in lock. -func (hs *serverHandshakeState) readClientFinished13(hasConfirmLock bool) error { - c := hs.c - - // If the client advertised and sends early data while the server does - // not accept it, it must be fully skipped until the Finished message. - for c.phase == discardingEarlyData { - if err := c.readRecord(recordTypeApplicationData); err != nil { - return err - } - // Assume receipt of Finished message (will be checked below). - if c.hand.Len() > 0 { - c.phase = waitingClientFinished - break - } - } - - // If the client sends early data followed by a Finished message (but - // no end_of_early_data), the server MUST terminate the connection. - if c.phase != waitingClientFinished { - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: did not expect Client Finished yet") - } - - c.phase = readingClientFinished - msg, err := c.readHandshake() - if err != nil { - return err - } - - // client authentication - // (4.4.2) Client MUST send certificate msg if requested by server - if c.config.ClientAuth >= RequestClientCert && !c.didResume { - certMsg, ok := msg.(*certificateMsg13) - if !ok { - c.sendAlert(alertCertificateRequired) - return unexpectedMessageError(certMsg, msg) - } - - hs.keySchedule.write(certMsg.marshal()) - certs := getCertsFromEntries(certMsg.certificates) - pubKey, err := hs.processCertsFromClient(certs) - if err != nil { - return err - } - - if len(certs) > 0 { - // 4.4.3: CertificateVerify MUST appear immediately after Certificate msg - msg, err = c.readHandshake() - if err != nil { - return err - } - - certVerify, ok := msg.(*certificateVerifyMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certVerify, msg) - } - - err, alertCode := verifyPeerHandshakeSignature( - certVerify, - pubKey, - supportedSignatureAlgorithms13, - hs.keySchedule.transcriptHash.Sum(nil), - "TLS 1.3, client CertificateVerify") - if err != nil { - c.sendAlert(alertCode) - return err - } - hs.keySchedule.write(certVerify.marshal()) - } - - // Read next chunk - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - clientFinished, ok := msg.(*finishedMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(clientFinished, msg) - } - - hash := hashForSuite(hs.suite) - expectedVerifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, hs.clientFinishedKey) - if len(expectedVerifyData) != len(clientFinished.verifyData) || - subtle.ConstantTimeCompare(expectedVerifyData, clientFinished.verifyData) != 1 { - c.sendAlert(alertDecryptError) - return errors.New("tls: client's Finished message is incorrect") - } - hs.keySchedule.write(clientFinished.marshal()) - - c.hs = nil // Discard the server handshake state - if c.hand.Len() > 0 { - return c.sendAlert(alertUnexpectedMessage) - } - c.in.exportKey(hs.keySchedule.suite, hs.appClientTrafficSecret) - c.in.setKey(c.vers, hs.keySchedule.suite, hs.appClientTrafficSecret) - c.in.traceErr, c.out.traceErr = nil, nil - c.phase = handshakeConfirmed - atomic.StoreInt32(&c.handshakeConfirmed, 1) - - // Any read operation after handshakeRunning and before handshakeConfirmed - // will be holding this lock, which we release as soon as the confirmation - // happens, even if the Read call might do more work. - // If a Handshake is pending, c.confirmMutex will never be locked as - // ConfirmHandshake will wait for the handshake to complete. If a - // handshake was complete, and this was a confirmation, unlock - // c.confirmMutex now to allow readers to proceed. - if hasConfirmLock { - c.confirmMutex.Unlock() - } - - return hs.sendSessionTicket13() // TODO: do in a goroutine -} - -func (hs *serverHandshakeState) sendCertificate13() error { - c := hs.c - - certEntries := []certificateEntry{} - for _, cert := range hs.cert.Certificate { - certEntries = append(certEntries, certificateEntry{data: cert}) - } - if len(certEntries) > 0 && hs.clientHello.ocspStapling { - certEntries[0].ocspStaple = hs.cert.OCSPStaple - } - if len(certEntries) > 0 && hs.clientHello.scts { - certEntries[0].sctList = hs.cert.SignedCertificateTimestamps - } - - // If hs.delegatedCredential is set (see hs.readClientHello()) then the - // server is using the delegated credential extension. The DC is added as an - // extension to the end-entity certificate, i.e., the last CertificateEntry - // of Certificate.certficate_list. (For details, see - // https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.) - if len(certEntries) > 0 && hs.clientHello.delegatedCredential && hs.delegatedCredential != nil { - certEntries[0].delegatedCredential = hs.delegatedCredential - } - - certMsg := &certificateMsg13{certificates: certEntries} - - hs.keySchedule.write(certMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { - return err - } - - sigScheme, err := hs.selectTLS13SignatureScheme() - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - sigHash := hashForSignatureScheme(sigScheme) - opts := crypto.SignerOpts(sigHash) - if signatureSchemeIsPSS(sigScheme) { - opts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} - } - - toSign := prepareDigitallySigned(sigHash, "TLS 1.3, server CertificateVerify", hs.keySchedule.transcriptHash.Sum(nil)) - signature, err := hs.privateKey.(crypto.Signer).Sign(c.config.rand(), toSign[:], opts) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - verifyMsg := &certificateVerifyMsg{ - hasSignatureAndHash: true, - signatureAlgorithm: sigScheme, - signature: signature, - } - hs.keySchedule.write(verifyMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, verifyMsg.marshal()); err != nil { - return err - } - - return nil -} - -func (c *Conn) handleEndOfEarlyData() error { - if c.phase != readingEarlyData || c.vers < VersionTLS13 { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - msg, err := c.readHandshake() - if err != nil { - return err - } - endOfEarlyData, ok := msg.(*endOfEarlyDataMsg) - // No handshake messages are allowed after EOD. - if !ok || c.hand.Len() > 0 { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - c.hs.keySchedule.write(endOfEarlyData.marshal()) - c.phase = waitingClientFinished - c.in.exportKey(c.hs.keySchedule.suite, c.hs.hsClientTrafficSecret) - c.in.setKey(c.vers, c.hs.keySchedule.suite, c.hs.hsClientTrafficSecret) - return nil -} - -// selectTLS13SignatureScheme chooses the SignatureScheme for the CertificateVerify -// based on the certificate type and client supported schemes. If no overlap is found, -// a fallback is selected. -// -// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.4.1.2 -func (hs *serverHandshakeState) selectTLS13SignatureScheme() (sigScheme SignatureScheme, err error) { - var supportedSchemes []SignatureScheme - signer, ok := hs.privateKey.(crypto.Signer) - if !ok { - return 0, errors.New("tls: private key does not implement crypto.Signer") - } - pk := signer.Public() - if _, ok := pk.(*rsa.PublicKey); ok { - sigScheme = PSSWithSHA256 - supportedSchemes = []SignatureScheme{PSSWithSHA256, PSSWithSHA384, PSSWithSHA512} - } else if pk, ok := pk.(*ecdsa.PublicKey); ok { - switch pk.Curve { - case elliptic.P256(): - sigScheme = ECDSAWithP256AndSHA256 - supportedSchemes = []SignatureScheme{ECDSAWithP256AndSHA256} - case elliptic.P384(): - sigScheme = ECDSAWithP384AndSHA384 - supportedSchemes = []SignatureScheme{ECDSAWithP384AndSHA384} - case elliptic.P521(): - sigScheme = ECDSAWithP521AndSHA512 - supportedSchemes = []SignatureScheme{ECDSAWithP521AndSHA512} - default: - return 0, errors.New("tls: unknown ECDSA certificate curve") - } - } else { - return 0, errors.New("tls: unknown certificate key type") - } - - for _, ss := range supportedSchemes { - for _, cs := range hs.clientHello.supportedSignatureAlgorithms { - if ss == cs { - return ss, nil - } - } - } - - return sigScheme, nil -} - -func signatureSchemeIsPSS(s SignatureScheme) bool { - return s == PSSWithSHA256 || s == PSSWithSHA384 || s == PSSWithSHA512 -} - -// hashForSignatureScheme returns the Hash used by a SignatureScheme which is -// supported by selectTLS13SignatureScheme. -func hashForSignatureScheme(ss SignatureScheme) crypto.Hash { - switch ss { - case PSSWithSHA256, ECDSAWithP256AndSHA256: - return crypto.SHA256 - case PSSWithSHA384, ECDSAWithP384AndSHA384: - return crypto.SHA384 - case PSSWithSHA512, ECDSAWithP521AndSHA512: - return crypto.SHA512 - default: - panic("unsupported SignatureScheme passed to hashForSignatureScheme") - } -} - -func hashForSuite(suite *cipherSuite) crypto.Hash { - if suite.flags&suiteSHA384 != 0 { - return crypto.SHA384 - } - return crypto.SHA256 -} - -func prepareDigitallySigned(hash crypto.Hash, context string, data []byte) []byte { - message := bytes.Repeat([]byte{32}, 64) - message = append(message, context...) - message = append(message, 0) - message = append(message, data...) - h := hash.New() - h.Write(message) - return h.Sum(nil) -} - -// generateKeyShare generates keypair. Private key is returned as first argument, public key -// is returned in keyShare.data. keyshare.curveID stores ID of the scheme used. -func (c *Conn) generateKeyShare(curveID CurveID) ([]byte, keyShare, error) { - if val, ok := dhKexStrat[curveID]; ok { - return val.generate(c, curveID) - } - return nil, keyShare{}, errors.New("tls: preferredCurves includes unsupported curve") -} - -// DH key agreement. ks stores public key, secretKey stores private key used for ephemeral -// key agreement. Function returns shared secret in case of success or empty slice otherwise. -func (c *Conn) deriveDHESecret(ks keyShare, secretKey []byte) []byte { - if val, ok := dhKexStrat[ks.group]; ok { - return val.derive(c, ks, secretKey) - } - return nil -} - -// HkdfExpandLabel HKDF expands a label -func HkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte { - return hkdfExpandLabel(hash, secret, hashValue, label, L) -} - -func hkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte { - prefix := "tls13 " - hkdfLabel := make([]byte, 4+len(prefix)+len(label)+len(hashValue)) - hkdfLabel[0] = byte(L >> 8) - hkdfLabel[1] = byte(L) - hkdfLabel[2] = byte(len(prefix) + len(label)) - copy(hkdfLabel[3:], prefix) - z := hkdfLabel[3+len(prefix):] - copy(z, label) - z = z[len(label):] - z[0] = byte(len(hashValue)) - copy(z[1:], hashValue) - - return hkdfExpand(hash, secret, hkdfLabel, L) -} - -func hmacOfSum(f crypto.Hash, hash hash.Hash, key []byte) []byte { - h := hmac.New(f.New, key) - h.Write(hash.Sum(nil)) - return h.Sum(nil) -} - -// Maximum allowed mismatch between the stated age of a ticket -// and the server-observed one. See -// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8.2. -const ticketAgeSkewAllowance = 10 * time.Second - -// checkPSK tries to resume using a PSK, returning true (and updating the -// early secret in the key schedule) if the PSK was used and false otherwise. -func (hs *serverHandshakeState) checkPSK() (isResumed bool, alert alert) { - if hs.c.config.SessionTicketsDisabled { - return false, alertSuccess - } - - foundDHE := false - for _, mode := range hs.clientHello.pskKeyExchangeModes { - if mode == pskDHEKeyExchange { - foundDHE = true - break - } - } - if !foundDHE { - return false, alertSuccess - } - - hash := hashForSuite(hs.suite) - hashSize := hash.Size() - for i := range hs.clientHello.psks { - sessionTicket := append([]uint8{}, hs.clientHello.psks[i].identity...) - if hs.c.config.SessionTicketSealer != nil { - var ok bool - sessionTicket, ok = hs.c.config.SessionTicketSealer.Unseal(hs.clientHelloInfo(), sessionTicket) - if !ok { - continue - } - } else { - sessionTicket, _ = hs.c.decryptTicket(sessionTicket) - if sessionTicket == nil { - continue - } - } - s := &sessionState13{} - if s.unmarshal(sessionTicket) != alertSuccess { - continue - } - if s.vers != hs.c.vers { - continue - } - clientAge := time.Duration(hs.clientHello.psks[i].obfTicketAge-s.ageAdd) * time.Millisecond - serverAge := time.Since(time.Unix(int64(s.createdAt), 0)) - if clientAge-serverAge > ticketAgeSkewAllowance || clientAge-serverAge < -ticketAgeSkewAllowance { - // XXX: NSS is off spec and sends obfuscated_ticket_age as seconds - clientAge = time.Duration(hs.clientHello.psks[i].obfTicketAge-s.ageAdd) * time.Second - if clientAge-serverAge > ticketAgeSkewAllowance || clientAge-serverAge < -ticketAgeSkewAllowance { - continue - } - } - - // This enforces the stricter 0-RTT requirements on all ticket uses. - // The benefit of using PSK+ECDHE without 0-RTT are small enough that - // we can give them up in the edge case of changed suite or ALPN or SNI. - if s.suite != hs.suite.id { - continue - } - if s.alpnProtocol != hs.c.clientProtocol { - continue - } - if s.SNI != hs.c.serverName { - continue - } - - hs.keySchedule.setSecret(s.pskSecret) - binderKey := hs.keySchedule.deriveSecret(secretResumptionPskBinder) - binderFinishedKey := hkdfExpandLabel(hash, binderKey, nil, "finished", hashSize) - chHash := hash.New() - chHash.Write(hs.clientHello.rawTruncated) - expectedBinder := hmacOfSum(hash, chHash, binderFinishedKey) - - if subtle.ConstantTimeCompare(expectedBinder, hs.clientHello.psks[i].binder) != 1 { - return false, alertDecryptError - } - - if i == 0 && hs.clientHello.earlyData { - // This is a ticket intended to be used for 0-RTT - if s.maxEarlyDataLen == 0 { - // But we had not tagged it as such. - return false, alertIllegalParameter - } - if hs.c.config.Accept0RTTData { - hs.c.binder = expectedBinder - hs.c.ticketMaxEarlyData = int64(s.maxEarlyDataLen) - hs.hello13Enc.earlyData = true - } - } - hs.hello.psk = true - hs.hello.pskIdentity = uint16(i) - return true, alertSuccess - } - - return false, alertSuccess -} - -func (hs *serverHandshakeState) sendSessionTicket13() error { - c := hs.c - if c.config.SessionTicketsDisabled { - return nil - } - - foundDHE := false - for _, mode := range hs.clientHello.pskKeyExchangeModes { - if mode == pskDHEKeyExchange { - foundDHE = true - break - } - } - if !foundDHE { - return nil - } - - resumptionMasterSecret := hs.keySchedule.deriveSecret(secretResumption) - - ageAddBuf := make([]byte, 4) - sessionState := &sessionState13{ - vers: c.vers, - suite: hs.suite.id, - createdAt: uint64(time.Now().Unix()), - alpnProtocol: c.clientProtocol, - SNI: c.serverName, - maxEarlyDataLen: c.config.Max0RTTDataSize, - } - hash := hashForSuite(hs.suite) - - for i := 0; i < numSessionTickets; i++ { - if _, err := io.ReadFull(c.config.rand(), ageAddBuf); err != nil { - c.sendAlert(alertInternalError) - return err - } - sessionState.ageAdd = uint32(ageAddBuf[0])<<24 | uint32(ageAddBuf[1])<<16 | - uint32(ageAddBuf[2])<<8 | uint32(ageAddBuf[3]) - // ticketNonce must be a unique value for this connection. - // Assume there are no more than 255 tickets, otherwise two - // tickets might have the same PSK which could be a problem if - // one of them is compromised. - ticketNonce := []byte{byte(i)} - sessionState.pskSecret = hkdfExpandLabel(hash, resumptionMasterSecret, ticketNonce, "resumption", hash.Size()) - ticket := sessionState.marshal() - var err error - if c.config.SessionTicketSealer != nil { - cs := c.ConnectionState() - ticket, err = c.config.SessionTicketSealer.Seal(&cs, ticket) - } else { - ticket, err = c.encryptTicket(ticket) - } - if err != nil { - c.sendAlert(alertInternalError) - return err - } - if ticket == nil { - continue - } - ticketMsg := &newSessionTicketMsg13{ - lifetime: 24 * 3600, // TODO(filippo) - maxEarlyDataLength: c.config.Max0RTTDataSize, - withEarlyDataInfo: c.config.Max0RTTDataSize > 0, - ageAdd: sessionState.ageAdd, - nonce: ticketNonce, - ticket: ticket, - } - if _, err := c.writeRecord(recordTypeHandshake, ticketMsg.marshal()); err != nil { - return err - } - } - - return nil -} - -func (hs *serverHandshakeState) traceErr(err error) { - if err == nil { - return - } - if os.Getenv("TLSDEBUG") == "error" { - if hs != nil && hs.clientHello != nil { - os.Stderr.WriteString(hex.Dump(hs.clientHello.marshal())) - } else if err == io.EOF { - return // don't stack trace on EOF before CH - } - fmt.Fprintf(os.Stderr, "\n%s\n", debug.Stack()) - } - if os.Getenv("TLSDEBUG") == "short" { - var pcs [4]uintptr - frames := runtime.CallersFrames(pcs[0:runtime.Callers(3, pcs[:])]) - for { - frame, more := frames.Next() - if frame.Function != "crypto/tls.(*halfConn).setErrorLocked" && - frame.Function != "crypto/tls.(*Conn).sendAlertLocked" && - frame.Function != "crypto/tls.(*Conn).sendAlert" { - file := frame.File[strings.LastIndex(frame.File, "/")+1:] - log.Printf("%s:%d (%s): %v", file, frame.Line, frame.Function, err) - return - } - if !more { - break - } - } - } -} - -func getCertsFromEntries(certEntries []certificateEntry) [][]byte { - certs := make([][]byte, len(certEntries)) - for i, cert := range certEntries { - certs[i] = cert.data - } - return certs -} - -func (hs *clientHandshakeState) processEncryptedExtensions(ee *encryptedExtensionsMsg) error { - c := hs.c - if ee.alpnProtocol != "" { - c.clientProtocol = ee.alpnProtocol - c.clientProtocolFallback = false - } - if hs.c.config.ReceivedExtensions != nil { - return hs.c.config.ReceivedExtensions(typeEncryptedExtensions, ee.additionalExtensions) - } - return nil -} - -func verifyPeerHandshakeSignature( - certVerify *certificateVerifyMsg, - pubKey crypto.PublicKey, - signAlgosKnown []SignatureScheme, - transHash []byte, - contextString string) (error, alert) { - - _, sigType, hashFunc, err := pickSignatureAlgorithm( - pubKey, - []SignatureScheme{certVerify.signatureAlgorithm}, - signAlgosKnown, - VersionTLS13) - if err != nil { - return err, alertHandshakeFailure - } - - digest := prepareDigitallySigned(hashFunc, contextString, transHash) - err = verifyHandshakeSignature(sigType, pubKey, hashFunc, digest, certVerify.signature) - - if err != nil { - return err, alertDecryptError - } - - return nil, alertSuccess -} - -func (hs *clientHandshakeState) getCertificate13(certReq *certificateRequestMsg13) (*Certificate, error) { - certReq12 := &certificateRequestMsg{ - hasSignatureAndHash: true, - supportedSignatureAlgorithms: certReq.supportedSignatureAlgorithms, - certificateAuthorities: certReq.certificateAuthorities, - } - - var rsaAvail, ecdsaAvail bool - for _, sigAlg := range certReq.supportedSignatureAlgorithms { - switch signatureFromSignatureScheme(sigAlg) { - case signaturePKCS1v15, signatureRSAPSS: - rsaAvail = true - case signatureECDSA: - ecdsaAvail = true - } - } - if rsaAvail { - certReq12.certificateTypes = append(certReq12.certificateTypes, certTypeRSASign) - } - if ecdsaAvail { - certReq12.certificateTypes = append(certReq12.certificateTypes, certTypeECDSASign) - } - - return hs.getCertificate(certReq12) -} - -func (hs *clientHandshakeState) sendCertificate13(chainToSend *Certificate, certReq *certificateRequestMsg13) error { - c := hs.c - - certEntries := []certificateEntry{} - for _, cert := range chainToSend.Certificate { - certEntries = append(certEntries, certificateEntry{data: cert}) - } - certMsg := &certificateMsg13{certificates: certEntries} - - hs.keySchedule.write(certMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { - return err - } - - if len(certEntries) == 0 { - // No client cert available, nothing to sign. - return nil - } - - key, ok := chainToSend.PrivateKey.(crypto.Signer) - if !ok { - c.sendAlert(alertInternalError) - return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) - } - - signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, hs.hello.supportedSignatureAlgorithms, c.vers) - if err != nil { - hs.c.sendAlert(alertHandshakeFailure) - return err - } - - digest := prepareDigitallySigned(hashFunc, "TLS 1.3, client CertificateVerify", hs.keySchedule.transcriptHash.Sum(nil)) - signOpts := crypto.SignerOpts(hashFunc) - if sigType == signatureRSAPSS { - signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc} - } - signature, err := key.Sign(c.config.rand(), digest, signOpts) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - verifyMsg := &certificateVerifyMsg{ - hasSignatureAndHash: true, - signatureAlgorithm: signatureAlgorithm, - signature: signature, - } - hs.keySchedule.write(verifyMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, verifyMsg.marshal()); err != nil { - return err - } - - return nil -} - -func (hs *clientHandshakeState) doTLS13Handshake() error { - c := hs.c - hash := hashForSuite(hs.suite) - hashSize := hash.Size() - serverHello := hs.serverHello - c.scts = serverHello.scts - - // middlebox compatibility mode, send CCS before second flight. - if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { - return err - } - - // TODO check if keyshare is unacceptable, raise HRR. - - clientKS := hs.hello.keyShares[0] - if serverHello.keyShare.group != clientKS.group { - c.sendAlert(alertIllegalParameter) - return errors.New("bad or missing key share from server") - } - - // 0-RTT is not supported yet, so use an empty PSK. - hs.keySchedule.setSecret(nil) - ecdheSecret := c.deriveDHESecret(serverHello.keyShare, hs.privateKey) - if ecdheSecret == nil { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: bad ECDHE server share") - } - - // Calculate handshake secrets. - hs.keySchedule.setSecret(ecdheSecret) - clientHandshakeSecret := hs.keySchedule.deriveSecret(secretHandshakeClient) - if c.hand.Len() > 0 { - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: unexpected data after Server Hello") - } - serverHandshakeSecret := hs.keySchedule.deriveSecret(secretHandshakeServer) - c.in.exportKey(hs.keySchedule.suite, serverHandshakeSecret) - // Already the sender key yet, when using an alternative record layer. - // QUIC needs the handshake write key in order to acknowledge Handshake packets. - c.out.exportKey(hs.keySchedule.suite, clientHandshakeSecret) - // Do not change the sender key yet, the server must authenticate first. - c.in.setKey(c.vers, hs.keySchedule.suite, serverHandshakeSecret) - - // Calculate MAC key for Finished messages. - serverFinishedKey := hkdfExpandLabel(hash, serverHandshakeSecret, nil, "finished", hashSize) - clientFinishedKey := hkdfExpandLabel(hash, clientHandshakeSecret, nil, "finished", hashSize) - - msg, err := c.readHandshake() - if err != nil { - return err - } - encryptedExtensions, ok := msg.(*encryptedExtensionsMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(encryptedExtensions, msg) - } - if err := hs.processEncryptedExtensions(encryptedExtensions); err != nil { - return err - } - hs.keySchedule.write(encryptedExtensions.marshal()) - - // PSKs are not supported, so receive Certificate message. - msg, err = c.readHandshake() - if err != nil { - return err - } - - var chainToSend *Certificate - certReq, isCertRequested := msg.(*certificateRequestMsg13) - if isCertRequested { - hs.keySchedule.write(certReq.marshal()) - - if chainToSend, err = hs.getCertificate13(certReq); err != nil { - c.sendAlert(alertInternalError) - return err - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - certMsg, ok := msg.(*certificateMsg13) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } - hs.keySchedule.write(certMsg.marshal()) - - // Validate certificates. - certs := getCertsFromEntries(certMsg.certificates) - if err := hs.processCertsFromServer(certs); err != nil { - return err - } - - // Receive CertificateVerify message. - msg, err = c.readHandshake() - if err != nil { - return err - } - certVerifyMsg, ok := msg.(*certificateVerifyMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certVerifyMsg, msg) - } - - // Validate the DC if present. The DC is only processed if the extension was - // indicated by the ClientHello; otherwise this call will result in an - // "illegal_parameter" alert. - if len(certMsg.certificates) > 0 { - if err := hs.processDelegatedCredentialFromServer( - certMsg.certificates[0].delegatedCredential, - certVerifyMsg.signatureAlgorithm); err != nil { - return err - } - } - - // Set the public key used to verify the handshake. - pk := hs.c.peerCertificates[0].PublicKey - - // If the delegated credential extension has successfully been negotiated, - // then the CertificateVerify signature will have been produced with the - // DelegatedCredential's private key. - if hs.c.verifiedDc != nil { - pk = hs.c.verifiedDc.cred.publicKey - } - - // Verify the handshake signature. - err, alertCode := verifyPeerHandshakeSignature( - certVerifyMsg, - pk, - hs.hello.supportedSignatureAlgorithms, - hs.keySchedule.transcriptHash.Sum(nil), - "TLS 1.3, server CertificateVerify") - if err != nil { - c.sendAlert(alertCode) - return err - } - hs.keySchedule.write(certVerifyMsg.marshal()) - - // Receive Finished message. - msg, err = c.readHandshake() - if err != nil { - return err - } - serverFinished, ok := msg.(*finishedMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(serverFinished, msg) - } - // Validate server Finished hash. - expectedVerifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, serverFinishedKey) - if subtle.ConstantTimeCompare(expectedVerifyData, serverFinished.verifyData) != 1 { - c.sendAlert(alertDecryptError) - return errors.New("tls: server's Finished message is incorrect") - } - hs.keySchedule.write(serverFinished.marshal()) - - // Server has authenticated itself. Calculate application traffic secrets. - hs.keySchedule.setSecret(nil) // derive master secret - - // Change outbound handshake cipher for final step - c.out.setKey(c.vers, hs.keySchedule.suite, clientHandshakeSecret) - - clientAppTrafficSecret := hs.keySchedule.deriveSecret(secretApplicationClient) - serverAppTrafficSecret := hs.keySchedule.deriveSecret(secretApplicationServer) - // TODO store initial traffic secret key for KeyUpdate GH #85 - - // Client auth requires sending a (possibly empty) Certificate followed - // by a CertificateVerify message (if there was an actual certificate). - if isCertRequested { - if err := hs.sendCertificate13(chainToSend, certReq); err != nil { - return err - } - } - - // Send Finished - verifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, clientFinishedKey) - clientFinished := &finishedMsg{ - verifyData: verifyData, - } - if _, err := c.writeRecord(recordTypeHandshake, clientFinished.marshal()); err != nil { - return err - } - - // Handshake done, set application traffic secret - // TODO store initial traffic secret key for KeyUpdate GH #85 - c.out.exportKey(hs.keySchedule.suite, clientAppTrafficSecret) - c.out.setKey(c.vers, hs.keySchedule.suite, clientAppTrafficSecret) - if c.hand.Len() > 0 { - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: unexpected data after handshake") - } - c.in.exportKey(hs.keySchedule.suite, serverAppTrafficSecret) - c.in.setKey(c.vers, hs.keySchedule.suite, serverAppTrafficSecret) - return nil -} - -// supportedSigAlgorithmsCert iterates over schemes and filters out those algorithms -// which are not supported for certificate verification. -func supportedSigAlgorithmsCert(schemes []SignatureScheme) (ret []SignatureScheme) { - for _, sig := range schemes { - // X509 doesn't support PSS signatures - if !signatureSchemeIsPSS(sig) { - ret = append(ret, sig) - } - } - return -} - -// Functions below implement dhKex interface for different DH shared secret agreements - -// KEX: P-256, P-384, P-512 KEX -func (kexNist) generate(c *Conn, groupId CurveID) (private []byte, ks keyShare, err error) { - // never fails - curve, _ := curveForCurveID(groupId) - private, x, y, err := elliptic.GenerateKey(curve, c.config.rand()) - if err != nil { - return nil, keyShare{}, err - } - ks.group = groupId - ks.data = elliptic.Marshal(curve, x, y) - return -} -func (kexNist) derive(c *Conn, ks keyShare, secretKey []byte) []byte { - // never fails - curve, _ := curveForCurveID(ks.group) - x, y := elliptic.Unmarshal(curve, ks.data) - if x == nil { - return nil - } - x, _ = curve.ScalarMult(x, y, secretKey) - xBytes := x.Bytes() - curveSize := (curve.Params().BitSize + 8 - 1) >> 3 - if len(xBytes) == curveSize { - return xBytes - } - buf := make([]byte, curveSize) - copy(buf[len(buf)-len(xBytes):], xBytes) - return buf -} - -// KEX: X25519 -func (kexX25519) generate(c *Conn, groupId CurveID) ([]byte, keyShare, error) { - var scalar, public [x25519SharedSecretSz]byte - if _, err := io.ReadFull(c.config.rand(), scalar[:]); err != nil { - return nil, keyShare{}, err - } - curve25519.ScalarBaseMult(&public, &scalar) - return scalar[:], keyShare{group: X25519, data: public[:]}, nil -} - -func (kexX25519) derive(c *Conn, ks keyShare, secretKey []byte) []byte { - var theirPublic, sharedKey, scalar [x25519SharedSecretSz]byte - if len(ks.data) != x25519SharedSecretSz { - return nil - } - copy(theirPublic[:], ks.data) - copy(scalar[:], secretKey) - curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic) - return sharedKey[:] -} - -// KEX: SIDH/503 -func (kexSIDHp503) generate(c *Conn, groupId CurveID) ([]byte, keyShare, error) { - var variant, _ = getSidhKeyVariant(c.isClient) - var prvKey = sidh.NewPrivateKey(sidh.FP_503, variant) - if prvKey.Generate(c.config.rand()) != nil { - return nil, keyShare{}, errors.New("tls: private SIDH key generation failed") - } - pubKey := prvKey.GeneratePublicKey() - return prvKey.Export(), keyShare{group: 0 /*UNUSED*/, data: pubKey.Export()}, nil -} - -func (kexSIDHp503) derive(c *Conn, ks keyShare, key []byte) []byte { - var prvVariant, pubVariant = getSidhKeyVariant(c.isClient) - var prvKeySize = P503PrvKeySz - - if len(ks.data) != P503PubKeySz || len(key) != prvKeySize { - return nil - } - - prvKey := sidh.NewPrivateKey(sidh.FP_503, prvVariant) - pubKey := sidh.NewPublicKey(sidh.FP_503, pubVariant) - - if err := prvKey.Import(key); err != nil { - return nil - } - if err := pubKey.Import(ks.data); err != nil { - return nil - } - - // Never fails - sharedKey, _ := sidh.DeriveSecret(prvKey, pubKey) - return sharedKey -} - -// KEX Hybrid SIDH/503-X25519 -func (kex *kexHybridSIDHp503X25519) generate(c *Conn, groupId CurveID) (private []byte, ks keyShare, err error) { - var pubHybrid [SIDHp503Curve25519PubKeySz]byte - var prvHybrid [SIDHp503Curve25519PrvKeySz]byte - - // Generate ephemeral key for classic x25519 - private, ks, err = kex.classicKEX.generate(c, groupId) - if err != nil { - return - } - copy(prvHybrid[:], private) - copy(pubHybrid[:], ks.data) - - // Generate PQ ephemeral key for SIDH - private, ks, err = kex.pqKEX.generate(c, groupId) - if err != nil { - return - } - copy(prvHybrid[x25519SharedSecretSz:], private) - copy(pubHybrid[x25519SharedSecretSz:], ks.data) - return prvHybrid[:], keyShare{group: HybridSIDHp503Curve25519, data: pubHybrid[:]}, nil -} - -func (kex *kexHybridSIDHp503X25519) derive(c *Conn, ks keyShare, key []byte) []byte { - var sharedKey [SIDHp503Curve25519SharedKeySz]byte - var ret []byte - var tmpKs keyShare - - // Key agreement for classic - tmpKs.group = X25519 - tmpKs.data = ks.data[:x25519SharedSecretSz] - ret = kex.classicKEX.derive(c, tmpKs, key[:x25519SharedSecretSz]) - if ret == nil { - return nil - } - copy(sharedKey[:], ret) - - // Key agreement for PQ - tmpKs.group = 0 /*UNUSED*/ - tmpKs.data = ks.data[x25519SharedSecretSz:] - ret = kex.pqKEX.derive(c, tmpKs, key[x25519SharedSecretSz:]) - if ret == nil { - return nil - } - copy(sharedKey[x25519SharedSecretSz:], ret) - return sharedKey[:] -} diff --git a/external/github.com/marten-seemann/qtls/LICENSE b/external/github.com/marten-seemann/qtls/LICENSE deleted file mode 100644 index 8c1dcdaf5..000000000 --- a/external/github.com/marten-seemann/qtls/LICENSE +++ /dev/null @@ -1,63 +0,0 @@ -Copyright (c) 2018 Cloudflare. 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 Cloudflare 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. - -======================================================================== - -The code for TLSv1.2 and older TLS versions was derived from the -Golang standard library , available -under the following BSD license: - -======================================================================== - -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. diff --git a/external/github.com/marten-seemann/qtls/README.md b/external/github.com/marten-seemann/qtls/README.md deleted file mode 100644 index be5c08c1d..000000000 --- a/external/github.com/marten-seemann/qtls/README.md +++ /dev/null @@ -1,107 +0,0 @@ -``` - _____ _ ____ _ _ -|_ _| | / ___| | |_ _ __(_)___ - | | | | \___ \ _____| __| '__| / __| - | | | |___ ___) |_____| |_| | | \__ \ - |_| |_____|____/ \__|_| |_|___/ - -``` - -crypto/tls, now with 100% more 1.3. - -THE API IS NOT STABLE AND DOCUMENTATION IS NOT GUARANTEED. - -[![Build Status](https://travis-ci.org/cloudflare/tls-tris.svg?branch=master)](https://travis-ci.org/cloudflare/tls-tris) - -## Usage - -Since `crypto/tls` is very deeply (and not that elegantly) coupled with the Go stdlib, -tls-tris shouldn't be used as an external package. It is also impossible to vendor it -as `crypto/tls` because stdlib packages would import the standard one and mismatch. - -So, to build with tls-tris, you need to use a custom GOROOT. - -A script is provided that will take care of it for you: `./_dev/go.sh`. -Just use that instead of the `go` tool. - -The script also transparently fetches the custom Cloudflare Go 1.10 compiler with the required backports. - -## Development - -### Dependencies - -Copy paste line bellow to install all required dependencies: - -* ArchLinux: -``` -pacman -S go docker gcc git make patch python2 python-docker rsync -``` - -* Debian: -``` -apt-get install build-essential docker go patch python python-pip rsync -pip install setuptools -pip install docker -``` - -* Ubuntu (18.04) : -``` -apt-get update -apt-get install build-essential docker docker.io golang patch python python-pip rsync sudo -pip install setuptools -pip install docker -sudo usermod -a -G docker $USER -``` - -Similar dependencies can be found on any UNIX based system/distribution. - -### Building - -There are number of things that need to be setup before running tests. Most important step is to copy ``go env GOROOT`` directory to ``_dev`` and swap TLS implementation and recompile GO. Then for testing we use go implementation from ``_dev/GOROOT``. - -``` -git clone https://github.com/cloudflare/tls-tris.git -cd tls-tris; cp _dev/utils/pre-commit .git/hooks/ -make -f _dev/Makefile build-all -``` - -### Testing - -We run 3 kinds of test:. - -* Unit testing:
``make -f _dev/Makefile test-unit`` -* Testing against BoringSSL test suite:
``make -f _dev/Makefile test-bogo`` -* Compatibility testing (see below):
``make -f _dev/Makefile test-interop`` - -To run all the tests in one go use: -``` -make -f _dev/Makefile test -``` - -### Testing interoperability with 3rd party libraries - -In order to ensure compatibility we are testing our implementation against BoringSSL, NSS and PicoTLS. - -Makefile has a specific target for testing interoperability with external libraries. Following command can be used in order to run such test: - -``` -make -f _dev/Makefile test-interop -``` - -The makefile target is just a wrapper and it executes ``_dev/interop_test_runner`` script written in python. The script implements interoperability tests using ``python unittest`` framework. - -Script can be started from command line directly. For example: - -``` -> ./interop_test_runner -v InteropServer_NSS.test_zero_rtt -test_zero_rtt (__main__.InteropServer_NSS) ... ok - ----------------------------------------------------------------------- -Ran 1 test in 8.765s - -OK -``` - -### Debugging - -When the environment variable `TLSDEBUG` is set to `error`, Tris will print a hexdump of the Client Hello and a stack trace if an handshake error occurs. If the value is `short`, only the error and the first meaningful stack frame are printed. diff --git a/external/github.com/marten-seemann/qtls/alert.go b/external/github.com/marten-seemann/qtls/alert.go deleted file mode 100644 index bfd552d53..000000000 --- a/external/github.com/marten-seemann/qtls/alert.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2009 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 qtls - -import "strconv" - -type alert uint8 - -const ( - // alert level - alertLevelWarning = 1 - alertLevelError = 2 -) - -const ( - alertCloseNotify alert = 0 - alertUnexpectedMessage alert = 10 - alertBadRecordMAC alert = 20 - alertDecryptionFailed alert = 21 - alertRecordOverflow alert = 22 - alertDecompressionFailure alert = 30 - alertHandshakeFailure alert = 40 - alertBadCertificate alert = 42 - alertUnsupportedCertificate alert = 43 - alertCertificateRevoked alert = 44 - alertCertificateExpired alert = 45 - alertCertificateUnknown alert = 46 - alertIllegalParameter alert = 47 - alertUnknownCA alert = 48 - alertAccessDenied alert = 49 - alertDecodeError alert = 50 - alertDecryptError alert = 51 - alertProtocolVersion alert = 70 - alertInsufficientSecurity alert = 71 - alertInternalError alert = 80 - alertInappropriateFallback alert = 86 - alertUserCanceled alert = 90 - alertNoRenegotiation alert = 100 - alertUnsupportedExtension alert = 110 - alertCertificateRequired alert = 116 - alertNoApplicationProtocol alert = 120 - alertSuccess alert = 255 // dummy value returned by unmarshal functions -) - -var alertText = map[alert]string{ - alertCloseNotify: "close notify", - alertUnexpectedMessage: "unexpected message", - alertBadRecordMAC: "bad record MAC", - alertDecryptionFailed: "decryption failed", - alertRecordOverflow: "record overflow", - alertDecompressionFailure: "decompression failure", - alertHandshakeFailure: "handshake failure", - alertBadCertificate: "bad certificate", - alertUnsupportedCertificate: "unsupported certificate", - alertCertificateRevoked: "revoked certificate", - alertCertificateExpired: "expired certificate", - alertCertificateUnknown: "unknown certificate", - alertIllegalParameter: "illegal parameter", - alertUnknownCA: "unknown certificate authority", - alertAccessDenied: "access denied", - alertDecodeError: "error decoding message", - alertDecryptError: "error decrypting message", - alertProtocolVersion: "protocol version not supported", - alertInsufficientSecurity: "insufficient security level", - alertInternalError: "internal error", - alertInappropriateFallback: "inappropriate fallback", - alertUserCanceled: "user canceled", - alertNoRenegotiation: "no renegotiation", - alertNoApplicationProtocol: "no application protocol", -} - -func (e alert) String() string { - s, ok := alertText[e] - if ok { - return "tls: " + s - } - return "tls: alert(" + strconv.Itoa(int(e)) + ")" -} - -func (e alert) Error() string { - return e.String() -} diff --git a/external/github.com/marten-seemann/qtls/auth.go b/external/github.com/marten-seemann/qtls/auth.go deleted file mode 100644 index a4e101f6a..000000000 --- a/external/github.com/marten-seemann/qtls/auth.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2017 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 qtls - -import ( - "crypto" - "crypto/ecdsa" - "crypto/rsa" - "encoding/asn1" - "errors" - "fmt" -) - -// pickSignatureAlgorithm selects a signature algorithm that is compatible with -// the given public key and the list of algorithms from both sides of connection. -// The lists of signature algorithms (peerSigAlgs and ourSigAlgs) are ignored -// for tlsVersion < VersionTLS12. -// -// The returned SignatureScheme codepoint is only meaningful for TLS 1.2 and newer -// previous TLS versions have a fixed hash function. -func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []SignatureScheme, tlsVersion uint16) (SignatureScheme, uint8, crypto.Hash, error) { - if tlsVersion < VersionTLS12 || len(peerSigAlgs) == 0 { - // If the client didn't specify any signature_algorithms - // extension then we can assume that it supports SHA1. See - // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 - switch pubkey.(type) { - case *rsa.PublicKey: - if tlsVersion < VersionTLS12 { - return 0, signaturePKCS1v15, crypto.MD5SHA1, nil - } else { - return PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1, nil - } - case *ecdsa.PublicKey: - return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil - default: - return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey) - } - } - for _, sigAlg := range peerSigAlgs { - if !isSupportedSignatureAlgorithm(sigAlg, ourSigAlgs) { - continue - } - hashAlg, err := lookupTLSHash(sigAlg) - if err != nil { - panic("tls: supported signature algorithm has an unknown hash function") - } - sigType := signatureFromSignatureScheme(sigAlg) - if (sigType == signaturePKCS1v15 || hashAlg == crypto.SHA1) && tlsVersion >= VersionTLS13 { - // TLS 1.3 forbids RSASSA-PKCS1-v1_5 and SHA-1 for - // handshake messages. - continue - } - switch pubkey.(type) { - case *rsa.PublicKey: - if sigType == signaturePKCS1v15 || sigType == signatureRSAPSS { - return sigAlg, sigType, hashAlg, nil - } - case *ecdsa.PublicKey: - if sigType == signatureECDSA { - return sigAlg, sigType, hashAlg, nil - } - } - } - return 0, 0, 0, errors.New("tls: peer doesn't support any common signature algorithms") -} - -// verifyHandshakeSignature verifies a signature against pre-hashed handshake -// contents. -func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, digest, sig []byte) error { - switch sigType { - case signatureECDSA: - pubKey, ok := pubkey.(*ecdsa.PublicKey) - if !ok { - return errors.New("tls: ECDSA signing requires a ECDSA public key") - } - ecdsaSig := new(ecdsaSignature) - if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil { - return err - } - if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { - return errors.New("tls: ECDSA signature contained zero or negative values") - } - if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) { - return errors.New("tls: ECDSA verification failure") - } - case signaturePKCS1v15: - pubKey, ok := pubkey.(*rsa.PublicKey) - if !ok { - return errors.New("tls: RSA signing requires a RSA public key") - } - if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil { - return err - } - case signatureRSAPSS: - pubKey, ok := pubkey.(*rsa.PublicKey) - if !ok { - return errors.New("tls: RSA signing requires a RSA public key") - } - signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash} - if err := rsa.VerifyPSS(pubKey, hashFunc, digest, sig, signOpts); err != nil { - return err - } - default: - return errors.New("tls: unknown signature algorithm") - } - return nil -} diff --git a/external/github.com/marten-seemann/qtls/cipher_suites.go b/external/github.com/marten-seemann/qtls/cipher_suites.go deleted file mode 100644 index 781c32282..000000000 --- a/external/github.com/marten-seemann/qtls/cipher_suites.go +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright 2010 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 qtls - -import ( - "crypto" - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/hmac" - "crypto/rc4" - "crypto/sha1" - "crypto/sha256" - "hash" - - "golang.org/x/crypto/chacha20poly1305" -) - -// a keyAgreement implements the client and server side of a TLS key agreement -// protocol by generating and processing key exchange messages. -type keyAgreement interface { - // On the server side, the first two methods are called in order. - - // In the case that the key agreement protocol doesn't use a - // ServerKeyExchange message, generateServerKeyExchange can return nil, - // nil. - generateServerKeyExchange(*Config, crypto.PrivateKey, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error) - processClientKeyExchange(*Config, crypto.PrivateKey, *clientKeyExchangeMsg, uint16) ([]byte, error) - - // On the client side, the next two methods are called in order. - - // This method may not be called if the server doesn't send a - // ServerKeyExchange message. - processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, crypto.PublicKey, *serverKeyExchangeMsg) error - generateClientKeyExchange(*Config, *clientHelloMsg, crypto.PublicKey) ([]byte, *clientKeyExchangeMsg, error) -} - -const ( - // suiteECDH indicates that the cipher suite involves elliptic curve - // Diffie-Hellman. This means that it should only be selected when the - // client indicates that it supports ECC with a curve and point format - // that we're happy with. - suiteECDHE = 1 << iota - // suiteECDSA indicates that the cipher suite involves an ECDSA - // signature and therefore may only be selected when the server's - // certificate is ECDSA. If this is not set then the cipher suite is - // RSA based. - suiteECDSA - // suiteTLS12 indicates that the cipher suite should only be advertised - // and accepted when using TLS 1.2. - suiteTLS12 - // suiteTLS13 indicates that the ones and only cipher suites to be - // advertised and accepted when using TLS 1.3. - suiteTLS13 - // suiteSHA384 indicates that the cipher suite uses SHA384 as the - // handshake hash. - suiteSHA384 - // suiteDefaultOff indicates that this cipher suite is not included by - // default. - suiteDefaultOff -) - -// A cipherSuite is a specific combination of key agreement, cipher and MAC -// function. -type cipherSuite struct { - id uint16 - // the lengths, in bytes, of the key material needed for each component. - keyLen int - macLen int - ivLen int - ka func(version uint16) keyAgreement - // flags is a bitmask of the suite* values, above. - flags int - cipher func(key, iv []byte, isRead bool) interface{} - mac func(version uint16, macKey []byte) macFunction - aead func(key, fixedNonce []byte) cipher.AEAD -} - -type CipherSuite struct { - cipherSuite -} - -func (c *CipherSuite) Hash() crypto.Hash { return hashForSuite(&c.cipherSuite) } -func (c *CipherSuite) KeyLen() int { return c.keyLen } -func (c *CipherSuite) IVLen() int { return c.ivLen } -func (c *CipherSuite) AEAD(key, fixedNonce []byte) cipher.AEAD { return c.aead(key, fixedNonce) } - -var cipherSuites = []*cipherSuite{ - // TLS 1.3 ciphersuites specify only the AEAD and the HKDF hash. - {TLS_CHACHA20_POLY1305_SHA256, 32, 0, 12, nil, suiteTLS13, nil, nil, aeadChaCha20Poly1305}, - {TLS_AES_128_GCM_SHA256, 16, 0, 12, nil, suiteTLS13, nil, nil, aeadAESGCM13}, - {TLS_AES_256_GCM_SHA384, 32, 0, 12, nil, suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM13}, - - // Ciphersuite order is chosen so that ECDHE comes before plain RSA and - // AEADs are the top preference. - {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305}, - {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadChaCha20Poly1305}, - {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM12}, - {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM12}, - {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM12}, - {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM12}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, - {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, - {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, - {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM12}, - {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM12}, - {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil}, - {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, - {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, - {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, - {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil}, - - // RC4-based cipher suites are disabled by default. - {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil}, - {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil}, - {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil}, -} - -func cipherRC4(key, iv []byte, isRead bool) interface{} { - cipher, _ := rc4.NewCipher(key) - return cipher -} - -func cipher3DES(key, iv []byte, isRead bool) interface{} { - block, _ := des.NewTripleDESCipher(key) - if isRead { - return cipher.NewCBCDecrypter(block, iv) - } - return cipher.NewCBCEncrypter(block, iv) -} - -func cipherAES(key, iv []byte, isRead bool) interface{} { - block, _ := aes.NewCipher(key) - if isRead { - return cipher.NewCBCDecrypter(block, iv) - } - return cipher.NewCBCEncrypter(block, iv) -} - -// macSHA1 returns a macFunction for the given protocol version. -func macSHA1(version uint16, key []byte) macFunction { - if version == VersionSSL30 { - mac := ssl30MAC{ - h: sha1.New(), - key: make([]byte, len(key)), - } - copy(mac.key, key) - return mac - } - return tls10MAC{hmac.New(newConstantTimeHash(sha1.New), key)} -} - -// macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2 -// so the given version is ignored. -func macSHA256(version uint16, key []byte) macFunction { - return tls10MAC{hmac.New(sha256.New, key)} -} - -type macFunction interface { - Size() int - MAC(digestBuf, seq, header, data, extra []byte) []byte -} - -type aead interface { - cipher.AEAD - - // explicitIVLen returns the number of bytes used by the explicit nonce - // that is included in the record. This is eight for older AEADs and - // zero for modern ones. - explicitNonceLen() int -} - -// fixedNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to -// each call. -type fixedNonceAEAD struct { - // nonce contains the fixed part of the nonce in the first four bytes. - nonce [12]byte - aead cipher.AEAD -} - -func (f *fixedNonceAEAD) NonceSize() int { return 8 } - -// Overhead returns the maximum difference between the lengths of a -// plaintext and its ciphertext. -func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() } -func (f *fixedNonceAEAD) explicitNonceLen() int { return 8 } - -func (f *fixedNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte { - copy(f.nonce[4:], nonce) - return f.aead.Seal(out, f.nonce[:], plaintext, additionalData) -} - -func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) { - copy(f.nonce[4:], nonce) - return f.aead.Open(out, f.nonce[:], plaintext, additionalData) -} - -// xoredNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce -// before each call. -type xorNonceAEAD struct { - nonceMask [12]byte - aead cipher.AEAD -} - -func (f *xorNonceAEAD) NonceSize() int { return 8 } -func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() } -func (f *xorNonceAEAD) explicitNonceLen() int { return 0 } - -func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte { - for i, b := range nonce { - f.nonceMask[4+i] ^= b - } - result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData) - for i, b := range nonce { - f.nonceMask[4+i] ^= b - } - - return result -} - -func (f *xorNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) { - for i, b := range nonce { - f.nonceMask[4+i] ^= b - } - result, err := f.aead.Open(out, f.nonceMask[:], plaintext, additionalData) - for i, b := range nonce { - f.nonceMask[4+i] ^= b - } - - return result, err -} - -func aeadAESGCM12(key, fixedNonce []byte) cipher.AEAD { - aes, err := aes.NewCipher(key) - if err != nil { - panic(err) - } - aead, err := cipher.NewGCM(aes) - if err != nil { - panic(err) - } - - ret := &fixedNonceAEAD{aead: aead} - copy(ret.nonce[:], fixedNonce) - return ret -} - -// AEADAESGCM13 creates a new AES-GCM AEAD for TLS 1.3 -func AEADAESGCM13(key, fixedNonce []byte) cipher.AEAD { - return aeadAESGCM13(key, fixedNonce) -} - -func aeadAESGCM13(key, fixedNonce []byte) cipher.AEAD { - aes, err := aes.NewCipher(key) - if err != nil { - panic(err) - } - aead, err := cipher.NewGCM(aes) - if err != nil { - panic(err) - } - - ret := &xorNonceAEAD{aead: aead} - copy(ret.nonceMask[:], fixedNonce) - return ret -} - -func aeadChaCha20Poly1305(key, fixedNonce []byte) cipher.AEAD { - aead, err := chacha20poly1305.New(key) - if err != nil { - panic(err) - } - - ret := &xorNonceAEAD{aead: aead} - copy(ret.nonceMask[:], fixedNonce) - return ret -} - -// ssl30MAC implements the SSLv3 MAC function, as defined in -// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1 -type ssl30MAC struct { - h hash.Hash - key []byte -} - -func (s ssl30MAC) Size() int { - return s.h.Size() -} - -var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36} - -var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c} - -// MAC does not offer constant timing guarantees for SSL v3.0, since it's deemed -// useless considering the similar, protocol-level POODLE vulnerability. -func (s ssl30MAC) MAC(digestBuf, seq, header, data, extra []byte) []byte { - padLength := 48 - if s.h.Size() == 20 { - padLength = 40 - } - - s.h.Reset() - s.h.Write(s.key) - s.h.Write(ssl30Pad1[:padLength]) - s.h.Write(seq) - s.h.Write(header[:1]) - s.h.Write(header[3:5]) - s.h.Write(data) - digestBuf = s.h.Sum(digestBuf[:0]) - - s.h.Reset() - s.h.Write(s.key) - s.h.Write(ssl30Pad2[:padLength]) - s.h.Write(digestBuf) - return s.h.Sum(digestBuf[:0]) -} - -type constantTimeHash interface { - hash.Hash - ConstantTimeSum(b []byte) []byte -} - -// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces -// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC. -type cthWrapper struct { - h constantTimeHash -} - -func (c *cthWrapper) Size() int { return c.h.Size() } -func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() } -func (c *cthWrapper) Reset() { c.h.Reset() } -func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) } -func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) } - -func newConstantTimeHash(h func() hash.Hash) func() hash.Hash { - return func() hash.Hash { - return &cthWrapper{h().(constantTimeHash)} - } -} - -// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3. -type tls10MAC struct { - h hash.Hash -} - -func (s tls10MAC) Size() int { - return s.h.Size() -} - -// MAC is guaranteed to take constant time, as long as -// len(seq)+len(header)+len(data)+len(extra) is constant. extra is not fed into -// the MAC, but is only provided to make the timing profile constant. -func (s tls10MAC) MAC(digestBuf, seq, header, data, extra []byte) []byte { - s.h.Reset() - s.h.Write(seq) - s.h.Write(header) - s.h.Write(data) - res := s.h.Sum(digestBuf[:0]) - if extra != nil { - s.h.Write(extra) - } - return res -} - -func rsaKA(version uint16) keyAgreement { - return rsaKeyAgreement{} -} - -func ecdheECDSAKA(version uint16) keyAgreement { - return &ecdheKeyAgreement{ - isRSA: false, - version: version, - } -} - -func ecdheRSAKA(version uint16) keyAgreement { - return &ecdheKeyAgreement{ - isRSA: true, - version: version, - } -} - -// mutualCipherSuite returns a cipherSuite given a list of supported -// ciphersuites and the id requested by the peer. -func mutualCipherSuite(have []uint16, want uint16) *cipherSuite { - for _, id := range have { - if id == want { - for _, suite := range cipherSuites { - if suite.id == want { - return suite - } - } - return nil - } - } - return nil -} - -// A list of cipher suite IDs that are, or have been, implemented by this -// package. -// -// Taken from http://www.iana.org/assignments/tls-parameters/tls-parameters.xml -const ( - // TLS 1.0 - 1.2 cipher suites. - TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005 - TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a - TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f - TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035 - TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c - TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c - TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009 - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a - TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011 - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012 - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013 - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023 - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca8 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca9 - - // TLS 1.3+ cipher suites. - TLS_AES_128_GCM_SHA256 uint16 = 0x1301 - TLS_AES_256_GCM_SHA384 uint16 = 0x1302 - TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303 - - // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator - // that the client is doing version fallback. See - // https://tools.ietf.org/html/rfc7507. - TLS_FALLBACK_SCSV uint16 = 0x5600 -) diff --git a/external/github.com/marten-seemann/qtls/common.go b/external/github.com/marten-seemann/qtls/common.go deleted file mode 100644 index a8eee83d3..000000000 --- a/external/github.com/marten-seemann/qtls/common.go +++ /dev/null @@ -1,1230 +0,0 @@ -// Copyright 2009 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 qtls - -import ( - "container/list" - "crypto" - "crypto/rand" - "crypto/sha512" - "crypto/tls" - "crypto/x509" - "errors" - "fmt" - "io" - "math/big" - "net" - "strings" - "sync" - "time" -) - -const ( - VersionSSL30 = 0x0300 - VersionTLS10 = 0x0301 - VersionTLS11 = 0x0302 - VersionTLS12 = 0x0303 - VersionTLS13 = 0x0304 -) - -const ( - maxPlaintext = 16384 // maximum plaintext payload length - maxCiphertext = 16384 + 2048 // maximum ciphertext payload length - recordHeaderLen = 5 // record header length - maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) - maxWarnAlertCount = 5 // maximum number of consecutive warning alerts - - minVersion = VersionTLS12 - maxVersion = VersionTLS13 -) - -// TLS record types. -type recordType uint8 - -const ( - recordTypeChangeCipherSpec recordType = 20 - recordTypeAlert recordType = 21 - recordTypeHandshake recordType = 22 - recordTypeApplicationData recordType = 23 -) - -// TLS handshake message types. -const ( - typeHelloRequest uint8 = 0 - typeClientHello uint8 = 1 - typeServerHello uint8 = 2 - typeNewSessionTicket uint8 = 4 - typeEndOfEarlyData uint8 = 5 - typeEncryptedExtensions uint8 = 8 - typeCertificate uint8 = 11 - typeServerKeyExchange uint8 = 12 - typeCertificateRequest uint8 = 13 - typeServerHelloDone uint8 = 14 - typeCertificateVerify uint8 = 15 - typeClientKeyExchange uint8 = 16 - typeFinished uint8 = 20 - typeCertificateStatus uint8 = 22 - typeNextProtocol uint8 = 67 // Not IANA assigned -) - -// TLS compression types. -const ( - compressionNone uint8 = 0 -) - -type Extension struct { - Type uint16 - Data []byte -} - -// TLS extension numbers -const ( - extensionServerName uint16 = 0 - extensionStatusRequest uint16 = 5 - extensionSupportedCurves uint16 = 10 // Supported Groups in 1.3 nomenclature - extensionSupportedPoints uint16 = 11 - extensionSignatureAlgorithms uint16 = 13 - extensionALPN uint16 = 16 - extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6 - extensionEMS uint16 = 23 - extensionSessionTicket uint16 = 35 - extensionPreSharedKey uint16 = 41 - extensionEarlyData uint16 = 42 - extensionSupportedVersions uint16 = 43 - extensionPSKKeyExchangeModes uint16 = 45 - extensionCAs uint16 = 47 - extensionSignatureAlgorithmsCert uint16 = 50 - extensionKeyShare uint16 = 51 - extensionNextProtoNeg uint16 = 13172 // not IANA assigned - extensionRenegotiationInfo uint16 = 0xff01 - extensionDelegatedCredential uint16 = 0xff02 // TODO(any) Get IANA assignment -) - -// TLS signaling cipher suite values -const ( - scsvRenegotiation uint16 = 0x00ff -) - -// PSK Key Exchange Modes -// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.7 -const ( - pskDHEKeyExchange uint8 = 1 -) - -// CurveID is tls.CurveID -// TLS 1.3 refers to these as Groups, but this library implements only -// curve-based ones anyway. See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4. -type CurveID = tls.CurveID - -const ( - // Exported IDs - CurveP256 = tls.CurveP256 - CurveP384 = tls.CurveP384 - CurveP521 = tls.CurveP521 - X25519 = tls.X25519 - - // Experimental KEX - HybridSIDHp503Curve25519 CurveID = 0xFE30 -) - -// TLS 1.3 Key Share -// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5 -type keyShare struct { - group CurveID - data []byte -} - -// TLS 1.3 PSK Identity and Binder, as sent by the client -// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6 - -type psk struct { - identity []byte - obfTicketAge uint32 - binder []byte -} - -// TLS Elliptic Curve Point Formats -// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9 -const ( - pointFormatUncompressed uint8 = 0 -) - -// TLS CertificateStatusType (RFC 3546) -const ( - statusTypeOCSP uint8 = 1 -) - -// Certificate types (for certificateRequestMsg) -const ( - certTypeRSASign = 1 // A certificate containing an RSA key - certTypeDSSSign = 2 // A certificate containing a DSA key - certTypeRSAFixedDH = 3 // A certificate containing a static DH key - certTypeDSSFixedDH = 4 // A certificate containing a static DH key - - // See RFC 4492 sections 3 and 5.5. - certTypeECDSASign = 64 // A certificate containing an ECDSA-capable public key, signed with ECDSA. - certTypeRSAFixedECDH = 65 // A certificate containing an ECDH-capable public key, signed with RSA. - certTypeECDSAFixedECDH = 66 // A certificate containing an ECDH-capable public key, signed with ECDSA. - - // Rest of these are reserved by the TLS spec -) - -// Signature algorithms (for internal signaling use). Starting at 16 to avoid overlap with -// TLS 1.2 codepoints (RFC 5246, section A.4.1), with which these have nothing to do. -const ( - signaturePKCS1v15 uint8 = iota + 16 - signatureECDSA - signatureRSAPSS -) - -// supportedSignatureAlgorithms contains the signature and hash algorithms that -// the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2 -// CertificateRequest. The two fields are merged to match with TLS 1.3. -// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc. -var supportedSignatureAlgorithms = []SignatureScheme{ - PKCS1WithSHA256, - ECDSAWithP256AndSHA256, - PKCS1WithSHA384, - ECDSAWithP384AndSHA384, - PKCS1WithSHA512, - ECDSAWithP521AndSHA512, - PKCS1WithSHA1, - ECDSAWithSHA1, -} - -// supportedSignatureAlgorithms13 lists the advertised signature algorithms -// allowed for digital signatures. It includes TLS 1.2 + PSS. -var supportedSignatureAlgorithms13 = []SignatureScheme{ - PSSWithSHA256, - PKCS1WithSHA256, - ECDSAWithP256AndSHA256, - PSSWithSHA384, - PKCS1WithSHA384, - ECDSAWithP384AndSHA384, - PSSWithSHA512, - PKCS1WithSHA512, - ECDSAWithP521AndSHA512, - PKCS1WithSHA1, - ECDSAWithSHA1, -} - -// ConnectionState records basic TLS details about the connection. -type ConnectionState struct { - ConnectionID []byte // Random unique connection id - Version uint16 // TLS version used by the connection (e.g. VersionTLS12) - HandshakeComplete bool // TLS handshake is complete - DidResume bool // connection resumes a previous TLS connection - CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) - NegotiatedProtocol string // negotiated next protocol (not guaranteed to be from Config.NextProtos) - NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server (client side only) - ServerName string // server name requested by client, if any (server side only) - PeerCertificates []*x509.Certificate // certificate chain presented by remote peer - VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates - SignedCertificateTimestamps [][]byte // SCTs from the server, if any - OCSPResponse []byte // stapled OCSP response from server, if any - DelegatedCredential []byte // Delegated credential sent by the server, if any - - // TLSUnique contains the "tls-unique" channel binding value (see RFC - // 5929, section 3). For resumed sessions this value will be nil - // because resumption does not include enough context (see - // https://mitls.org/pages/attacks/3SHAKE#channelbindings). This will - // change in future versions of Go once the TLS master-secret fix has - // been standardized and implemented. - TLSUnique []byte - - // HandshakeConfirmed is true once all data returned by Read - // (past and future) is guaranteed not to be replayed. - HandshakeConfirmed bool - - // Unique0RTTToken is a value that never repeats, and can be used - // to detect replay attacks against 0-RTT connections. - // Unique0RTTToken is only present if HandshakeConfirmed is false. - Unique0RTTToken []byte - - ClientHello []byte // ClientHello packet -} - -// The ClientAuthType is the tls.ClientAuthType -type ClientAuthType = tls.ClientAuthType - -const ( - NoClientCert = tls.NoClientCert - RequestClientCert = tls.RequestClientCert - RequireAnyClientCert = tls.RequireAnyClientCert - VerifyClientCertIfGiven = tls.VerifyClientCertIfGiven - RequireAndVerifyClientCert = tls.RequireAndVerifyClientCert -) - -// ClientSessionState contains the state needed by clients to resume TLS -// sessions. -type ClientSessionState struct { - sessionTicket []uint8 // Encrypted ticket used for session resumption with server - vers uint16 // SSL/TLS version negotiated for the session - cipherSuite uint16 // Ciphersuite negotiated for the session - masterSecret []byte // MasterSecret generated by client on a full handshake - serverCertificates []*x509.Certificate // Certificate chain presented by the server - verifiedChains [][]*x509.Certificate // Certificate chains we built for verification - useEMS bool // State of extended master secret -} - -// ClientSessionCache is a cache of ClientSessionState objects that can be used -// by a client to resume a TLS session with a given server. ClientSessionCache -// implementations should expect to be called concurrently from different -// goroutines. Only ticket-based resumption is supported, not SessionID-based -// resumption. -type ClientSessionCache interface { - // Get searches for a ClientSessionState associated with the given key. - // On return, ok is true if one was found. - Get(sessionKey string) (session *ClientSessionState, ok bool) - - // Put adds the ClientSessionState to the cache with the given key. - Put(sessionKey string, cs *ClientSessionState) -} - -// SignatureScheme is a tls.SignatureScheme -type SignatureScheme = tls.SignatureScheme - -const ( - PKCS1WithSHA1 = tls.PKCS1WithSHA1 - PKCS1WithSHA256 = tls.PKCS1WithSHA256 - PKCS1WithSHA384 = tls.PKCS1WithSHA384 - PKCS1WithSHA512 = tls.PKCS1WithSHA512 - - PSSWithSHA256 = tls.PSSWithSHA256 - PSSWithSHA384 = tls.PSSWithSHA384 - PSSWithSHA512 = tls.PSSWithSHA512 - - ECDSAWithP256AndSHA256 = tls.ECDSAWithP256AndSHA256 - ECDSAWithP384AndSHA384 = tls.ECDSAWithP384AndSHA384 - ECDSAWithP521AndSHA512 = tls.ECDSAWithP521AndSHA512 - - // Legacy signature and hash algorithms for TLS 1.2. - ECDSAWithSHA1 = tls.ECDSAWithSHA1 -) - -// ClientHelloInfo contains information from a ClientHello message in order to -// guide certificate selection in the GetCertificate callback. -type ClientHelloInfo struct { - // CipherSuites lists the CipherSuites supported by the client (e.g. - // TLS_RSA_WITH_RC4_128_SHA). - CipherSuites []uint16 - - // ServerName indicates the name of the server requested by the client - // in order to support virtual hosting. ServerName is only set if the - // client is using SNI (see - // http://tools.ietf.org/html/rfc4366#section-3.1). - ServerName string - - // SupportedCurves lists the elliptic curves supported by the client. - // SupportedCurves is set only if the Supported Elliptic Curves - // Extension is being used (see - // http://tools.ietf.org/html/rfc4492#section-5.1.1). - SupportedCurves []CurveID - - // SupportedPoints lists the point formats supported by the client. - // SupportedPoints is set only if the Supported Point Formats Extension - // is being used (see - // http://tools.ietf.org/html/rfc4492#section-5.1.2). - SupportedPoints []uint8 - - // SignatureSchemes lists the signature and hash schemes that the client - // is willing to verify. SignatureSchemes is set only if the Signature - // Algorithms Extension is being used (see - // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1). - SignatureSchemes []SignatureScheme - - // SupportedProtos lists the application protocols supported by the client. - // SupportedProtos is set only if the Application-Layer Protocol - // Negotiation Extension is being used (see - // https://tools.ietf.org/html/rfc7301#section-3.1). - // - // Servers can select a protocol by setting Config.NextProtos in a - // GetConfigForClient return value. - SupportedProtos []string - - // SupportedVersions lists the TLS versions supported by the client. - // For TLS versions less than 1.3, this is extrapolated from the max - // version advertised by the client, so values other than the greatest - // might be rejected if used. - SupportedVersions []uint16 - - // Conn is the underlying net.Conn for the connection. Do not read - // from, or write to, this connection; that will cause the TLS - // connection to fail. - Conn net.Conn - - // Offered0RTTData is true if the client announced that it will send - // 0-RTT data. If the server Config.Accept0RTTData is true, and the - // client offered a session ticket valid for that purpose, it will - // be notified that the 0-RTT data is accepted and it will be made - // immediately available for Read. - Offered0RTTData bool - - // AcceptsDelegatedCredential is true if the client indicated willingness - // to negotiate the delegated credential extension. - AcceptsDelegatedCredential bool - - // The Fingerprint is an sequence of bytes unique to this Client Hello. - // It can be used to prevent or mitigate 0-RTT data replays as it's - // guaranteed that a replayed connection will have the same Fingerprint. - Fingerprint []byte -} - -// The CertificateRequestInfo is a tls.CertificateRequestInfo -type CertificateRequestInfo = tls.CertificateRequestInfo - -// RenegotiationSupport is a tls.RenegotiationSupport -type RenegotiationSupport = tls.RenegotiationSupport - -const ( - // RenegotiateNever disables renegotiation. - RenegotiateNever = tls.RenegotiateNever - - // RenegotiateOnceAsClient allows a remote server to request - // renegotiation once per connection. - RenegotiateOnceAsClient = tls.RenegotiateOnceAsClient - - // RenegotiateFreelyAsClient allows a remote server to repeatedly - // request renegotiation. - RenegotiateFreelyAsClient = tls.RenegotiateFreelyAsClient -) - -// A Config structure is used to configure a TLS client or server. -// After one has been passed to a TLS function it must not be -// modified. A Config may be reused; the tls package will also not -// modify it. -type Config struct { - // Rand provides the source of entropy for nonces and RSA blinding. - // If Rand is nil, TLS uses the cryptographic random reader in package - // crypto/rand. - // The Reader must be safe for use by multiple goroutines. - Rand io.Reader - - // Time returns the current time as the number of seconds since the epoch. - // If Time is nil, TLS uses time.Now. - Time func() time.Time - - // Certificates contains one or more certificate chains to present to - // the other side of the connection. Server configurations must include - // at least one certificate or else set GetCertificate. Clients doing - // client-authentication may set either Certificates or - // GetClientCertificate. - Certificates []Certificate - - // NameToCertificate maps from a certificate name to an element of - // Certificates. Note that a certificate name can be of the form - // '*.example.com' and so doesn't have to be a domain name as such. - // See Config.BuildNameToCertificate - // The nil value causes the first element of Certificates to be used - // for all connections. - NameToCertificate map[string]*Certificate - - // GetCertificate returns a Certificate based on the given - // ClientHelloInfo. It will only be called if the client supplies SNI - // information or if Certificates is empty. - // - // If GetCertificate is nil or returns nil, then the certificate is - // retrieved from NameToCertificate. If NameToCertificate is nil, the - // first element of Certificates will be used. - GetCertificate func(*ClientHelloInfo) (*Certificate, error) - - // GetClientCertificate, if not nil, is called when a server requests a - // certificate from a client. If set, the contents of Certificates will - // be ignored. - // - // If GetClientCertificate returns an error, the handshake will be - // aborted and that error will be returned. Otherwise - // GetClientCertificate must return a non-nil Certificate. If - // Certificate.Certificate is empty then no certificate will be sent to - // the server. If this is unacceptable to the server then it may abort - // the handshake. - // - // GetClientCertificate may be called multiple times for the same - // connection if renegotiation occurs or if TLS 1.3 is in use. - GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error) - - // GetConfigForClient, if not nil, is called after a ClientHello is - // received from a client. It may return a non-nil Config in order to - // change the Config that will be used to handle this connection. If - // the returned Config is nil, the original Config will be used. The - // Config returned by this callback may not be subsequently modified. - // - // If GetConfigForClient is nil, the Config passed to Server() will be - // used for all connections. - // - // Uniquely for the fields in the returned Config, session ticket keys - // will be duplicated from the original Config if not set. - // Specifically, if SetSessionTicketKeys was called on the original - // config but not on the returned config then the ticket keys from the - // original config will be copied into the new config before use. - // Otherwise, if SessionTicketKey was set in the original config but - // not in the returned config then it will be copied into the returned - // config before use. If neither of those cases applies then the key - // material from the returned config will be used for session tickets. - GetConfigForClient func(*ClientHelloInfo) (*Config, error) - - // VerifyPeerCertificate, if not nil, is called after normal - // certificate verification by either a TLS client or server. It - // receives the raw ASN.1 certificates provided by the peer and also - // any verified chains that normal processing found. If it returns a - // non-nil error, the handshake is aborted and that error results. - // - // If normal verification fails then the handshake will abort before - // considering this callback. If normal verification is disabled by - // setting InsecureSkipVerify, or (for a server) when ClientAuth is - // RequestClientCert or RequireAnyClientCert, then this callback will - // be considered but the verifiedChains argument will always be nil. - VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error - - // RootCAs defines the set of root certificate authorities - // that clients use when verifying server certificates. - // If RootCAs is nil, TLS uses the host's root CA set. - RootCAs *x509.CertPool - - // NextProtos is a list of supported, application level protocols. - NextProtos []string - - // ServerName is used to verify the hostname on the returned - // certificates unless InsecureSkipVerify is given. It is also included - // in the client's handshake to support virtual hosting unless it is - // an IP address. - ServerName string - - // ClientAuth determines the server's policy for - // TLS Client Authentication. The default is NoClientCert. - ClientAuth ClientAuthType - - // ClientCAs defines the set of root certificate authorities - // that servers use if required to verify a client certificate - // by the policy in ClientAuth. - ClientCAs *x509.CertPool - - // InsecureSkipVerify controls whether a client verifies the - // server's certificate chain and host name. - // If InsecureSkipVerify is true, TLS accepts any certificate - // presented by the server and any host name in that certificate. - // In this mode, TLS is susceptible to man-in-the-middle attacks. - // This should be used only for testing. - InsecureSkipVerify bool - - // CipherSuites is a list of supported cipher suites to be used in - // TLS 1.0-1.2. If CipherSuites is nil, TLS uses a list of suites - // supported by the implementation. - CipherSuites []uint16 - - // PreferServerCipherSuites controls whether the server selects the - // client's most preferred ciphersuite, or the server's most preferred - // ciphersuite. If true then the server's preference, as expressed in - // the order of elements in CipherSuites, is used. - PreferServerCipherSuites bool - - // SessionTicketsDisabled may be set to true to disable session ticket - // (resumption) support. Note that on clients, session ticket support is - // also disabled if ClientSessionCache is nil. - SessionTicketsDisabled bool - - // SessionTicketKey is used by TLS servers to provide session - // resumption. See RFC 5077. If zero, it will be filled with - // random data before the first server handshake. - // - // If multiple servers are terminating connections for the same host - // they should all have the same SessionTicketKey. If the - // SessionTicketKey leaks, previously recorded and future TLS - // connections using that key are compromised. - SessionTicketKey [32]byte - - // ClientSessionCache is a cache of ClientSessionState entries for TLS - // session resumption. It is only used by clients. - ClientSessionCache ClientSessionCache - - // MinVersion contains the minimum SSL/TLS version that is acceptable. - // If zero, then TLS 1.0 is taken as the minimum. - MinVersion uint16 - - // MaxVersion contains the maximum SSL/TLS version that is acceptable. - // If zero, then the maximum version supported by this package is used, - // which is currently TLS 1.2. - MaxVersion uint16 - - // CurvePreferences contains the elliptic curves that will be used in - // an ECDHE handshake, in preference order. If empty, the default will - // be used. - CurvePreferences []CurveID - - // DynamicRecordSizingDisabled disables adaptive sizing of TLS records. - // When true, the largest possible TLS record size is always used. When - // false, the size of TLS records may be adjusted in an attempt to - // improve latency. - DynamicRecordSizingDisabled bool - - // Renegotiation controls what types of renegotiation are supported. - // The default, none, is correct for the vast majority of applications. - Renegotiation RenegotiationSupport - - // KeyLogWriter optionally specifies a destination for TLS master secrets - // in NSS key log format that can be used to allow external programs - // such as Wireshark to decrypt TLS connections. - // See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. - // Use of KeyLogWriter compromises security and should only be - // used for debugging. - KeyLogWriter io.Writer - - // If Max0RTTDataSize is not zero, the client will be allowed to use - // session tickets to send at most this number of bytes of 0-RTT data. - // 0-RTT data is subject to replay and has memory DoS implications. - // The server will later be able to refuse the 0-RTT data with - // Accept0RTTData, or wait for the client to prove that it's not - // replayed with Conn.ConfirmHandshake. - // - // It has no meaning on the client. - // - // See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-2.3. - Max0RTTDataSize uint32 - - // Accept0RTTData makes the 0-RTT data received from the client - // immediately available to Read. 0-RTT data is subject to replay. - // Use Conn.ConfirmHandshake to wait until the data is known not - // to be replayed after reading it. - // - // It has no meaning on the client. - // - // See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-2.3. - Accept0RTTData bool - - // SessionTicketSealer, if not nil, is used to wrap and unwrap - // session tickets, instead of SessionTicketKey. - SessionTicketSealer SessionTicketSealer - - // AcceptDelegatedCredential is true if the client is willing to negotiate - // the delegated credential extension. - // - // This value has no meaning for the server. - // - // See https://tools.ietf.org/html/draft-ietf-tls-subcerts-02. - AcceptDelegatedCredential bool - - // GetDelegatedCredential returns a DC and its private key for use in the - // delegated credential extension. The inputs to the callback are some - // information parsed from the ClientHello, as well as the protocol version - // selected by the server. This is necessary because the DC is bound to the - // protocol version in which it's used. The return value is the raw DC - // encoded in the wire format specified in - // https://tools.ietf.org/html/draft-ietf-tls-subcerts-02. If the return - // value is nil, then the server will not offer negotiate the extension. - // - // This value has no meaning for the client. - GetDelegatedCredential func(*ClientHelloInfo, uint16) ([]byte, crypto.PrivateKey, error) - - // GetExtensions, if not nil, is called before a message that allows - // sending of extensions is sent. - // Currently only implemented for the ClientHello message (for the client) - // and for the EncryptedExtensions message (for the server). - // Only valid for TLS 1.3. - GetExtensions func(handshakeMessageType uint8) []Extension - - // ReceivedExtensions, if not nil, is called when a message that allows the - // inclusion of extensions is received. - // It is called with an empty slice of extensions, if the message didn't - // contain any extensions. - // Currently only implemented for the ClientHello message (sent by the - // client) and for the EncryptedExtensions message (sent by the server). - // Only valid for TLS 1.3. - ReceivedExtensions func(handshakeMessageType uint8, exts []Extension) error - - serverInitOnce sync.Once // guards calling (*Config).serverInit - - // mutex protects sessionTicketKeys. - mutex sync.RWMutex - // sessionTicketKeys contains zero or more ticket keys. If the length - // is zero, SessionTicketsDisabled must be true. The first key is used - // for new tickets and any subsequent keys can be used to decrypt old - // tickets. - sessionTicketKeys []ticketKey - - // UseExtendedMasterSecret indicates whether or not the connection - // should use the extended master secret computation if available - UseExtendedMasterSecret bool - - // AlternativeRecordLayer is used by QUIC - AlternativeRecordLayer RecordLayer -} - -type RecordLayer interface { - SetReadKey(suite *CipherSuite, trafficSecret []byte) - SetWriteKey(suite *CipherSuite, trafficSecret []byte) - ReadHandshakeMessage() ([]byte, error) - WriteRecord([]byte) (int, error) -} - -// ticketKeyNameLen is the number of bytes of identifier that is prepended to -// an encrypted session ticket in order to identify the key used to encrypt it. -const ticketKeyNameLen = 16 - -// ticketKey is the internal representation of a session ticket key. -type ticketKey struct { - // keyName is an opaque byte string that serves to identify the session - // ticket key. It's exposed as plaintext in every session ticket. - keyName [ticketKeyNameLen]byte - aesKey [16]byte - hmacKey [16]byte -} - -// ticketKeyFromBytes converts from the external representation of a session -// ticket key to a ticketKey. Externally, session ticket keys are 32 random -// bytes and this function expands that into sufficient name and key material. -func ticketKeyFromBytes(b [32]byte) (key ticketKey) { - hashed := sha512.Sum512(b[:]) - copy(key.keyName[:], hashed[:ticketKeyNameLen]) - copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16]) - copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32]) - return key -} - -// Clone returns a shallow clone of c. It is safe to clone a Config that is -// being used concurrently by a TLS client or server. -func (c *Config) Clone() *Config { - // Running serverInit ensures that it's safe to read - // SessionTicketsDisabled. - c.serverInitOnce.Do(func() { c.serverInit(nil) }) - - var sessionTicketKeys []ticketKey - c.mutex.RLock() - sessionTicketKeys = c.sessionTicketKeys - c.mutex.RUnlock() - - return &Config{ - Rand: c.Rand, - Time: c.Time, - Certificates: c.Certificates, - NameToCertificate: c.NameToCertificate, - GetCertificate: c.GetCertificate, - GetClientCertificate: c.GetClientCertificate, - GetConfigForClient: c.GetConfigForClient, - VerifyPeerCertificate: c.VerifyPeerCertificate, - RootCAs: c.RootCAs, - NextProtos: c.NextProtos, - ServerName: c.ServerName, - ClientAuth: c.ClientAuth, - ClientCAs: c.ClientCAs, - InsecureSkipVerify: c.InsecureSkipVerify, - CipherSuites: c.CipherSuites, - PreferServerCipherSuites: c.PreferServerCipherSuites, - SessionTicketsDisabled: c.SessionTicketsDisabled, - SessionTicketKey: c.SessionTicketKey, - ClientSessionCache: c.ClientSessionCache, - MinVersion: c.MinVersion, - MaxVersion: c.MaxVersion, - CurvePreferences: c.CurvePreferences, - DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, - Renegotiation: c.Renegotiation, - KeyLogWriter: c.KeyLogWriter, - Accept0RTTData: c.Accept0RTTData, - Max0RTTDataSize: c.Max0RTTDataSize, - SessionTicketSealer: c.SessionTicketSealer, - AcceptDelegatedCredential: c.AcceptDelegatedCredential, - GetDelegatedCredential: c.GetDelegatedCredential, - GetExtensions: c.GetExtensions, - ReceivedExtensions: c.ReceivedExtensions, - sessionTicketKeys: sessionTicketKeys, - UseExtendedMasterSecret: c.UseExtendedMasterSecret, - } -} - -// serverInit is run under c.serverInitOnce to do initialization of c. If c was -// returned by a GetConfigForClient callback then the argument should be the -// Config that was passed to Server, otherwise it should be nil. -func (c *Config) serverInit(originalConfig *Config) { - if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 || c.SessionTicketSealer != nil { - return - } - - alreadySet := false - for _, b := range c.SessionTicketKey { - if b != 0 { - alreadySet = true - break - } - } - - if !alreadySet { - if originalConfig != nil { - copy(c.SessionTicketKey[:], originalConfig.SessionTicketKey[:]) - } else if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil { - c.SessionTicketsDisabled = true - return - } - } - - if originalConfig != nil { - originalConfig.mutex.RLock() - c.sessionTicketKeys = originalConfig.sessionTicketKeys - originalConfig.mutex.RUnlock() - } else { - c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)} - } -} - -func (c *Config) ticketKeys() []ticketKey { - c.mutex.RLock() - // c.sessionTicketKeys is constant once created. SetSessionTicketKeys - // will only update it by replacing it with a new value. - ret := c.sessionTicketKeys - c.mutex.RUnlock() - return ret -} - -// SetSessionTicketKeys updates the session ticket keys for a server. The first -// key will be used when creating new tickets, while all keys can be used for -// decrypting tickets. It is safe to call this function while the server is -// running in order to rotate the session ticket keys. The function will panic -// if keys is empty. -func (c *Config) SetSessionTicketKeys(keys [][32]byte) { - if len(keys) == 0 { - panic("tls: keys must have at least one key") - } - - newKeys := make([]ticketKey, len(keys)) - for i, bytes := range keys { - newKeys[i] = ticketKeyFromBytes(bytes) - } - - c.mutex.Lock() - c.sessionTicketKeys = newKeys - c.mutex.Unlock() -} - -func (c *Config) rand() io.Reader { - r := c.Rand - if r == nil { - return rand.Reader - } - return r -} - -func (c *Config) time() time.Time { - t := c.Time - if t == nil { - t = time.Now - } - return t() -} - -func hasOverlappingCipherSuites(cs1, cs2 []uint16) bool { - for _, c1 := range cs1 { - for _, c2 := range cs2 { - if c1 == c2 { - return true - } - } - } - return false -} - -func (c *Config) cipherSuites() []uint16 { - s := c.CipherSuites - if s == nil { - s = defaultCipherSuites() - } else if c.maxVersion() >= VersionTLS13 { - // Ensure that TLS 1.3 suites are always present, but respect - // the application cipher suite preferences. - s13 := defaultTLS13CipherSuites() - if !hasOverlappingCipherSuites(s, s13) { - allSuites := make([]uint16, len(s13)+len(s)) - allSuites = append(allSuites, s13...) - s = append(allSuites, s...) - } - } - return s -} - -func (c *Config) minVersion() uint16 { - if c == nil || c.MinVersion == 0 { - return minVersion - } - return c.MinVersion -} - -func (c *Config) maxVersion() uint16 { - if c == nil || c.MaxVersion == 0 { - return maxVersion - } - return c.MaxVersion -} - -var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521} - -func (c *Config) curvePreferences() []CurveID { - if c == nil || len(c.CurvePreferences) == 0 { - return defaultCurvePreferences - } - return c.CurvePreferences -} - -// mutualVersion returns the protocol version to use given the advertised -// version of the peer using the legacy non-extension methods. -func (c *Config) mutualVersion(vers uint16) (uint16, bool) { - minVersion := c.minVersion() - maxVersion := c.maxVersion() - - // Version 1.3 and higher are not negotiated via this mechanism. - if maxVersion > VersionTLS12 { - maxVersion = VersionTLS12 - } - - if vers < minVersion { - return 0, false - } - if vers > maxVersion { - vers = maxVersion - } - return vers, true -} - -// pickVersion returns the protocol version to use given the advertised -// versions of the peer using the Supported Versions extension. -func (c *Config) pickVersion(peerSupportedVersions []uint16) (uint16, bool) { - supportedVersions := c.getSupportedVersions() - for _, supportedVersion := range supportedVersions { - for _, version := range peerSupportedVersions { - if version == supportedVersion { - return version, true - } - } - } - return 0, false -} - -// configSuppVersArray is the backing array of Config.getSupportedVersions -var configSuppVersArray = [...]uint16{VersionTLS13, VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30} - -// getSupportedVersions returns the protocol versions that are supported by the -// current configuration. -func (c *Config) getSupportedVersions() []uint16 { - minVersion := c.minVersion() - maxVersion := c.maxVersion() - // Sanity check to avoid advertising unsupported versions. - if minVersion < VersionSSL30 { - minVersion = VersionSSL30 - } - if maxVersion > VersionTLS13 { - maxVersion = VersionTLS13 - } - if maxVersion < minVersion { - return nil - } - return configSuppVersArray[VersionTLS13-maxVersion : VersionTLS13-minVersion+1] -} - -// getCertificate returns the best certificate for the given ClientHelloInfo, -// defaulting to the first element of c.Certificates. -func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) { - if c.GetCertificate != nil && - (len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) { - cert, err := c.GetCertificate(clientHello) - if cert != nil || err != nil { - return cert, err - } - } - - if len(c.Certificates) == 0 { - return nil, errors.New("tls: no certificates configured") - } - - if len(c.Certificates) == 1 || c.NameToCertificate == nil { - // There's only one choice, so no point doing any work. - return &c.Certificates[0], nil - } - - name := strings.ToLower(clientHello.ServerName) - for len(name) > 0 && name[len(name)-1] == '.' { - name = name[:len(name)-1] - } - - if cert, ok := c.NameToCertificate[name]; ok { - return cert, nil - } - - // try replacing labels in the name with wildcards until we get a - // match. - labels := strings.Split(name, ".") - for i := range labels { - labels[i] = "*" - candidate := strings.Join(labels, ".") - if cert, ok := c.NameToCertificate[candidate]; ok { - return cert, nil - } - } - - // If nothing matches, return the first certificate. - return &c.Certificates[0], nil -} - -// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate -// from the CommonName and SubjectAlternateName fields of each of the leaf -// certificates. -func (c *Config) BuildNameToCertificate() { - c.NameToCertificate = make(map[string]*Certificate) - for i := range c.Certificates { - cert := &c.Certificates[i] - x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - continue - } - if len(x509Cert.Subject.CommonName) > 0 { - c.NameToCertificate[x509Cert.Subject.CommonName] = cert - } - for _, san := range x509Cert.DNSNames { - c.NameToCertificate[san] = cert - } - } -} - -// writeKeyLog logs client random and master secret if logging was enabled by -// setting c.KeyLogWriter. -func (c *Config) writeKeyLog(what string, clientRandom, masterSecret []byte) error { - if c.KeyLogWriter == nil { - return nil - } - - logLine := []byte(fmt.Sprintf("%s %x %x\n", what, clientRandom, masterSecret)) - - writerMutex.Lock() - _, err := c.KeyLogWriter.Write(logLine) - writerMutex.Unlock() - - return err -} - -// writerMutex protects all KeyLogWriters globally. It is rarely enabled, -// and is only for debugging, so a global mutex saves space. -var writerMutex sync.Mutex - -// A Certificate is a tls.Certificate -type Certificate = tls.Certificate - -type handshakeMessage interface { - marshal() []byte - unmarshal([]byte) alert -} - -// lruSessionCache is a ClientSessionCache implementation that uses an LRU -// caching strategy. -type lruSessionCache struct { - sync.Mutex - - m map[string]*list.Element - q *list.List - capacity int -} - -type lruSessionCacheEntry struct { - sessionKey string - state *ClientSessionState -} - -// NewLRUClientSessionCache returns a ClientSessionCache with the given -// capacity that uses an LRU strategy. If capacity is < 1, a default capacity -// is used instead. -func NewLRUClientSessionCache(capacity int) ClientSessionCache { - const defaultSessionCacheCapacity = 64 - - if capacity < 1 { - capacity = defaultSessionCacheCapacity - } - return &lruSessionCache{ - m: make(map[string]*list.Element), - q: list.New(), - capacity: capacity, - } -} - -// Put adds the provided (sessionKey, cs) pair to the cache. -func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) { - c.Lock() - defer c.Unlock() - - if elem, ok := c.m[sessionKey]; ok { - entry := elem.Value.(*lruSessionCacheEntry) - entry.state = cs - c.q.MoveToFront(elem) - return - } - - if c.q.Len() < c.capacity { - entry := &lruSessionCacheEntry{sessionKey, cs} - c.m[sessionKey] = c.q.PushFront(entry) - return - } - - elem := c.q.Back() - entry := elem.Value.(*lruSessionCacheEntry) - delete(c.m, entry.sessionKey) - entry.sessionKey = sessionKey - entry.state = cs - c.q.MoveToFront(elem) - c.m[sessionKey] = elem -} - -// Get returns the ClientSessionState value associated with a given key. It -// returns (nil, false) if no value is found. -func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) { - c.Lock() - defer c.Unlock() - - if elem, ok := c.m[sessionKey]; ok { - c.q.MoveToFront(elem) - return elem.Value.(*lruSessionCacheEntry).state, true - } - return nil, false -} - -// TODO(jsing): Make these available to both crypto/x509 and crypto/tls. -type dsaSignature struct { - R, S *big.Int -} - -type ecdsaSignature dsaSignature - -var emptyConfig Config - -func defaultConfig() *Config { - return &emptyConfig -} - -var ( - once sync.Once - varDefaultCipherSuites []uint16 - varDefaultTLS13CipherSuites []uint16 -) - -func defaultCipherSuites() []uint16 { - once.Do(initDefaultCipherSuites) - return varDefaultCipherSuites -} - -func defaultTLS13CipherSuites() []uint16 { - once.Do(initDefaultCipherSuites) - return varDefaultTLS13CipherSuites -} - -func initDefaultCipherSuites() { - var topCipherSuites, topTLS13CipherSuites []uint16 - - // TODO: check for hardware support - // Check the cpu flags for each platform that has optimized GCM implementations. - // Worst case, these variables will just all be false - // hasGCMAsmAMD64 := cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ - - // hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL - - // // Keep in sync with crypto/aes/cipher_s390x.go. - // hasGCMAsmS390X := cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) - - // hasGCMAsm := hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X - - if true { - // If AES-GCM hardware is provided then prioritise AES-GCM - // cipher suites. - topTLS13CipherSuites = []uint16{ - TLS_AES_128_GCM_SHA256, - TLS_AES_256_GCM_SHA384, - TLS_CHACHA20_POLY1305_SHA256, - } - topCipherSuites = []uint16{ - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - } - } else { - // Without AES-GCM hardware, we put the ChaCha20-Poly1305 - // cipher suites first. - topTLS13CipherSuites = []uint16{ - TLS_CHACHA20_POLY1305_SHA256, - TLS_AES_128_GCM_SHA256, - TLS_AES_256_GCM_SHA384, - } - topCipherSuites = []uint16{ - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - } - } - - varDefaultTLS13CipherSuites = make([]uint16, 0, len(cipherSuites)) - varDefaultTLS13CipherSuites = append(varDefaultTLS13CipherSuites, topTLS13CipherSuites...) - varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites)) - varDefaultCipherSuites = append(varDefaultCipherSuites, topCipherSuites...) - -NextCipherSuite: - for _, suite := range cipherSuites { - if suite.flags&suiteDefaultOff != 0 { - continue - } - if suite.flags&suiteTLS13 != 0 { - for _, existing := range varDefaultTLS13CipherSuites { - if existing == suite.id { - continue NextCipherSuite - } - } - varDefaultTLS13CipherSuites = append(varDefaultTLS13CipherSuites, suite.id) - } else { - for _, existing := range varDefaultCipherSuites { - if existing == suite.id { - continue NextCipherSuite - } - } - varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id) - } - } - varDefaultCipherSuites = append(varDefaultTLS13CipherSuites, varDefaultCipherSuites...) -} - -func unexpectedMessageError(wanted, got interface{}) error { - return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted) -} - -func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool { - for _, s := range supportedSignatureAlgorithms { - if s == sigAlg { - return true - } - } - return false -} - -// signatureFromSignatureScheme maps a signature algorithm to the underlying -// signature method (without hash function). -func signatureFromSignatureScheme(signatureAlgorithm SignatureScheme) uint8 { - switch signatureAlgorithm { - case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512: - return signaturePKCS1v15 - case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512: - return signatureRSAPSS - case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512: - return signatureECDSA - default: - return 0 - } -} - -// TODO(kk): Use variable length encoding? -func getUint24(b []byte) int { - n := int(b[2]) - n += int(b[1] << 8) - n += int(b[0] << 16) - return n -} - -func putUint24(b []byte, n int) { - b[0] = byte(n >> 16) - b[1] = byte(n >> 8) - b[2] = byte(n & 0xff) -} diff --git a/external/github.com/marten-seemann/qtls/conn.go b/external/github.com/marten-seemann/qtls/conn.go deleted file mode 100644 index 669315399..000000000 --- a/external/github.com/marten-seemann/qtls/conn.go +++ /dev/null @@ -1,1771 +0,0 @@ -// Copyright 2010 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. - -// TLS low level connection and record layer - -package qtls - -import ( - "bytes" - "crypto/cipher" - "crypto/subtle" - "crypto/x509" - "encoding/binary" - "errors" - "fmt" - "io" - "net" - "sync" - "sync/atomic" - "time" -) - -// A Conn represents a secured connection. -// It implements the net.Conn interface. -type Conn struct { - // constant - conn net.Conn - isClient bool - - phase handshakeStatus // protected by in.Mutex - // handshakeConfirmed is an atomic bool for phase == handshakeConfirmed - handshakeConfirmed int32 - // confirmMutex is held by any read operation before handshakeConfirmed - confirmMutex sync.Mutex - - // constant after handshake; protected by handshakeMutex - handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex - handshakeErr error // error resulting from handshake - connID []byte // Random connection id - clientHello []byte // ClientHello packet contents - vers uint16 // TLS version - haveVers bool // version has been negotiated - config *Config // configuration passed to constructor - // handshakeComplete is true if the connection reached application data - // and it's equivalent to phase > handshakeRunning - handshakeComplete bool - // handshakes counts the number of handshakes performed on the - // connection so far. If renegotiation is disabled then this is either - // zero or one. - handshakes int - didResume bool // whether this connection was a session resumption - cipherSuite uint16 - ocspResponse []byte // stapled OCSP response - scts [][]byte // Signed certificate timestamps from server - peerCertificates []*x509.Certificate - // verifiedChains contains the certificate chains that we built, as - // opposed to the ones presented by the server. - verifiedChains [][]*x509.Certificate - // verifiedDc is set by a client who negotiates the use of a valid delegated - // credential. - verifiedDc *delegatedCredential - // serverName contains the server name indicated by the client, if any. - serverName string - // secureRenegotiation is true if the server echoed the secure - // renegotiation extension. (This is meaningless as a server because - // renegotiation is not supported in that case.) - secureRenegotiation bool - // indicates wether extended MasterSecret extension is used (see RFC7627) - useEMS bool - - // clientFinishedIsFirst is true if the client sent the first Finished - // message during the most recent handshake. This is recorded because - // the first transmitted Finished message is the tls-unique - // channel-binding value. - clientFinishedIsFirst bool - - // closeNotifyErr is any error from sending the alertCloseNotify record. - closeNotifyErr error - // closeNotifySent is true if the Conn attempted to send an - // alertCloseNotify record. - closeNotifySent bool - - // clientFinished and serverFinished contain the Finished message sent - // by the client or server in the most recent handshake. This is - // retained to support the renegotiation extension and tls-unique - // channel-binding. - clientFinished [12]byte - serverFinished [12]byte - - clientProtocol string - clientProtocolFallback bool - - // ticketMaxEarlyData is the maximum bytes of 0-RTT application data - // that the client is allowed to send on the ticket it used. - ticketMaxEarlyData int64 - - // input/output - in, out halfConn // in.Mutex < out.Mutex - rawInput *block // raw input, right off the wire - input *block // application data waiting to be read - hand bytes.Buffer // handshake data waiting to be read - buffering bool // whether records are buffered in sendBuf - sendBuf []byte // a buffer of records waiting to be sent - - // bytesSent counts the bytes of application data sent. - // packetsSent counts packets. - bytesSent int64 - packetsSent int64 - - // warnCount counts the number of consecutive warning alerts received - // by Conn.readRecord. Protected by in.Mutex. - warnCount int - - // activeCall is an atomic int32; the low bit is whether Close has - // been called. the rest of the bits are the number of goroutines - // in Conn.Write. - activeCall int32 - - // TLS 1.3 needs the server state until it reaches the Client Finished - hs *serverHandshakeState - - // earlyDataBytes is the number of bytes of early data received so - // far. Tracked to enforce max_early_data_size. - // We don't keep track of rejected 0-RTT data since there's no need - // to ever buffer it. in.Mutex. - earlyDataBytes int64 - - // binder is the value of the PSK binder that was validated to - // accept the 0-RTT data. Exposed as ConnectionState.Unique0RTTToken. - binder []byte - - tmp [16]byte -} - -type handshakeStatus int - -const ( - handshakeRunning handshakeStatus = iota - discardingEarlyData - readingEarlyData - waitingClientFinished - readingClientFinished - handshakeConfirmed -) - -// Access to net.Conn methods. -// Cannot just embed net.Conn because that would -// export the struct field too. - -// LocalAddr returns the local network address. -func (c *Conn) LocalAddr() net.Addr { - return c.conn.LocalAddr() -} - -// RemoteAddr returns the remote network address. -func (c *Conn) RemoteAddr() net.Addr { - return c.conn.RemoteAddr() -} - -// SetDeadline sets the read and write deadlines associated with the connection. -// A zero value for t means Read and Write will not time out. -// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. -func (c *Conn) SetDeadline(t time.Time) error { - return c.conn.SetDeadline(t) -} - -// SetReadDeadline sets the read deadline on the underlying connection. -// A zero value for t means Read will not time out. -func (c *Conn) SetReadDeadline(t time.Time) error { - return c.conn.SetReadDeadline(t) -} - -// SetWriteDeadline sets the write deadline on the underlying connection. -// A zero value for t means Write will not time out. -// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. -func (c *Conn) SetWriteDeadline(t time.Time) error { - return c.conn.SetWriteDeadline(t) -} - -// A halfConn represents one direction of the record layer -// connection, either sending or receiving. -type halfConn struct { - sync.Mutex - - err error // first permanent error - version uint16 // protocol version - cipher interface{} // cipher algorithm - mac macFunction - seq [8]byte // 64-bit sequence number - bfree *block // list of free blocks - additionalData [13]byte // to avoid allocs; interface method args escape - - nextCipher interface{} // next encryption state - nextMac macFunction // next MAC algorithm - - // used to save allocating a new buffer for each MAC. - inDigestBuf, outDigestBuf []byte - - setKeyCallback func(suite *CipherSuite, trafficSecret []byte) - - traceErr func(error) -} - -func (hc *halfConn) setErrorLocked(err error) error { - hc.err = err - if hc.traceErr != nil { - hc.traceErr(err) - } - return err -} - -// prepareCipherSpec sets the encryption and MAC states -// that a subsequent changeCipherSpec will use. -func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) { - hc.version = version - hc.nextCipher = cipher - hc.nextMac = mac -} - -// changeCipherSpec changes the encryption and MAC states -// to the ones previously passed to prepareCipherSpec. -func (hc *halfConn) changeCipherSpec() error { - if hc.nextCipher == nil { - return alertInternalError - } - hc.cipher = hc.nextCipher - hc.mac = hc.nextMac - hc.nextCipher = nil - hc.nextMac = nil - for i := range hc.seq { - hc.seq[i] = 0 - } - return nil -} - -func (hc *halfConn) exportKey(suite *cipherSuite, trafficSecret []byte) { - if hc.setKeyCallback != nil { - hc.setKeyCallback(&CipherSuite{*suite}, trafficSecret) - } -} - -func (hc *halfConn) setKey(version uint16, suite *cipherSuite, trafficSecret []byte) { - if hc.setKeyCallback != nil { - return - } - hc.version = version - hash := hashForSuite(suite) - key := hkdfExpandLabel(hash, trafficSecret, nil, "key", suite.keyLen) - iv := hkdfExpandLabel(hash, trafficSecret, nil, "iv", suite.ivLen) - hc.cipher = suite.aead(key, iv) - for i := range hc.seq { - hc.seq[i] = 0 - } -} - -// incSeq increments the sequence number. -func (hc *halfConn) incSeq() { - for i := 7; i >= 0; i-- { - hc.seq[i]++ - if hc.seq[i] != 0 { - return - } - } - - // Not allowed to let sequence number wrap. - // Instead, must renegotiate before it does. - // Not likely enough to bother. - panic("TLS: sequence number wraparound") -} - -// extractPadding returns, in constant time, the length of the padding to remove -// from the end of payload. It also returns a byte which is equal to 255 if the -// padding was valid and 0 otherwise. See RFC 2246, section 6.2.3.2 -func extractPadding(payload []byte) (toRemove int, good byte) { - if len(payload) < 1 { - return 0, 0 - } - - paddingLen := payload[len(payload)-1] - t := uint(len(payload)-1) - uint(paddingLen) - // if len(payload) >= (paddingLen - 1) then the MSB of t is zero - good = byte(int32(^t) >> 31) - - // The maximum possible padding length plus the actual length field - toCheck := 256 - // The length of the padded data is public, so we can use an if here - if toCheck > len(payload) { - toCheck = len(payload) - } - - for i := 0; i < toCheck; i++ { - t := uint(paddingLen) - uint(i) - // if i <= paddingLen then the MSB of t is zero - mask := byte(int32(^t) >> 31) - b := payload[len(payload)-1-i] - good &^= mask&paddingLen ^ mask&b - } - - // We AND together the bits of good and replicate the result across - // all the bits. - good &= good << 4 - good &= good << 2 - good &= good << 1 - good = uint8(int8(good) >> 7) - - toRemove = int(paddingLen) + 1 - return -} - -// extractPaddingSSL30 is a replacement for extractPadding in the case that the -// protocol version is SSLv3. In this version, the contents of the padding -// are random and cannot be checked. -func extractPaddingSSL30(payload []byte) (toRemove int, good byte) { - if len(payload) < 1 { - return 0, 0 - } - - paddingLen := int(payload[len(payload)-1]) + 1 - if paddingLen > len(payload) { - return 0, 0 - } - - return paddingLen, 255 -} - -func roundUp(a, b int) int { - return a + (b-a%b)%b -} - -// cbcMode is an interface for block ciphers using cipher block chaining. -type cbcMode interface { - cipher.BlockMode - SetIV([]byte) -} - -// decrypt checks and strips the mac and decrypts the data in b. Returns a -// success boolean, the number of bytes to skip from the start of the record in -// order to get the application payload, and an optional alert value. -func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) { - // pull out payload - payload := b.data[recordHeaderLen:] - - macSize := 0 - if hc.mac != nil { - macSize = hc.mac.Size() - } - - paddingGood := byte(255) - paddingLen := 0 - explicitIVLen := 0 - - // decrypt - if hc.cipher != nil { - switch c := hc.cipher.(type) { - case cipher.Stream: - c.XORKeyStream(payload, payload) - case aead: - explicitIVLen = c.explicitNonceLen() - if len(payload) < explicitIVLen { - return false, 0, alertBadRecordMAC - } - nonce := payload[:explicitIVLen] - payload = payload[explicitIVLen:] - - if len(nonce) == 0 { - nonce = hc.seq[:] - } - - var additionalData []byte - if hc.version < VersionTLS13 { - copy(hc.additionalData[:], hc.seq[:]) - copy(hc.additionalData[8:], b.data[:3]) - n := len(payload) - c.Overhead() - hc.additionalData[11] = byte(n >> 8) - hc.additionalData[12] = byte(n) - additionalData = hc.additionalData[:] - } else { - if len(payload) > int((1<<14)+256) { - return false, 0, alertRecordOverflow - } - // Check AD header, see 5.2 of RFC8446 - additionalData = make([]byte, 5) - additionalData[0] = byte(recordTypeApplicationData) - binary.BigEndian.PutUint16(additionalData[1:], VersionTLS12) - binary.BigEndian.PutUint16(additionalData[3:], uint16(len(payload))) - } - var err error - payload, err = c.Open(payload[:0], nonce, payload, additionalData) - if err != nil { - return false, 0, alertBadRecordMAC - } - b.resize(recordHeaderLen + explicitIVLen + len(payload)) - case cbcMode: - blockSize := c.BlockSize() - if hc.version >= VersionTLS11 { - explicitIVLen = blockSize - } - - if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) { - return false, 0, alertBadRecordMAC - } - - if explicitIVLen > 0 { - c.SetIV(payload[:explicitIVLen]) - payload = payload[explicitIVLen:] - } - c.CryptBlocks(payload, payload) - if hc.version == VersionSSL30 { - paddingLen, paddingGood = extractPaddingSSL30(payload) - } else { - paddingLen, paddingGood = extractPadding(payload) - - // To protect against CBC padding oracles like Lucky13, the data - // past paddingLen (which is secret) is passed to the MAC - // function as extra data, to be fed into the HMAC after - // computing the digest. This makes the MAC constant time as - // long as the digest computation is constant time and does not - // affect the subsequent write. - } - default: - panic("unknown cipher type") - } - } - - // check, strip mac - if hc.mac != nil { - if len(payload) < macSize { - return false, 0, alertBadRecordMAC - } - - // strip mac off payload, b.data - n := len(payload) - macSize - paddingLen - n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 } - b.data[3] = byte(n >> 8) - b.data[4] = byte(n) - remoteMAC := payload[n : n+macSize] - localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n], payload[n+macSize:]) - - if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 { - return false, 0, alertBadRecordMAC - } - hc.inDigestBuf = localMAC - - b.resize(recordHeaderLen + explicitIVLen + n) - } - hc.incSeq() - - return true, recordHeaderLen + explicitIVLen, 0 -} - -// padToBlockSize calculates the needed padding block, if any, for a payload. -// On exit, prefix aliases payload and extends to the end of the last full -// block of payload. finalBlock is a fresh slice which contains the contents of -// any suffix of payload as well as the needed padding to make finalBlock a -// full block. -func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) { - overrun := len(payload) % blockSize - paddingLen := blockSize - overrun - prefix = payload[:len(payload)-overrun] - finalBlock = make([]byte, blockSize) - copy(finalBlock, payload[len(payload)-overrun:]) - for i := overrun; i < blockSize; i++ { - finalBlock[i] = byte(paddingLen - 1) - } - return -} - -// encrypt encrypts and macs the data in b. -func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) { - // mac - if hc.mac != nil { - mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:], nil) - - n := len(b.data) - b.resize(n + len(mac)) - copy(b.data[n:], mac) - hc.outDigestBuf = mac - } - - payload := b.data[recordHeaderLen:] - - // encrypt - if hc.cipher != nil { - switch c := hc.cipher.(type) { - case cipher.Stream: - c.XORKeyStream(payload, payload) - case aead: - // explicitIVLen is always 0 for TLS1.3 - payloadLen := len(b.data) - recordHeaderLen - explicitIVLen - payloadOffset := recordHeaderLen + explicitIVLen - nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] - if len(nonce) == 0 { - nonce = hc.seq[:] - } - - var additionalData []byte - if hc.version < VersionTLS13 { - // make room in a buffer for payload + MAC - b.resize(len(b.data) + c.Overhead()) - - payload = b.data[payloadOffset : payloadOffset+payloadLen] - copy(hc.additionalData[:], hc.seq[:]) - copy(hc.additionalData[8:], b.data[:3]) - binary.BigEndian.PutUint16(hc.additionalData[11:], uint16(payloadLen)) - additionalData = hc.additionalData[:] - } else { - // make room in a buffer for TLSCiphertext.encrypted_record: - // payload + MAC + extra data if needed - b.resize(len(b.data) + c.Overhead() + 1) - - payload = b.data[payloadOffset : payloadOffset+payloadLen+1] - // 1 byte of content type is appended to payload and encrypted - payload[len(payload)-1] = b.data[0] - - // opaque_type - b.data[0] = byte(recordTypeApplicationData) - - // Add AD header, see 5.2 of RFC8446 - additionalData = make([]byte, 5) - additionalData[0] = b.data[0] - binary.BigEndian.PutUint16(additionalData[1:], VersionTLS12) - binary.BigEndian.PutUint16(additionalData[3:], uint16(len(payload)+c.Overhead())) - } - c.Seal(payload[:0], nonce, payload, additionalData) - case cbcMode: - blockSize := c.BlockSize() - if explicitIVLen > 0 { - c.SetIV(payload[:explicitIVLen]) - payload = payload[explicitIVLen:] - } - prefix, finalBlock := padToBlockSize(payload, blockSize) - b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock)) - c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix) - c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock) - default: - panic("unknown cipher type") - } - } - - // update length to include MAC and any block padding needed. - n := len(b.data) - recordHeaderLen - b.data[3] = byte(n >> 8) - b.data[4] = byte(n) - hc.incSeq() - - return true, 0 -} - -// A block is a simple data buffer. -type block struct { - data []byte - off int // index for Read - link *block -} - -// resize resizes block to be n bytes, growing if necessary. -func (b *block) resize(n int) { - if n > cap(b.data) { - b.reserve(n) - } - b.data = b.data[0:n] -} - -// reserve makes sure that block contains a capacity of at least n bytes. -func (b *block) reserve(n int) { - if cap(b.data) >= n { - return - } - m := cap(b.data) - if m == 0 { - m = 1024 - } - for m < n { - m *= 2 - } - data := make([]byte, len(b.data), m) - copy(data, b.data) - b.data = data -} - -// readFromUntil reads from r into b until b contains at least n bytes -// or else returns an error. -func (b *block) readFromUntil(r io.Reader, n int) error { - // quick case - if len(b.data) >= n { - return nil - } - - // read until have enough. - b.reserve(n) - for { - m, err := r.Read(b.data[len(b.data):cap(b.data)]) - b.data = b.data[0 : len(b.data)+m] - if len(b.data) >= n { - // TODO(bradfitz,agl): slightly suspicious - // that we're throwing away r.Read's err here. - break - } - if err != nil { - return err - } - } - return nil -} - -func (b *block) Read(p []byte) (n int, err error) { - n = copy(p, b.data[b.off:]) - b.off += n - if b.off >= len(b.data) { - err = io.EOF - } - return -} - -// newBlock allocates a new block, from hc's free list if possible. -func (hc *halfConn) newBlock() *block { - b := hc.bfree - if b == nil { - return new(block) - } - hc.bfree = b.link - b.link = nil - b.resize(0) - return b -} - -// freeBlock returns a block to hc's free list. -// The protocol is such that each side only has a block or two on -// its free list at a time, so there's no need to worry about -// trimming the list, etc. -func (hc *halfConn) freeBlock(b *block) { - b.link = hc.bfree - hc.bfree = b -} - -// splitBlock splits a block after the first n bytes, -// returning a block with those n bytes and a -// block with the remainder. the latter may be nil. -func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) { - if len(b.data) <= n { - return b, nil - } - bb := hc.newBlock() - bb.resize(len(b.data) - n) - copy(bb.data, b.data[n:]) - b.data = b.data[0:n] - return b, bb -} - -// RecordHeaderError results when a TLS record header is invalid. -type RecordHeaderError struct { - // Msg contains a human readable string that describes the error. - Msg string - // RecordHeader contains the five bytes of TLS record header that - // triggered the error. - RecordHeader [5]byte -} - -func (e RecordHeaderError) Error() string { return "tls: " + e.Msg } - -func (c *Conn) newRecordHeaderError(msg string) (err RecordHeaderError) { - err.Msg = msg - copy(err.RecordHeader[:], c.rawInput.data) - return err -} - -// readRecord reads the next TLS record from the connection -// and updates the record layer state. -// c.in.Mutex <= L; c.input == nil. -// c.input can still be nil after a call, retry if so. -func (c *Conn) readRecord(want recordType) error { - // Caller must be in sync with connection: - // handshake data if handshake not yet completed, - // else application data. - switch want { - default: - c.sendAlert(alertInternalError) - return c.in.setErrorLocked(errors.New("tls: unknown record type requested")) - case recordTypeHandshake, recordTypeChangeCipherSpec: - if c.phase != handshakeRunning && c.phase != readingClientFinished { - c.sendAlert(alertInternalError) - return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested while not in handshake")) - } - case recordTypeApplicationData: - if c.phase == handshakeRunning || c.phase == readingClientFinished { - c.sendAlert(alertInternalError) - return c.in.setErrorLocked(errors.New("tls: application data record requested while in handshake")) - } - } - -Again: - if c.rawInput == nil { - c.rawInput = c.in.newBlock() - } - b := c.rawInput - - // Read header, payload. - if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil { - // RFC suggests that EOF without an alertCloseNotify is - // an error, but popular web sites seem to do this, - // so we can't make it an error. - // if err == io.EOF { - // err = io.ErrUnexpectedEOF - // } - if e, ok := err.(net.Error); !ok || !e.Temporary() { - c.in.setErrorLocked(err) - } - return err - } - typ := recordType(b.data[0]) - - // No valid TLS record has a type of 0x80, however SSLv2 handshakes - // start with a uint16 length where the MSB is set and the first record - // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests - // an SSLv2 client. - if want == recordTypeHandshake && typ == 0x80 { - c.sendAlert(alertProtocolVersion) - return c.in.setErrorLocked(c.newRecordHeaderError("unsupported SSLv2 handshake received")) - } - - vers := uint16(b.data[1])<<8 | uint16(b.data[2]) - n := int(b.data[3])<<8 | int(b.data[4]) - if n > maxCiphertext { - c.sendAlert(alertRecordOverflow) - msg := fmt.Sprintf("oversized record received with length %d", n) - return c.in.setErrorLocked(c.newRecordHeaderError(msg)) - } - if !c.haveVers { - // First message, be extra suspicious: this might not be a TLS - // client. Bail out before reading a full 'body', if possible. - // The current max version is 3.3 so if the version is >= 16.0, - // it's probably not real. - if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 { - c.sendAlert(alertUnexpectedMessage) - return c.in.setErrorLocked(c.newRecordHeaderError("first record does not look like a TLS handshake")) - } - } - if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - if e, ok := err.(net.Error); !ok || !e.Temporary() { - c.in.setErrorLocked(err) - } - return err - } - - // Process message. - b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n) - - // TLS 1.3 middlebox compatibility: skip over unencrypted CCS. - if c.vers >= VersionTLS13 && typ == recordTypeChangeCipherSpec && c.phase != handshakeConfirmed { - if len(b.data) != 6 || b.data[5] != 1 { - c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - c.in.freeBlock(b) - return c.in.err - } - - peekedAlert := peekAlert(b) // peek at a possible alert before decryption - ok, off, alertValue := c.in.decrypt(b) - switch { - case !ok && c.phase == discardingEarlyData: - // If the client said that it's sending early data and we did not - // accept it, we are expected to fail decryption. - c.in.freeBlock(b) - return nil - case ok && c.phase == discardingEarlyData: - c.phase = waitingClientFinished - case !ok: - c.in.traceErr, c.out.traceErr = nil, nil // not that interesting - c.in.freeBlock(b) - err := c.sendAlert(alertValue) - // If decryption failed because the message is an unencrypted - // alert, return a more meaningful error message - if alertValue == alertBadRecordMAC && peekedAlert != nil { - err = peekedAlert - } - return c.in.setErrorLocked(err) - } - b.off = off - data := b.data[b.off:] - if (c.vers < VersionTLS13 && len(data) > maxPlaintext) || len(data) > maxPlaintext+1 { - c.in.freeBlock(b) - return c.in.setErrorLocked(c.sendAlert(alertRecordOverflow)) - } - - // After checking the plaintext length, remove 1.3 padding and - // extract the real content type. - // See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-5.4. - if c.vers >= VersionTLS13 { - i := len(data) - 1 - for i >= 0 { - if data[i] != 0 { - break - } - i-- - } - if i < 0 { - c.in.freeBlock(b) - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - typ = recordType(data[i]) - data = data[:i] - b.resize(b.off + i) // shrinks, guaranteed not to reallocate - } - - if typ != recordTypeAlert && len(data) > 0 { - // this is a valid non-alert message: reset the count of alerts - c.warnCount = 0 - } - - switch typ { - default: - c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - - case recordTypeAlert: - if len(data) != 2 { - c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - break - } - if alert(data[1]) == alertCloseNotify { - c.in.setErrorLocked(io.EOF) - break - } - switch data[0] { - case alertLevelWarning: - // drop on the floor - c.in.freeBlock(b) - - c.warnCount++ - if c.warnCount > maxWarnAlertCount { - c.sendAlert(alertUnexpectedMessage) - return c.in.setErrorLocked(errors.New("tls: too many warn alerts")) - } - - goto Again - case alertLevelError: - c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])}) - default: - c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - - case recordTypeChangeCipherSpec: - if typ != want || len(data) != 1 || data[0] != 1 || c.vers >= VersionTLS13 { - c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - break - } - // Handshake messages are not allowed to fragment across the CCS - if c.hand.Len() > 0 { - c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - break - } - // Handshake messages are not allowed to fragment across the CCS - if c.hand.Len() > 0 { - c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - break - } - err := c.in.changeCipherSpec() - if err != nil { - c.in.setErrorLocked(c.sendAlert(err.(alert))) - } - - case recordTypeApplicationData: - if typ != want || c.phase == waitingClientFinished { - c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - break - } - if c.phase == readingEarlyData { - c.earlyDataBytes += int64(len(b.data) - b.off) - if c.earlyDataBytes > c.ticketMaxEarlyData { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - } - c.input = b - b = nil - - case recordTypeHandshake: - // TODO(rsc): Should at least pick off connection close. - // If early data was being read, a Finished message is expected - // instead of (early) application data. Other post-handshake - // messages include HelloRequest and NewSessionTicket. - if typ != want && want != recordTypeApplicationData { - return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - c.hand.Write(data) - } - - if b != nil { - c.in.freeBlock(b) - } - return c.in.err -} - -// peekAlert looks at a message to spot an unencrypted alert. It must be -// called before decryption to avoid a side channel, and its result must -// only be used if decryption fails, to avoid false positives. -func peekAlert(b *block) error { - if len(b.data) < 7 { - return nil - } - if recordType(b.data[0]) != recordTypeAlert { - return nil - } - return &net.OpError{Op: "remote error", Err: alert(b.data[6])} -} - -// sendAlert sends a TLS alert message. -// c.out.Mutex <= L. -func (c *Conn) sendAlertLocked(err alert) error { - switch err { - case alertNoRenegotiation, alertCloseNotify: - c.tmp[0] = alertLevelWarning - default: - c.tmp[0] = alertLevelError - } - c.tmp[1] = byte(err) - - _, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2]) - if err == alertCloseNotify { - // closeNotify is a special case in that it isn't an error. - return writeErr - } - - return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) -} - -// sendAlert sends a TLS alert message. -// L < c.out.Mutex. -func (c *Conn) sendAlert(err alert) error { - if c.config.AlternativeRecordLayer != nil { - return nil - } - c.out.Lock() - defer c.out.Unlock() - return c.sendAlertLocked(err) -} - -const ( - // tcpMSSEstimate is a conservative estimate of the TCP maximum segment - // size (MSS). A constant is used, rather than querying the kernel for - // the actual MSS, to avoid complexity. The value here is the IPv6 - // minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40 - // bytes) and a TCP header with timestamps (32 bytes). - tcpMSSEstimate = 1208 - - // recordSizeBoostThreshold is the number of bytes of application data - // sent after which the TLS record size will be increased to the - // maximum. - recordSizeBoostThreshold = 128 * 1024 -) - -// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the -// next application data record. There is the following trade-off: -// -// - For latency-sensitive applications, such as web browsing, each TLS -// record should fit in one TCP segment. -// - For throughput-sensitive applications, such as large file transfers, -// larger TLS records better amortize framing and encryption overheads. -// -// A simple heuristic that works well in practice is to use small records for -// the first 1MB of data, then use larger records for subsequent data, and -// reset back to smaller records after the connection becomes idle. See "High -// Performance Web Networking", Chapter 4, or: -// https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/ -// -// In the interests of simplicity and determinism, this code does not attempt -// to reset the record size once the connection is idle, however. -// -// c.out.Mutex <= L. -func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int { - if c.config.DynamicRecordSizingDisabled || typ != recordTypeApplicationData { - return maxPlaintext - } - - if c.bytesSent >= recordSizeBoostThreshold { - return maxPlaintext - } - - // Subtract TLS overheads to get the maximum payload size. - macSize := 0 - if c.out.mac != nil { - macSize = c.out.mac.Size() - } - - payloadBytes := tcpMSSEstimate - recordHeaderLen - explicitIVLen - if c.out.cipher != nil { - switch ciph := c.out.cipher.(type) { - case cipher.Stream: - payloadBytes -= macSize - case cipher.AEAD: - payloadBytes -= ciph.Overhead() - if c.vers >= VersionTLS13 { - payloadBytes -= 1 // ContentType - } - case cbcMode: - blockSize := ciph.BlockSize() - // The payload must fit in a multiple of blockSize, with - // room for at least one padding byte. - payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1 - // The MAC is appended before padding so affects the - // payload size directly. - payloadBytes -= macSize - default: - panic("unknown cipher type") - } - } - - // Allow packet growth in arithmetic progression up to max. - pkt := c.packetsSent - c.packetsSent++ - if pkt > 1000 { - return maxPlaintext // avoid overflow in multiply below - } - - n := payloadBytes * int(pkt+1) - if n > maxPlaintext { - n = maxPlaintext - } - return n -} - -// c.out.Mutex <= L. -func (c *Conn) write(data []byte) (int, error) { - if c.buffering { - c.sendBuf = append(c.sendBuf, data...) - return len(data), nil - } - - n, err := c.conn.Write(data) - c.bytesSent += int64(n) - return n, err -} - -func (c *Conn) flush() (int, error) { - if len(c.sendBuf) == 0 { - return 0, nil - } - - n, err := c.conn.Write(c.sendBuf) - c.bytesSent += int64(n) - c.sendBuf = nil - c.buffering = false - return n, err -} - -// writeRecordLocked writes a TLS record with the given type and payload to the -// connection and updates the record layer state. -// c.out.Mutex <= L. -func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) { - b := c.out.newBlock() - defer c.out.freeBlock(b) - - var n int - for len(data) > 0 { - explicitIVLen := 0 - explicitIVIsSeq := false - - var cbc cbcMode - if c.out.version >= VersionTLS11 { - var ok bool - if cbc, ok = c.out.cipher.(cbcMode); ok { - explicitIVLen = cbc.BlockSize() - } - } - if explicitIVLen == 0 { - if c, ok := c.out.cipher.(aead); ok { - explicitIVLen = c.explicitNonceLen() - - // The AES-GCM construction in TLS has an - // explicit nonce so that the nonce can be - // random. However, the nonce is only 8 bytes - // which is too small for a secure, random - // nonce. Therefore we use the sequence number - // as the nonce. - explicitIVIsSeq = explicitIVLen > 0 - } - } - m := len(data) - if maxPayload := c.maxPayloadSizeForWrite(typ, explicitIVLen); m > maxPayload { - m = maxPayload - } - b.resize(recordHeaderLen + explicitIVLen + m) - b.data[0] = byte(typ) - vers := c.vers - if vers == 0 { - // Some TLS servers fail if the record version is - // greater than TLS 1.0 for the initial ClientHello. - vers = VersionTLS10 - } - if c.vers >= VersionTLS13 { - // TLS 1.3 froze the record layer version at { 3, 1 }. - // See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-5.1. - // But for draft 22, this was changed to { 3, 3 }. - vers = VersionTLS12 - } - b.data[1] = byte(vers >> 8) - b.data[2] = byte(vers) - b.data[3] = byte(m >> 8) - b.data[4] = byte(m) - if explicitIVLen > 0 { - explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] - if explicitIVIsSeq { - copy(explicitIV, c.out.seq[:]) - } else { - if _, err := io.ReadFull(c.config.rand(), explicitIV); err != nil { - return n, err - } - } - } - copy(b.data[recordHeaderLen+explicitIVLen:], data) - c.out.encrypt(b, explicitIVLen) - if _, err := c.write(b.data); err != nil { - return n, err - } - n += m - data = data[m:] - } - - if typ == recordTypeChangeCipherSpec && c.vers < VersionTLS13 { - if err := c.out.changeCipherSpec(); err != nil { - return n, c.sendAlertLocked(err.(alert)) - } - } - - return n, nil -} - -// writeRecord writes a TLS record with the given type and payload to the -// connection and updates the record layer state. -// L < c.out.Mutex. -func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) { - if c.config.AlternativeRecordLayer != nil { - if typ == recordTypeChangeCipherSpec { - return len(data), nil - } - return c.config.AlternativeRecordLayer.WriteRecord(data) - } - - c.out.Lock() - defer c.out.Unlock() - - return c.writeRecordLocked(typ, data) -} - -// readHandshake reads the next handshake message from -// the record layer. -// c.in.Mutex < L; c.out.Mutex < L. -func (c *Conn) readHandshake() (interface{}, error) { - var data []byte - if c.config.AlternativeRecordLayer != nil { - var err error - data, err = c.config.AlternativeRecordLayer.ReadHandshakeMessage() - if err != nil { - return nil, err - } - } else { - for c.hand.Len() < 4 { - if err := c.in.err; err != nil { - return nil, err - } - if err := c.readRecord(recordTypeHandshake); err != nil { - return nil, err - } - } - - data = c.hand.Bytes() - n := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) - if n > maxHandshake { - c.sendAlertLocked(alertInternalError) - return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)) - } - for c.hand.Len() < 4+n { - if err := c.in.err; err != nil { - return nil, err - } - if err := c.readRecord(recordTypeHandshake); err != nil { - return nil, err - } - } - data = c.hand.Next(4 + n) - } - var m handshakeMessage - switch data[0] { - case typeHelloRequest: - m = new(helloRequestMsg) - case typeClientHello: - m = new(clientHelloMsg) - case typeServerHello: - m = new(serverHelloMsg) - case typeEncryptedExtensions: - m = new(encryptedExtensionsMsg) - case typeNewSessionTicket: - if c.vers >= VersionTLS13 { - m = new(newSessionTicketMsg13) - } else { - m = new(newSessionTicketMsg) - } - case typeEndOfEarlyData: - m = new(endOfEarlyDataMsg) - case typeCertificate: - if c.vers >= VersionTLS13 { - m = new(certificateMsg13) - } else { - m = new(certificateMsg) - } - case typeCertificateRequest: - if c.vers >= VersionTLS13 { - m = new(certificateRequestMsg13) - } else { - m = &certificateRequestMsg{ - hasSignatureAndHash: c.vers >= VersionTLS12, - } - } - case typeCertificateStatus: - m = new(certificateStatusMsg) - case typeServerKeyExchange: - m = new(serverKeyExchangeMsg) - case typeServerHelloDone: - m = new(serverHelloDoneMsg) - case typeClientKeyExchange: - m = new(clientKeyExchangeMsg) - case typeCertificateVerify: - m = &certificateVerifyMsg{ - hasSignatureAndHash: c.vers >= VersionTLS12, - } - case typeNextProtocol: - m = new(nextProtoMsg) - case typeFinished: - m = new(finishedMsg) - default: - return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } - - // The handshake message unmarshalers - // expect to be able to keep references to data, - // so pass in a fresh copy that won't be overwritten. - data = append([]byte(nil), data...) - - if unmarshalAlert := m.unmarshal(data); unmarshalAlert != alertSuccess { - return nil, c.in.setErrorLocked(c.sendAlert(unmarshalAlert)) - } - return m, nil -} - -var ( - errClosed = errors.New("tls: use of closed connection") - errShutdown = errors.New("tls: protocol is shutdown") -) - -// Write writes data to the connection. -func (c *Conn) Write(b []byte) (int, error) { - // interlock with Close below - for { - x := atomic.LoadInt32(&c.activeCall) - if x&1 != 0 { - return 0, errClosed - } - if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) { - defer atomic.AddInt32(&c.activeCall, -2) - break - } - } - - if err := c.Handshake(); err != nil { - return 0, err - } - - c.out.Lock() - defer c.out.Unlock() - - if err := c.out.err; err != nil { - return 0, err - } - - if !c.handshakeComplete { - return 0, alertInternalError - } - - if c.closeNotifySent { - return 0, errShutdown - } - - // SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext - // attack when using block mode ciphers due to predictable IVs. - // This can be prevented by splitting each Application Data - // record into two records, effectively randomizing the IV. - // - // http://www.openssl.org/~bodo/tls-cbc.txt - // https://bugzilla.mozilla.org/show_bug.cgi?id=665814 - // http://www.imperialviolet.org/2012/01/15/beastfollowup.html - - var m int - if len(b) > 1 && c.vers <= VersionTLS10 { - if _, ok := c.out.cipher.(cipher.BlockMode); ok { - n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1]) - if err != nil { - return n, c.out.setErrorLocked(err) - } - m, b = 1, b[1:] - } - } - - n, err := c.writeRecordLocked(recordTypeApplicationData, b) - return n + m, c.out.setErrorLocked(err) -} - -// Process Handshake messages after the handshake has completed. -// c.in.Mutex <= L -func (c *Conn) handlePostHandshake() error { - msg, err := c.readHandshake() - if err != nil { - return err - } - - switch hm := msg.(type) { - case *helloRequestMsg: - return c.handleRenegotiation(hm) - case *newSessionTicketMsg13: - if !c.isClient { - c.sendAlert(alertUnexpectedMessage) - return alertUnexpectedMessage - } - return nil // TODO implement session tickets - default: - c.sendAlert(alertUnexpectedMessage) - return alertUnexpectedMessage - } -} - -// handleRenegotiation processes a HelloRequest handshake message. -// c.in.Mutex <= L -func (c *Conn) handleRenegotiation(*helloRequestMsg) error { - if !c.isClient { - return c.sendAlert(alertNoRenegotiation) - } - - if c.vers >= VersionTLS13 { - return c.sendAlert(alertNoRenegotiation) - } - - switch c.config.Renegotiation { - case RenegotiateNever: - return c.sendAlert(alertNoRenegotiation) - case RenegotiateOnceAsClient: - if c.handshakes > 1 { - return c.sendAlert(alertNoRenegotiation) - } - case RenegotiateFreelyAsClient: - // Ok. - default: - c.sendAlert(alertInternalError) - return errors.New("tls: unknown Renegotiation value") - } - - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - - c.phase = handshakeRunning - c.handshakeComplete = false - if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil { - c.handshakes++ - } - return c.handshakeErr -} - -func (c *Conn) setAlternativeRecordLayer() { - if c.config.AlternativeRecordLayer != nil { - c.in.setKeyCallback = c.config.AlternativeRecordLayer.SetReadKey - c.out.setKeyCallback = c.config.AlternativeRecordLayer.SetWriteKey - } -} - -// ConfirmHandshake waits for the handshake to reach a point at which -// the connection is certainly not replayed. That is, after receiving -// the Client Finished. -// -// If ConfirmHandshake returns an error and until ConfirmHandshake -// returns, the 0-RTT data should not be trusted not to be replayed. -// -// This is only meaningful in TLS 1.3 when Accept0RTTData is true and the -// client sent valid 0-RTT data. In any other case it's equivalent to -// calling Handshake. -func (c *Conn) ConfirmHandshake() error { - if c.isClient { - panic("ConfirmHandshake should only be called for servers") - } - - if err := c.Handshake(); err != nil { - return err - } - - if c.vers < VersionTLS13 { - return nil - } - - c.confirmMutex.Lock() - if atomic.LoadInt32(&c.handshakeConfirmed) == 1 { // c.phase == handshakeConfirmed - c.confirmMutex.Unlock() - return nil - } else { - defer func() { - // If we transitioned to handshakeConfirmed we already released the lock, - // otherwise do it here. - if c.phase != handshakeConfirmed { - c.confirmMutex.Unlock() - } - }() - } - - c.in.Lock() - defer c.in.Unlock() - - var input *block - // Try to read all data (if phase==readingEarlyData) or extract the - // remaining data from the previous read that could not fit in the read - // buffer (if c.input != nil). - if c.phase == readingEarlyData || c.input != nil { - buf := &bytes.Buffer{} - if _, err := buf.ReadFrom(earlyDataReader{c}); err != nil { - c.in.setErrorLocked(err) - return err - } - input = &block{data: buf.Bytes()} - } - - // At this point, earlyDataReader has read all early data and received - // the end_of_early_data signal. Expect a Finished message. - // Locks held so far: c.confirmMutex, c.in - // not confirmed implies c.phase == discardingEarlyData || c.phase == waitingClientFinished - for c.phase != handshakeConfirmed { - if err := c.hs.readClientFinished13(true); err != nil { - c.in.setErrorLocked(err) - return err - } - } - - if c.phase != handshakeConfirmed { - panic("should have reached handshakeConfirmed state") - } - if c.input != nil { - panic("should not have read past the Client Finished") - } - - c.input = input - - return nil -} - -// earlyDataReader wraps a Conn and reads only early data, both buffered -// and still on the wire. -type earlyDataReader struct { - c *Conn -} - -// c.in.Mutex <= L -func (r earlyDataReader) Read(b []byte) (n int, err error) { - c := r.c - - if c.phase == handshakeConfirmed { - // c.input might not be early data - panic("earlyDataReader called at handshakeConfirmed") - } - - for c.input == nil && c.in.err == nil && c.phase == readingEarlyData { - if err := c.readRecord(recordTypeApplicationData); err != nil { - return 0, err - } - if c.hand.Len() > 0 { - if err := c.handleEndOfEarlyData(); err != nil { - return 0, err - } - } - } - if err := c.in.err; err != nil { - return 0, err - } - - if c.input != nil { - n, err = c.input.Read(b) - if err == io.EOF { - err = nil - c.in.freeBlock(c.input) - c.input = nil - } - } - - // Following early application data, an end_of_early_data is expected. - if err == nil && c.phase != readingEarlyData && c.input == nil { - err = io.EOF - } - return -} - -// Read can be made to time out and return a net.Error with Timeout() == true -// after a fixed time limit; see SetDeadline and SetReadDeadline. -func (c *Conn) Read(b []byte) (n int, err error) { - if err = c.Handshake(); err != nil { - return - } - if len(b) == 0 { - // Put this after Handshake, in case people were calling - // Read(nil) for the side effect of the Handshake. - return - } - - c.confirmMutex.Lock() - if atomic.LoadInt32(&c.handshakeConfirmed) == 1 { // c.phase == handshakeConfirmed - c.confirmMutex.Unlock() - } else { - defer func() { - // If we transitioned to handshakeConfirmed we already released the lock, - // otherwise do it here. - if c.phase != handshakeConfirmed { - c.confirmMutex.Unlock() - } - }() - } - - c.in.Lock() - defer c.in.Unlock() - - // Some OpenSSL servers send empty records in order to randomize the - // CBC IV. So this loop ignores a limited number of empty records. - const maxConsecutiveEmptyRecords = 100 - for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ { - for c.input == nil && c.in.err == nil { - if err := c.readRecord(recordTypeApplicationData); err != nil { - // Soft error, like EAGAIN - return 0, err - } - if c.hand.Len() > 0 { - if c.phase == readingEarlyData || c.phase == waitingClientFinished { - if c.phase == readingEarlyData { - if err := c.handleEndOfEarlyData(); err != nil { - return 0, err - } - } - // Server has received all early data, confirm - // by reading the Client Finished message. - if err := c.hs.readClientFinished13(true); err != nil { - c.in.setErrorLocked(err) - return 0, err - } - continue - } - if err := c.handlePostHandshake(); err != nil { - return 0, err - } - } - } - if err := c.in.err; err != nil { - return 0, err - } - - n, err = c.input.Read(b) - if err == io.EOF { - err = nil - c.in.freeBlock(c.input) - c.input = nil - } - - // If a close-notify alert is waiting, read it so that - // we can return (n, EOF) instead of (n, nil), to signal - // to the HTTP response reading goroutine that the - // connection is now closed. This eliminates a race - // where the HTTP response reading goroutine would - // otherwise not observe the EOF until its next read, - // by which time a client goroutine might have already - // tried to reuse the HTTP connection for a new - // request. - // See https://codereview.appspot.com/76400046 - // and https://golang.org/issue/3514 - if ri := c.rawInput; ri != nil && - n != 0 && err == nil && - c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert { - if recErr := c.readRecord(recordTypeApplicationData); recErr != nil { - err = recErr // will be io.EOF on closeNotify - } - } - - if n != 0 || err != nil { - return n, err - } - } - - return 0, io.ErrNoProgress -} - -// Close closes the connection. -func (c *Conn) Close() error { - // Interlock with Conn.Write above. - var x int32 - for { - x = atomic.LoadInt32(&c.activeCall) - if x&1 != 0 { - return errClosed - } - if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) { - break - } - } - if x != 0 { - // io.Writer and io.Closer should not be used concurrently. - // If Close is called while a Write is currently in-flight, - // interpret that as a sign that this Close is really just - // being used to break the Write and/or clean up resources and - // avoid sending the alertCloseNotify, which may block - // waiting on handshakeMutex or the c.out mutex. - return c.conn.Close() - } - - var alertErr error - - c.handshakeMutex.Lock() - if c.handshakeComplete { - alertErr = c.closeNotify() - } - c.handshakeMutex.Unlock() - - if err := c.conn.Close(); err != nil { - return err - } - return alertErr -} - -var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete") - -// CloseWrite shuts down the writing side of the connection. It should only be -// called once the handshake has completed and does not call CloseWrite on the -// underlying connection. Most callers should just use Close. -func (c *Conn) CloseWrite() error { - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - if !c.handshakeComplete { - return errEarlyCloseWrite - } - - return c.closeNotify() -} - -func (c *Conn) closeNotify() error { - c.out.Lock() - defer c.out.Unlock() - - if !c.closeNotifySent { - c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify) - c.closeNotifySent = true - } - return c.closeNotifyErr -} - -// Handshake runs the client or server handshake -// protocol if it has not yet been run. -// Most uses of this package need not call Handshake -// explicitly: the first Read or Write will call it automatically. -// -// In TLS 1.3 Handshake returns after the client and server first flights, -// without waiting for the Client Finished. -func (c *Conn) Handshake() error { - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - - if err := c.handshakeErr; err != nil { - return err - } - if c.handshakeComplete { - return nil - } - - c.in.Lock() - defer c.in.Unlock() - - // The handshake cannot have completed when handshakeMutex was unlocked - // because this goroutine set handshakeCond. - if c.handshakeErr != nil || c.handshakeComplete { - panic("handshake should not have been able to complete after handshakeCond was set") - } - - c.connID = make([]byte, 8) - if _, err := io.ReadFull(c.config.rand(), c.connID); err != nil { - return err - } - - if c.isClient { - c.handshakeErr = c.clientHandshake() - } else { - c.handshakeErr = c.serverHandshake() - } - if c.handshakeErr == nil { - c.handshakes++ - } else { - // If an error occurred during the hadshake try to flush the - // alert that might be left in the buffer. - c.flush() - } - - if c.handshakeErr == nil && !c.handshakeComplete { - panic("handshake should have had a result.") - } - - return c.handshakeErr -} - -// ConnectionState returns basic TLS details about the connection. -func (c *Conn) ConnectionState() ConnectionState { - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - - var state ConnectionState - state.HandshakeComplete = c.handshakeComplete - state.ServerName = c.serverName - - if c.handshakeComplete { - state.ConnectionID = c.connID - state.ClientHello = c.clientHello - state.Version = c.vers - state.NegotiatedProtocol = c.clientProtocol - state.DidResume = c.didResume - state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback - state.CipherSuite = c.cipherSuite - state.PeerCertificates = c.peerCertificates - state.VerifiedChains = c.verifiedChains - state.SignedCertificateTimestamps = c.scts - state.OCSPResponse = c.ocspResponse - if c.verifiedDc != nil { - state.DelegatedCredential = c.verifiedDc.raw - } - state.HandshakeConfirmed = atomic.LoadInt32(&c.handshakeConfirmed) == 1 - if !state.HandshakeConfirmed { - state.Unique0RTTToken = c.binder - } - if !c.didResume { - if c.clientFinishedIsFirst { - state.TLSUnique = c.clientFinished[:] - } else { - state.TLSUnique = c.serverFinished[:] - } - } - } - - return state -} - -// OCSPResponse returns the stapled OCSP response from the TLS server, if -// any. (Only valid for client connections.) -func (c *Conn) OCSPResponse() []byte { - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - - return c.ocspResponse -} - -// VerifyHostname checks that the peer certificate chain is valid for -// connecting to host. If so, it returns nil; if not, it returns an error -// describing the problem. -func (c *Conn) VerifyHostname(host string) error { - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - if !c.isClient { - return errors.New("tls: VerifyHostname called on TLS server connection") - } - if !c.handshakeComplete { - return errors.New("tls: handshake has not yet been performed") - } - if len(c.verifiedChains) == 0 { - return errors.New("tls: handshake did not verify certificate chain") - } - return c.peerCertificates[0].VerifyHostname(host) -} diff --git a/external/github.com/marten-seemann/qtls/handshake_client.go b/external/github.com/marten-seemann/qtls/handshake_client.go deleted file mode 100644 index fbc5acadb..000000000 --- a/external/github.com/marten-seemann/qtls/handshake_client.go +++ /dev/null @@ -1,1006 +0,0 @@ -// Copyright 2009 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 qtls - -import ( - "bytes" - "crypto" - "crypto/ecdsa" - "crypto/rsa" - "crypto/subtle" - "crypto/x509" - "errors" - "fmt" - "io" - "net" - "strconv" - "strings" - "sync/atomic" -) - -type clientHandshakeState struct { - c *Conn - serverHello *serverHelloMsg - hello *clientHelloMsg - suite *cipherSuite - masterSecret []byte - session *ClientSessionState - - // TLS 1.0-1.2 fields - finishedHash finishedHash - - // TLS 1.3 fields - keySchedule *keySchedule13 - privateKey []byte -} - -func makeClientHello(config *Config) (*clientHelloMsg, error) { - if len(config.ServerName) == 0 && !config.InsecureSkipVerify { - return nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") - } - - nextProtosLength := 0 - for _, proto := range config.NextProtos { - if l := len(proto); l == 0 || l > 255 { - return nil, errors.New("tls: invalid NextProtos value") - } else { - nextProtosLength += 1 + l - } - } - - if nextProtosLength > 0xffff { - return nil, errors.New("tls: NextProtos values too large") - } - - hello := &clientHelloMsg{ - vers: config.maxVersion(), - compressionMethods: []uint8{compressionNone}, - random: make([]byte, 32), - ocspStapling: true, - scts: true, - serverName: hostnameInSNI(config.ServerName), - supportedCurves: config.curvePreferences(), - supportedPoints: []uint8{pointFormatUncompressed}, - nextProtoNeg: len(config.NextProtos) > 0, - secureRenegotiationSupported: true, - delegatedCredential: config.AcceptDelegatedCredential, - alpnProtocols: config.NextProtos, - extendedMSSupported: config.UseExtendedMasterSecret, - } - possibleCipherSuites := config.cipherSuites() - hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites)) - -NextCipherSuite: - for _, suiteId := range possibleCipherSuites { - for _, suite := range cipherSuites { - if suite.id != suiteId { - continue - } - // Don't advertise TLS 1.2-only cipher suites unless - // we're attempting TLS 1.2. - if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 { - continue NextCipherSuite - } - // Don't advertise TLS 1.3-only cipher suites unless - // we're attempting TLS 1.3. - if hello.vers < VersionTLS13 && suite.flags&suiteTLS13 != 0 { - continue NextCipherSuite - } - hello.cipherSuites = append(hello.cipherSuites, suiteId) - continue NextCipherSuite - } - } - - _, err := io.ReadFull(config.rand(), hello.random) - if err != nil { - return nil, errors.New("tls: short read from Rand: " + err.Error()) - } - - if hello.vers >= VersionTLS12 { - hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms - } - - if hello.vers >= VersionTLS13 { - // Version preference is indicated via "supported_extensions", - // set legacy_version to TLS 1.2 for backwards compatibility. - hello.vers = VersionTLS12 - hello.supportedVersions = config.getSupportedVersions() - hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms13 - hello.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13) - if config.GetExtensions != nil { - hello.additionalExtensions = config.GetExtensions(typeClientHello) - } - } - - return hello, nil -} - -// c.out.Mutex <= L; c.handshakeMutex <= L. -func (c *Conn) clientHandshake() error { - if c.config == nil { - c.config = defaultConfig() - } - c.setAlternativeRecordLayer() - - // This may be a renegotiation handshake, in which case some fields - // need to be reset. - c.didResume = false - - hello, err := makeClientHello(c.config) - if err != nil { - return err - } - - if c.handshakes > 0 { - hello.secureRenegotiation = c.clientFinished[:] - } - - var session *ClientSessionState - var cacheKey string - sessionCache := c.config.ClientSessionCache - // TLS 1.3 has no session resumption based on session tickets. - if c.config.SessionTicketsDisabled || c.config.maxVersion() >= VersionTLS13 { - sessionCache = nil - } - - if sessionCache != nil { - hello.ticketSupported = true - } - - // Session resumption is not allowed if renegotiating because - // renegotiation is primarily used to allow a client to send a client - // certificate, which would be skipped if session resumption occurred. - if sessionCache != nil && c.handshakes == 0 { - // Try to resume a previously negotiated TLS session, if - // available. - cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config) - candidateSession, ok := sessionCache.Get(cacheKey) - if ok { - // Check that the ciphersuite/version used for the - // previous session are still valid. - cipherSuiteOk := false - for _, id := range hello.cipherSuites { - if id == candidateSession.cipherSuite { - cipherSuiteOk = true - break - } - } - - versOk := candidateSession.vers >= c.config.minVersion() && - candidateSession.vers <= c.config.maxVersion() - if versOk && cipherSuiteOk { - session = candidateSession - } - } - } - - if session != nil { - hello.sessionTicket = session.sessionTicket - // A random session ID is used to detect when the - // server accepted the ticket and is resuming a session - // (see RFC 5077). - hello.sessionId = make([]byte, 16) - if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil { - return errors.New("tls: short read from Rand: " + err.Error()) - } - } - - hs := &clientHandshakeState{ - c: c, - hello: hello, - session: session, - } - - var clientKS keyShare - if c.config.maxVersion() >= VersionTLS13 { - // Create one keyshare for the first default curve. If it is not - // appropriate, the server should raise a HRR. - defaultGroup := c.config.curvePreferences()[0] - hs.privateKey, clientKS, err = c.generateKeyShare(defaultGroup) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - hello.keyShares = []keyShare{clientKS} - // middlebox compatibility mode, provide a non-empty session ID - hello.sessionId = make([]byte, 16) - if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil { - return errors.New("tls: short read from Rand: " + err.Error()) - } - } - - if err = hs.handshake(); err != nil { - return err - } - - // If we had a successful handshake and hs.session is different from - // the one already cached - cache a new one - if sessionCache != nil && hs.session != nil && session != hs.session && c.vers < VersionTLS13 { - sessionCache.Put(cacheKey, hs.session) - } - - return nil -} - -// Does the handshake, either a full one or resumes old session. -// Requires hs.c, hs.hello, and, optionally, hs.session to be set. -func (hs *clientHandshakeState) handshake() error { - c := hs.c - - // send ClientHello - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { - return err - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - - var ok bool - if hs.serverHello, ok = msg.(*serverHelloMsg); !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(hs.serverHello, msg) - } - - if err = hs.pickTLSVersion(); err != nil { - return err - } - - if err = hs.pickCipherSuite(); err != nil { - return err - } - - var isResume bool - if c.vers >= VersionTLS13 { - hs.keySchedule = newKeySchedule13(hs.suite, c.config, hs.hello.random) - hs.keySchedule.write(hs.hello.marshal()) - hs.keySchedule.write(hs.serverHello.marshal()) - } else { - isResume, err = hs.processServerHello() - if err != nil { - return err - } - - hs.finishedHash = newFinishedHash(c.vers, hs.suite) - - // No signatures of the handshake are needed in a resumption. - // Otherwise, in a full handshake, if we don't have any certificates - // configured then we will never send a CertificateVerify message and - // thus no signatures are needed in that case either. - if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) { - hs.finishedHash.discardHandshakeBuffer() - } - - hs.finishedHash.Write(hs.hello.marshal()) - hs.finishedHash.Write(hs.serverHello.marshal()) - } - - c.buffering = true - if c.vers >= VersionTLS13 { - if err := hs.doTLS13Handshake(); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - } else if isResume { - if err := hs.establishKeys(); err != nil { - return err - } - if err := hs.readSessionTicket(); err != nil { - return err - } - if err := hs.readFinished(c.serverFinished[:]); err != nil { - return err - } - c.clientFinishedIsFirst = false - if err := hs.sendFinished(c.clientFinished[:]); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - } else { - if err := hs.doFullHandshake(); err != nil { - return err - } - if err := hs.establishKeys(); err != nil { - return err - } - if err := hs.sendFinished(c.clientFinished[:]); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - c.clientFinishedIsFirst = true - if err := hs.readSessionTicket(); err != nil { - return err - } - if err := hs.readFinished(c.serverFinished[:]); err != nil { - return err - } - } - - c.didResume = isResume - c.phase = handshakeConfirmed - atomic.StoreInt32(&c.handshakeConfirmed, 1) - c.handshakeComplete = true - - return nil -} - -func (hs *clientHandshakeState) pickTLSVersion() error { - vers, ok := hs.c.config.pickVersion([]uint16{hs.serverHello.vers}) - if !ok || vers < VersionTLS10 { - // TLS 1.0 is the minimum version supported as a client. - hs.c.sendAlert(alertProtocolVersion) - return fmt.Errorf("tls: server selected unsupported protocol version %x", hs.serverHello.vers) - } - - hs.c.vers = vers - hs.c.haveVers = true - - return nil -} - -func (hs *clientHandshakeState) pickCipherSuite() error { - if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil { - hs.c.sendAlert(alertHandshakeFailure) - return errors.New("tls: server chose an unconfigured cipher suite") - } - // Check that the chosen cipher suite matches the protocol version. - if hs.c.vers >= VersionTLS13 && hs.suite.flags&suiteTLS13 == 0 || - hs.c.vers < VersionTLS13 && hs.suite.flags&suiteTLS13 != 0 { - hs.c.sendAlert(alertHandshakeFailure) - return errors.New("tls: server chose an inappropriate cipher suite") - } - - hs.c.cipherSuite = hs.suite.id - return nil -} - -// processCertsFromServer takes a chain of server certificates from a -// Certificate message and verifies them. -func (hs *clientHandshakeState) processCertsFromServer(certificates [][]byte) error { - c := hs.c - certs := make([]*x509.Certificate, len(certificates)) - for i, asn1Data := range certificates { - cert, err := x509.ParseCertificate(asn1Data) - if err != nil { - c.sendAlert(alertBadCertificate) - return errors.New("tls: failed to parse certificate from server: " + err.Error()) - } - certs[i] = cert - } - - if !c.config.InsecureSkipVerify { - opts := x509.VerifyOptions{ - Roots: c.config.RootCAs, - CurrentTime: c.config.time(), - DNSName: c.config.ServerName, - Intermediates: x509.NewCertPool(), - } - - for i, cert := range certs { - if i == 0 { - continue - } - opts.Intermediates.AddCert(cert) - } - var err error - c.verifiedChains, err = certs[0].Verify(opts) - if err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - - if c.config.VerifyPeerCertificate != nil { - if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil { - c.sendAlert(alertBadCertificate) - return err - } - } - - switch certs[0].PublicKey.(type) { - case *rsa.PublicKey, *ecdsa.PublicKey: - break - default: - c.sendAlert(alertUnsupportedCertificate) - return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey) - } - - c.peerCertificates = certs - return nil -} - -// processDelegatedCredentialFromServer unmarshals the delegated credential -// offered by the server (if present) and validates it using the peer -// certificate and the signature scheme (`scheme`) indicated by the server in -// the "signature_scheme" extension. -func (hs *clientHandshakeState) processDelegatedCredentialFromServer(serialized []byte, scheme SignatureScheme) error { - c := hs.c - - var dc *delegatedCredential - var err error - if serialized != nil { - // Assert that the DC extension was indicated by the client. - if !hs.hello.delegatedCredential { - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: got delegated credential extension without indication") - } - - // Parse the delegated credential. - dc, err = unmarshalDelegatedCredential(serialized) - if err != nil { - c.sendAlert(alertDecodeError) - return fmt.Errorf("tls: delegated credential: %s", err) - } - } - - if dc != nil && !c.config.InsecureSkipVerify { - if v, err := dc.validate(c.peerCertificates[0], c.config.time()); err != nil { - c.sendAlert(alertIllegalParameter) - return fmt.Errorf("delegated credential: %s", err) - } else if !v { - c.sendAlert(alertIllegalParameter) - return errors.New("delegated credential: signature invalid") - } else if dc.cred.expectedVersion != hs.c.vers { - c.sendAlert(alertIllegalParameter) - return errors.New("delegated credential: protocol version mismatch") - } else if dc.cred.expectedCertVerifyAlgorithm != scheme { - c.sendAlert(alertIllegalParameter) - return errors.New("delegated credential: signature scheme mismatch") - } - } - - c.verifiedDc = dc - return nil -} - -func (hs *clientHandshakeState) doFullHandshake() error { - c := hs.c - - msg, err := c.readHandshake() - if err != nil { - return err - } - certMsg, ok := msg.(*certificateMsg) - if !ok || len(certMsg.certificates) == 0 { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } - hs.finishedHash.Write(certMsg.marshal()) - - if c.handshakes == 0 { - // If this is the first handshake on a connection, process and - // (optionally) verify the server's certificates. - if err := hs.processCertsFromServer(certMsg.certificates); err != nil { - return err - } - } else { - // This is a renegotiation handshake. We require that the - // server's identity (i.e. leaf certificate) is unchanged and - // thus any previous trust decision is still valid. - // - // See https://mitls.org/pages/attacks/3SHAKE for the - // motivation behind this requirement. - if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) { - c.sendAlert(alertBadCertificate) - return errors.New("tls: server's identity changed during renegotiation") - } - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - - cs, ok := msg.(*certificateStatusMsg) - if ok { - // RFC4366 on Certificate Status Request: - // The server MAY return a "certificate_status" message. - - if !hs.serverHello.ocspStapling { - // If a server returns a "CertificateStatus" message, then the - // server MUST have included an extension of type "status_request" - // with empty "extension_data" in the extended server hello. - - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: received unexpected CertificateStatus message") - } - hs.finishedHash.Write(cs.marshal()) - - if cs.statusType == statusTypeOCSP { - c.ocspResponse = cs.response - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - keyAgreement := hs.suite.ka(c.vers) - - // Set the public key used to verify the handshake. - pk := c.peerCertificates[0].PublicKey - - skx, ok := msg.(*serverKeyExchangeMsg) - if ok { - hs.finishedHash.Write(skx.marshal()) - - err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, pk, skx) - if err != nil { - c.sendAlert(alertUnexpectedMessage) - return err - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - var chainToSend *Certificate - var certRequested bool - certReq, ok := msg.(*certificateRequestMsg) - if ok { - certRequested = true - hs.finishedHash.Write(certReq.marshal()) - - if chainToSend, err = hs.getCertificate(certReq); err != nil { - c.sendAlert(alertInternalError) - return err - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - shd, ok := msg.(*serverHelloDoneMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(shd, msg) - } - hs.finishedHash.Write(shd.marshal()) - - // If the server requested a certificate then we have to send a - // Certificate message, even if it's empty because we don't have a - // certificate to send. - if certRequested { - certMsg = new(certificateMsg) - certMsg.certificates = chainToSend.Certificate - hs.finishedHash.Write(certMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { - return err - } - } - - preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, pk) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - if ckx != nil { - hs.finishedHash.Write(ckx.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil { - return err - } - } - c.useEMS = hs.serverHello.extendedMSSupported - hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random, hs.finishedHash, c.useEMS) - - if err := c.config.writeKeyLog("CLIENT_RANDOM", hs.hello.random, hs.masterSecret); err != nil { - c.sendAlert(alertInternalError) - return errors.New("tls: failed to write to key log: " + err.Error()) - } - - if chainToSend != nil && len(chainToSend.Certificate) > 0 { - certVerify := &certificateVerifyMsg{ - hasSignatureAndHash: c.vers >= VersionTLS12, - } - - key, ok := chainToSend.PrivateKey.(crypto.Signer) - if !ok { - c.sendAlert(alertInternalError) - return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) - } - - signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, hs.hello.supportedSignatureAlgorithms, c.vers) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - // SignatureAndHashAlgorithm was introduced in TLS 1.2. - if certVerify.hasSignatureAndHash { - certVerify.signatureAlgorithm = signatureAlgorithm - } - digest, err := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - signOpts := crypto.SignerOpts(hashFunc) - if sigType == signatureRSAPSS { - signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc} - } - certVerify.signature, err = key.Sign(c.config.rand(), digest, signOpts) - if err != nil { - c.sendAlert(alertInternalError) - return err - } - - hs.finishedHash.Write(certVerify.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil { - return err - } - } - - hs.finishedHash.discardHandshakeBuffer() - - return nil -} - -func (hs *clientHandshakeState) establishKeys() error { - c := hs.c - - clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := - keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) - var clientCipher, serverCipher interface{} - var clientHash, serverHash macFunction - if hs.suite.cipher != nil { - clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */) - clientHash = hs.suite.mac(c.vers, clientMAC) - serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */) - serverHash = hs.suite.mac(c.vers, serverMAC) - } else { - clientCipher = hs.suite.aead(clientKey, clientIV) - serverCipher = hs.suite.aead(serverKey, serverIV) - } - - c.in.prepareCipherSpec(c.vers, serverCipher, serverHash) - c.out.prepareCipherSpec(c.vers, clientCipher, clientHash) - return nil -} - -func (hs *clientHandshakeState) serverResumedSession() bool { - // If the server responded with the same sessionId then it means the - // sessionTicket is being used to resume a TLS session. - return hs.session != nil && hs.hello.sessionId != nil && - bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId) -} - -func (hs *clientHandshakeState) processServerHello() (bool, error) { - c := hs.c - - if hs.serverHello.compressionMethod != compressionNone { - c.sendAlert(alertUnexpectedMessage) - return false, errors.New("tls: server selected unsupported compression format") - } - - if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported { - c.secureRenegotiation = true - if len(hs.serverHello.secureRenegotiation) != 0 { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: initial handshake had non-empty renegotiation extension") - } - } - - if c.handshakes > 0 && c.secureRenegotiation { - var expectedSecureRenegotiation [24]byte - copy(expectedSecureRenegotiation[:], c.clientFinished[:]) - copy(expectedSecureRenegotiation[12:], c.serverFinished[:]) - if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: incorrect renegotiation extension contents") - } - } - - if hs.serverHello.extendedMSSupported { - if hs.hello.extendedMSSupported { - c.useEMS = true - } else { - // server wants to calculate master secret in a different way than client - c.sendAlert(alertUnsupportedExtension) - return false, errors.New("tls: unexpected extension (EMS) received in SH") - } - } - - clientDidNPN := hs.hello.nextProtoNeg - clientDidALPN := len(hs.hello.alpnProtocols) > 0 - serverHasNPN := hs.serverHello.nextProtoNeg - serverHasALPN := len(hs.serverHello.alpnProtocol) > 0 - - if !clientDidNPN && serverHasNPN { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: server advertised unrequested NPN extension") - } - - if !clientDidALPN && serverHasALPN { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: server advertised unrequested ALPN extension") - } - - if serverHasNPN && serverHasALPN { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: server advertised both NPN and ALPN extensions") - } - - if serverHasALPN { - c.clientProtocol = hs.serverHello.alpnProtocol - c.clientProtocolFallback = false - } - c.scts = hs.serverHello.scts - - if !hs.serverResumedSession() { - return false, nil - } - - if hs.session.useEMS != c.useEMS { - return false, errors.New("differing EMS state") - } - - if hs.session.vers != c.vers { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: server resumed a session with a different version") - } - - if hs.session.cipherSuite != hs.suite.id { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: server resumed a session with a different cipher suite") - } - - // Restore masterSecret and peerCerts from previous state - hs.masterSecret = hs.session.masterSecret - c.peerCertificates = hs.session.serverCertificates - c.verifiedChains = hs.session.verifiedChains - return true, nil -} - -func (hs *clientHandshakeState) readFinished(out []byte) error { - c := hs.c - - c.readRecord(recordTypeChangeCipherSpec) - if c.in.err != nil { - return c.in.err - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - serverFinished, ok := msg.(*finishedMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(serverFinished, msg) - } - - verify := hs.finishedHash.serverSum(hs.masterSecret) - if len(verify) != len(serverFinished.verifyData) || - subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 { - c.sendAlert(alertDecryptError) - return errors.New("tls: server's Finished message was incorrect") - } - hs.finishedHash.Write(serverFinished.marshal()) - copy(out, verify) - return nil -} - -func (hs *clientHandshakeState) readSessionTicket() error { - if !hs.serverHello.ticketSupported { - return nil - } - - c := hs.c - msg, err := c.readHandshake() - if err != nil { - return err - } - sessionTicketMsg, ok := msg.(*newSessionTicketMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(sessionTicketMsg, msg) - } - hs.finishedHash.Write(sessionTicketMsg.marshal()) - - hs.session = &ClientSessionState{ - sessionTicket: sessionTicketMsg.ticket, - vers: c.vers, - cipherSuite: hs.suite.id, - masterSecret: hs.masterSecret, - serverCertificates: c.peerCertificates, - verifiedChains: c.verifiedChains, - useEMS: c.useEMS, - } - - return nil -} - -func (hs *clientHandshakeState) sendFinished(out []byte) error { - c := hs.c - - if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { - return err - } - if hs.serverHello.nextProtoNeg { - nextProto := new(nextProtoMsg) - proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos) - nextProto.proto = proto - c.clientProtocol = proto - c.clientProtocolFallback = fallback - - hs.finishedHash.Write(nextProto.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, nextProto.marshal()); err != nil { - return err - } - } - - finished := new(finishedMsg) - finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) - hs.finishedHash.Write(finished.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { - return err - } - copy(out, finished.verifyData) - return nil -} - -// tls11SignatureSchemes contains the signature schemes that we synthesise for -// a TLS <= 1.1 connection, based on the supported certificate types. -var tls11SignatureSchemes = []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1} - -const ( - // tls11SignatureSchemesNumECDSA is the number of initial elements of - // tls11SignatureSchemes that use ECDSA. - tls11SignatureSchemesNumECDSA = 3 - // tls11SignatureSchemesNumRSA is the number of trailing elements of - // tls11SignatureSchemes that use RSA. - tls11SignatureSchemesNumRSA = 4 -) - -func (hs *clientHandshakeState) getCertificate(certReq *certificateRequestMsg) (*Certificate, error) { - c := hs.c - - var rsaAvail, ecdsaAvail bool - for _, certType := range certReq.certificateTypes { - switch certType { - case certTypeRSASign: - rsaAvail = true - case certTypeECDSASign: - ecdsaAvail = true - } - } - - if c.config.GetClientCertificate != nil { - var signatureSchemes []SignatureScheme - - if !certReq.hasSignatureAndHash { - // Prior to TLS 1.2, the signature schemes were not - // included in the certificate request message. In this - // case we use a plausible list based on the acceptable - // certificate types. - signatureSchemes = tls11SignatureSchemes - if !ecdsaAvail { - signatureSchemes = signatureSchemes[tls11SignatureSchemesNumECDSA:] - } - if !rsaAvail { - signatureSchemes = signatureSchemes[:len(signatureSchemes)-tls11SignatureSchemesNumRSA] - } - } else { - signatureSchemes = certReq.supportedSignatureAlgorithms - } - - return c.config.GetClientCertificate(&CertificateRequestInfo{ - AcceptableCAs: certReq.certificateAuthorities, - SignatureSchemes: signatureSchemes, - }) - } - - // RFC 4346 on the certificateAuthorities field: A list of the - // distinguished names of acceptable certificate authorities. - // These distinguished names may specify a desired - // distinguished name for a root CA or for a subordinate CA; - // thus, this message can be used to describe both known roots - // and a desired authorization space. If the - // certificate_authorities list is empty then the client MAY - // send any certificate of the appropriate - // ClientCertificateType, unless there is some external - // arrangement to the contrary. - - // We need to search our list of client certs for one - // where SignatureAlgorithm is acceptable to the server and the - // Issuer is in certReq.certificateAuthorities -findCert: - for i, chain := range c.config.Certificates { - if !rsaAvail && !ecdsaAvail { - continue - } - - for j, cert := range chain.Certificate { - x509Cert := chain.Leaf - // parse the certificate if this isn't the leaf - // node, or if chain.Leaf was nil - if j != 0 || x509Cert == nil { - var err error - if x509Cert, err = x509.ParseCertificate(cert); err != nil { - c.sendAlert(alertInternalError) - return nil, errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error()) - } - } - - switch { - case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA: - case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA: - default: - continue findCert - } - - if len(certReq.certificateAuthorities) == 0 { - // they gave us an empty list, so just take the - // first cert from c.config.Certificates - return &chain, nil - } - - for _, ca := range certReq.certificateAuthorities { - if bytes.Equal(x509Cert.RawIssuer, ca) { - return &chain, nil - } - } - } - } - - // No acceptable certificate found. Don't send a certificate. - return new(Certificate), nil -} - -// clientSessionCacheKey returns a key used to cache sessionTickets that could -// be used to resume previously negotiated TLS sessions with a server. -func clientSessionCacheKey(serverAddr net.Addr, config *Config) string { - if len(config.ServerName) > 0 { - return config.ServerName - } - return serverAddr.String() -} - -// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol -// given list of possible protocols and a list of the preference order. The -// first list must not be empty. It returns the resulting protocol and flag -// indicating if the fallback case was reached. -func mutualProtocol(protos, preferenceProtos []string) (string, bool) { - for _, s := range preferenceProtos { - for _, c := range protos { - if s == c { - return s, false - } - } - } - - return protos[0], true -} - -// hostnameInSNI converts name into an appropriate hostname for SNI. -// Literal IP addresses and absolute FQDNs are not permitted as SNI values. -// See https://tools.ietf.org/html/rfc6066#section-3. -func hostnameInSNI(name string) string { - host := name - if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' { - host = host[1 : len(host)-1] - } - if i := strings.LastIndex(host, "%"); i > 0 { - host = host[:i] - } - if net.ParseIP(host) != nil { - return "" - } - for len(name) > 0 && name[len(name)-1] == '.' { - name = name[:len(name)-1] - } - return name -} diff --git a/external/github.com/marten-seemann/qtls/handshake_messages.go b/external/github.com/marten-seemann/qtls/handshake_messages.go deleted file mode 100644 index 8e4a0d3a8..000000000 --- a/external/github.com/marten-seemann/qtls/handshake_messages.go +++ /dev/null @@ -1,2781 +0,0 @@ -// Copyright 2009 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 qtls - -import ( - "bytes" - "encoding/binary" - "strings" -) - -// signAlgosCertList helper function returns either list of signature algorithms in case -// signature_algorithms_cert extension should be marshalled or nil in the other case. -// signAlgos is a list of algorithms from signature_algorithms extension. signAlgosCert is a list -// of algorithms from signature_algorithms_cert extension. -func signAlgosCertList(signAlgos, signAlgosCert []SignatureScheme) []SignatureScheme { - if eqSignatureAlgorithms(signAlgos, signAlgosCert) { - // ensure that only supported_algorithms extension is send if supported_algorithms_cert - // has identical content - return nil - } - return signAlgosCert -} - -type clientHelloMsg struct { - raw []byte - rawTruncated []byte // for PSK binding - vers uint16 - random []byte - sessionId []byte - cipherSuites []uint16 - compressionMethods []uint8 - nextProtoNeg bool - serverName string - ocspStapling bool - scts bool - supportedCurves []CurveID - supportedPoints []uint8 - ticketSupported bool - sessionTicket []uint8 - supportedSignatureAlgorithms []SignatureScheme - supportedSignatureAlgorithmsCert []SignatureScheme - secureRenegotiation []byte - secureRenegotiationSupported bool - alpnProtocols []string - keyShares []keyShare - supportedVersions []uint16 - psks []psk - pskKeyExchangeModes []uint8 - earlyData bool - delegatedCredential bool - extendedMSSupported bool // RFC7627 - additionalExtensions []Extension -} - -// Function used for signature_algorithms and signature_algorithrms_cert -// extensions only (for more details, see TLS 1.3 draft 28, 4.2.3). -// -// It advances data slice and returns it, so that it can be used for further -// processing -func marshalExtensionSignatureAlgorithms(extension uint16, data []byte, schemes []SignatureScheme) []byte { - algNum := uint16(len(schemes)) - if algNum == 0 { - return data - } - - binary.BigEndian.PutUint16(data, extension) - data = data[2:] - binary.BigEndian.PutUint16(data, (2*algNum)+2) // +1 for length - data = data[2:] - binary.BigEndian.PutUint16(data, (2 * algNum)) - data = data[2:] - - for _, algo := range schemes { - binary.BigEndian.PutUint16(data, uint16(algo)) - data = data[2:] - } - return data -} - -// Function used for unmarshalling signature_algorithms or signature_algorithms_cert extensions only -// (for more details, see TLS 1.3 draft 28, 4.2.3) -// In case of error function returns alertDecoderError otherwise filled SignatureScheme slice and alertSuccess -func unmarshalExtensionSignatureAlgorithms(data []byte, length int) ([]SignatureScheme, alert) { - - if length < 2 || length&1 != 0 { - return nil, alertDecodeError - } - - algLen := binary.BigEndian.Uint16(data) - idx := 2 - - if int(algLen) != length-2 { - return nil, alertDecodeError - } - - schemes := make([]SignatureScheme, algLen/2) - for i := range schemes { - schemes[i] = SignatureScheme(binary.BigEndian.Uint16(data[idx:])) - idx += 2 - } - return schemes, alertSuccess -} - -func (m *clientHelloMsg) equal(i interface{}) bool { - m1, ok := i.(*clientHelloMsg) - if !ok { - return false - } - - if len(m.additionalExtensions) != len(m1.additionalExtensions) { - return false - } - for i, ex := range m.additionalExtensions { - ex1 := m1.additionalExtensions[i] - if ex.Type != ex1.Type || !bytes.Equal(ex.Data, ex1.Data) { - return false - } - } - - return bytes.Equal(m.raw, m1.raw) && - m.vers == m1.vers && - bytes.Equal(m.random, m1.random) && - bytes.Equal(m.sessionId, m1.sessionId) && - eqUint16s(m.cipherSuites, m1.cipherSuites) && - bytes.Equal(m.compressionMethods, m1.compressionMethods) && - m.nextProtoNeg == m1.nextProtoNeg && - m.serverName == m1.serverName && - m.ocspStapling == m1.ocspStapling && - m.scts == m1.scts && - eqCurveIDs(m.supportedCurves, m1.supportedCurves) && - bytes.Equal(m.supportedPoints, m1.supportedPoints) && - m.ticketSupported == m1.ticketSupported && - bytes.Equal(m.sessionTicket, m1.sessionTicket) && - eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) && - eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert) && - m.secureRenegotiationSupported == m1.secureRenegotiationSupported && - bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) && - eqStrings(m.alpnProtocols, m1.alpnProtocols) && - eqKeyShares(m.keyShares, m1.keyShares) && - eqUint16s(m.supportedVersions, m1.supportedVersions) && - m.earlyData == m1.earlyData && - m.delegatedCredential == m1.delegatedCredential && - m.extendedMSSupported == m1.extendedMSSupported -} - -func (m *clientHelloMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods) - numExtensions := 0 - extensionsLength := 0 - - if m.nextProtoNeg { - numExtensions++ - } - if m.ocspStapling { - extensionsLength += 1 + 2 + 2 - numExtensions++ - } - if len(m.serverName) > 0 { - extensionsLength += 5 + len(m.serverName) - numExtensions++ - } - if len(m.supportedCurves) > 0 { - extensionsLength += 2 + 2*len(m.supportedCurves) - numExtensions++ - } - if len(m.supportedPoints) > 0 { - extensionsLength += 1 + len(m.supportedPoints) - numExtensions++ - } - if m.ticketSupported { - extensionsLength += len(m.sessionTicket) - numExtensions++ - } - if len(m.supportedSignatureAlgorithms) > 0 { - extensionsLength += 2 + 2*len(m.supportedSignatureAlgorithms) - numExtensions++ - } - if m.getSignatureAlgorithmsCert() != nil { - extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert()) - numExtensions++ - } - if m.secureRenegotiationSupported { - extensionsLength += 1 + len(m.secureRenegotiation) - numExtensions++ - } - if len(m.alpnProtocols) > 0 { - extensionsLength += 2 - for _, s := range m.alpnProtocols { - if l := len(s); l == 0 || l > 255 { - panic("invalid ALPN protocol") - } - extensionsLength++ - extensionsLength += len(s) - } - numExtensions++ - } - if m.scts { - numExtensions++ - } - if len(m.keyShares) > 0 { - extensionsLength += 2 - for _, k := range m.keyShares { - extensionsLength += 4 + len(k.data) - } - numExtensions++ - } - if len(m.supportedVersions) > 0 { - extensionsLength += 1 + 2*len(m.supportedVersions) - numExtensions++ - } - if m.earlyData { - numExtensions++ - } - if m.delegatedCredential { - numExtensions++ - } - if m.extendedMSSupported { - numExtensions++ - } - if len(m.additionalExtensions) > 0 { - numExtensions += len(m.additionalExtensions) - for _, ex := range m.additionalExtensions { - extensionsLength += len(ex.Data) - } - } - if numExtensions > 0 { - extensionsLength += 4 * numExtensions - length += 2 + extensionsLength - } - - x := make([]byte, 4+length) - x[0] = typeClientHello - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - x[4] = uint8(m.vers >> 8) - x[5] = uint8(m.vers) - copy(x[6:38], m.random) - x[38] = uint8(len(m.sessionId)) - copy(x[39:39+len(m.sessionId)], m.sessionId) - y := x[39+len(m.sessionId):] - y[0] = uint8(len(m.cipherSuites) >> 7) - y[1] = uint8(len(m.cipherSuites) << 1) - for i, suite := range m.cipherSuites { - y[2+i*2] = uint8(suite >> 8) - y[3+i*2] = uint8(suite) - } - z := y[2+len(m.cipherSuites)*2:] - z[0] = uint8(len(m.compressionMethods)) - copy(z[1:], m.compressionMethods) - - z = z[1+len(m.compressionMethods):] - if numExtensions > 0 { - z[0] = byte(extensionsLength >> 8) - z[1] = byte(extensionsLength) - z = z[2:] - } - if m.nextProtoNeg { - z[0] = byte(extensionNextProtoNeg >> 8) - z[1] = byte(extensionNextProtoNeg & 0xff) - // The length is always 0 - z = z[4:] - } - if len(m.serverName) > 0 { - z[0] = byte(extensionServerName >> 8) - z[1] = byte(extensionServerName & 0xff) - l := len(m.serverName) + 5 - z[2] = byte(l >> 8) - z[3] = byte(l) - z = z[4:] - - // RFC 3546, section 3.1 - // - // struct { - // NameType name_type; - // select (name_type) { - // case host_name: HostName; - // } name; - // } ServerName; - // - // enum { - // host_name(0), (255) - // } NameType; - // - // opaque HostName<1..2^16-1>; - // - // struct { - // ServerName server_name_list<1..2^16-1> - // } ServerNameList; - - z[0] = byte((len(m.serverName) + 3) >> 8) - z[1] = byte(len(m.serverName) + 3) - z[3] = byte(len(m.serverName) >> 8) - z[4] = byte(len(m.serverName)) - copy(z[5:], []byte(m.serverName)) - z = z[l:] - } - if m.ocspStapling { - // RFC 4366, section 3.6 - z[0] = byte(extensionStatusRequest >> 8) - z[1] = byte(extensionStatusRequest) - z[2] = 0 - z[3] = 5 - z[4] = 1 // OCSP type - // Two zero valued uint16s for the two lengths. - z = z[9:] - } - if len(m.supportedCurves) > 0 { - // http://tools.ietf.org/html/rfc4492#section-5.5.1 - // https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4 - z[0] = byte(extensionSupportedCurves >> 8) - z[1] = byte(extensionSupportedCurves) - l := 2 + 2*len(m.supportedCurves) - z[2] = byte(l >> 8) - z[3] = byte(l) - l -= 2 - z[4] = byte(l >> 8) - z[5] = byte(l) - z = z[6:] - for _, curve := range m.supportedCurves { - z[0] = byte(curve >> 8) - z[1] = byte(curve) - z = z[2:] - } - } - if len(m.supportedPoints) > 0 { - // http://tools.ietf.org/html/rfc4492#section-5.5.2 - z[0] = byte(extensionSupportedPoints >> 8) - z[1] = byte(extensionSupportedPoints) - l := 1 + len(m.supportedPoints) - z[2] = byte(l >> 8) - z[3] = byte(l) - l-- - z[4] = byte(l) - z = z[5:] - for _, pointFormat := range m.supportedPoints { - z[0] = pointFormat - z = z[1:] - } - } - if m.ticketSupported { - // http://tools.ietf.org/html/rfc5077#section-3.2 - z[0] = byte(extensionSessionTicket >> 8) - z[1] = byte(extensionSessionTicket) - l := len(m.sessionTicket) - z[2] = byte(l >> 8) - z[3] = byte(l) - z = z[4:] - copy(z, m.sessionTicket) - z = z[len(m.sessionTicket):] - } - - if len(m.supportedSignatureAlgorithms) > 0 { - z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms) - } - if m.getSignatureAlgorithmsCert() != nil { - // Ensure only one list of algorithms is sent if supported_algorithms and supported_algorithms_cert are the same - z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert()) - } - - if m.secureRenegotiationSupported { - z[0] = byte(extensionRenegotiationInfo >> 8) - z[1] = byte(extensionRenegotiationInfo & 0xff) - z[2] = 0 - z[3] = byte(len(m.secureRenegotiation) + 1) - z[4] = byte(len(m.secureRenegotiation)) - z = z[5:] - copy(z, m.secureRenegotiation) - z = z[len(m.secureRenegotiation):] - } - if len(m.alpnProtocols) > 0 { - z[0] = byte(extensionALPN >> 8) - z[1] = byte(extensionALPN & 0xff) - lengths := z[2:] - z = z[6:] - - stringsLength := 0 - for _, s := range m.alpnProtocols { - l := len(s) - z[0] = byte(l) - copy(z[1:], s) - z = z[1+l:] - stringsLength += 1 + l - } - - lengths[2] = byte(stringsLength >> 8) - lengths[3] = byte(stringsLength) - stringsLength += 2 - lengths[0] = byte(stringsLength >> 8) - lengths[1] = byte(stringsLength) - } - if m.scts { - // https://tools.ietf.org/html/rfc6962#section-3.3.1 - z[0] = byte(extensionSCT >> 8) - z[1] = byte(extensionSCT) - // zero uint16 for the zero-length extension_data - z = z[4:] - } - if len(m.keyShares) > 0 { - // https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5 - z[0] = byte(extensionKeyShare >> 8) - z[1] = byte(extensionKeyShare) - lengths := z[2:] - z = z[6:] - - totalLength := 0 - for _, ks := range m.keyShares { - z[0] = byte(ks.group >> 8) - z[1] = byte(ks.group) - z[2] = byte(len(ks.data) >> 8) - z[3] = byte(len(ks.data)) - copy(z[4:], ks.data) - z = z[4+len(ks.data):] - totalLength += 4 + len(ks.data) - } - - lengths[2] = byte(totalLength >> 8) - lengths[3] = byte(totalLength) - totalLength += 2 - lengths[0] = byte(totalLength >> 8) - lengths[1] = byte(totalLength) - } - if len(m.supportedVersions) > 0 { - z[0] = byte(extensionSupportedVersions >> 8) - z[1] = byte(extensionSupportedVersions) - l := 1 + 2*len(m.supportedVersions) - z[2] = byte(l >> 8) - z[3] = byte(l) - l -= 1 - z[4] = byte(l) - z = z[5:] - for _, v := range m.supportedVersions { - z[0] = byte(v >> 8) - z[1] = byte(v) - z = z[2:] - } - } - if m.earlyData { - z[0] = byte(extensionEarlyData >> 8) - z[1] = byte(extensionEarlyData) - z = z[4:] - } - if m.delegatedCredential { - binary.BigEndian.PutUint16(z, extensionDelegatedCredential) - z = z[4:] - } - if m.extendedMSSupported { - binary.BigEndian.PutUint16(z, extensionEMS) - z = z[4:] - } - for _, ex := range m.additionalExtensions { - z[0] = byte(ex.Type >> 8) - z[1] = byte(ex.Type) - l := len(ex.Data) - z[2] = byte(l >> 8) - z[3] = byte(l) - copy(z[4:], ex.Data) - z = z[4+l:] - } - - m.raw = x - - return x -} - -func (m *clientHelloMsg) unmarshal(data []byte) alert { - if len(data) < 42 { - return alertDecodeError - } - m.raw = data - m.vers = uint16(data[4])<<8 | uint16(data[5]) - m.random = data[6:38] - sessionIdLen := int(data[38]) - if sessionIdLen > 32 || len(data) < 39+sessionIdLen { - return alertDecodeError - } - m.sessionId = data[39 : 39+sessionIdLen] - data = data[39+sessionIdLen:] - bindersOffset := 39 + sessionIdLen - if len(data) < 2 { - return alertDecodeError - } - // cipherSuiteLen is the number of bytes of cipher suite numbers. Since - // they are uint16s, the number must be even. - cipherSuiteLen := int(data[0])<<8 | int(data[1]) - if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen { - return alertDecodeError - } - numCipherSuites := cipherSuiteLen / 2 - m.cipherSuites = make([]uint16, numCipherSuites) - for i := 0; i < numCipherSuites; i++ { - m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i]) - if m.cipherSuites[i] == scsvRenegotiation { - m.secureRenegotiationSupported = true - } - } - data = data[2+cipherSuiteLen:] - bindersOffset += 2 + cipherSuiteLen - if len(data) < 1 { - return alertDecodeError - } - compressionMethodsLen := int(data[0]) - if len(data) < 1+compressionMethodsLen { - return alertDecodeError - } - m.compressionMethods = data[1 : 1+compressionMethodsLen] - - data = data[1+compressionMethodsLen:] - bindersOffset += 1 + compressionMethodsLen - - m.nextProtoNeg = false - m.serverName = "" - m.ocspStapling = false - m.ticketSupported = false - m.sessionTicket = nil - m.supportedSignatureAlgorithms = nil - m.alpnProtocols = nil - m.scts = false - m.keyShares = nil - m.supportedVersions = nil - m.psks = nil - m.pskKeyExchangeModes = nil - m.earlyData = false - m.delegatedCredential = false - m.extendedMSSupported = false - - if len(data) == 0 { - // ClientHello is optionally followed by extension data - return alertSuccess - } - if len(data) < 2 { - return alertDecodeError - } - - extensionsLength := int(data[0])<<8 | int(data[1]) - data = data[2:] - bindersOffset += 2 - if extensionsLength != len(data) { - return alertDecodeError - } - - for len(data) != 0 { - if len(data) < 4 { - return alertDecodeError - } - ext := uint16(data[0])<<8 | uint16(data[1]) - length := int(data[2])<<8 | int(data[3]) - data = data[4:] - bindersOffset += 4 - if len(data) < length { - return alertDecodeError - } - - switch ext { - case extensionServerName: - d := data[:length] - if len(d) < 2 { - return alertDecodeError - } - namesLen := int(d[0])<<8 | int(d[1]) - d = d[2:] - if len(d) != namesLen { - return alertDecodeError - } - for len(d) > 0 { - if len(d) < 3 { - return alertDecodeError - } - nameType := d[0] - nameLen := int(d[1])<<8 | int(d[2]) - d = d[3:] - if len(d) < nameLen { - return alertDecodeError - } - if nameType == 0 { - m.serverName = string(d[:nameLen]) - // An SNI value may not include a - // trailing dot. See - // https://tools.ietf.org/html/rfc6066#section-3. - if strings.HasSuffix(m.serverName, ".") { - // TODO use alertDecodeError? - return alertUnexpectedMessage - } - break - } - d = d[nameLen:] - } - case extensionNextProtoNeg: - if length > 0 { - return alertDecodeError - } - m.nextProtoNeg = true - case extensionStatusRequest: - m.ocspStapling = length > 0 && data[0] == statusTypeOCSP - case extensionSupportedCurves: - // http://tools.ietf.org/html/rfc4492#section-5.5.1 - // https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4 - if length < 2 { - return alertDecodeError - } - l := int(data[0])<<8 | int(data[1]) - if l%2 == 1 || length != l+2 { - return alertDecodeError - } - numCurves := l / 2 - m.supportedCurves = make([]CurveID, numCurves) - d := data[2:] - for i := 0; i < numCurves; i++ { - m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1]) - d = d[2:] - } - case extensionSupportedPoints: - // http://tools.ietf.org/html/rfc4492#section-5.5.2 - if length < 1 { - return alertDecodeError - } - l := int(data[0]) - if length != l+1 { - return alertDecodeError - } - m.supportedPoints = make([]uint8, l) - copy(m.supportedPoints, data[1:]) - case extensionSessionTicket: - // http://tools.ietf.org/html/rfc5077#section-3.2 - m.ticketSupported = true - m.sessionTicket = data[:length] - case extensionSignatureAlgorithms: - // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 - // https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3 - if length < 2 || length&1 != 0 { - return alertDecodeError - } - l := int(data[0])<<8 | int(data[1]) - if l != length-2 { - return alertDecodeError - } - n := l / 2 - d := data[2:] - m.supportedSignatureAlgorithms = make([]SignatureScheme, n) - for i := range m.supportedSignatureAlgorithms { - m.supportedSignatureAlgorithms[i] = SignatureScheme(d[0])<<8 | SignatureScheme(d[1]) - d = d[2:] - } - case extensionRenegotiationInfo: - if length == 0 { - return alertDecodeError - } - d := data[:length] - l := int(d[0]) - d = d[1:] - if l != len(d) { - return alertDecodeError - } - - m.secureRenegotiation = d - m.secureRenegotiationSupported = true - case extensionALPN: - if length < 2 { - return alertDecodeError - } - l := int(data[0])<<8 | int(data[1]) - if l != length-2 { - return alertDecodeError - } - d := data[2:length] - for len(d) != 0 { - stringLen := int(d[0]) - d = d[1:] - if stringLen == 0 || stringLen > len(d) { - return alertDecodeError - } - m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen])) - d = d[stringLen:] - } - case extensionSCT: - m.scts = true - if length != 0 { - return alertDecodeError - } - case extensionKeyShare: - // https://tools.ietf.org/html/rfc8446#section-4.2.8 - if length < 2 { - return alertDecodeError - } - l := int(data[0])<<8 | int(data[1]) - if l != length-2 { - return alertDecodeError - } - d := data[2:length] - for len(d) != 0 { - if len(d) < 4 { - return alertDecodeError - } - dataLen := int(d[2])<<8 | int(d[3]) - if dataLen == 0 || 4+dataLen > len(d) { - return alertDecodeError - } - m.keyShares = append(m.keyShares, keyShare{ - group: CurveID(d[0])<<8 | CurveID(d[1]), - data: d[4 : 4+dataLen], - }) - d = d[4+dataLen:] - } - case extensionSupportedVersions: - // https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.1 - if length < 1 { - return alertDecodeError - } - l := int(data[0]) - if l%2 == 1 || length != l+1 { - return alertDecodeError - } - n := l / 2 - d := data[1:] - for i := 0; i < n; i++ { - v := uint16(d[0])<<8 + uint16(d[1]) - m.supportedVersions = append(m.supportedVersions, v) - d = d[2:] - } - case extensionPreSharedKey: - // https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6 - if length < 2 { - return alertDecodeError - } - // Ensure this extension is the last one in the Client Hello - if len(data) != length { - return alertIllegalParameter - } - li := int(data[0])<<8 | int(data[1]) - if 2+li+2 > length { - return alertDecodeError - } - d := data[2 : 2+li] - bindersOffset += 2 + li - for len(d) > 0 { - if len(d) < 6 { - return alertDecodeError - } - l := int(d[0])<<8 | int(d[1]) - if len(d) < 2+l+4 { - return alertDecodeError - } - m.psks = append(m.psks, psk{ - identity: d[2 : 2+l], - obfTicketAge: uint32(d[l+2])<<24 | uint32(d[l+3])<<16 | - uint32(d[l+4])<<8 | uint32(d[l+5]), - }) - d = d[2+l+4:] - } - lb := int(data[li+2])<<8 | int(data[li+3]) - d = data[2+li+2:] - if lb != len(d) || lb == 0 { - return alertDecodeError - } - i := 0 - for len(d) > 0 { - if i >= len(m.psks) { - return alertIllegalParameter - } - if len(d) < 1 { - return alertDecodeError - } - l := int(d[0]) - if l > len(d)-1 { - return alertDecodeError - } - if i >= len(m.psks) { - return alertIllegalParameter - } - m.psks[i].binder = d[1 : 1+l] - d = d[1+l:] - i++ - } - if i != len(m.psks) { - return alertIllegalParameter - } - m.rawTruncated = m.raw[:bindersOffset] - case extensionPSKKeyExchangeModes: - if length < 2 { - return alertDecodeError - } - l := int(data[0]) - if length != l+1 { - return alertDecodeError - } - m.pskKeyExchangeModes = data[1:length] - case extensionEarlyData: - // https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8 - m.earlyData = true - case extensionDelegatedCredential: - // https://tools.ietf.org/html/draft-ietf-tls-subcerts-02 - m.delegatedCredential = true - case extensionEMS: - // RFC 7627 - m.extendedMSSupported = true - if length != 0 { - return alertDecodeError - } - default: - m.additionalExtensions = append(m.additionalExtensions, - Extension{Type: ext, Data: data[:length]}) - } - data = data[length:] - bindersOffset += length - } - - return alertSuccess -} - -func (m *clientHelloMsg) getSignatureAlgorithmsCert() []SignatureScheme { - return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert) -} - -type serverHelloMsg struct { - raw []byte - vers uint16 - random []byte - sessionId []byte - cipherSuite uint16 - compressionMethod uint8 - nextProtoNeg bool - nextProtos []string - ocspStapling bool - scts [][]byte - ticketSupported bool - secureRenegotiation []byte - secureRenegotiationSupported bool - alpnProtocol string - - // TLS 1.3 - keyShare keyShare - psk bool - pskIdentity uint16 - - // RFC7627 - extendedMSSupported bool -} - -func (m *serverHelloMsg) equal(i interface{}) bool { - m1, ok := i.(*serverHelloMsg) - if !ok { - return false - } - - if len(m.scts) != len(m1.scts) { - return false - } - for i, sct := range m.scts { - if !bytes.Equal(sct, m1.scts[i]) { - return false - } - } - - return bytes.Equal(m.raw, m1.raw) && - m.vers == m1.vers && - bytes.Equal(m.random, m1.random) && - bytes.Equal(m.sessionId, m1.sessionId) && - m.cipherSuite == m1.cipherSuite && - m.compressionMethod == m1.compressionMethod && - m.nextProtoNeg == m1.nextProtoNeg && - eqStrings(m.nextProtos, m1.nextProtos) && - m.ocspStapling == m1.ocspStapling && - m.ticketSupported == m1.ticketSupported && - m.secureRenegotiationSupported == m1.secureRenegotiationSupported && - bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) && - m.alpnProtocol == m1.alpnProtocol && - m.keyShare.group == m1.keyShare.group && - bytes.Equal(m.keyShare.data, m1.keyShare.data) && - m.psk == m1.psk && - m.pskIdentity == m1.pskIdentity && - m.extendedMSSupported == m1.extendedMSSupported -} - -func (m *serverHelloMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - length := 38 + len(m.sessionId) - numExtensions := 0 - extensionsLength := 0 - - nextProtoLen := 0 - if m.nextProtoNeg { - numExtensions++ - for _, v := range m.nextProtos { - nextProtoLen += len(v) - } - nextProtoLen += len(m.nextProtos) - extensionsLength += nextProtoLen - } - if m.ocspStapling { - numExtensions++ - } - if m.ticketSupported { - numExtensions++ - } - if m.secureRenegotiationSupported { - extensionsLength += 1 + len(m.secureRenegotiation) - numExtensions++ - } - if m.extendedMSSupported { - numExtensions++ - } - if alpnLen := len(m.alpnProtocol); alpnLen > 0 { - if alpnLen >= 256 { - panic("invalid ALPN protocol") - } - extensionsLength += 2 + 1 + alpnLen - numExtensions++ - } - sctLen := 0 - if len(m.scts) > 0 { - for _, sct := range m.scts { - sctLen += len(sct) + 2 - } - extensionsLength += 2 + sctLen - numExtensions++ - } - if m.keyShare.group != 0 { - extensionsLength += 4 + len(m.keyShare.data) - numExtensions++ - } - if m.psk { - extensionsLength += 2 - numExtensions++ - } - // supported_versions extension - if m.vers >= VersionTLS13 { - extensionsLength += 2 - numExtensions++ - } - - if numExtensions > 0 { - extensionsLength += 4 * numExtensions - length += 2 + extensionsLength - } - - x := make([]byte, 4+length) - x[0] = typeServerHello - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - if m.vers >= VersionTLS13 { - x[4] = 3 - x[5] = 3 - } else { - x[4] = uint8(m.vers >> 8) - x[5] = uint8(m.vers) - } - copy(x[6:38], m.random) - z := x[38:] - x[38] = uint8(len(m.sessionId)) - copy(x[39:39+len(m.sessionId)], m.sessionId) - z = x[39+len(m.sessionId):] - z[0] = uint8(m.cipherSuite >> 8) - z[1] = uint8(m.cipherSuite) - z[2] = m.compressionMethod - z = z[3:] - - if numExtensions > 0 { - z[0] = byte(extensionsLength >> 8) - z[1] = byte(extensionsLength) - z = z[2:] - } - if m.vers >= VersionTLS13 { - z[0] = byte(extensionSupportedVersions >> 8) - z[1] = byte(extensionSupportedVersions) - z[3] = 2 - z[4] = uint8(m.vers >> 8) - z[5] = uint8(m.vers) - z = z[6:] - } - if m.nextProtoNeg { - z[0] = byte(extensionNextProtoNeg >> 8) - z[1] = byte(extensionNextProtoNeg & 0xff) - z[2] = byte(nextProtoLen >> 8) - z[3] = byte(nextProtoLen) - z = z[4:] - - for _, v := range m.nextProtos { - l := len(v) - if l > 255 { - l = 255 - } - z[0] = byte(l) - copy(z[1:], []byte(v[0:l])) - z = z[1+l:] - } - } - if m.ocspStapling { - z[0] = byte(extensionStatusRequest >> 8) - z[1] = byte(extensionStatusRequest) - z = z[4:] - } - if m.ticketSupported { - z[0] = byte(extensionSessionTicket >> 8) - z[1] = byte(extensionSessionTicket) - z = z[4:] - } - if m.secureRenegotiationSupported { - z[0] = byte(extensionRenegotiationInfo >> 8) - z[1] = byte(extensionRenegotiationInfo & 0xff) - z[2] = 0 - z[3] = byte(len(m.secureRenegotiation) + 1) - z[4] = byte(len(m.secureRenegotiation)) - z = z[5:] - copy(z, m.secureRenegotiation) - z = z[len(m.secureRenegotiation):] - } - if alpnLen := len(m.alpnProtocol); alpnLen > 0 { - z[0] = byte(extensionALPN >> 8) - z[1] = byte(extensionALPN & 0xff) - l := 2 + 1 + alpnLen - z[2] = byte(l >> 8) - z[3] = byte(l) - l -= 2 - z[4] = byte(l >> 8) - z[5] = byte(l) - l -= 1 - z[6] = byte(l) - copy(z[7:], []byte(m.alpnProtocol)) - z = z[7+alpnLen:] - } - if sctLen > 0 { - z[0] = byte(extensionSCT >> 8) - z[1] = byte(extensionSCT) - l := sctLen + 2 - z[2] = byte(l >> 8) - z[3] = byte(l) - z[4] = byte(sctLen >> 8) - z[5] = byte(sctLen) - - z = z[6:] - for _, sct := range m.scts { - z[0] = byte(len(sct) >> 8) - z[1] = byte(len(sct)) - copy(z[2:], sct) - z = z[len(sct)+2:] - } - } - if m.keyShare.group != 0 { - z[0] = uint8(extensionKeyShare >> 8) - z[1] = uint8(extensionKeyShare) - l := 4 + len(m.keyShare.data) - z[2] = uint8(l >> 8) - z[3] = uint8(l) - z[4] = uint8(m.keyShare.group >> 8) - z[5] = uint8(m.keyShare.group) - l -= 4 - z[6] = uint8(l >> 8) - z[7] = uint8(l) - copy(z[8:], m.keyShare.data) - z = z[8+l:] - } - - if m.psk { - z[0] = byte(extensionPreSharedKey >> 8) - z[1] = byte(extensionPreSharedKey) - z[3] = 2 - z[4] = byte(m.pskIdentity >> 8) - z[5] = byte(m.pskIdentity) - z = z[6:] - } - if m.extendedMSSupported { - binary.BigEndian.PutUint16(z, extensionEMS) - z = z[4:] - } - - m.raw = x - - return x -} - -func (m *serverHelloMsg) unmarshal(data []byte) alert { - if len(data) < 42 { - return alertDecodeError - } - m.raw = data - m.vers = uint16(data[4])<<8 | uint16(data[5]) - m.random = data[6:38] - sessionIdLen := int(data[38]) - if sessionIdLen > 32 || len(data) < 39+sessionIdLen { - return alertDecodeError - } - m.sessionId = data[39 : 39+sessionIdLen] - data = data[39+sessionIdLen:] - if len(data) < 3 { - return alertDecodeError - } - m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]) - m.compressionMethod = data[2] - data = data[3:] - - m.nextProtoNeg = false - m.nextProtos = nil - m.ocspStapling = false - m.scts = nil - m.ticketSupported = false - m.alpnProtocol = "" - m.keyShare.group = 0 - m.keyShare.data = nil - m.psk = false - m.pskIdentity = 0 - m.extendedMSSupported = false - - if len(data) == 0 { - // ServerHello is optionally followed by extension data - return alertSuccess - } - if len(data) < 2 { - return alertDecodeError - } - - extensionsLength := int(data[0])<<8 | int(data[1]) - data = data[2:] - if len(data) != extensionsLength { - return alertDecodeError - } - - svData := findExtension(data, extensionSupportedVersions) - if svData != nil { - if len(svData) != 2 { - return alertDecodeError - } - if m.vers != VersionTLS12 { - return alertDecodeError - } - rcvVer := binary.BigEndian.Uint16(svData[0:]) - if rcvVer < VersionTLS13 { - return alertIllegalParameter - } - m.vers = rcvVer - } - - for len(data) != 0 { - if len(data) < 4 { - return alertDecodeError - } - extension := uint16(data[0])<<8 | uint16(data[1]) - length := int(data[2])<<8 | int(data[3]) - data = data[4:] - if len(data) < length { - return alertDecodeError - } - - switch extension { - case extensionNextProtoNeg: - m.nextProtoNeg = true - d := data[:length] - for len(d) > 0 { - l := int(d[0]) - d = d[1:] - if l == 0 || l > len(d) { - return alertDecodeError - } - m.nextProtos = append(m.nextProtos, string(d[:l])) - d = d[l:] - } - case extensionStatusRequest: - if length > 0 { - return alertDecodeError - } - m.ocspStapling = true - case extensionSessionTicket: - if length > 0 { - return alertDecodeError - } - m.ticketSupported = true - case extensionRenegotiationInfo: - if length == 0 { - return alertDecodeError - } - d := data[:length] - l := int(d[0]) - d = d[1:] - if l != len(d) { - return alertDecodeError - } - - m.secureRenegotiation = d - m.secureRenegotiationSupported = true - case extensionALPN: - d := data[:length] - if len(d) < 3 { - return alertDecodeError - } - l := int(d[0])<<8 | int(d[1]) - if l != len(d)-2 { - return alertDecodeError - } - d = d[2:] - l = int(d[0]) - if l != len(d)-1 { - return alertDecodeError - } - d = d[1:] - if len(d) == 0 { - // ALPN protocols must not be empty. - return alertDecodeError - } - m.alpnProtocol = string(d) - case extensionSCT: - d := data[:length] - - if len(d) < 2 { - return alertDecodeError - } - l := int(d[0])<<8 | int(d[1]) - d = d[2:] - if len(d) != l || l == 0 { - return alertDecodeError - } - - m.scts = make([][]byte, 0, 3) - for len(d) != 0 { - if len(d) < 2 { - return alertDecodeError - } - sctLen := int(d[0])<<8 | int(d[1]) - d = d[2:] - if sctLen == 0 || len(d) < sctLen { - return alertDecodeError - } - m.scts = append(m.scts, d[:sctLen]) - d = d[sctLen:] - } - case extensionKeyShare: - d := data[:length] - - if len(d) < 4 { - return alertDecodeError - } - m.keyShare.group = CurveID(d[0])<<8 | CurveID(d[1]) - l := int(d[2])<<8 | int(d[3]) - d = d[4:] - if len(d) != l { - return alertDecodeError - } - m.keyShare.data = d[:l] - case extensionPreSharedKey: - if length != 2 { - return alertDecodeError - } - m.psk = true - m.pskIdentity = uint16(data[0])<<8 | uint16(data[1]) - case extensionEMS: - m.extendedMSSupported = true - } - data = data[length:] - } - - return alertSuccess -} - -type encryptedExtensionsMsg struct { - raw []byte - alpnProtocol string - earlyData bool - - additionalExtensions []Extension -} - -func (m *encryptedExtensionsMsg) equal(i interface{}) bool { - m1, ok := i.(*encryptedExtensionsMsg) - if !ok { - return false - } - - if len(m.additionalExtensions) != len(m1.additionalExtensions) { - return false - } - for i, ex := range m.additionalExtensions { - ex1 := m1.additionalExtensions[i] - if ex.Type != ex1.Type || !bytes.Equal(ex.Data, ex1.Data) { - return false - } - } - - return bytes.Equal(m.raw, m1.raw) && - m.alpnProtocol == m1.alpnProtocol && - m.earlyData == m1.earlyData -} - -func (m *encryptedExtensionsMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - length := 2 - - if m.earlyData { - length += 4 - } - alpnLen := len(m.alpnProtocol) - if alpnLen > 0 { - if alpnLen >= 256 { - panic("invalid ALPN protocol") - } - length += 2 + 2 + 2 + 1 + alpnLen - } - if len(m.additionalExtensions) > 0 { - for _, ex := range m.additionalExtensions { - length += 4 + len(ex.Data) - } - } - - x := make([]byte, 4+length) - x[0] = typeEncryptedExtensions - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - length -= 2 - x[4] = uint8(length >> 8) - x[5] = uint8(length) - - z := x[6:] - if alpnLen > 0 { - z[0] = byte(extensionALPN >> 8) - z[1] = byte(extensionALPN) - l := 2 + 1 + alpnLen - z[2] = byte(l >> 8) - z[3] = byte(l) - l -= 2 - z[4] = byte(l >> 8) - z[5] = byte(l) - l -= 1 - z[6] = byte(l) - copy(z[7:], []byte(m.alpnProtocol)) - z = z[7+alpnLen:] - } - - if m.earlyData { - z[0] = byte(extensionEarlyData >> 8) - z[1] = byte(extensionEarlyData) - z = z[4:] - } - - for _, ex := range m.additionalExtensions { - z[0] = byte(ex.Type >> 8) - z[1] = byte(ex.Type) - l := len(ex.Data) - z[2] = byte(l >> 8) - z[3] = byte(l) - copy(z[4:], ex.Data) - z = z[4+l:] - } - - m.raw = x - return x -} - -func (m *encryptedExtensionsMsg) unmarshal(data []byte) alert { - if len(data) < 6 { - return alertDecodeError - } - m.raw = data - - m.alpnProtocol = "" - m.earlyData = false - - extensionsLength := int(data[4])<<8 | int(data[5]) - data = data[6:] - if len(data) != extensionsLength { - return alertDecodeError - } - - for len(data) != 0 { - if len(data) < 4 { - return alertDecodeError - } - ext := uint16(data[0])<<8 | uint16(data[1]) - length := int(data[2])<<8 | int(data[3]) - data = data[4:] - if len(data) < length { - return alertDecodeError - } - - switch ext { - case extensionALPN: - d := data[:length] - if len(d) < 3 { - return alertDecodeError - } - l := int(d[0])<<8 | int(d[1]) - if l != len(d)-2 { - return alertDecodeError - } - d = d[2:] - l = int(d[0]) - if l != len(d)-1 { - return alertDecodeError - } - d = d[1:] - if len(d) == 0 { - // ALPN protocols must not be empty. - return alertDecodeError - } - m.alpnProtocol = string(d) - case extensionEarlyData: - // https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8 - m.earlyData = true - default: - m.additionalExtensions = append(m.additionalExtensions, - Extension{Type: ext, Data: data[:length]}) - } - - data = data[length:] - } - - return alertSuccess -} - -type certificateMsg struct { - raw []byte - certificates [][]byte -} - -func (m *certificateMsg) equal(i interface{}) bool { - m1, ok := i.(*certificateMsg) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - eqByteSlices(m.certificates, m1.certificates) -} - -func (m *certificateMsg) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - var i int - for _, slice := range m.certificates { - i += len(slice) - } - - length := 3 + 3*len(m.certificates) + i - x = make([]byte, 4+length) - x[0] = typeCertificate - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - - certificateOctets := length - 3 - x[4] = uint8(certificateOctets >> 16) - x[5] = uint8(certificateOctets >> 8) - x[6] = uint8(certificateOctets) - - y := x[7:] - for _, slice := range m.certificates { - y[0] = uint8(len(slice) >> 16) - y[1] = uint8(len(slice) >> 8) - y[2] = uint8(len(slice)) - copy(y[3:], slice) - y = y[3+len(slice):] - } - - m.raw = x - return -} - -func (m *certificateMsg) unmarshal(data []byte) alert { - if len(data) < 7 { - return alertDecodeError - } - - m.raw = data - certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]) - if uint32(len(data)) != certsLen+7 { - return alertDecodeError - } - - numCerts := 0 - d := data[7:] - for certsLen > 0 { - if len(d) < 4 { - return alertDecodeError - } - certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) - if uint32(len(d)) < 3+certLen { - return alertDecodeError - } - d = d[3+certLen:] - certsLen -= 3 + certLen - numCerts++ - } - - m.certificates = make([][]byte, numCerts) - d = data[7:] - for i := 0; i < numCerts; i++ { - certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) - m.certificates[i] = d[3 : 3+certLen] - d = d[3+certLen:] - } - - return alertSuccess -} - -type certificateEntry struct { - data []byte - ocspStaple []byte - sctList [][]byte - delegatedCredential []byte -} - -type certificateMsg13 struct { - raw []byte - requestContext []byte - certificates []certificateEntry -} - -func (m *certificateMsg13) equal(i interface{}) bool { - m1, ok := i.(*certificateMsg13) - if !ok { - return false - } - - if len(m.certificates) != len(m1.certificates) { - return false - } - for i := range m.certificates { - ok := bytes.Equal(m.certificates[i].data, m1.certificates[i].data) - ok = ok && bytes.Equal(m.certificates[i].ocspStaple, m1.certificates[i].ocspStaple) - ok = ok && eqByteSlices(m.certificates[i].sctList, m1.certificates[i].sctList) - ok = ok && bytes.Equal(m.certificates[i].delegatedCredential, m1.certificates[i].delegatedCredential) - if !ok { - return false - } - } - - return bytes.Equal(m.raw, m1.raw) && - bytes.Equal(m.requestContext, m1.requestContext) -} - -func (m *certificateMsg13) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - var i int - for _, cert := range m.certificates { - i += len(cert.data) - if len(cert.ocspStaple) != 0 { - i += 8 + len(cert.ocspStaple) - } - if len(cert.sctList) != 0 { - i += 6 - for _, sct := range cert.sctList { - i += 2 + len(sct) - } - } - if len(cert.delegatedCredential) != 0 { - i += 4 + len(cert.delegatedCredential) - } - } - - length := 3 + 3*len(m.certificates) + i - length += 2 * len(m.certificates) // extensions - length += 1 + len(m.requestContext) - x = make([]byte, 4+length) - x[0] = typeCertificate - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - - z := x[4:] - - z[0] = byte(len(m.requestContext)) - copy(z[1:], m.requestContext) - z = z[1+len(m.requestContext):] - - certificateOctets := len(z) - 3 - z[0] = uint8(certificateOctets >> 16) - z[1] = uint8(certificateOctets >> 8) - z[2] = uint8(certificateOctets) - - z = z[3:] - for _, cert := range m.certificates { - z[0] = uint8(len(cert.data) >> 16) - z[1] = uint8(len(cert.data) >> 8) - z[2] = uint8(len(cert.data)) - copy(z[3:], cert.data) - z = z[3+len(cert.data):] - - extLenPos := z[:2] - z = z[2:] - - extensionLen := 0 - if len(cert.ocspStaple) != 0 { - stapleLen := 4 + len(cert.ocspStaple) - z[0] = uint8(extensionStatusRequest >> 8) - z[1] = uint8(extensionStatusRequest) - z[2] = uint8(stapleLen >> 8) - z[3] = uint8(stapleLen) - - stapleLen -= 4 - z[4] = statusTypeOCSP - z[5] = uint8(stapleLen >> 16) - z[6] = uint8(stapleLen >> 8) - z[7] = uint8(stapleLen) - copy(z[8:], cert.ocspStaple) - z = z[8+stapleLen:] - - extensionLen += 8 + stapleLen - } - if len(cert.sctList) != 0 { - z[0] = uint8(extensionSCT >> 8) - z[1] = uint8(extensionSCT) - sctLenPos := z[2:6] - z = z[6:] - extensionLen += 6 - - sctLen := 2 - for _, sct := range cert.sctList { - z[0] = uint8(len(sct) >> 8) - z[1] = uint8(len(sct)) - copy(z[2:], sct) - z = z[2+len(sct):] - - extensionLen += 2 + len(sct) - sctLen += 2 + len(sct) - } - sctLenPos[0] = uint8(sctLen >> 8) - sctLenPos[1] = uint8(sctLen) - sctLen -= 2 - sctLenPos[2] = uint8(sctLen >> 8) - sctLenPos[3] = uint8(sctLen) - } - if len(cert.delegatedCredential) != 0 { - binary.BigEndian.PutUint16(z, extensionDelegatedCredential) - binary.BigEndian.PutUint16(z[2:], uint16(len(cert.delegatedCredential))) - z = z[4:] - copy(z, cert.delegatedCredential) - z = z[len(cert.delegatedCredential):] - extensionLen += 4 + len(cert.delegatedCredential) - } - - extLenPos[0] = uint8(extensionLen >> 8) - extLenPos[1] = uint8(extensionLen) - } - - m.raw = x - return -} - -func (m *certificateMsg13) unmarshal(data []byte) alert { - if len(data) < 5 { - return alertDecodeError - } - - m.raw = data - - ctxLen := data[4] - if len(data) < int(ctxLen)+5+3 { - return alertDecodeError - } - m.requestContext = data[5 : 5+ctxLen] - - d := data[5+ctxLen:] - certsLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) - if uint32(len(d)) != certsLen+3 { - return alertDecodeError - } - - numCerts := 0 - d = d[3:] - for certsLen > 0 { - if len(d) < 4 { - return alertDecodeError - } - certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) - if uint32(len(d)) < 3+certLen { - return alertDecodeError - } - d = d[3+certLen:] - - if len(d) < 2 { - return alertDecodeError - } - extLen := uint16(d[0])<<8 | uint16(d[1]) - if uint16(len(d)) < 2+extLen { - return alertDecodeError - } - d = d[2+extLen:] - - certsLen -= 3 + certLen + 2 + uint32(extLen) - numCerts++ - } - - m.certificates = make([]certificateEntry, numCerts) - d = data[8+ctxLen:] - for i := 0; i < numCerts; i++ { - certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) - m.certificates[i].data = d[3 : 3+certLen] - d = d[3+certLen:] - - extLen := uint16(d[0])<<8 | uint16(d[1]) - d = d[2:] - for extLen > 0 { - if extLen < 4 { - return alertDecodeError - } - typ := uint16(d[0])<<8 | uint16(d[1]) - bodyLen := uint16(d[2])<<8 | uint16(d[3]) - if extLen < 4+bodyLen { - return alertDecodeError - } - body := d[4 : 4+bodyLen] - d = d[4+bodyLen:] - extLen -= 4 + bodyLen - - switch typ { - case extensionStatusRequest: - if len(body) < 4 || body[0] != 0x01 { - return alertDecodeError - } - ocspLen := int(body[1])<<16 | int(body[2])<<8 | int(body[3]) - if len(body) != 4+ocspLen { - return alertDecodeError - } - m.certificates[i].ocspStaple = body[4:] - - case extensionSCT: - if len(body) < 2 { - return alertDecodeError - } - listLen := int(body[0])<<8 | int(body[1]) - body = body[2:] - if len(body) != listLen { - return alertDecodeError - } - for len(body) > 0 { - if len(body) < 2 { - return alertDecodeError - } - sctLen := int(body[0])<<8 | int(body[1]) - if len(body) < 2+sctLen { - return alertDecodeError - } - m.certificates[i].sctList = append(m.certificates[i].sctList, body[2:2+sctLen]) - body = body[2+sctLen:] - } - case extensionDelegatedCredential: - m.certificates[i].delegatedCredential = body - } - } - } - - return alertSuccess -} - -type serverKeyExchangeMsg struct { - raw []byte - key []byte -} - -func (m *serverKeyExchangeMsg) equal(i interface{}) bool { - m1, ok := i.(*serverKeyExchangeMsg) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - bytes.Equal(m.key, m1.key) -} - -func (m *serverKeyExchangeMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - length := len(m.key) - x := make([]byte, length+4) - x[0] = typeServerKeyExchange - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - copy(x[4:], m.key) - - m.raw = x - return x -} - -func (m *serverKeyExchangeMsg) unmarshal(data []byte) alert { - m.raw = data - if len(data) < 4 { - return alertDecodeError - } - m.key = data[4:] - return alertSuccess -} - -type certificateStatusMsg struct { - raw []byte - statusType uint8 - response []byte -} - -func (m *certificateStatusMsg) equal(i interface{}) bool { - m1, ok := i.(*certificateStatusMsg) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - m.statusType == m1.statusType && - bytes.Equal(m.response, m1.response) -} - -func (m *certificateStatusMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - - var x []byte - if m.statusType == statusTypeOCSP { - x = make([]byte, 4+4+len(m.response)) - x[0] = typeCertificateStatus - l := len(m.response) + 4 - x[1] = byte(l >> 16) - x[2] = byte(l >> 8) - x[3] = byte(l) - x[4] = statusTypeOCSP - - l -= 4 - x[5] = byte(l >> 16) - x[6] = byte(l >> 8) - x[7] = byte(l) - copy(x[8:], m.response) - } else { - x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType} - } - - m.raw = x - return x -} - -func (m *certificateStatusMsg) unmarshal(data []byte) alert { - m.raw = data - if len(data) < 5 { - return alertDecodeError - } - m.statusType = data[4] - - m.response = nil - if m.statusType == statusTypeOCSP { - if len(data) < 8 { - return alertDecodeError - } - respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) - if uint32(len(data)) != 4+4+respLen { - return alertDecodeError - } - m.response = data[8:] - } - return alertSuccess -} - -type serverHelloDoneMsg struct{} - -func (m *serverHelloDoneMsg) equal(i interface{}) bool { - _, ok := i.(*serverHelloDoneMsg) - return ok -} - -func (m *serverHelloDoneMsg) marshal() []byte { - x := make([]byte, 4) - x[0] = typeServerHelloDone - return x -} - -func (m *serverHelloDoneMsg) unmarshal(data []byte) alert { - if len(data) != 4 { - return alertDecodeError - } - return alertSuccess -} - -type clientKeyExchangeMsg struct { - raw []byte - ciphertext []byte -} - -func (m *clientKeyExchangeMsg) equal(i interface{}) bool { - m1, ok := i.(*clientKeyExchangeMsg) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - bytes.Equal(m.ciphertext, m1.ciphertext) -} - -func (m *clientKeyExchangeMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - length := len(m.ciphertext) - x := make([]byte, length+4) - x[0] = typeClientKeyExchange - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - copy(x[4:], m.ciphertext) - - m.raw = x - return x -} - -func (m *clientKeyExchangeMsg) unmarshal(data []byte) alert { - m.raw = data - if len(data) < 4 { - return alertDecodeError - } - l := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) - if l != len(data)-4 { - return alertDecodeError - } - m.ciphertext = data[4:] - return alertSuccess -} - -type finishedMsg struct { - raw []byte - verifyData []byte -} - -func (m *finishedMsg) equal(i interface{}) bool { - m1, ok := i.(*finishedMsg) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - bytes.Equal(m.verifyData, m1.verifyData) -} - -func (m *finishedMsg) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - x = make([]byte, 4+len(m.verifyData)) - x[0] = typeFinished - x[3] = byte(len(m.verifyData)) - copy(x[4:], m.verifyData) - m.raw = x - return -} - -func (m *finishedMsg) unmarshal(data []byte) alert { - m.raw = data - if len(data) < 4 { - return alertDecodeError - } - m.verifyData = data[4:] - return alertSuccess -} - -type nextProtoMsg struct { - raw []byte - proto string -} - -func (m *nextProtoMsg) equal(i interface{}) bool { - m1, ok := i.(*nextProtoMsg) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - m.proto == m1.proto -} - -func (m *nextProtoMsg) marshal() []byte { - if m.raw != nil { - return m.raw - } - l := len(m.proto) - if l > 255 { - l = 255 - } - - padding := 32 - (l+2)%32 - length := l + padding + 2 - x := make([]byte, length+4) - x[0] = typeNextProtocol - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - - y := x[4:] - y[0] = byte(l) - copy(y[1:], []byte(m.proto[0:l])) - y = y[1+l:] - y[0] = byte(padding) - - m.raw = x - - return x -} - -func (m *nextProtoMsg) unmarshal(data []byte) alert { - m.raw = data - - if len(data) < 5 { - return alertDecodeError - } - data = data[4:] - protoLen := int(data[0]) - data = data[1:] - if len(data) < protoLen { - return alertDecodeError - } - m.proto = string(data[0:protoLen]) - data = data[protoLen:] - - if len(data) < 1 { - return alertDecodeError - } - paddingLen := int(data[0]) - data = data[1:] - if len(data) != paddingLen { - return alertDecodeError - } - - return alertSuccess -} - -type certificateRequestMsg struct { - raw []byte - // hasSignatureAndHash indicates whether this message includes a list - // of signature and hash functions. This change was introduced with TLS - // 1.2. - hasSignatureAndHash bool - - certificateTypes []byte - supportedSignatureAlgorithms []SignatureScheme - certificateAuthorities [][]byte -} - -func (m *certificateRequestMsg) equal(i interface{}) bool { - m1, ok := i.(*certificateRequestMsg) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - bytes.Equal(m.certificateTypes, m1.certificateTypes) && - eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) && - eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) -} - -func (m *certificateRequestMsg) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - // See http://tools.ietf.org/html/rfc4346#section-7.4.4 - length := 1 + len(m.certificateTypes) + 2 - casLength := 0 - for _, ca := range m.certificateAuthorities { - casLength += 2 + len(ca) - } - length += casLength - - if m.hasSignatureAndHash { - length += 2 + 2*len(m.supportedSignatureAlgorithms) - } - - x = make([]byte, 4+length) - x[0] = typeCertificateRequest - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - - x[4] = uint8(len(m.certificateTypes)) - - copy(x[5:], m.certificateTypes) - y := x[5+len(m.certificateTypes):] - - if m.hasSignatureAndHash { - n := len(m.supportedSignatureAlgorithms) * 2 - y[0] = uint8(n >> 8) - y[1] = uint8(n) - y = y[2:] - for _, sigAlgo := range m.supportedSignatureAlgorithms { - y[0] = uint8(sigAlgo >> 8) - y[1] = uint8(sigAlgo) - y = y[2:] - } - } - - y[0] = uint8(casLength >> 8) - y[1] = uint8(casLength) - y = y[2:] - for _, ca := range m.certificateAuthorities { - y[0] = uint8(len(ca) >> 8) - y[1] = uint8(len(ca)) - y = y[2:] - copy(y, ca) - y = y[len(ca):] - } - - m.raw = x - return -} - -func (m *certificateRequestMsg) unmarshal(data []byte) alert { - m.raw = data - - if len(data) < 5 { - return alertDecodeError - } - - length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) - if uint32(len(data))-4 != length { - return alertDecodeError - } - - numCertTypes := int(data[4]) - data = data[5:] - if numCertTypes == 0 || len(data) <= numCertTypes { - return alertDecodeError - } - - m.certificateTypes = make([]byte, numCertTypes) - if copy(m.certificateTypes, data) != numCertTypes { - return alertDecodeError - } - - data = data[numCertTypes:] - - if m.hasSignatureAndHash { - if len(data) < 2 { - return alertDecodeError - } - sigAndHashLen := uint16(data[0])<<8 | uint16(data[1]) - data = data[2:] - if sigAndHashLen&1 != 0 { - return alertDecodeError - } - if len(data) < int(sigAndHashLen) { - return alertDecodeError - } - numSigAlgos := sigAndHashLen / 2 - m.supportedSignatureAlgorithms = make([]SignatureScheme, numSigAlgos) - for i := range m.supportedSignatureAlgorithms { - m.supportedSignatureAlgorithms[i] = SignatureScheme(data[0])<<8 | SignatureScheme(data[1]) - data = data[2:] - } - } - - if len(data) < 2 { - return alertDecodeError - } - casLength := uint16(data[0])<<8 | uint16(data[1]) - data = data[2:] - if len(data) < int(casLength) { - return alertDecodeError - } - cas := make([]byte, casLength) - copy(cas, data) - data = data[casLength:] - - m.certificateAuthorities = nil - for len(cas) > 0 { - if len(cas) < 2 { - return alertDecodeError - } - caLen := uint16(cas[0])<<8 | uint16(cas[1]) - cas = cas[2:] - - if len(cas) < int(caLen) { - return alertDecodeError - } - - m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen]) - cas = cas[caLen:] - } - - if len(data) != 0 { - return alertDecodeError - } - - return alertSuccess -} - -type certificateRequestMsg13 struct { - raw []byte - - requestContext []byte - supportedSignatureAlgorithms []SignatureScheme - supportedSignatureAlgorithmsCert []SignatureScheme - certificateAuthorities [][]byte -} - -func (m *certificateRequestMsg13) equal(i interface{}) bool { - m1, ok := i.(*certificateRequestMsg13) - return ok && - bytes.Equal(m.raw, m1.raw) && - bytes.Equal(m.requestContext, m1.requestContext) && - eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) && - eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) && - eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert) -} - -func (m *certificateRequestMsg13) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - // See https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.3.2 - length := 1 + len(m.requestContext) - numExtensions := 1 - extensionsLength := 2 + 2*len(m.supportedSignatureAlgorithms) - - if m.getSignatureAlgorithmsCert() != nil { - numExtensions += 1 - extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert()) - } - - casLength := 0 - if len(m.certificateAuthorities) > 0 { - for _, ca := range m.certificateAuthorities { - casLength += 2 + len(ca) - } - extensionsLength += 2 + casLength - numExtensions++ - } - - extensionsLength += 4 * numExtensions - length += 2 + extensionsLength - - x = make([]byte, 4+length) - x[0] = typeCertificateRequest - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - - x[4] = uint8(len(m.requestContext)) - copy(x[5:], m.requestContext) - z := x[5+len(m.requestContext):] - - z[0] = byte(extensionsLength >> 8) - z[1] = byte(extensionsLength) - z = z[2:] - - // TODO: this function should be reused by CH - z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms) - - if m.getSignatureAlgorithmsCert() != nil { - z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert()) - } - // certificate_authorities - if casLength > 0 { - z[0] = byte(extensionCAs >> 8) - z[1] = byte(extensionCAs) - l := 2 + casLength - z[2] = byte(l >> 8) - z[3] = byte(l) - z = z[4:] - - z[0] = uint8(casLength >> 8) - z[1] = uint8(casLength) - z = z[2:] - for _, ca := range m.certificateAuthorities { - z[0] = uint8(len(ca) >> 8) - z[1] = uint8(len(ca)) - z = z[2:] - copy(z, ca) - z = z[len(ca):] - } - } - - m.raw = x - return -} - -func (m *certificateRequestMsg13) unmarshal(data []byte) alert { - m.raw = data - m.supportedSignatureAlgorithms = nil - m.certificateAuthorities = nil - - if len(data) < 5 { - return alertDecodeError - } - - length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) - if uint32(len(data))-4 != length { - return alertDecodeError - } - - ctxLen := data[4] - if len(data) < 5+int(ctxLen)+2 { - return alertDecodeError - } - m.requestContext = data[5 : 5+ctxLen] - data = data[5+ctxLen:] - - extensionsLength := int(data[0])<<8 | int(data[1]) - data = data[2:] - if len(data) != extensionsLength { - return alertDecodeError - } - - for len(data) != 0 { - if len(data) < 4 { - return alertDecodeError - } - extension := uint16(data[0])<<8 | uint16(data[1]) - length := int(data[2])<<8 | int(data[3]) - data = data[4:] - if len(data) < length { - return alertDecodeError - } - - switch extension { - case extensionSignatureAlgorithms: - // TODO: unmarshalExtensionSignatureAlgorithms should be shared with CH and pre-1.3 CV - // https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.2.3 - var err alert - m.supportedSignatureAlgorithms, err = unmarshalExtensionSignatureAlgorithms(data, length) - if err != alertSuccess { - return err - } - case extensionSignatureAlgorithmsCert: - var err alert - m.supportedSignatureAlgorithmsCert, err = unmarshalExtensionSignatureAlgorithms(data, length) - if err != alertSuccess { - return err - } - case extensionCAs: - // TODO DRY: share code with CH - if length < 2 { - return alertDecodeError - } - l := int(data[0])<<8 | int(data[1]) - if l != length-2 || l < 3 { - return alertDecodeError - } - cas := make([]byte, l) - copy(cas, data[2:]) - m.certificateAuthorities = nil - for len(cas) > 0 { - if len(cas) < 2 { - return alertDecodeError - } - caLen := uint16(cas[0])<<8 | uint16(cas[1]) - cas = cas[2:] - - if len(cas) < int(caLen) { - return alertDecodeError - } - - m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen]) - cas = cas[caLen:] - } - } - data = data[length:] - } - - if len(m.supportedSignatureAlgorithms) == 0 { - return alertDecodeError - } - return alertSuccess -} - -func (m *certificateRequestMsg13) getSignatureAlgorithmsCert() []SignatureScheme { - return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert) -} - -type certificateVerifyMsg struct { - raw []byte - hasSignatureAndHash bool - signatureAlgorithm SignatureScheme - signature []byte -} - -func (m *certificateVerifyMsg) equal(i interface{}) bool { - m1, ok := i.(*certificateVerifyMsg) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - m.hasSignatureAndHash == m1.hasSignatureAndHash && - m.signatureAlgorithm == m1.signatureAlgorithm && - bytes.Equal(m.signature, m1.signature) -} - -func (m *certificateVerifyMsg) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - // See http://tools.ietf.org/html/rfc4346#section-7.4.8 - siglength := len(m.signature) - length := 2 + siglength - if m.hasSignatureAndHash { - length += 2 - } - x = make([]byte, 4+length) - x[0] = typeCertificateVerify - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - y := x[4:] - if m.hasSignatureAndHash { - y[0] = uint8(m.signatureAlgorithm >> 8) - y[1] = uint8(m.signatureAlgorithm) - y = y[2:] - } - y[0] = uint8(siglength >> 8) - y[1] = uint8(siglength) - copy(y[2:], m.signature) - - m.raw = x - - return -} - -func (m *certificateVerifyMsg) unmarshal(data []byte) alert { - m.raw = data - - if len(data) < 6 { - return alertDecodeError - } - - length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) - if uint32(len(data))-4 != length { - return alertDecodeError - } - - data = data[4:] - if m.hasSignatureAndHash { - m.signatureAlgorithm = SignatureScheme(data[0])<<8 | SignatureScheme(data[1]) - data = data[2:] - } - - if len(data) < 2 { - return alertDecodeError - } - siglength := int(data[0])<<8 + int(data[1]) - data = data[2:] - if len(data) != siglength { - return alertDecodeError - } - - m.signature = data - - return alertSuccess -} - -type newSessionTicketMsg struct { - raw []byte - ticket []byte -} - -func (m *newSessionTicketMsg) equal(i interface{}) bool { - m1, ok := i.(*newSessionTicketMsg) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - bytes.Equal(m.ticket, m1.ticket) -} - -func (m *newSessionTicketMsg) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - // See http://tools.ietf.org/html/rfc5077#section-3.3 - ticketLen := len(m.ticket) - length := 2 + 4 + ticketLen - x = make([]byte, 4+length) - x[0] = typeNewSessionTicket - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - x[8] = uint8(ticketLen >> 8) - x[9] = uint8(ticketLen) - copy(x[10:], m.ticket) - - m.raw = x - - return -} - -func (m *newSessionTicketMsg) unmarshal(data []byte) alert { - m.raw = data - - if len(data) < 10 { - return alertDecodeError - } - - length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) - if uint32(len(data))-4 != length { - return alertDecodeError - } - - ticketLen := int(data[8])<<8 + int(data[9]) - if len(data)-10 != ticketLen { - return alertDecodeError - } - - m.ticket = data[10:] - - return alertSuccess -} - -type newSessionTicketMsg13 struct { - raw []byte - lifetime uint32 - ageAdd uint32 - nonce []byte - ticket []byte - withEarlyDataInfo bool - maxEarlyDataLength uint32 -} - -func (m *newSessionTicketMsg13) equal(i interface{}) bool { - m1, ok := i.(*newSessionTicketMsg13) - if !ok { - return false - } - - return bytes.Equal(m.raw, m1.raw) && - m.lifetime == m1.lifetime && - m.ageAdd == m1.ageAdd && - bytes.Equal(m.nonce, m1.nonce) && - bytes.Equal(m.ticket, m1.ticket) && - m.withEarlyDataInfo == m1.withEarlyDataInfo && - m.maxEarlyDataLength == m1.maxEarlyDataLength -} - -func (m *newSessionTicketMsg13) marshal() (x []byte) { - if m.raw != nil { - return m.raw - } - - // See https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.6.1 - nonceLen := len(m.nonce) - ticketLen := len(m.ticket) - length := 13 + nonceLen + ticketLen - if m.withEarlyDataInfo { - length += 8 - } - x = make([]byte, 4+length) - x[0] = typeNewSessionTicket - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) - x[3] = uint8(length) - - x[4] = uint8(m.lifetime >> 24) - x[5] = uint8(m.lifetime >> 16) - x[6] = uint8(m.lifetime >> 8) - x[7] = uint8(m.lifetime) - x[8] = uint8(m.ageAdd >> 24) - x[9] = uint8(m.ageAdd >> 16) - x[10] = uint8(m.ageAdd >> 8) - x[11] = uint8(m.ageAdd) - - x[12] = uint8(nonceLen) - copy(x[13:13+nonceLen], m.nonce) - - y := x[13+nonceLen:] - y[0] = uint8(ticketLen >> 8) - y[1] = uint8(ticketLen) - copy(y[2:2+ticketLen], m.ticket) - - if m.withEarlyDataInfo { - z := y[2+ticketLen:] - // z[0] is already 0, this is the extensions vector length. - z[1] = 8 - z[2] = uint8(extensionEarlyData >> 8) - z[3] = uint8(extensionEarlyData) - z[5] = 4 - z[6] = uint8(m.maxEarlyDataLength >> 24) - z[7] = uint8(m.maxEarlyDataLength >> 16) - z[8] = uint8(m.maxEarlyDataLength >> 8) - z[9] = uint8(m.maxEarlyDataLength) - } - - m.raw = x - - return -} - -func (m *newSessionTicketMsg13) unmarshal(data []byte) alert { - m.raw = data - m.maxEarlyDataLength = 0 - m.withEarlyDataInfo = false - - if len(data) < 17 { - return alertDecodeError - } - - length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) - if uint32(len(data))-4 != length { - return alertDecodeError - } - - m.lifetime = uint32(data[4])<<24 | uint32(data[5])<<16 | - uint32(data[6])<<8 | uint32(data[7]) - m.ageAdd = uint32(data[8])<<24 | uint32(data[9])<<16 | - uint32(data[10])<<8 | uint32(data[11]) - - nonceLen := int(data[12]) - if nonceLen == 0 || 13+nonceLen+2 > len(data) { - return alertDecodeError - } - m.nonce = data[13 : 13+nonceLen] - - data = data[13+nonceLen:] - ticketLen := int(data[0])<<8 + int(data[1]) - if ticketLen == 0 || 2+ticketLen+2 > len(data) { - return alertDecodeError - } - m.ticket = data[2 : 2+ticketLen] - - data = data[2+ticketLen:] - extLen := int(data[0])<<8 + int(data[1]) - if extLen != len(data)-2 { - return alertDecodeError - } - - data = data[2:] - for len(data) > 0 { - if len(data) < 4 { - return alertDecodeError - } - extType := uint16(data[0])<<8 + uint16(data[1]) - length := int(data[2])<<8 + int(data[3]) - data = data[4:] - - switch extType { - case extensionEarlyData: - if length != 4 { - return alertDecodeError - } - m.withEarlyDataInfo = true - m.maxEarlyDataLength = uint32(data[0])<<24 | uint32(data[1])<<16 | - uint32(data[2])<<8 | uint32(data[3]) - } - data = data[length:] - } - - return alertSuccess -} - -type endOfEarlyDataMsg struct { -} - -func (*endOfEarlyDataMsg) marshal() []byte { - return []byte{typeEndOfEarlyData, 0, 0, 0} -} - -func (*endOfEarlyDataMsg) unmarshal(data []byte) alert { - if len(data) != 4 { - return alertDecodeError - } - return alertSuccess -} - -type helloRequestMsg struct { -} - -func (*helloRequestMsg) marshal() []byte { - return []byte{typeHelloRequest, 0, 0, 0} -} - -func (*helloRequestMsg) unmarshal(data []byte) alert { - if len(data) != 4 { - return alertDecodeError - } - return alertSuccess -} - -func eqUint16s(x, y []uint16) bool { - if len(x) != len(y) { - return false - } - for i, v := range x { - if y[i] != v { - return false - } - } - return true -} - -func eqCurveIDs(x, y []CurveID) bool { - if len(x) != len(y) { - return false - } - for i, v := range x { - if y[i] != v { - return false - } - } - return true -} - -func eqStrings(x, y []string) bool { - if len(x) != len(y) { - return false - } - for i, v := range x { - if y[i] != v { - return false - } - } - return true -} - -func eqByteSlices(x, y [][]byte) bool { - if len(x) != len(y) { - return false - } - for i, v := range x { - if !bytes.Equal(v, y[i]) { - return false - } - } - return true -} - -func eqSignatureAlgorithms(x, y []SignatureScheme) bool { - if len(x) != len(y) { - return false - } - for i, v := range x { - if v != y[i] { - return false - } - } - return true -} - -func eqKeyShares(x, y []keyShare) bool { - if len(x) != len(y) { - return false - } - for i := range x { - if x[i].group != y[i].group { - return false - } - if !bytes.Equal(x[i].data, y[i].data) { - return false - } - } - return true -} - -func findExtension(data []byte, extensionType uint16) []byte { - for len(data) != 0 { - if len(data) < 4 { - return nil - } - extension := uint16(data[0])<<8 | uint16(data[1]) - length := int(data[2])<<8 | int(data[3]) - data = data[4:] - if len(data) < length { - return nil - } - if extension == extensionType { - return data[:length] - } - data = data[length:] - } - return nil -} diff --git a/external/github.com/marten-seemann/qtls/handshake_server.go b/external/github.com/marten-seemann/qtls/handshake_server.go deleted file mode 100644 index 38004fe72..000000000 --- a/external/github.com/marten-seemann/qtls/handshake_server.go +++ /dev/null @@ -1,943 +0,0 @@ -// Copyright 2009 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 qtls - -import ( - "crypto" - "crypto/ecdsa" - "crypto/rsa" - "crypto/subtle" - "crypto/x509" - "errors" - "fmt" - "io" - "sync/atomic" -) - -// serverHandshakeState contains details of a server handshake in progress. -// It's discarded once the handshake has completed. -type serverHandshakeState struct { - c *Conn - suite *cipherSuite - masterSecret []byte - cachedClientHelloInfo *ClientHelloInfo - clientHello *clientHelloMsg - hello *serverHelloMsg - cert *Certificate - privateKey crypto.PrivateKey - - // A marshalled DelegatedCredential to be sent to the client in the - // handshake. - delegatedCredential []byte - - // TLS 1.0-1.2 fields - ellipticOk bool - ecdsaOk bool - rsaDecryptOk bool - rsaSignOk bool - sessionState *sessionState - finishedHash finishedHash - certsFromClient [][]byte - - // TLS 1.3 fields - hello13Enc *encryptedExtensionsMsg - keySchedule *keySchedule13 - clientFinishedKey []byte - hsClientTrafficSecret []byte - appClientTrafficSecret []byte -} - -// serverHandshake performs a TLS handshake as a server. -// c.out.Mutex <= L; c.handshakeMutex <= L. -func (c *Conn) serverHandshake() error { - // If this is the first server handshake, we generate a random key to - // encrypt the tickets with. - c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) }) - c.setAlternativeRecordLayer() - - hs := serverHandshakeState{ - c: c, - } - c.in.traceErr = hs.traceErr - c.out.traceErr = hs.traceErr - isResume, err := hs.readClientHello() - if err != nil { - return err - } - - // For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3 - // and https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-2 - c.buffering = true - if c.vers >= VersionTLS13 { - if err := hs.doTLS13Handshake(); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - c.hs = &hs - // If the client is sending early data while the server expects - // it, delay the Finished check until HandshakeConfirmed() is - // called or until all early data is Read(). Otherwise, complete - // authenticating the client now (there is no support for - // sending 0.5-RTT data to a potential unauthenticated client). - if c.phase != readingEarlyData { - if err := hs.readClientFinished13(false); err != nil { - return err - } - } - c.handshakeComplete = true - return nil - } else if isResume { - // The client has included a session ticket and so we do an abbreviated handshake. - if err := hs.doResumeHandshake(); err != nil { - return err - } - if err := hs.establishKeys(); err != nil { - return err - } - // ticketSupported is set in a resumption handshake if the - // ticket from the client was encrypted with an old session - // ticket key and thus a refreshed ticket should be sent. - if hs.hello.ticketSupported { - if err := hs.sendSessionTicket(); err != nil { - return err - } - } - if err := hs.sendFinished(c.serverFinished[:]); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - c.clientFinishedIsFirst = false - if err := hs.readFinished(nil); err != nil { - return err - } - c.didResume = true - } else { - // The client didn't include a session ticket, or it wasn't - // valid so we do a full handshake. - if err := hs.doFullHandshake(); err != nil { - return err - } - if err := hs.establishKeys(); err != nil { - return err - } - if err := hs.readFinished(c.clientFinished[:]); err != nil { - return err - } - c.clientFinishedIsFirst = true - c.buffering = true - if err := hs.sendSessionTicket(); err != nil { - return err - } - if err := hs.sendFinished(nil); err != nil { - return err - } - if _, err := c.flush(); err != nil { - return err - } - } - if c.hand.Len() > 0 { - return c.sendAlert(alertUnexpectedMessage) - } - c.phase = handshakeConfirmed - atomic.StoreInt32(&c.handshakeConfirmed, 1) - c.handshakeComplete = true - - return nil -} - -// readClientHello reads a ClientHello message from the client and decides -// whether we will perform session resumption. -func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { - c := hs.c - - msg, err := c.readHandshake() - if err != nil { - return false, err - } - var ok bool - hs.clientHello, ok = msg.(*clientHelloMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return false, unexpectedMessageError(hs.clientHello, msg) - } - - if c.config.GetConfigForClient != nil { - if newConfig, err := c.config.GetConfigForClient(hs.clientHelloInfo()); err != nil { - c.out.traceErr, c.in.traceErr = nil, nil // disable tracing - c.sendAlert(alertInternalError) - return false, err - } else if newConfig != nil { - newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) }) - c.config = newConfig - } - } - - var keyShares []CurveID - for _, ks := range hs.clientHello.keyShares { - keyShares = append(keyShares, ks.group) - } - - if hs.clientHello.supportedVersions != nil { - c.vers, ok = c.config.pickVersion(hs.clientHello.supportedVersions) - if !ok { - c.sendAlert(alertProtocolVersion) - return false, fmt.Errorf("tls: none of the client versions (%x) are supported", hs.clientHello.supportedVersions) - } - } else { - c.vers, ok = c.config.mutualVersion(hs.clientHello.vers) - if !ok { - c.sendAlert(alertProtocolVersion) - return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers) - } - } - c.haveVers = true - - preferredCurves := c.config.curvePreferences() -Curves: - for _, curve := range hs.clientHello.supportedCurves { - for _, supported := range preferredCurves { - if supported == curve { - hs.ellipticOk = true - break Curves - } - } - } - - // If present, the supported points extension must include uncompressed. - // Can be absent. This behavior mirrors BoringSSL. - if hs.clientHello.supportedPoints != nil { - supportedPointFormat := false - for _, pointFormat := range hs.clientHello.supportedPoints { - if pointFormat == pointFormatUncompressed { - supportedPointFormat = true - break - } - } - if !supportedPointFormat { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: client does not support uncompressed points") - } - } - - foundCompression := false - // We only support null compression, so check that the client offered it. - for _, compression := range hs.clientHello.compressionMethods { - if compression == compressionNone { - foundCompression = true - break - } - } - - if !foundCompression { - c.sendAlert(alertIllegalParameter) - return false, errors.New("tls: client does not support uncompressed connections") - } - if len(hs.clientHello.compressionMethods) != 1 && c.vers >= VersionTLS13 { - c.sendAlert(alertIllegalParameter) - return false, errors.New("tls: 1.3 client offered compression") - } - - if len(hs.clientHello.secureRenegotiation) != 0 { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: initial handshake had non-empty renegotiation extension") - } - - if c.vers < VersionTLS13 { - hs.hello = new(serverHelloMsg) - hs.hello.vers = c.vers - hs.hello.random = make([]byte, 32) - _, err = io.ReadFull(c.config.rand(), hs.hello.random) - if err != nil { - c.sendAlert(alertInternalError) - return false, err - } - hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported - hs.hello.compressionMethod = compressionNone - } else { - if hs.c.config.ReceivedExtensions != nil { - if err := hs.c.config.ReceivedExtensions(typeClientHello, hs.clientHello.additionalExtensions); err != nil { - c.sendAlert(alertInternalError) - return false, err - } - } - hs.hello = new(serverHelloMsg) - hs.hello13Enc = new(encryptedExtensionsMsg) - if hs.c.config.GetExtensions != nil { - hs.hello13Enc.additionalExtensions = hs.c.config.GetExtensions(typeEncryptedExtensions) - } - hs.hello.vers = c.vers - hs.hello.random = make([]byte, 32) - hs.hello.sessionId = hs.clientHello.sessionId - _, err = io.ReadFull(c.config.rand(), hs.hello.random) - if err != nil { - c.sendAlert(alertInternalError) - return false, err - } - } - - if len(hs.clientHello.serverName) > 0 { - c.serverName = hs.clientHello.serverName - } - - if len(hs.clientHello.alpnProtocols) > 0 { - if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback { - if hs.hello13Enc != nil { - hs.hello13Enc.alpnProtocol = selectedProto - } else { - hs.hello.alpnProtocol = selectedProto - } - c.clientProtocol = selectedProto - } - } else { - // Although sending an empty NPN extension is reasonable, Firefox has - // had a bug around this. Best to send nothing at all if - // c.config.NextProtos is empty. See - // https://golang.org/issue/5445. - if hs.clientHello.nextProtoNeg && len(c.config.NextProtos) > 0 && c.vers < VersionTLS13 { - hs.hello.nextProtoNeg = true - hs.hello.nextProtos = c.config.NextProtos - } - } - - hs.cert, err = c.config.getCertificate(hs.clientHelloInfo()) - if err != nil { - c.sendAlert(alertInternalError) - return false, err - } - - // Set the private key for this handshake to the certificate's secret key. - hs.privateKey = hs.cert.PrivateKey - - if hs.clientHello.scts { - hs.hello.scts = hs.cert.SignedCertificateTimestamps - } - - // Set the private key to the DC private key if the client and server are - // willing to negotiate the delegated credential extension. - // - // Check to see if a DelegatedCredential is available and should be used. - // If one is available, the session is using TLS >= 1.2, and the client - // accepts the delegated credential extension, then set the handshake - // private key to the DC private key. - if c.config.GetDelegatedCredential != nil && hs.clientHello.delegatedCredential && c.vers >= VersionTLS12 { - dc, sk, err := c.config.GetDelegatedCredential(hs.clientHelloInfo(), c.vers) - if err != nil { - c.sendAlert(alertInternalError) - return false, err - } - - // Set the handshake private key. - if dc != nil { - hs.privateKey = sk - hs.delegatedCredential = dc - } - } - - if priv, ok := hs.privateKey.(crypto.Signer); ok { - switch priv.Public().(type) { - case *ecdsa.PublicKey: - hs.ecdsaOk = true - case *rsa.PublicKey: - hs.rsaSignOk = true - default: - c.sendAlert(alertInternalError) - return false, fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public()) - } - } - if priv, ok := hs.privateKey.(crypto.Decrypter); ok { - switch priv.Public().(type) { - case *rsa.PublicKey: - hs.rsaDecryptOk = true - default: - c.sendAlert(alertInternalError) - return false, fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public()) - } - } - - if c.vers != VersionTLS13 && hs.checkForResumption() { - return true, nil - } - - var preferenceList, supportedList []uint16 - if c.config.PreferServerCipherSuites { - preferenceList = c.config.cipherSuites() - supportedList = hs.clientHello.cipherSuites - } else { - preferenceList = hs.clientHello.cipherSuites - supportedList = c.config.cipherSuites() - } - - for _, id := range preferenceList { - if hs.setCipherSuite(id, supportedList, c.vers) { - break - } - } - - if hs.suite == nil { - c.sendAlert(alertHandshakeFailure) - return false, errors.New("tls: no cipher suite supported by both client and server") - } - - // See https://tools.ietf.org/html/rfc7507. - for _, id := range hs.clientHello.cipherSuites { - if id == TLS_FALLBACK_SCSV { - // The client is doing a fallback connection. - if c.vers < c.config.maxVersion() { - c.sendAlert(alertInappropriateFallback) - return false, errors.New("tls: client using inappropriate protocol fallback") - } - break - } - } - - return false, nil -} - -// checkForResumption reports whether we should perform resumption on this connection. -func (hs *serverHandshakeState) checkForResumption() bool { - c := hs.c - - if c.config.SessionTicketsDisabled { - return false - } - - sessionTicket := append([]uint8{}, hs.clientHello.sessionTicket...) - serializedState, usedOldKey := c.decryptTicket(sessionTicket) - hs.sessionState = &sessionState{usedOldKey: usedOldKey} - if hs.sessionState.unmarshal(serializedState) != alertSuccess { - return false - } - - // Never resume a session for a different TLS version. - if c.vers != hs.sessionState.vers { - return false - } - - // Do not resume connections where client support for EMS has changed - if (hs.clientHello.extendedMSSupported && c.config.UseExtendedMasterSecret) != hs.sessionState.usedEMS { - return false - } - - cipherSuiteOk := false - // Check that the client is still offering the ciphersuite in the session. - for _, id := range hs.clientHello.cipherSuites { - if id == hs.sessionState.cipherSuite { - cipherSuiteOk = true - break - } - } - if !cipherSuiteOk { - return false - } - - // Check that we also support the ciphersuite from the session. - if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) { - return false - } - - sessionHasClientCerts := len(hs.sessionState.certificates) != 0 - needClientCerts := c.config.ClientAuth == RequireAnyClientCert || c.config.ClientAuth == RequireAndVerifyClientCert - if needClientCerts && !sessionHasClientCerts { - return false - } - if sessionHasClientCerts && c.config.ClientAuth == NoClientCert { - return false - } - - return true -} - -func (hs *serverHandshakeState) doResumeHandshake() error { - c := hs.c - - hs.hello.cipherSuite = hs.suite.id - // We echo the client's session ID in the ServerHello to let it know - // that we're doing a resumption. - hs.hello.sessionId = hs.clientHello.sessionId - hs.hello.ticketSupported = hs.sessionState.usedOldKey - hs.hello.extendedMSSupported = hs.clientHello.extendedMSSupported && c.config.UseExtendedMasterSecret - hs.finishedHash = newFinishedHash(c.vers, hs.suite) - hs.finishedHash.discardHandshakeBuffer() - hs.finishedHash.Write(hs.clientHello.marshal()) - hs.finishedHash.Write(hs.hello.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { - return err - } - - if len(hs.sessionState.certificates) > 0 { - if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil { - return err - } - } - - hs.masterSecret = hs.sessionState.masterSecret - c.useEMS = hs.sessionState.usedEMS - - return nil -} - -func (hs *serverHandshakeState) doFullHandshake() error { - c := hs.c - - if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 { - hs.hello.ocspStapling = true - } - - hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled - hs.hello.cipherSuite = hs.suite.id - hs.hello.extendedMSSupported = hs.clientHello.extendedMSSupported && c.config.UseExtendedMasterSecret - - hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite) - if c.config.ClientAuth == NoClientCert { - // No need to keep a full record of the handshake if client - // certificates won't be used. - hs.finishedHash.discardHandshakeBuffer() - } - hs.finishedHash.Write(hs.clientHello.marshal()) - hs.finishedHash.Write(hs.hello.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { - return err - } - - certMsg := new(certificateMsg) - certMsg.certificates = hs.cert.Certificate - hs.finishedHash.Write(certMsg.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { - return err - } - - if hs.hello.ocspStapling { - certStatus := new(certificateStatusMsg) - certStatus.statusType = statusTypeOCSP - certStatus.response = hs.cert.OCSPStaple - hs.finishedHash.Write(certStatus.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil { - return err - } - } - - keyAgreement := hs.suite.ka(c.vers) - skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.privateKey, hs.clientHello, hs.hello) - if err != nil { - c.sendAlert(alertHandshakeFailure) - return err - } - if skx != nil { - hs.finishedHash.Write(skx.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil { - return err - } - } - - if c.config.ClientAuth >= RequestClientCert { - // Request a client certificate - certReq := new(certificateRequestMsg) - certReq.certificateTypes = []byte{ - byte(certTypeRSASign), - byte(certTypeECDSASign), - } - if c.vers >= VersionTLS12 { - certReq.hasSignatureAndHash = true - certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms - } - - // An empty list of certificateAuthorities signals to - // the client that it may send any certificate in response - // to our request. When we know the CAs we trust, then - // we can send them down, so that the client can choose - // an appropriate certificate to give to us. - if c.config.ClientCAs != nil { - certReq.certificateAuthorities = c.config.ClientCAs.Subjects() - } - hs.finishedHash.Write(certReq.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil { - return err - } - } - - helloDone := new(serverHelloDoneMsg) - hs.finishedHash.Write(helloDone.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil { - return err - } - - if _, err := c.flush(); err != nil { - return err - } - - var pub crypto.PublicKey // public key for client auth, if any - - msg, err := c.readHandshake() - if err != nil { - return err - } - - var ok bool - // If we requested a client certificate, then the client must send a - // certificate message, even if it's empty. - if c.config.ClientAuth >= RequestClientCert { - if certMsg, ok = msg.(*certificateMsg); !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } - hs.finishedHash.Write(certMsg.marshal()) - - pub, err = hs.processCertsFromClient(certMsg.certificates) - if err != nil { - return err - } - - msg, err = c.readHandshake() - if err != nil { - return err - } - } - - // Get client key exchange - ckx, ok := msg.(*clientKeyExchangeMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(ckx, msg) - } - hs.finishedHash.Write(ckx.marshal()) - - preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.privateKey, ckx, c.vers) - if err != nil { - if err == errClientKeyExchange { - c.sendAlert(alertDecodeError) - } else { - c.sendAlert(alertInternalError) - } - return err - } - c.useEMS = hs.hello.extendedMSSupported - hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random, hs.finishedHash, c.useEMS) - if err := c.config.writeKeyLog("CLIENT_RANDOM", hs.clientHello.random, hs.masterSecret); err != nil { - c.sendAlert(alertInternalError) - return err - } - - // If we received a client cert in response to our certificate request message, - // the client will send us a certificateVerifyMsg immediately after the - // clientKeyExchangeMsg. This message is a digest of all preceding - // handshake-layer messages that is signed using the private key corresponding - // to the client's certificate. This allows us to verify that the client is in - // possession of the private key of the certificate. - if len(c.peerCertificates) > 0 { - msg, err = c.readHandshake() - if err != nil { - return err - } - certVerify, ok := msg.(*certificateVerifyMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certVerify, msg) - } - - // Determine the signature type. - _, sigType, hashFunc, err := pickSignatureAlgorithm(pub, []SignatureScheme{certVerify.signatureAlgorithm}, supportedSignatureAlgorithms, c.vers) - if err != nil { - c.sendAlert(alertIllegalParameter) - return err - } - - var digest []byte - if digest, err = hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret); err == nil { - err = verifyHandshakeSignature(sigType, pub, hashFunc, digest, certVerify.signature) - } - if err != nil { - c.sendAlert(alertBadCertificate) - return errors.New("tls: could not validate signature of connection nonces: " + err.Error()) - } - - hs.finishedHash.Write(certVerify.marshal()) - } - - hs.finishedHash.discardHandshakeBuffer() - - return nil -} - -func (hs *serverHandshakeState) establishKeys() error { - c := hs.c - - clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := - keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) - - var clientCipher, serverCipher interface{} - var clientHash, serverHash macFunction - - if hs.suite.aead == nil { - clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */) - clientHash = hs.suite.mac(c.vers, clientMAC) - serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */) - serverHash = hs.suite.mac(c.vers, serverMAC) - } else { - clientCipher = hs.suite.aead(clientKey, clientIV) - serverCipher = hs.suite.aead(serverKey, serverIV) - } - - c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) - c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) - - return nil -} - -func (hs *serverHandshakeState) readFinished(out []byte) error { - c := hs.c - - c.readRecord(recordTypeChangeCipherSpec) - if c.in.err != nil { - return c.in.err - } - - if hs.hello.nextProtoNeg { - msg, err := c.readHandshake() - if err != nil { - return err - } - nextProto, ok := msg.(*nextProtoMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(nextProto, msg) - } - hs.finishedHash.Write(nextProto.marshal()) - c.clientProtocol = nextProto.proto - } - - msg, err := c.readHandshake() - if err != nil { - return err - } - clientFinished, ok := msg.(*finishedMsg) - if !ok { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(clientFinished, msg) - } - - verify := hs.finishedHash.clientSum(hs.masterSecret) - if len(verify) != len(clientFinished.verifyData) || - subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 { - c.sendAlert(alertDecryptError) - return errors.New("tls: client's Finished message is incorrect") - } - - hs.finishedHash.Write(clientFinished.marshal()) - copy(out, verify) - return nil -} - -func (hs *serverHandshakeState) sendSessionTicket() error { - if !hs.hello.ticketSupported { - return nil - } - - c := hs.c - m := new(newSessionTicketMsg) - - var err error - state := sessionState{ - vers: c.vers, - cipherSuite: hs.suite.id, - masterSecret: hs.masterSecret, - certificates: hs.certsFromClient, - usedEMS: c.useEMS, - } - m.ticket, err = c.encryptTicket(state.marshal()) - if err != nil { - return err - } - - hs.finishedHash.Write(m.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil { - return err - } - - return nil -} - -func (hs *serverHandshakeState) sendFinished(out []byte) error { - c := hs.c - - if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { - return err - } - - finished := new(finishedMsg) - finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) - hs.finishedHash.Write(finished.marshal()) - if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { - return err - } - - c.cipherSuite = hs.suite.id - copy(out, finished.verifyData) - - return nil -} - -// processCertsFromClient takes a chain of client certificates either from a -// Certificates message or from a sessionState and verifies them. It returns -// the public key of the leaf certificate. -func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (crypto.PublicKey, error) { - c := hs.c - - if len(certificates) == 0 { - // The client didn't actually send a certificate - switch c.config.ClientAuth { - case RequireAnyClientCert, RequireAndVerifyClientCert: - c.sendAlert(alertBadCertificate) - return nil, errors.New("tls: client didn't provide a certificate") - } - } - - hs.certsFromClient = certificates - certs := make([]*x509.Certificate, len(certificates)) - var err error - for i, asn1Data := range certificates { - if certs[i], err = x509.ParseCertificate(asn1Data); err != nil { - c.sendAlert(alertBadCertificate) - return nil, errors.New("tls: failed to parse client certificate: " + err.Error()) - } - } - - if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 { - opts := x509.VerifyOptions{ - Roots: c.config.ClientCAs, - CurrentTime: c.config.time(), - Intermediates: x509.NewCertPool(), - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, - } - - for _, cert := range certs[1:] { - opts.Intermediates.AddCert(cert) - } - - chains, err := certs[0].Verify(opts) - if err != nil { - c.sendAlert(alertBadCertificate) - return nil, errors.New("tls: failed to verify client's certificate: " + err.Error()) - } - - c.verifiedChains = chains - } - - if c.config.VerifyPeerCertificate != nil { - if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil { - c.sendAlert(alertBadCertificate) - return nil, err - } - } - - if len(certs) == 0 { - return nil, nil - } - - var pub crypto.PublicKey - switch key := certs[0].PublicKey.(type) { - case *ecdsa.PublicKey, *rsa.PublicKey: - pub = key - default: - c.sendAlert(alertUnsupportedCertificate) - return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey) - } - c.peerCertificates = certs - return pub, nil -} - -// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState -// suite if that cipher suite is acceptable to use. -// It returns a bool indicating if the suite was set. -func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool { - for _, supported := range supportedCipherSuites { - if id == supported { - var candidate *cipherSuite - - for _, s := range cipherSuites { - if s.id == id { - candidate = s - break - } - } - if candidate == nil { - continue - } - - if version >= VersionTLS13 && candidate.flags&suiteTLS13 != 0 { - hs.suite = candidate - return true - } - if version < VersionTLS13 && candidate.flags&suiteTLS13 != 0 { - continue - } - - // Don't select a ciphersuite which we can't - // support for this client. - if candidate.flags&suiteECDHE != 0 { - if !hs.ellipticOk { - continue - } - if candidate.flags&suiteECDSA != 0 { - if !hs.ecdsaOk { - continue - } - } else if !hs.rsaSignOk { - continue - } - } else if !hs.rsaDecryptOk { - continue - } - if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 { - continue - } - hs.suite = candidate - return true - } - } - return false -} - -// suppVersArray is the backing array of ClientHelloInfo.SupportedVersions -var suppVersArray = [...]uint16{VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30} - -func (hs *serverHandshakeState) clientHelloInfo() *ClientHelloInfo { - if hs.cachedClientHelloInfo != nil { - return hs.cachedClientHelloInfo - } - - var supportedVersions []uint16 - if hs.clientHello.supportedVersions != nil { - supportedVersions = hs.clientHello.supportedVersions - } else if hs.clientHello.vers > VersionTLS12 { - supportedVersions = suppVersArray[:] - } else if hs.clientHello.vers >= VersionSSL30 { - supportedVersions = suppVersArray[VersionTLS12-hs.clientHello.vers:] - } - - var pskBinder []byte - if len(hs.clientHello.psks) > 0 { - pskBinder = hs.clientHello.psks[0].binder - } - - hs.cachedClientHelloInfo = &ClientHelloInfo{ - CipherSuites: hs.clientHello.cipherSuites, - ServerName: hs.clientHello.serverName, - SupportedCurves: hs.clientHello.supportedCurves, - SupportedPoints: hs.clientHello.supportedPoints, - SignatureSchemes: hs.clientHello.supportedSignatureAlgorithms, - SupportedProtos: hs.clientHello.alpnProtocols, - SupportedVersions: supportedVersions, - Conn: hs.c.conn, - Offered0RTTData: hs.clientHello.earlyData, - AcceptsDelegatedCredential: hs.clientHello.delegatedCredential, - Fingerprint: pskBinder, - } - - return hs.cachedClientHelloInfo -} diff --git a/external/github.com/marten-seemann/qtls/hkdf.go b/external/github.com/marten-seemann/qtls/hkdf.go deleted file mode 100644 index 456de3f7b..000000000 --- a/external/github.com/marten-seemann/qtls/hkdf.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2014 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 qtls - -// Mostly derived from golang.org/x/crypto/hkdf, but with an exposed -// Extract API. -// -// HKDF is a cryptographic key derivation function (KDF) with the goal of -// expanding limited input keying material into one or more cryptographically -// strong secret keys. -// -// RFC 5869: https://tools.ietf.org/html/rfc5869 - -import ( - "crypto" - "crypto/hmac" -) - -func hkdfExpand(hash crypto.Hash, prk, info []byte, l int) []byte { - var ( - expander = hmac.New(hash.New, prk) - res = make([]byte, l) - counter = byte(1) - prev []byte - ) - - if l > 255*expander.Size() { - panic("hkdf: requested too much output") - } - - p := res - for len(p) > 0 { - expander.Reset() - expander.Write(prev) - expander.Write(info) - expander.Write([]byte{counter}) - prev = expander.Sum(prev[:0]) - counter++ - n := copy(p, prev) - p = p[n:] - } - - return res -} - -// HkdfExtract generates a pseudorandom key for use with Expand from an input secret and an optional independent salt. -func HkdfExtract(hash crypto.Hash, secret, salt []byte) []byte { - return hkdfExtract(hash, secret, salt) -} - -func hkdfExtract(hash crypto.Hash, secret, salt []byte) []byte { - if salt == nil { - salt = make([]byte, hash.Size()) - } - if secret == nil { - secret = make([]byte, hash.Size()) - } - extractor := hmac.New(hash.New, salt) - extractor.Write(secret) - return extractor.Sum(nil) -} diff --git a/external/github.com/marten-seemann/qtls/key_agreement.go b/external/github.com/marten-seemann/qtls/key_agreement.go deleted file mode 100644 index 6bdbbd949..000000000 --- a/external/github.com/marten-seemann/qtls/key_agreement.go +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright 2010 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 qtls - -import ( - "crypto" - "crypto/elliptic" - "crypto/md5" - "crypto/rsa" - "crypto/sha1" - "errors" - "io" - "math/big" - - "golang.org/x/crypto/curve25519" -) - -var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message") -var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message") - -// rsaKeyAgreement implements the standard TLS key agreement where the client -// encrypts the pre-master secret to the server's public key. -type rsaKeyAgreement struct{} - -func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, sk crypto.PrivateKey, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { - return nil, nil -} - -func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, sk crypto.PrivateKey, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { - if len(ckx.ciphertext) < 2 { - return nil, errClientKeyExchange - } - - ciphertext := ckx.ciphertext - if version != VersionSSL30 { - ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1]) - if ciphertextLen != len(ckx.ciphertext)-2 { - return nil, errClientKeyExchange - } - ciphertext = ckx.ciphertext[2:] - } - priv, ok := sk.(crypto.Decrypter) - if !ok { - return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter") - } - // Perform constant time RSA PKCS#1 v1.5 decryption - preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48}) - if err != nil { - return nil, err - } - // We don't check the version number in the premaster secret. For one, - // by checking it, we would leak information about the validity of the - // encrypted pre-master secret. Secondly, it provides only a small - // benefit against a downgrade attack and some implementations send the - // wrong version anyway. See the discussion at the end of section - // 7.4.7.1 of RFC 4346. - return preMasterSecret, nil -} - -func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, pk crypto.PublicKey, skx *serverKeyExchangeMsg) error { - return errors.New("tls: unexpected ServerKeyExchange") -} - -func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, pk crypto.PublicKey) ([]byte, *clientKeyExchangeMsg, error) { - preMasterSecret := make([]byte, 48) - preMasterSecret[0] = byte(clientHello.vers >> 8) - preMasterSecret[1] = byte(clientHello.vers) - _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) - if err != nil { - return nil, nil, err - } - - encrypted, err := rsa.EncryptPKCS1v15(config.rand(), pk.(*rsa.PublicKey), preMasterSecret) - if err != nil { - return nil, nil, err - } - ckx := new(clientKeyExchangeMsg) - ckx.ciphertext = make([]byte, len(encrypted)+2) - ckx.ciphertext[0] = byte(len(encrypted) >> 8) - ckx.ciphertext[1] = byte(len(encrypted)) - copy(ckx.ciphertext[2:], encrypted) - return preMasterSecret, ckx, nil -} - -// sha1Hash calculates a SHA1 hash over the given byte slices. -func sha1Hash(slices [][]byte) []byte { - hsha1 := sha1.New() - for _, slice := range slices { - hsha1.Write(slice) - } - return hsha1.Sum(nil) -} - -// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the -// concatenation of an MD5 and SHA1 hash. -func md5SHA1Hash(slices [][]byte) []byte { - md5sha1 := make([]byte, md5.Size+sha1.Size) - hmd5 := md5.New() - for _, slice := range slices { - hmd5.Write(slice) - } - copy(md5sha1, hmd5.Sum(nil)) - copy(md5sha1[md5.Size:], sha1Hash(slices)) - return md5sha1 -} - -// hashForServerKeyExchange hashes the given slices and returns their digest -// using the given hash function. -func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) ([]byte, error) { - if version >= VersionTLS12 { - h := hashFunc.New() - for _, slice := range slices { - h.Write(slice) - } - digest := h.Sum(nil) - return digest, nil - } - if sigType == signatureECDSA { - return sha1Hash(slices), nil - } - return md5SHA1Hash(slices), nil -} - -func curveForCurveID(id CurveID) (elliptic.Curve, bool) { - switch id { - case CurveP256: - return elliptic.P256(), true - case CurveP384: - return elliptic.P384(), true - case CurveP521: - return elliptic.P521(), true - default: - return nil, false - } - -} - -// ecdheKeyAgreement implements a TLS key agreement where the server -// generates an ephemeral EC public/private key pair and signs it. The -// pre-master secret is then calculated using ECDH. The signature may -// either be ECDSA or RSA. -type ecdheKeyAgreement struct { - version uint16 - isRSA bool - privateKey []byte - curveid CurveID - - // publicKey is used to store the peer's public value when X25519 is - // being used. - publicKey []byte - // x and y are used to store the peer's public value when one of the - // NIST curves is being used. - x, y *big.Int -} - -func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, sk crypto.PrivateKey, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { - preferredCurves := config.curvePreferences() - -NextCandidate: - for _, candidate := range preferredCurves { - for _, c := range clientHello.supportedCurves { - if candidate == c { - ka.curveid = c - break NextCandidate - } - } - } - - if ka.curveid == 0 { - return nil, errors.New("tls: no supported elliptic curves offered") - } - - var ecdhePublic []byte - - if ka.curveid == X25519 { - var scalar, public [32]byte - if _, err := io.ReadFull(config.rand(), scalar[:]); err != nil { - return nil, err - } - - curve25519.ScalarBaseMult(&public, &scalar) - ka.privateKey = scalar[:] - ecdhePublic = public[:] - } else { - curve, ok := curveForCurveID(ka.curveid) - if !ok { - return nil, errors.New("tls: preferredCurves includes unsupported curve") - } - - var x, y *big.Int - var err error - ka.privateKey, x, y, err = elliptic.GenerateKey(curve, config.rand()) - if err != nil { - return nil, err - } - ecdhePublic = elliptic.Marshal(curve, x, y) - } - - // http://tools.ietf.org/html/rfc4492#section-5.4 - serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic)) - serverECDHParams[0] = 3 // named curve - serverECDHParams[1] = byte(ka.curveid >> 8) - serverECDHParams[2] = byte(ka.curveid) - serverECDHParams[3] = byte(len(ecdhePublic)) - copy(serverECDHParams[4:], ecdhePublic) - - priv, ok := sk.(crypto.Signer) - if !ok { - return nil, errors.New("tls: certificate private key does not implement crypto.Signer") - } - - signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(priv.Public(), clientHello.supportedSignatureAlgorithms, supportedSignatureAlgorithms, ka.version) - if err != nil { - return nil, err - } - if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { - return nil, errors.New("tls: certificate cannot be used with the selected cipher suite") - } - - digest, err := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, hello.random, serverECDHParams) - if err != nil { - return nil, err - } - - var sig []byte - signOpts := crypto.SignerOpts(hashFunc) - if sigType == signatureRSAPSS { - signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc} - } - sig, err = priv.Sign(config.rand(), digest, signOpts) - if err != nil { - return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error()) - } - - skx := new(serverKeyExchangeMsg) - sigAndHashLen := 0 - if ka.version >= VersionTLS12 { - sigAndHashLen = 2 - } - skx.key = make([]byte, len(serverECDHParams)+sigAndHashLen+2+len(sig)) - copy(skx.key, serverECDHParams) - k := skx.key[len(serverECDHParams):] - if ka.version >= VersionTLS12 { - k[0] = byte(signatureAlgorithm >> 8) - k[1] = byte(signatureAlgorithm) - k = k[2:] - } - k[0] = byte(len(sig) >> 8) - k[1] = byte(len(sig)) - copy(k[2:], sig) - - return skx, nil -} - -func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, sk crypto.PrivateKey, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { - if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { - return nil, errClientKeyExchange - } - - if ka.curveid == X25519 { - if len(ckx.ciphertext) != 1+32 { - return nil, errClientKeyExchange - } - - var theirPublic, sharedKey, scalar [32]byte - copy(theirPublic[:], ckx.ciphertext[1:]) - copy(scalar[:], ka.privateKey) - curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic) - return sharedKey[:], nil - } - - curve, ok := curveForCurveID(ka.curveid) - if !ok { - panic("internal error") - } - x, y := elliptic.Unmarshal(curve, ckx.ciphertext[1:]) // Unmarshal also checks whether the given point is on the curve - if x == nil { - return nil, errClientKeyExchange - } - x, _ = curve.ScalarMult(x, y, ka.privateKey) - curveSize := (curve.Params().BitSize + 7) >> 3 - xBytes := x.Bytes() - if len(xBytes) == curveSize { - return xBytes, nil - } - preMasterSecret := make([]byte, curveSize) - copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) - return preMasterSecret, nil -} - -func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, pk crypto.PublicKey, skx *serverKeyExchangeMsg) error { - if len(skx.key) < 4 { - return errServerKeyExchange - } - if skx.key[0] != 3 { // named curve - return errors.New("tls: server selected unsupported curve") - } - ka.curveid = CurveID(skx.key[1])<<8 | CurveID(skx.key[2]) - - publicLen := int(skx.key[3]) - if publicLen+4 > len(skx.key) { - return errServerKeyExchange - } - serverECDHParams := skx.key[:4+publicLen] - publicKey := serverECDHParams[4:] - - sig := skx.key[4+publicLen:] - if len(sig) < 2 { - return errServerKeyExchange - } - - if ka.curveid == X25519 { - if len(publicKey) != 32 { - return errors.New("tls: bad X25519 public value") - } - ka.publicKey = publicKey - } else { - curve, ok := curveForCurveID(ka.curveid) - if !ok { - return errors.New("tls: server selected unsupported curve") - } - ka.x, ka.y = elliptic.Unmarshal(curve, publicKey) // Unmarshal also checks whether the given point is on the curve - if ka.x == nil { - return errServerKeyExchange - } - } - - var signatureAlgorithm SignatureScheme - if ka.version >= VersionTLS12 { - // handle SignatureAndHashAlgorithm - signatureAlgorithm = SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1]) - sig = sig[2:] - if len(sig) < 2 { - return errServerKeyExchange - } - } - _, sigType, hashFunc, err := pickSignatureAlgorithm(pk, []SignatureScheme{signatureAlgorithm}, clientHello.supportedSignatureAlgorithms, ka.version) - if err != nil { - return err - } - if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { - return errServerKeyExchange - } - - sigLen := int(sig[0])<<8 | int(sig[1]) - if sigLen+2 != len(sig) { - return errServerKeyExchange - } - sig = sig[2:] - - digest, err := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, serverHello.random, serverECDHParams) - if err != nil { - return err - } - return verifyHandshakeSignature(sigType, pk, hashFunc, digest, sig) -} - -func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, pk crypto.PublicKey) ([]byte, *clientKeyExchangeMsg, error) { - if ka.curveid == 0 { - return nil, nil, errors.New("tls: missing ServerKeyExchange message") - } - - var serialized, preMasterSecret []byte - - if ka.curveid == X25519 { - var ourPublic, theirPublic, sharedKey, scalar [32]byte - - if _, err := io.ReadFull(config.rand(), scalar[:]); err != nil { - return nil, nil, err - } - - copy(theirPublic[:], ka.publicKey) - curve25519.ScalarBaseMult(&ourPublic, &scalar) - curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic) - serialized = ourPublic[:] - preMasterSecret = sharedKey[:] - } else { - curve, ok := curveForCurveID(ka.curveid) - if !ok { - panic("internal error") - } - priv, mx, my, err := elliptic.GenerateKey(curve, config.rand()) - if err != nil { - return nil, nil, err - } - x, _ := curve.ScalarMult(ka.x, ka.y, priv) - preMasterSecret = make([]byte, (curve.Params().BitSize+7)>>3) - xBytes := x.Bytes() - copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) - - serialized = elliptic.Marshal(curve, mx, my) - } - - ckx := new(clientKeyExchangeMsg) - ckx.ciphertext = make([]byte, 1+len(serialized)) - ckx.ciphertext[0] = byte(len(serialized)) - copy(ckx.ciphertext[1:], serialized) - - return preMasterSecret, ckx, nil -} diff --git a/external/github.com/marten-seemann/qtls/prf.go b/external/github.com/marten-seemann/qtls/prf.go deleted file mode 100644 index 1a6d3156d..000000000 --- a/external/github.com/marten-seemann/qtls/prf.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2009 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 qtls - -import ( - "crypto" - "crypto/hmac" - "crypto/md5" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "errors" - "fmt" - "hash" -) - -// Split a premaster secret in two as specified in RFC 4346, section 5. -func splitPreMasterSecret(secret []byte) (s1, s2 []byte) { - s1 = secret[0 : (len(secret)+1)/2] - s2 = secret[len(secret)/2:] - return -} - -// pHash implements the P_hash function, as defined in RFC 4346, section 5. -func pHash(result, secret, seed []byte, hash func() hash.Hash) { - h := hmac.New(hash, secret) - h.Write(seed) - a := h.Sum(nil) - - j := 0 - for j < len(result) { - h.Reset() - h.Write(a) - h.Write(seed) - b := h.Sum(nil) - copy(result[j:], b) - j += len(b) - - h.Reset() - h.Write(a) - a = h.Sum(nil) - } -} - -// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5. -func prf10(result, secret, label, seed []byte) { - hashSHA1 := sha1.New - hashMD5 := md5.New - - labelAndSeed := make([]byte, len(label)+len(seed)) - copy(labelAndSeed, label) - copy(labelAndSeed[len(label):], seed) - - s1, s2 := splitPreMasterSecret(secret) - pHash(result, s1, labelAndSeed, hashMD5) - result2 := make([]byte, len(result)) - pHash(result2, s2, labelAndSeed, hashSHA1) - - for i, b := range result2 { - result[i] ^= b - } -} - -// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5. -func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) { - return func(result, secret, label, seed []byte) { - labelAndSeed := make([]byte, len(label)+len(seed)) - copy(labelAndSeed, label) - copy(labelAndSeed[len(label):], seed) - - pHash(result, secret, labelAndSeed, hashFunc) - } -} - -// prf30 implements the SSL 3.0 pseudo-random function, as defined in -// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6. -func prf30(result, secret, label, seed []byte) { - hashSHA1 := sha1.New() - hashMD5 := md5.New() - - done := 0 - i := 0 - // RFC 5246 section 6.3 says that the largest PRF output needed is 128 - // bytes. Since no more ciphersuites will be added to SSLv3, this will - // remain true. Each iteration gives us 16 bytes so 10 iterations will - // be sufficient. - var b [11]byte - for done < len(result) { - for j := 0; j <= i; j++ { - b[j] = 'A' + byte(i) - } - - hashSHA1.Reset() - hashSHA1.Write(b[:i+1]) - hashSHA1.Write(secret) - hashSHA1.Write(seed) - digest := hashSHA1.Sum(nil) - - hashMD5.Reset() - hashMD5.Write(secret) - hashMD5.Write(digest) - - done += copy(result[done:], hashMD5.Sum(nil)) - i++ - } -} - -const ( - tlsRandomLength = 32 // Length of a random nonce in TLS 1.1. - masterSecretLength = 48 // Length of a master secret in TLS 1.1. - finishedVerifyLength = 12 // Length of verify_data in a Finished message. -) - -var masterSecretLabel = []byte("master secret") -var keyExpansionLabel = []byte("key expansion") -var clientFinishedLabel = []byte("client finished") -var serverFinishedLabel = []byte("server finished") -var extendedMasterSecretLabel = []byte("extended master secret") - -func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) { - switch version { - case VersionSSL30: - return prf30, crypto.Hash(0) - case VersionTLS10, VersionTLS11: - return prf10, crypto.Hash(0) - case VersionTLS12: - if suite.flags&suiteSHA384 != 0 { - return prf12(sha512.New384), crypto.SHA384 - } - return prf12(sha256.New), crypto.SHA256 - default: - panic("unknown version") - } -} - -func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) { - prf, _ := prfAndHashForVersion(version, suite) - return prf -} - -// masterFromPreMasterSecret generates the master secret from the pre-master -// secret. See http://tools.ietf.org/html/rfc5246#section-8.1 -func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte, fin finishedHash, ems bool) []byte { - if ems { - session_hash := fin.Sum() - masterSecret := make([]byte, masterSecretLength) - prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, session_hash) - return masterSecret - } else { - seed := make([]byte, 0, len(clientRandom)+len(serverRandom)) - seed = append(seed, clientRandom...) - seed = append(seed, serverRandom...) - - masterSecret := make([]byte, masterSecretLength) - prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed) - return masterSecret - } -} - -// keysFromMasterSecret generates the connection keys from the master -// secret, given the lengths of the MAC key, cipher key and IV, as defined in -// RFC 2246, section 6.3. -func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { - seed := make([]byte, 0, len(serverRandom)+len(clientRandom)) - seed = append(seed, serverRandom...) - seed = append(seed, clientRandom...) - - n := 2*macLen + 2*keyLen + 2*ivLen - keyMaterial := make([]byte, n) - prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed) - clientMAC = keyMaterial[:macLen] - keyMaterial = keyMaterial[macLen:] - serverMAC = keyMaterial[:macLen] - keyMaterial = keyMaterial[macLen:] - clientKey = keyMaterial[:keyLen] - keyMaterial = keyMaterial[keyLen:] - serverKey = keyMaterial[:keyLen] - keyMaterial = keyMaterial[keyLen:] - clientIV = keyMaterial[:ivLen] - keyMaterial = keyMaterial[ivLen:] - serverIV = keyMaterial[:ivLen] - return -} - -// lookupTLSHash looks up the corresponding crypto.Hash for a given -// hash from a TLS SignatureScheme. -func lookupTLSHash(signatureAlgorithm SignatureScheme) (crypto.Hash, error) { - switch signatureAlgorithm { - case PKCS1WithSHA1, ECDSAWithSHA1: - return crypto.SHA1, nil - case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256: - return crypto.SHA256, nil - case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384: - return crypto.SHA384, nil - case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512: - return crypto.SHA512, nil - default: - return 0, fmt.Errorf("tls: unsupported signature algorithm: %#04x", signatureAlgorithm) - } -} - -func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash { - var buffer []byte - if version == VersionSSL30 || version >= VersionTLS12 { - buffer = []byte{} - } - - prf, hash := prfAndHashForVersion(version, cipherSuite) - if hash != 0 { - return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf} - } - - return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf} -} - -// A finishedHash calculates the hash of a set of handshake messages suitable -// for including in a Finished message. -type finishedHash struct { - client hash.Hash - server hash.Hash - - // Prior to TLS 1.2, an additional MD5 hash is required. - clientMD5 hash.Hash - serverMD5 hash.Hash - - // In TLS 1.2, a full buffer is sadly required. - buffer []byte - - version uint16 - prf func(result, secret, label, seed []byte) -} - -func (h *finishedHash) Write(msg []byte) (n int, err error) { - h.client.Write(msg) - h.server.Write(msg) - - if h.version < VersionTLS12 { - h.clientMD5.Write(msg) - h.serverMD5.Write(msg) - } - - if h.buffer != nil { - h.buffer = append(h.buffer, msg...) - } - - return len(msg), nil -} - -func (h finishedHash) Sum() []byte { - if h.version >= VersionTLS12 { - return h.client.Sum(nil) - } - - out := make([]byte, 0, md5.Size+sha1.Size) - out = h.clientMD5.Sum(out) - return h.client.Sum(out) -} - -// finishedSum30 calculates the contents of the verify_data member of a SSLv3 -// Finished message given the MD5 and SHA1 hashes of a set of handshake -// messages. -func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte { - md5.Write(magic) - md5.Write(masterSecret) - md5.Write(ssl30Pad1[:]) - md5Digest := md5.Sum(nil) - - md5.Reset() - md5.Write(masterSecret) - md5.Write(ssl30Pad2[:]) - md5.Write(md5Digest) - md5Digest = md5.Sum(nil) - - sha1.Write(magic) - sha1.Write(masterSecret) - sha1.Write(ssl30Pad1[:40]) - sha1Digest := sha1.Sum(nil) - - sha1.Reset() - sha1.Write(masterSecret) - sha1.Write(ssl30Pad2[:40]) - sha1.Write(sha1Digest) - sha1Digest = sha1.Sum(nil) - - ret := make([]byte, len(md5Digest)+len(sha1Digest)) - copy(ret, md5Digest) - copy(ret[len(md5Digest):], sha1Digest) - return ret -} - -var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54} -var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52} - -// clientSum returns the contents of the verify_data member of a client's -// Finished message. -func (h finishedHash) clientSum(masterSecret []byte) []byte { - if h.version == VersionSSL30 { - return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:]) - } - - out := make([]byte, finishedVerifyLength) - h.prf(out, masterSecret, clientFinishedLabel, h.Sum()) - return out -} - -// serverSum returns the contents of the verify_data member of a server's -// Finished message. -func (h finishedHash) serverSum(masterSecret []byte) []byte { - if h.version == VersionSSL30 { - return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:]) - } - - out := make([]byte, finishedVerifyLength) - h.prf(out, masterSecret, serverFinishedLabel, h.Sum()) - return out -} - -// hashForClientCertificate returns a digest over the handshake messages so far, -// suitable for signing by a TLS client certificate. -func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) ([]byte, error) { - if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil { - panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer") - } - - if h.version == VersionSSL30 { - if sigType != signaturePKCS1v15 { - return nil, errors.New("tls: unsupported signature type for client certificate") - } - - md5Hash := md5.New() - md5Hash.Write(h.buffer) - sha1Hash := sha1.New() - sha1Hash.Write(h.buffer) - return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), nil - } - if h.version >= VersionTLS12 { - hash := hashAlg.New() - hash.Write(h.buffer) - return hash.Sum(nil), nil - } - - if sigType == signatureECDSA { - return h.server.Sum(nil), nil - } - - return h.Sum(), nil -} - -// discardHandshakeBuffer is called when there is no more need to -// buffer the entirety of the handshake messages. -func (h *finishedHash) discardHandshakeBuffer() { - h.buffer = nil -} diff --git a/external/github.com/marten-seemann/qtls/subcerts.go b/external/github.com/marten-seemann/qtls/subcerts.go deleted file mode 100644 index e1cfaf430..000000000 --- a/external/github.com/marten-seemann/qtls/subcerts.go +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright 2018 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 qtls - -// Delegated credentials for TLS -// (https://tools.ietf.org/html/draft-ietf-tls-subcerts-02) is an IETF Internet -// draft and proposed TLS extension. This allows a backend server to delegate -// TLS termination to a trusted frontend. If the client supports this extension, -// then the frontend may use a "delegated credential" as the signing key in the -// handshake. A delegated credential is a short lived key pair delegated to the -// server by an entity trusted by the client. Once issued, credentials can't be -// revoked; in order to mitigate risk in case the frontend is compromised, the -// credential is only valid for a short time (days, hours, or even minutes). -// -// This implements draft 02. This draft doesn't specify an object identifier for -// the X.509 extension; we use one assigned by Cloudflare. In addition, IANA has -// not assigned an extension ID for this extension; we picked up one that's not -// yet taken. -// -// TODO(cjpatton) Only ECDSA is supported with delegated credentials for now; -// we'd like to suppoort for EcDSA signatures once these have better support -// upstream. - -import ( - "bytes" - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/x509" - "encoding/asn1" - "encoding/binary" - "errors" - "fmt" - "time" -) - -const ( - // length of the public key field - dcPubKeyFieldLen = 3 - dcMaxTTLSeconds = 60 * 60 * 24 * 7 // 7 days - dcMaxTTL = time.Duration(dcMaxTTLSeconds * time.Second) - dcMaxPublicKeyLen = 1 << 24 // Bytes - dcMaxSignatureLen = 1 << 16 // Bytes -) - -var errNoDelegationUsage = errors.New("certificate not authorized for delegation") - -// delegationUsageId is the DelegationUsage X.509 extension OID -// -// NOTE(cjpatton) This OID is a child of Cloudflare's IANA-assigned OID. -var delegationUsageId = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 44} - -// canDelegate returns true if a certificate can be used for delegated -// credentials. -func canDelegate(cert *x509.Certificate) bool { - // Check that the digitalSignature key usage is set. - if (cert.KeyUsage & x509.KeyUsageDigitalSignature) == 0 { - return false - } - - // Check that the certificate has the DelegationUsage extension and that - // it's non-critical (per the spec). - for _, extension := range cert.Extensions { - if extension.Id.Equal(delegationUsageId) { - return true - } - } - return false -} - -// credential stores the public components of a credential. -type credential struct { - // The serialized form of the credential. - raw []byte - - // The amount of time for which the credential is valid. Specifically, the - // the credential expires `ValidTime` seconds after the `notBefore` of the - // delegation certificate. The delegator shall not issue delegated - // credentials that are valid for more than 7 days from the current time. - // - // When this data structure is serialized, this value is converted to a - // uint32 representing the duration in seconds. - validTime time.Duration - - // The signature scheme associated with the delegated credential public key. - expectedCertVerifyAlgorithm SignatureScheme - - // The version of TLS in which the credential will be used. - expectedVersion uint16 - - // The credential public key. - publicKey crypto.PublicKey -} - -// isExpired returns true if the credential has expired. The end of the validity -// interval is defined as the delegator certificate's notBefore field (`start`) -// plus ValidTime seconds. This function simply checks that the current time -// (`now`) is before the end of the valdity interval. -func (cred *credential) isExpired(start, now time.Time) bool { - end := start.Add(cred.validTime) - return !now.Before(end) -} - -// invalidTTL returns true if the credential's validity period is longer than the -// maximum permitted. This is defined by the certificate's notBefore field -// (`start`) plus the ValidTime, minus the current time (`now`). -func (cred *credential) invalidTTL(start, now time.Time) bool { - return cred.validTime > (now.Sub(start) + dcMaxTTL).Round(time.Second) -} - -// marshalSubjectPublicKeyInfo returns a DER encoded SubjectPublicKeyInfo structure -// (as defined in the X.509 standard) for the credential. -func (cred *credential) marshalSubjectPublicKeyInfo() ([]byte, error) { - switch cred.expectedCertVerifyAlgorithm { - case ECDSAWithP256AndSHA256, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512: - serializedPublicKey, err := x509.MarshalPKIXPublicKey(cred.publicKey) - if err != nil { - return nil, err - } - return serializedPublicKey, nil - - default: - return nil, fmt.Errorf("unsupported signature scheme: 0x%04x", cred.expectedCertVerifyAlgorithm) - } -} - -// marshal encodes a credential in the wire format specified in -// https://tools.ietf.org/html/draft-ietf-tls-subcerts-02. -func (cred *credential) marshal() ([]byte, error) { - // The number of bytes comprising the DC parameters, which includes the - // validity time (4 bytes), the signature scheme of the public key (2 bytes), and - // the protocol version (2 bytes). - paramsLen := 8 - - // The first 4 bytes are the valid_time, scheme, and version fields. - serialized := make([]byte, paramsLen+dcPubKeyFieldLen) - binary.BigEndian.PutUint32(serialized, uint32(cred.validTime/time.Second)) - binary.BigEndian.PutUint16(serialized[4:], uint16(cred.expectedCertVerifyAlgorithm)) - binary.BigEndian.PutUint16(serialized[6:], cred.expectedVersion) - - // Encode the public key and assert that the encoding is no longer than 2^16 - // bytes (per the spec). - serializedPublicKey, err := cred.marshalSubjectPublicKeyInfo() - if err != nil { - return nil, err - } - if len(serializedPublicKey) > dcMaxPublicKeyLen { - return nil, errors.New("public key is too long") - } - - // The next 3 bytes are the length of the public key field, which may be up - // to 2^24 bytes long. - putUint24(serialized[paramsLen:], len(serializedPublicKey)) - - // The remaining bytes are the public key itself. - serialized = append(serialized, serializedPublicKey...) - cred.raw = serialized - return serialized, nil -} - -// unmarshalCredential decodes a credential and returns it. -func unmarshalCredential(serialized []byte) (*credential, error) { - // The number of bytes comprising the DC parameters. - paramsLen := 8 - - if len(serialized) < paramsLen+dcPubKeyFieldLen { - return nil, errors.New("credential is too short") - } - - // Parse the valid_time, scheme, and version fields. - validTime := time.Duration(binary.BigEndian.Uint32(serialized)) * time.Second - scheme := SignatureScheme(binary.BigEndian.Uint16(serialized[4:])) - version := binary.BigEndian.Uint16(serialized[6:]) - - // Parse the SubjectPublicKeyInfo. - pk, err := x509.ParsePKIXPublicKey(serialized[paramsLen+dcPubKeyFieldLen:]) - if err != nil { - return nil, err - } - - if _, ok := pk.(*ecdsa.PublicKey); !ok { - return nil, fmt.Errorf("unsupported delegation key type: %T", pk) - } - - return &credential{ - raw: serialized, - validTime: validTime, - expectedCertVerifyAlgorithm: scheme, - expectedVersion: version, - publicKey: pk, - }, nil -} - -// getCredentialLen returns the number of bytes comprising the serialized -// credential that starts at the beginning of the input slice. It returns an -// error if the input is too short to contain a credential. -func getCredentialLen(serialized []byte) (int, error) { - paramsLen := 8 - if len(serialized) < paramsLen+dcPubKeyFieldLen { - return 0, errors.New("credential is too short") - } - // First several bytes are the valid_time, scheme, and version fields. - serialized = serialized[paramsLen:] - - // The next 3 bytes are the length of the serialized public key, which may - // be up to 2^24 bytes in length. - serializedPublicKeyLen := getUint24(serialized) - serialized = serialized[dcPubKeyFieldLen:] - - if len(serialized) < serializedPublicKeyLen { - return 0, errors.New("public key of credential is too short") - } - - return paramsLen + dcPubKeyFieldLen + serializedPublicKeyLen, nil -} - -// delegatedCredential stores a credential and its delegation. -type delegatedCredential struct { - raw []byte - - // The credential, which contains a public and its validity time. - cred *credential - - // The signature scheme used to sign the credential. - algorithm SignatureScheme - - // The credential's delegation. - signature []byte -} - -// ensureCertificateHasLeaf parses the leaf certificate if needed. -func ensureCertificateHasLeaf(cert *Certificate) error { - var err error - if cert.Leaf == nil { - if len(cert.Certificate[0]) == 0 { - return errors.New("missing leaf certificate") - } - cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return err - } - } - return nil -} - -// validate checks that that the signature is valid, that the credential hasn't -// expired, and that the TTL is valid. It also checks that certificate can be -// used for delegation. -func (dc *delegatedCredential) validate(cert *x509.Certificate, now time.Time) (bool, error) { - // Check that the cert can delegate. - if !canDelegate(cert) { - return false, errNoDelegationUsage - } - - if dc.cred.isExpired(cert.NotBefore, now) { - return false, errors.New("credential has expired") - } - - if dc.cred.invalidTTL(cert.NotBefore, now) { - return false, errors.New("credential TTL is invalid") - } - - // Prepare the credential for verification. - rawCred, err := dc.cred.marshal() - if err != nil { - return false, err - } - hash := getHash(dc.algorithm) - in := prepareDelegation(hash, rawCred, cert.Raw, dc.algorithm) - - // TODO(any) This code overlaps significantly with verifyHandshakeSignature() - // in ../auth.go. This should be refactored. - switch dc.algorithm { - case ECDSAWithP256AndSHA256, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512: - pk, ok := cert.PublicKey.(*ecdsa.PublicKey) - if !ok { - return false, errors.New("expected ECDSA public key") - } - sig := new(ecdsaSignature) - if _, err = asn1.Unmarshal(dc.signature, sig); err != nil { - return false, err - } - return ecdsa.Verify(pk, in, sig.R, sig.S), nil - - default: - return false, fmt.Errorf( - "unsupported signature scheme: 0x%04x", dc.algorithm) - } -} - -// unmarshalDelegatedCredential decodes a DelegatedCredential structure. -func unmarshalDelegatedCredential(serialized []byte) (*delegatedCredential, error) { - // Get the length of the serialized credential that begins at the start of - // the input slice. - serializedCredentialLen, err := getCredentialLen(serialized) - if err != nil { - return nil, err - } - - // Parse the credential. - cred, err := unmarshalCredential(serialized[:serializedCredentialLen]) - if err != nil { - return nil, err - } - - // Parse the signature scheme. - serialized = serialized[serializedCredentialLen:] - if len(serialized) < 4 { - return nil, errors.New("delegated credential is too short") - } - scheme := SignatureScheme(binary.BigEndian.Uint16(serialized)) - - // Parse the signature length. - serialized = serialized[2:] - serializedSignatureLen := binary.BigEndian.Uint16(serialized) - - // Prase the signature. - serialized = serialized[2:] - if len(serialized) < int(serializedSignatureLen) { - return nil, errors.New("signature of delegated credential is too short") - } - sig := serialized[:serializedSignatureLen] - - return &delegatedCredential{ - raw: serialized, - cred: cred, - algorithm: scheme, - signature: sig, - }, nil -} - -// getCurve maps the SignatureScheme to its corresponding elliptic.Curve. -func getCurve(scheme SignatureScheme) elliptic.Curve { - switch scheme { - case ECDSAWithP256AndSHA256: - return elliptic.P256() - case ECDSAWithP384AndSHA384: - return elliptic.P384() - case ECDSAWithP521AndSHA512: - return elliptic.P521() - default: - return nil - } -} - -// getHash maps the SignatureScheme to its corresponding hash function. -// -// TODO(any) This function overlaps with hashForSignatureScheme in 13.go. -func getHash(scheme SignatureScheme) crypto.Hash { - switch scheme { - case ECDSAWithP256AndSHA256: - return crypto.SHA256 - case ECDSAWithP384AndSHA384: - return crypto.SHA384 - case ECDSAWithP521AndSHA512: - return crypto.SHA512 - default: - return 0 // Unknown hash function - } -} - -// prepareDelegation returns a hash of the message that the delegator is to -// sign. The inputs are the credential (`cred`), the DER-encoded delegator -// certificate (`delegatorCert`) and the signature scheme of the delegator -// (`delegatorAlgorithm`). -func prepareDelegation(hash crypto.Hash, cred, delegatorCert []byte, delegatorAlgorithm SignatureScheme) []byte { - h := hash.New() - - // The header. - h.Write(bytes.Repeat([]byte{0x20}, 64)) - h.Write([]byte("TLS, server delegated credentials")) - h.Write([]byte{0x00}) - - // The delegation certificate. - h.Write(delegatorCert) - - // The credential. - h.Write(cred) - - // The delegator signature scheme. - var serializedScheme [2]byte - binary.BigEndian.PutUint16(serializedScheme[:], uint16(delegatorAlgorithm)) - h.Write(serializedScheme[:]) - - return h.Sum(nil) -} diff --git a/external/github.com/marten-seemann/qtls/ticket.go b/external/github.com/marten-seemann/qtls/ticket.go deleted file mode 100644 index e5bffa99c..000000000 --- a/external/github.com/marten-seemann/qtls/ticket.go +++ /dev/null @@ -1,326 +0,0 @@ -// Copyright 2012 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 qtls - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/hmac" - "crypto/sha256" - "crypto/subtle" - "errors" - "io" -) - -// A SessionTicketSealer provides a way to securely encapsulate -// session state for storage on the client. All methods are safe for -// concurrent use. -type SessionTicketSealer interface { - // Seal returns a session ticket value that can be later passed to Unseal - // to recover the content, usually by encrypting it. The ticket will be sent - // to the client to be stored, and will be sent back in plaintext, so it can - // be read and modified by an attacker. - Seal(cs *ConnectionState, content []byte) (ticket []byte, err error) - - // Unseal returns a session ticket contents. The ticket can't be safely - // assumed to have been generated by Seal. - // If unable to unseal the ticket, the connection will proceed with a - // complete handshake. - Unseal(chi *ClientHelloInfo, ticket []byte) (content []byte, success bool) -} - -// sessionState contains the information that is serialized into a session -// ticket in order to later resume a connection. -type sessionState struct { - vers uint16 - cipherSuite uint16 - usedEMS bool - masterSecret []byte - certificates [][]byte - // usedOldKey is true if the ticket from which this session came from - // was encrypted with an older key and thus should be refreshed. - usedOldKey bool -} - -func (s *sessionState) equal(i interface{}) bool { - s1, ok := i.(*sessionState) - if !ok { - return false - } - - if s.vers != s1.vers || - s.usedEMS != s1.usedEMS || - s.cipherSuite != s1.cipherSuite || - !bytes.Equal(s.masterSecret, s1.masterSecret) { - return false - } - - if len(s.certificates) != len(s1.certificates) { - return false - } - - for i := range s.certificates { - if !bytes.Equal(s.certificates[i], s1.certificates[i]) { - return false - } - } - - return true -} - -func (s *sessionState) marshal() []byte { - length := 2 + 2 + 2 + len(s.masterSecret) + 2 - for _, cert := range s.certificates { - length += 4 + len(cert) - } - - ret := make([]byte, length) - x := ret - was_used := byte(0) - if s.usedEMS { - was_used = byte(0x80) - } - - x[0] = byte(s.vers>>8) | byte(was_used) - x[1] = byte(s.vers) - x[2] = byte(s.cipherSuite >> 8) - x[3] = byte(s.cipherSuite) - x[4] = byte(len(s.masterSecret) >> 8) - x[5] = byte(len(s.masterSecret)) - x = x[6:] - copy(x, s.masterSecret) - x = x[len(s.masterSecret):] - - x[0] = byte(len(s.certificates) >> 8) - x[1] = byte(len(s.certificates)) - x = x[2:] - - for _, cert := range s.certificates { - x[0] = byte(len(cert) >> 24) - x[1] = byte(len(cert) >> 16) - x[2] = byte(len(cert) >> 8) - x[3] = byte(len(cert)) - copy(x[4:], cert) - x = x[4+len(cert):] - } - - return ret -} - -func (s *sessionState) unmarshal(data []byte) alert { - if len(data) < 8 { - return alertDecodeError - } - - s.vers = (uint16(data[0])<<8 | uint16(data[1])) & 0x7fff - s.cipherSuite = uint16(data[2])<<8 | uint16(data[3]) - s.usedEMS = (data[0] & 0x80) == 0x80 - masterSecretLen := int(data[4])<<8 | int(data[5]) - data = data[6:] - if len(data) < masterSecretLen { - return alertDecodeError - } - - s.masterSecret = data[:masterSecretLen] - data = data[masterSecretLen:] - - if len(data) < 2 { - return alertDecodeError - } - - numCerts := int(data[0])<<8 | int(data[1]) - data = data[2:] - - s.certificates = make([][]byte, numCerts) - for i := range s.certificates { - if len(data) < 4 { - return alertDecodeError - } - certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3]) - data = data[4:] - if certLen < 0 { - return alertDecodeError - } - if len(data) < certLen { - return alertDecodeError - } - s.certificates[i] = data[:certLen] - data = data[certLen:] - } - - if len(data) != 0 { - return alertDecodeError - } - return alertSuccess -} - -type sessionState13 struct { - vers uint16 - suite uint16 - ageAdd uint32 - createdAt uint64 - maxEarlyDataLen uint32 - pskSecret []byte - alpnProtocol string - SNI string -} - -func (s *sessionState13) equal(i interface{}) bool { - s1, ok := i.(*sessionState13) - if !ok { - return false - } - - return s.vers == s1.vers && - s.suite == s1.suite && - s.ageAdd == s1.ageAdd && - s.createdAt == s1.createdAt && - s.maxEarlyDataLen == s1.maxEarlyDataLen && - subtle.ConstantTimeCompare(s.pskSecret, s1.pskSecret) == 1 && - s.alpnProtocol == s1.alpnProtocol && - s.SNI == s1.SNI -} - -func (s *sessionState13) marshal() []byte { - length := 2 + 2 + 4 + 8 + 4 + 2 + len(s.pskSecret) + 2 + len(s.alpnProtocol) + 2 + len(s.SNI) - - x := make([]byte, length) - x[0] = byte(s.vers >> 8) - x[1] = byte(s.vers) - x[2] = byte(s.suite >> 8) - x[3] = byte(s.suite) - x[4] = byte(s.ageAdd >> 24) - x[5] = byte(s.ageAdd >> 16) - x[6] = byte(s.ageAdd >> 8) - x[7] = byte(s.ageAdd) - x[8] = byte(s.createdAt >> 56) - x[9] = byte(s.createdAt >> 48) - x[10] = byte(s.createdAt >> 40) - x[11] = byte(s.createdAt >> 32) - x[12] = byte(s.createdAt >> 24) - x[13] = byte(s.createdAt >> 16) - x[14] = byte(s.createdAt >> 8) - x[15] = byte(s.createdAt) - x[16] = byte(s.maxEarlyDataLen >> 24) - x[17] = byte(s.maxEarlyDataLen >> 16) - x[18] = byte(s.maxEarlyDataLen >> 8) - x[19] = byte(s.maxEarlyDataLen) - x[20] = byte(len(s.pskSecret) >> 8) - x[21] = byte(len(s.pskSecret)) - copy(x[22:], s.pskSecret) - z := x[22+len(s.pskSecret):] - z[0] = byte(len(s.alpnProtocol) >> 8) - z[1] = byte(len(s.alpnProtocol)) - copy(z[2:], s.alpnProtocol) - z = z[2+len(s.alpnProtocol):] - z[0] = byte(len(s.SNI) >> 8) - z[1] = byte(len(s.SNI)) - copy(z[2:], s.SNI) - - return x -} - -func (s *sessionState13) unmarshal(data []byte) alert { - if len(data) < 24 { - return alertDecodeError - } - - s.vers = uint16(data[0])<<8 | uint16(data[1]) - s.suite = uint16(data[2])<<8 | uint16(data[3]) - s.ageAdd = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) - s.createdAt = uint64(data[8])<<56 | uint64(data[9])<<48 | uint64(data[10])<<40 | uint64(data[11])<<32 | - uint64(data[12])<<24 | uint64(data[13])<<16 | uint64(data[14])<<8 | uint64(data[15]) - s.maxEarlyDataLen = uint32(data[16])<<24 | uint32(data[17])<<16 | uint32(data[18])<<8 | uint32(data[19]) - - l := int(data[20])<<8 | int(data[21]) - if len(data) < 22+l+2 { - return alertDecodeError - } - s.pskSecret = data[22 : 22+l] - z := data[22+l:] - - l = int(z[0])<<8 | int(z[1]) - if len(z) < 2+l+2 { - return alertDecodeError - } - s.alpnProtocol = string(z[2 : 2+l]) - z = z[2+l:] - - l = int(z[0])<<8 | int(z[1]) - if len(z) != 2+l { - return alertDecodeError - } - s.SNI = string(z[2 : 2+l]) - - return alertSuccess -} - -func (c *Conn) encryptTicket(serialized []byte) ([]byte, error) { - encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size) - keyName := encrypted[:ticketKeyNameLen] - iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] - macBytes := encrypted[len(encrypted)-sha256.Size:] - - if _, err := io.ReadFull(c.config.rand(), iv); err != nil { - return nil, err - } - key := c.config.ticketKeys()[0] - copy(keyName, key.keyName[:]) - block, err := aes.NewCipher(key.aesKey[:]) - if err != nil { - return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) - } - cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized) - - mac := hmac.New(sha256.New, key.hmacKey[:]) - mac.Write(encrypted[:len(encrypted)-sha256.Size]) - mac.Sum(macBytes[:0]) - - return encrypted, nil -} - -func (c *Conn) decryptTicket(encrypted []byte) (serialized []byte, usedOldKey bool) { - if c.config.SessionTicketsDisabled || - len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size { - return nil, false - } - - keyName := encrypted[:ticketKeyNameLen] - iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] - macBytes := encrypted[len(encrypted)-sha256.Size:] - - keys := c.config.ticketKeys() - keyIndex := -1 - for i, candidateKey := range keys { - if bytes.Equal(keyName, candidateKey.keyName[:]) { - keyIndex = i - break - } - } - - if keyIndex == -1 { - return nil, false - } - key := &keys[keyIndex] - - mac := hmac.New(sha256.New, key.hmacKey[:]) - mac.Write(encrypted[:len(encrypted)-sha256.Size]) - expected := mac.Sum(nil) - - if subtle.ConstantTimeCompare(macBytes, expected) != 1 { - return nil, false - } - - block, err := aes.NewCipher(key.aesKey[:]) - if err != nil { - return nil, false - } - ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size] - plaintext := ciphertext - cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) - - return plaintext, keyIndex > 0 -} diff --git a/external/github.com/marten-seemann/qtls/tls.go b/external/github.com/marten-seemann/qtls/tls.go deleted file mode 100644 index 21e2c4db0..000000000 --- a/external/github.com/marten-seemann/qtls/tls.go +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2009 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 tls partially implements TLS 1.2, as specified in RFC 5246. -package qtls - -// BUG(agl): The crypto/tls package only implements some countermeasures -// against Lucky13 attacks on CBC-mode encryption, and only on SHA1 -// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and -// https://www.imperialviolet.org/2013/02/04/luckythirteen.html. - -import ( - "crypto" - "crypto/ecdsa" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - "io/ioutil" - "net" - "strings" - "time" -) - -// Server returns a new TLS server side connection -// using conn as the underlying transport. -// The configuration config must be non-nil and must include -// at least one certificate or else set GetCertificate. -func Server(conn net.Conn, config *Config) *Conn { - return &Conn{conn: conn, config: config} -} - -// Client returns a new TLS client side connection -// using conn as the underlying transport. -// The config cannot be nil: users must set either ServerName or -// InsecureSkipVerify in the config. -func Client(conn net.Conn, config *Config) *Conn { - return &Conn{conn: conn, config: config, isClient: true} -} - -// A listener implements a network listener (net.Listener) for TLS connections. -type listener struct { - net.Listener - config *Config -} - -// Accept waits for and returns the next incoming TLS connection. -// The returned connection is of type *Conn. -func (l *listener) Accept() (net.Conn, error) { - c, err := l.Listener.Accept() - if err != nil { - return nil, err - } - return Server(c, l.config), nil -} - -// NewListener creates a Listener which accepts connections from an inner -// Listener and wraps each connection with Server. -// The configuration config must be non-nil and must include -// at least one certificate or else set GetCertificate. -func NewListener(inner net.Listener, config *Config) net.Listener { - l := new(listener) - l.Listener = inner - l.config = config - return l -} - -// Listen creates a TLS listener accepting connections on the -// given network address using net.Listen. -// The configuration config must be non-nil and must include -// at least one certificate or else set GetCertificate. -func Listen(network, laddr string, config *Config) (net.Listener, error) { - if config == nil || (len(config.Certificates) == 0 && config.GetCertificate == nil) { - return nil, errors.New("tls: neither Certificates nor GetCertificate set in Config") - } - l, err := net.Listen(network, laddr) - if err != nil { - return nil, err - } - return NewListener(l, config), nil -} - -type timeoutError struct{} - -func (timeoutError) Error() string { return "tls: DialWithDialer timed out" } -func (timeoutError) Timeout() bool { return true } -func (timeoutError) Temporary() bool { return true } - -// DialWithDialer connects to the given network address using dialer.Dial and -// then initiates a TLS handshake, returning the resulting TLS connection. Any -// timeout or deadline given in the dialer apply to connection and TLS -// handshake as a whole. -// -// DialWithDialer interprets a nil configuration as equivalent to the zero -// configuration; see the documentation of Config for the defaults. -func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { - // We want the Timeout and Deadline values from dialer to cover the - // whole process: TCP connection and TLS handshake. This means that we - // also need to start our own timers now. - timeout := dialer.Timeout - - if !dialer.Deadline.IsZero() { - deadlineTimeout := time.Until(dialer.Deadline) - if timeout == 0 || deadlineTimeout < timeout { - timeout = deadlineTimeout - } - } - - var errChannel chan error - - if timeout != 0 { - errChannel = make(chan error, 2) - time.AfterFunc(timeout, func() { - errChannel <- timeoutError{} - }) - } - - rawConn, err := dialer.Dial(network, addr) - if err != nil { - return nil, err - } - - colonPos := strings.LastIndex(addr, ":") - if colonPos == -1 { - colonPos = len(addr) - } - hostname := addr[:colonPos] - - if config == nil { - config = defaultConfig() - } - // If no ServerName is set, infer the ServerName - // from the hostname we're connecting to. - if config.ServerName == "" { - // Make a copy to avoid polluting argument or default. - c := config.Clone() - c.ServerName = hostname - config = c - } - - conn := Client(rawConn, config) - - if timeout == 0 { - err = conn.Handshake() - } else { - go func() { - errChannel <- conn.Handshake() - }() - - err = <-errChannel - } - - if err != nil { - rawConn.Close() - return nil, err - } - - return conn, nil -} - -// Dial connects to the given network address using net.Dial -// and then initiates a TLS handshake, returning the resulting -// TLS connection. -// Dial interprets a nil configuration as equivalent to -// the zero configuration; see the documentation of Config -// for the defaults. -func Dial(network, addr string, config *Config) (*Conn, error) { - return DialWithDialer(new(net.Dialer), network, addr, config) -} - -// LoadX509KeyPair reads and parses a public/private key pair from a pair -// of files. The files must contain PEM encoded data. The certificate file -// may contain intermediate certificates following the leaf certificate to -// form a certificate chain. On successful return, Certificate.Leaf will -// be nil because the parsed form of the certificate is not retained. -func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { - certPEMBlock, err := ioutil.ReadFile(certFile) - if err != nil { - return Certificate{}, err - } - keyPEMBlock, err := ioutil.ReadFile(keyFile) - if err != nil { - return Certificate{}, err - } - return X509KeyPair(certPEMBlock, keyPEMBlock) -} - -// X509KeyPair parses a public/private key pair from a pair of -// PEM encoded data. On successful return, Certificate.Leaf will be nil because -// the parsed form of the certificate is not retained. -func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { - fail := func(err error) (Certificate, error) { return Certificate{}, err } - - var cert Certificate - var skippedBlockTypes []string - for { - var certDERBlock *pem.Block - certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) - if certDERBlock == nil { - break - } - if certDERBlock.Type == "CERTIFICATE" { - cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) - } else { - skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type) - } - } - - if len(cert.Certificate) == 0 { - if len(skippedBlockTypes) == 0 { - return fail(errors.New("tls: failed to find any PEM data in certificate input")) - } - if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") { - return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched")) - } - return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) - } - - skippedBlockTypes = skippedBlockTypes[:0] - var keyDERBlock *pem.Block - for { - keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) - if keyDERBlock == nil { - if len(skippedBlockTypes) == 0 { - return fail(errors.New("tls: failed to find any PEM data in key input")) - } - if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" { - return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key")) - } - return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) - } - if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { - break - } - skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type) - } - - // We don't need to parse the public key for TLS, but we so do anyway - // to check that it looks sane and matches the private key. - x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return fail(err) - } - - cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) - if err != nil { - return fail(err) - } - - switch pub := x509Cert.PublicKey.(type) { - case *rsa.PublicKey: - priv, ok := cert.PrivateKey.(*rsa.PrivateKey) - if !ok { - return fail(errors.New("tls: private key type does not match public key type")) - } - if pub.N.Cmp(priv.N) != 0 { - return fail(errors.New("tls: private key does not match public key")) - } - case *ecdsa.PublicKey: - priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) - if !ok { - return fail(errors.New("tls: private key type does not match public key type")) - } - if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { - return fail(errors.New("tls: private key does not match public key")) - } - default: - return fail(errors.New("tls: unknown public key algorithm")) - } - - return cert, nil -} - -// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates -// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. -// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. -func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { - if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { - return key, nil - } - if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { - switch key := key.(type) { - case *rsa.PrivateKey, *ecdsa.PrivateKey: - return key, nil - default: - return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping") - } - } - if key, err := x509.ParseECPrivateKey(der); err == nil { - return key, nil - } - - return nil, errors.New("tls: failed to parse private key") -} diff --git a/external/update-deps.sh b/external/update-deps.sh deleted file mode 100755 index 400785f3e..000000000 --- a/external/update-deps.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -pushd $GOPATH/src/v2ray.com/core/external - -rsync -rv "$GOPATH/src/github.com/lucas-clemente/quic-go/" "./github.com/lucas-clemente/quic-go/" -rm -rf ./github.com/lucas-clemente/quic-go/\.* -rm -rf ./github.com/lucas-clemente/quic-go/benchmark -rm -rf ./github.com/lucas-clemente/quic-go/docs -rm -rf ./github.com/lucas-clemente/quic-go/example -rm -rf ./github.com/lucas-clemente/quic-go/h2quic -rm -rf ./github.com/lucas-clemente/quic-go/integrationtests -rm -rf ./github.com/lucas-clemente/quic-go/internal/mocks -rm ./github.com/lucas-clemente/quic-go/vendor/vendor.json - -rsync -rv "./github.com/lucas-clemente/quic-go/vendor/github.com/cheekybits/" "./github.com/cheekybits/" -rsync -rv "./github.com/lucas-clemente/quic-go/vendor/github.com/cloudflare/" "./github.com/cloudflare/" -rsync -rv "./github.com/lucas-clemente/quic-go/vendor/github.com/marten-seemann/" "./github.com/marten-seemann/" -rm -rf "./github.com/lucas-clemente/quic-go/vendor/" - - -find . -name "*_test.go" -delete -find . -name "*.yml" -delete -find . -name "*.go" -type f -print0 | LC_ALL=C xargs -0 sed -i '' 's#\"github\.com#\"v2ray\.com/core/external/github\.com#g' - -popd diff --git a/go.mod b/go.mod index c2b006e8d..0cdf645c7 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/golang/protobuf v1.4.2 github.com/google/go-cmp v0.5.2 github.com/gorilla/websocket v1.4.2 + github.com/lucas-clemente/quic-go v0.18.1 github.com/miekg/dns v1.1.31 github.com/pires/go-proxyproto v0.2.0 github.com/seiflotfy/cuckoofilter v0.0.0-20200511222245-56093a4d3841 diff --git a/go.sum b/go.sum index 5ea0ec46d..1bf907cde 100644 --- a/go.sum +++ b/go.sum @@ -1,26 +1,59 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E= github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a h1:YtdtTUN1iH97s+6PUjLnaiKSQj4oG1/EZ3N9bx6g4kU= github.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a/go.mod h1:/CZpbhAusDOobpcb9yubw46kdYjq0zRC0Wpg9a9zFQM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -31,6 +64,7 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -38,67 +72,187 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI= github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lucas-clemente/quic-go v0.18.1 h1:DMR7guC0NtVS8zNZR3IO7NARZvZygkSC56GGtC6cyys= +github.com/lucas-clemente/quic-go v0.18.1/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marten-seemann/qpack v0.2.0/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= +github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= +github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= +github.com/marten-seemann/qtls-go1-15 v0.1.0 h1:i/YPXVxz8q9umso/5y474CNcHmTpA+5DH+mFPjx6PZg= +github.com/marten-seemann/qtls-go1-15 v0.1.0/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pires/go-proxyproto v0.2.0 h1:WyYKlv9pkt77b+LjMvPfwrsAxviaGCFhG4KDIy1ofLY= github.com/pires/go-proxyproto v0.2.0/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/seiflotfy/cuckoofilter v0.0.0-20200511222245-56093a4d3841 h1:pnfutQFsV7ySmHUeX6ANGfPsBo29RctUvDn8G3rmJVw= github.com/seiflotfy/cuckoofilter v0.0.0-20200511222245-56093a4d3841/go.mod h1:ET5mVvNjwaGXRgZxO9UZr7X+8eAf87AfIYNwRSp9s4Y= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/xiaokangwang/VSign v0.0.0-20200828155424-dc1c86b73fbf h1:d4keT3SwLbrgnEe2zbtijPLgKE15n0ZbvJZzRH/a9GM= github.com/xiaokangwang/VSign v0.0.0-20200828155424-dc1c86b73fbf/go.mod h1:jTwBnzBuqZP3VX/Z65ErYb9zd4anQprSC7N38TmAp1E= github.com/xtls/go v0.0.0-20201007031018-d42c13c57942 h1:J+h5T5dtgVtszPN0vOFBzTapdVRZ16sXP6o6RPFNs20= github.com/xtls/go v0.0.0-20201007031018-d42c13c57942/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.starlark.net v0.0.0-20201006213952-227f4aabceb5 h1:ApvY/1gw+Yiqb/FKeks3KnVPWpkR3xzij82XPKLjJVw= go.starlark.net v0.0.0-20201006213952-227f4aabceb5/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200930132711-30421366ff76 h1:JnxiSYT3Nm0BT2a8CyvYyM6cnrWpidecD1UuSYbhKm0= golang.org/x/sync v0.0.0-20200930132711-30421366ff76/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201006155630-ac719f4daadf h1:Bg47KQy0JhTHuf4sLiQwTMKwUMfSDwgSGatrxGR7nLM= golang.org/x/sys v0.0.0-20201006155630-ac719f4daadf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -108,13 +262,27 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -132,9 +300,27 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= h12.io/socks v1.0.1 h1:bXESSI/+hbdrp+22vcc7/JiXjmLH4UWktKdYgGr3ShA= h12.io/socks v1.0.1/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/transport/internet/quic/conn.go b/transport/internet/quic/conn.go index 7f039fe16..c59b2a7b6 100644 --- a/transport/internet/quic/conn.go +++ b/transport/internet/quic/conn.go @@ -8,10 +8,10 @@ import ( "errors" "time" + "github.com/lucas-clemente/quic-go" "v2ray.com/core/common" "v2ray.com/core/common/buf" "v2ray.com/core/common/net" - quic "v2ray.com/core/external/github.com/lucas-clemente/quic-go" "v2ray.com/core/transport/internet" ) diff --git a/transport/internet/quic/dialer.go b/transport/internet/quic/dialer.go index 1a382eb11..daec007f5 100644 --- a/transport/internet/quic/dialer.go +++ b/transport/internet/quic/dialer.go @@ -7,10 +7,10 @@ import ( "sync" "time" + "github.com/lucas-clemente/quic-go" "v2ray.com/core/common" "v2ray.com/core/common/net" "v2ray.com/core/common/task" - quic "v2ray.com/core/external/github.com/lucas-clemente/quic-go" "v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet/tls" ) @@ -63,7 +63,7 @@ func removeInactiveSessions(sessions []*sessionContext) []*sessionContext { activeSessions = append(activeSessions, s) continue } - if err := s.session.Close(); err != nil { + if err := s.session.CloseWithError(0, ""); err != nil { newError("failed to close session").Base(err).WriteToLog() } if err := s.rawConn.Close(); err != nil { @@ -151,7 +151,7 @@ func (s *clientSessions) openConnection(destAddr net.Addr, config *Config, tlsCo quicConfig := &quic.Config{ ConnectionIDLength: 12, HandshakeTimeout: time.Second * 8, - IdleTimeout: time.Second * 30, + MaxIdleTimeout: time.Second * 30, } conn, err := wrapSysConn(rawConn, config) diff --git a/transport/internet/quic/hub.go b/transport/internet/quic/hub.go index 11865f692..372d96e8d 100644 --- a/transport/internet/quic/hub.go +++ b/transport/internet/quic/hub.go @@ -6,11 +6,11 @@ import ( "context" "time" + "github.com/lucas-clemente/quic-go" "v2ray.com/core/common" "v2ray.com/core/common/net" "v2ray.com/core/common/protocol/tls/cert" "v2ray.com/core/common/signal/done" - quic "v2ray.com/core/external/github.com/lucas-clemente/quic-go" "v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet/tls" ) @@ -25,14 +25,16 @@ type Listener struct { func (l *Listener) acceptStreams(session quic.Session) { for { - stream, err := session.AcceptStream() + stream, err := session.AcceptStream(context.Background()) if err != nil { newError("failed to accept stream").Base(err).WriteToLog() select { case <-session.Context().Done(): return case <-l.done.Wait(): - session.Close() + if err := session.CloseWithError(0, ""); err != nil { + newError("failed to close session").Base(err).WriteToLog() + } return default: time.Sleep(time.Second) @@ -53,7 +55,7 @@ func (l *Listener) acceptStreams(session quic.Session) { func (l *Listener) keepAccepting() { for { - conn, err := l.listener.Accept() + conn, err := l.listener.Accept(context.Background()) if err != nil { newError("failed to accept QUIC sessions").Base(err).WriteToLog() if l.done.Done() { @@ -105,7 +107,7 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti quicConfig := &quic.Config{ ConnectionIDLength: 12, HandshakeTimeout: time.Second * 8, - IdleTimeout: time.Second * 45, + MaxIdleTimeout: time.Second * 45, MaxIncomingStreams: 32, MaxIncomingUniStreams: -1, } diff --git a/transport/internet/quic/quic_test.go b/transport/internet/quic/quic_test.go index 3f42bd8cd..73639e9e9 100644 --- a/transport/internet/quic/quic_test.go +++ b/transport/internet/quic/quic_test.go @@ -29,7 +29,13 @@ func TestQuicConnection(t *testing.T) { ProtocolSettings: &quic.Config{}, SecurityType: "tls", SecuritySettings: &tls.Config{ - Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil, cert.DNSNames("www.v2ray.com"), cert.CommonName("www.v2ray.com")))}, + Certificate: []*tls.Certificate{ + tls.ParseCertificate( + cert.MustGenerate(nil, + cert.DNSNames("www.v2fly.org"), + ), + ), + }, }, }, func(conn internet.Connection) { go func() { @@ -59,7 +65,7 @@ func TestQuicConnection(t *testing.T) { ProtocolSettings: &quic.Config{}, SecurityType: "tls", SecuritySettings: &tls.Config{ - ServerName: "www.v2ray.com", + ServerName: "www.v2fly.org", AllowInsecure: true, }, })