package libp2pwebtransport

import (
	
	
	
	
	
	
	
	
	
	
	
	
	

	

	ic 

	
	
)

const deterministicCertInfo = "determinisitic cert"

func getTLSConf( ic.PrivKey, ,  time.Time) (*tls.Config, error) {
	, ,  := generateCert(, , )
	if  != nil {
		return nil, 
	}
	return &tls.Config{
		Certificates: []tls.Certificate{{
			Certificate: [][]byte{.Raw},
			PrivateKey:  ,
			Leaf:        ,
		}},
		NextProtos: []string{http3.NextProtoH3},
	}, nil
}

// generateCert generates certs deterministically based on the `key` and start
// time passed in. Uses `golang.org/x/crypto/hkdf`.
func generateCert( ic.PrivKey, ,  time.Time) (*x509.Certificate, *ecdsa.PrivateKey, error) {
	,  := .Raw()
	if  != nil {
		return nil, nil, 
	}

	 := make([]byte, 8)
	binary.LittleEndian.PutUint64(, uint64(.UnixNano()))
	 := newDeterministicReader(, , deterministicCertInfo)

	 := make([]byte, 8)
	if ,  := .Read();  != nil {
		return nil, nil, 
	}
	 := int64(binary.BigEndian.Uint64())
	if  < 0 {
		 = -
	}
	 := &x509.Certificate{
		SerialNumber:          big.NewInt(),
		Subject:               pkix.Name{},
		NotBefore:             ,
		NotAfter:              ,
		IsCA:                  true,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
		BasicConstraintsValid: true,
	}

	,  := ecdsa.GenerateKey(elliptic.P256(), )
	if  != nil {
		return nil, nil, 
	}
	,  := x509.CreateCertificate(, , , .Public(), )
	if  != nil {
		return nil, nil, 
	}
	,  := x509.ParseCertificate()
	if  != nil {
		return nil, nil, 
	}
	return , , nil
}

type ErrCertHashMismatch struct {
	Expected []byte
	Actual   [][]byte
}

func ( ErrCertHashMismatch) () string {
	return fmt.Sprintf("cert hash not found: %x (expected: %#x)", .Expected, .Actual)
}

func verifyRawCerts( [][]byte,  []multihash.DecodedMultihash) error {
	if len() < 1 {
		return errors.New("no cert")
	}
	 := [len()-1]
	// The W3C WebTransport specification currently only allows SHA-256 certificates for serverCertificateHashes.
	 := sha256.Sum256()
	var  bool
	for ,  := range  {
		if .Code == multihash.SHA2_256 && bytes.Equal(.Digest, [:]) {
			 = true
			break
		}
	}
	if ! {
		 := make([][]byte, 0, len())
		for ,  := range  {
			 = append(, .Digest)
		}
		return ErrCertHashMismatch{Expected: [:], Actual: }
	}

	,  := x509.ParseCertificate()
	if  != nil {
		return 
	}
	// TODO: is this the best (and complete?) way to identify RSA certificates?
	switch .SignatureAlgorithm {
	case x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA, x509.MD2WithRSA, x509.MD5WithRSA:
		return errors.New("cert uses RSA")
	}
	if  := .NotAfter.Sub(.NotBefore);  > 14*24*time.Hour {
		return fmt.Errorf("cert must not be valid for longer than 14 days (NotBefore: %s, NotAfter: %s, Length: %s)", .NotBefore, .NotAfter, )
	}
	 := time.Now()
	if .Before(.NotBefore) || .After(.NotAfter) {
		return fmt.Errorf("cert not valid (NotBefore: %s, NotAfter: %s)", .NotBefore, .NotAfter)
	}
	return nil
}

// deterministicReader is a hack. It counter-acts the Go library's attempt at
// making ECDSA signatures non-deterministic. Go adds non-determinism by
// randomly dropping a singly byte from the reader stream. This counteracts this
// by detecting when a read is a single byte and using a different reader
// instead.
type deterministicReader struct {
	reader           io.Reader
	singleByteReader io.Reader
}

func newDeterministicReader( []byte,  []byte,  string) io.Reader {
	 := hkdf.New(sha256.New, , , []byte())
	 := hkdf.New(sha256.New, , , []byte(+" single byte"))

	return &deterministicReader{
		reader:           ,
		singleByteReader: ,
	}
}

func ( *deterministicReader) ( []byte) ( int,  error) {
	if len() == 1 {
		return .singleByteReader.Read()
	}
	return .reader.Read()
}