######################################################################
#
#  This virtual server controls TLS sessions.
#
#  When a TLS session is used, the server will automatically create
#  attributes in the session-state list with details extracted from
#  the client certificate chain.
#
#  The number of certificates decoded depends on the setting of
#  setting of `attriubte_mode` in the `verify` section of the
#  appropriate TLS configuration.
#
#  Certificates are decoded into nested attributes e.g.
#
#	TLS-Certificate = {
#		Subject = '...',
#		Common-Name = '...',
#		Issuer = '...'
#	}
#
#  When more than one certificate is decoded, the first ( i.e.
#  &session-state.TLS-Certificate[0] ) will be the client certificate,
#  with the next being its issuer.
#
#	$Id: 18c929679822b0ce0500c25734d418d0b90a7397 $
#
######################################################################
server tls-session {
	namespace = tls

	#
	#  This section can be run to verify a client certificate if
	#  additional checks need to be performed beyond standard
	#  checks verification against a trust chain, CRLs and OCSP.
	#
	#  Attributes extracted from the certificates forming the
	#  client certificate chain will be in the session state list.
	#
	#  Returning 'ok', 'updated' or 'noop' will cause the verification
	#  to succeed.  Other return codes will cause the verification
	#  to fail.
	#
	verify certificate {
		#
		#  Check the client certificate matches a string, and reject otherwise
		#
#		if ("%{session-state.TLS-Certificate.Common-Name}" != 'client.example.com') {
#			reject
#		}

		#
		#  Check the client certificate common name against the supplied identity
		#
#		if (&EAP-Identity != "host/%{session-state.TLS-Certificate.Common-Name}") {
#			reject
#		}

		#
		#  This is a convenient place to call LDAP, for example, when using
		#  EAP-TLS, as it will only be called once, after all certificates as
		#  part of the EAP-TLS challenge process have been verified.
		#
		#  An example could be to use LDAP to check that the connecting host, as
		#  well as presenting a valid certificate, is also in a group based on
		#  the EAP-Identity (assuming this contains the service principal name).
		#  Settings such as the following could be used in the ldap module
		#  configuration:
		#
		#  basedn = "dc=example, dc=com"
		#  filter = "(servicePrincipalName=%{EAP-Identity})"
		#  base_filter = "(objectClass=computer)"
		#  groupname_attribute = cn
		#  groupmembership_filter = "(&(objectClass=group)(member=%{control.Ldap-UserDn}))"
		#

#		ldap

		#
		#  Now let's test membership of an LDAP group (the ldap bind user will
		#  need permission to read this group membership):
		#

#		if (!%ldap.group("Permitted-Laptops")) {
#			reject
#		}

		#  or, to be more specific, you could use the group's full DN:
		#  if (!%ldap.group("CN=Permitted-Laptops,OU=Groups,DC=example,DC=org")) {

		#
		#  This may be a better place to call the files modules when using
		#  EAP-TLS, as it will only be called once, after the challenge-response
		#  iteration has completed.
		#

#		files

		ok
	}

	#
	#  This section is run whenever the server needs to read an
	#  entry from the TLS session cache.
	#
	#  It should read the attribute &session-state.TLS-Session-Data
	#  from the cache, along with any other attributes which
	#  were in the cache
	#
	#  On success it should return 'ok' or 'updated'.
	#
	#  The return code has no real effect on session processing
	#  and will just cause the server to emit a warning.
	#
	load session {
		&control.Cache-Allow-Insert := no

		cache_tls_session
	}

	#
	#  This section is run whenever the server needs to write an
	#  entry to the TLS session cache.
	#
	#  It should write the attribute &session-state.Session-Data
	#  to the cache, along with any other attributes which
	#  need to be cached.
	#
	#  On success it should return 'ok' or 'updated'.
	#
	#  The return code has no real effect on session processing
	#  and will just cause the server to emit a warning.
	#
	store session {
		&control.Cache-TTL := 0

		cache_tls_session
	}

	#
	#  This section is run whenever the server needs to delete an
	#  entry from the TLS session cache.
	#
	#  On success it should return 'ok', 'updated', 'noop' or 'notfound'
	#
	#  The return code has no real effect on session processing
	#  and will just cause the server to emit a warning.
	#
	clear session {
		&control.Cache-TTL := 0
		&control.Cache-Allow-Insert := no

		cache_tls_session
	}

	#
	#  This section is run after certificate attributes are added
	#  to the request list, and before performing OCSP validation.
	#
	#  It should read the attribute &control.TLS-OCSP-Cert-Valid
	#  from the cache.
	#
	#  On success it should return 'ok', 'updated', 'noop' or 'notfound'
	#  To force OCSP validation failure, it should return 'reject'.
	#
	load ocsp-state {
		&control.Cache-Allow-Insert := no

		cache_ocsp
	}

	#
	#  This section is run after OCSP validation has completed.
	#
	#  It should write the attribute &reply.TLS-OCSP-Cert-Valid
	#  to the cache.
	#
	#  On success it should return 'ok' or 'updated'.
	#
	#  The return code has no real effect on session processing
	#  and will just cause the server to emit a warning.
	#
	store ocsp-state {
		&control.Cache-TTL := "%{&reply.TLS-OCSP-Next-Update * -1}"
		&control.Cache-Allow-Merge := no

		cache_ocsp
	}
}
