<commit_before>package mint

import (
	"crypto"
	"crypto/x509"
	"encoding/hex"
	"fmt"
	"io"
	"net"
	"sync"
	"time"
)

type Certificate struct {
	Chain      []*x509.Certificate
	PrivateKey crypto.Signer
}

type PreSharedKey struct {
	CipherSuite  CipherSuite
	IsResumption bool
	Identity     []byte
	Key          []byte
}

// Config is the struct used to pass configuration settings to a TLS client or
// server instance.  The settings for client and server are pretty different,
// but we just throw them all in here.
type Config struct {
	// Only in crypto/tls:
	// SessionTicketsDisabled   bool               // TODO(#6) -> Both
	// SessionTicketKey         [32]byte           // TODO(#6) -> Server
	// Rand                     io.Reader          // TODO(#23) -> Both
	// PreferServerCipherSuites bool               // TODO(#22) -> Server
	// NextProtos               []string           // TODO(#21) -> Both
	// ClientAuth               ClientAuthType     // TODO(#20)
	// NameToCertificate        map[string]*Certificate // Unused (simplicity)
	// GetCertificate           func(clientHello *ClientHelloInfo) (*Certificate, error) // Unused (simplicity)
	// ClientCAs                *x509.CertPool     // Unused (no PKI)
	// RootCAs                  *x509.CertPool     // Unused (no PKI)
	// InsecureSkipVerify       bool               // Unused (no PKI)
	// MinVersion               uint16             // Unused (only 1.3)
	// MaxVersion               uint16             // Unused (only 1.3)
	// Time                     func() time.Time   // Unused (no time in 1.3)
	// ClientSessionCache       ClientSessionCache // Unused (PSKs only in 1.3)

	// Only here:
	// AuthCertificate          func(chain []*x509.Certificate) error
	// ClientPSKs               map[string]PreSharedKey
	// ServerPSKs               []PreSharedKey

	// ---------------------------------------

	// Client fields
	ServerName      string
	AuthCertificate func(chain []certificateEntry) error // TODO(#20) -> Both

	// Server fields
	Certificates       []*Certificate
	SendSessionTickets bool
	TicketLifetime     uint32
	TicketLen          int

	// Shared fields
	CipherSuites     []CipherSuite
	Groups           []NamedGroup
	SignatureSchemes []SignatureScheme
	NextProtos       []string
	PSKs             map[string]PreSharedKey

	// Hidden fields (used for caching in convenient form)
	enabledSuite  map[CipherSuite]bool
	enabledGroup  map[NamedGroup]bool
	enabledProto  map[string]bool
	enabledScheme map[SignatureScheme]bool
	certsByName   map[string]*Certificate

	// The same config object can be shared among different connections, so it
	// needs its own mutex
	mutex sync.RWMutex
}

func (c *Config) Init(isClient bool) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// Set defaults
	if len(c.CipherSuites) == 0 {
		c.CipherSuites = defaultSupportedCipherSuites
	}
	if len(c.Groups) == 0 {
		c.Groups = defaultSupportedGroups
	}
	if len(c.SignatureSchemes) == 0 {
		c.SignatureSchemes = defaultSignatureSchemes
	}
	if c.TicketLen == 0 {
		c.TicketLen = defaultTicketLen
	}
	if c.PSKs == nil {
		c.PSKs = map[string]PreSharedKey{}
	}

	// If there is no certificate, generate one
	if !isClient && len(c.Certificates) == 0 {
		priv, err := newSigningKey(RSA_PSS_SHA256)
		if err != nil {
			return err
		}

		cert, err := newSelfSigned(c.ServerName, RSA_PKCS1_SHA256, priv)
		if err != nil {
			return err
		}

		c.Certificates = []*Certificate{
			&Certificate{
				Chain:      []*x509.Certificate{cert},
				PrivateKey: priv,
			},
		}
	}

	return nil
}

func (c Config) validForServer() bool {
	return len(c.Certificates) > 0 &&
		len(c.Certificates[0].Chain) > 0 &&
		c.Certificates[0].PrivateKey != nil
}

func (c Config) validForClient() bool {
	return len(c.ServerName) > 0
}

