Documentation
¶
Overview ¶
Package dtls implements the subset of DTLS 1.2 (RFC 6347) that the AnyConnect data channel needs: a pre-shared-key handshake with AES-GCM, in both the client and server roles.
It is deliberately not a general-purpose DTLS stack. AnyConnect's PSK-NEGOTIATE mode derives the pre-shared key from the already-established CSTP/TLS session with an RFC 5705 exporter, so there are no certificates, no chain validation and no key exchange to negotiate — which removes most of what makes DTLS large. What remains is the record layer, the PSK handshake flights, and the reliability machinery DTLS needs because it runs over UDP: retransmission, fragmentation and reassembly, and replay detection.
Only AEAD cipher suites are supported, so there is no CBC/MAC-then-encrypt path and none of the padding-oracle surface that comes with it. Everything is built on the standard library's AES-GCM, HMAC and SHA-2.
Index ¶
- func ClientHelloSessionID(datagram []byte) ([]byte, bool)
- func IsClientHello(datagram []byte) bool
- type Config
- type Conn
- func (c *Conn) CipherSuite() uint16
- func (c *Conn) Close() error
- func (c *Conn) LocalAddr() net.Addr
- func (c *Conn) Read(b []byte) (int, error)
- func (c *Conn) RemoteAddr() net.Addr
- func (c *Conn) SetDeadline(t time.Time) error
- func (c *Conn) SetReadDeadline(t time.Time) error
- func (c *Conn) SetWriteDeadline(t time.Time) error
- func (c *Conn) Write(b []byte) (int, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ClientHelloSessionID ¶
ClientHelloSessionID extracts the session-id from a datagram that looks like an initial ClientHello, reporting false for anything else.
func IsClientHello ¶
IsClientHello reports whether a datagram is an initial ClientHello. It is for a server whose sessions are not keyed by anything in the hello — Fortinet's certificate-based channel authorises the flow afterwards, with a cookie inside the established session, so all the demultiplexer needs to know here is that this datagram is plausibly the start of a handshake.
Types ¶
type Config ¶
type Config struct {
// PSK is the pre-shared key. For AnyConnect it comes from an RFC 5705
// exporter on the CSTP/TLS session, so it is already bound to that session.
PSK []byte
// PSKIdentity names the key. AnyConnect uses a fixed identity.
PSKIdentity []byte
// SessionID is placed in the ClientHello's session-id field. AnyConnect
// carries the hex-decoded X-DTLS-App-ID here, which is how a server ties the
// UDP flow back to the HTTPS session that authorised it.
SessionID []byte
// Certificate is the server's certificate and key for a certificate-based
// (ECDHE-ECDSA) handshake. When set, the connection uses ECDHE rather than
// PSK. It is ignored on a client.
Certificate *tls.Certificate
// InsecureSkipVerify, on a client, skips X.509 chain and hostname validation
// of the server certificate. The ServerKeyExchange signature is still checked
// against the presented certificate regardless -- that is what proves the
// server holds the key -- so this relaxes only trust in the issuer.
InsecureSkipVerify bool
// VerifyPeerCertificate, on a client, receives the server's raw certificate
// chain to pin or otherwise check it; a non-nil error aborts the handshake.
VerifyPeerCertificate func(rawCerts [][]byte) error
// ServerName is the expected certificate hostname, checked during chain
// validation unless InsecureSkipVerify is set.
ServerName string
// RootCAs is the set of trust anchors chain validation uses; nil uses the
// host's. A private gateway signed by a private CA is the ordinary case here.
RootCAs *x509.CertPool
// MTU bounds handshake fragments. Zero uses a conservative default.
MTU int
// HandshakeTimeout bounds the whole handshake.
HandshakeTimeout time.Duration
}
Config parameters one DTLS connection.
It selects the key exchange by what is set: a PSK gives the AnyConnect pre-shared-key handshake, and a Certificate gives Fortinet's certificate-based ECDHE handshake. The two are never mixed on one connection.
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn is an established DTLS connection carrying application datagrams. It wraps a net.Conn that must deliver whole datagrams — a connected UDP socket, or one side of a demultiplexing server.
Read and Write are datagram-oriented: each Write becomes one record and each Read returns one record's payload, so unlike a stream there is no framing for the caller to do.
func Client ¶
Client performs a DTLS handshake in the client role and returns the established connection.
func Server ¶
Server performs a DTLS handshake in the server role. It answers the client's first ClientHello with a HelloVerifyRequest, so no state is kept for a peer that has not proven it can receive at its claimed address.
func (*Conn) CipherSuite ¶
CipherSuite reports the negotiated suite, for logging.
func (*Conn) RemoteAddr ¶
func (*Conn) SetDeadline ¶
SetDeadline and friends pass through to the underlying connection.