var (
	defaultSupportedCipherSuites = []CipherSuite{
		TLS_AES_128_GCM_SHA256,
		TLS_AES_256_GCM_SHA384,
	}<commit_msg>Support PSK-only server operation<commit_after>package mint

import (
	"crypto"
	"crypto/x509"
	"encoding/hex"
	"fmt"
	"io"
	"net"
	"sync"
	"time"
)

type Certificate struct {
	Chain      []*x509.Certificate
	PrivateKey crypto.Signer
}

type PreSharedKey struct {
	CipherSuite  CipherSuite
	IsResumption bool
	Identity     []byte
	Key          []byte
}

// Config is the struct used to pass configuration settings to a TLS client or
// server instance.  The settings for client and server are pretty different,
// but we just throw them all in here.
type Config struct {
	// Only in crypto/tls:
	// SessionTicketsDisabled   bool               // TODO(#6) -> Both
	// SessionTicketKey         [32]byte           // TODO(#6) -> Server
	// Rand                     io.Reader          // TODO(#23) -> Both
	// PreferServerCipherSuites bool               // TODO(#22) -> Server
	// NextProtos               []string           // TODO(#21) -> Both
	// ClientAuth               ClientAuthType     // TODO(#20)
	// NameToCertificate        map[string]*Certificate // Unused (simplicity)
	// GetCertificate           func(clientHello *ClientHelloInfo) (*Certificate, error) // Unused (simplicity)
	// ClientCAs                *x509.CertPool     // Unused (no PKI)
	// RootCAs                  *x509.CertPool     // Unused (no PKI)
	// InsecureSkipVerify       bool               // Unused (no PKI)
	// MinVersion               uint16             // Unused (only 1.3)
	// MaxVersion               uint16             // Unused (only 1.3)
	// Time                     func() time.Time   // Unused (no time in 1.3)
	// ClientSessionCache       ClientSessionCache // Unused (PSKs only in 1.3)

	// Only here:
	// AuthCertificate          func(chain []*x509.Certificate) error
	// ClientPSKs               map[string]PreSharedKey
	// ServerPSKs               []PreSharedKey

	// ---------------------------------------

	// Client fields
	ServerName      string
	AuthCertificate func(chain []certificateEntry) error // TODO(#20) -> Both

	// Server fields
	Certificates       []*Certificate
	SendSessionTickets bool
	TicketLifetime     uint32
	TicketLen          int

	// Shared fields
	CipherSuites     []CipherSuite
	Groups           []NamedGroup
	SignatureSchemes []SignatureScheme
	NextProtos       []string
	PSKs             map[string]PreSharedKey

	// Hidden fields (used for caching in convenient form)
	enabledSuite  map[CipherSuite]bool
	enabledGroup  map[NamedGroup]bool
	enabledProto  map[string]bool
	enabledScheme map[SignatureScheme]bool
	certsByName   map[string]*Certificate

	// The same config object can be shared among different connections, so it
	// needs its own mutex
	mutex sync.RWMutex
}

func (c *Config) Init(isClient bool) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// Set defaults
	if len(c.CipherSuites) == 0 {
		c.CipherSuites = defaultSupportedCipherSuites
	}
	if len(c.Groups) == 0 {
		c.Groups = defaultSupportedGroups
	}
	if len(c.SignatureSchemes) == 0 {
		c.SignatureSchemes = defaultSignatureSchemes
	}
	if c.TicketLen == 0 {
		c.TicketLen = defaultTicketLen
	}
	if c.PSKs == nil {
		c.PSKs = map[string]PreSharedKey{}
	}

	// If there is no certificate, generate one
	if !isClient && len(c.Certificates) == 0 {
		priv, err := newSigningKey(RSA_PSS_SHA256)
		if err != nil {
			return err
		}

		cert, err := newSelfSigned(c.ServerName, RSA_PKCS1_SHA256, priv)
		if err != nil {
			return err
		}

		c.Certificates = []*Certificate{
			&Certificate{
				Chain:      []*x509.Certificate{cert},
				PrivateKey: priv,
			},
		}
	}

	return nil
}

func (c Config) validForServer() bool {
	return (len(c.PSKs) > 0) ||
		(len(c.Certificates) > 0 &&
			len(c.Certificates[0].Chain) > 0 &&
			c.Certificates[0].PrivateKey != nil)
}

func (c Config) validForClient() bool {
	return len(c.ServerName) > 0
}

var (
	defaultSupportedCipherSuites = []CipherSuite{
		TLS_AES_128_GCM_SHA256,
		TLS_AES_256_GCM_SHA384,
	}
{'fraction_non_alphanumeric': 0.11792513095694392, 'fraction_numerical': 0.019292193688514116, 'mean_word_length': 2.339590443686007, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '427126', 'n_tokens_mistral': 2676, 'n_tokens_neox': 2457, 'n_words': 643}