view include/waaad/security-api.h @ 129:f185f65e213f

Changed transport prototype for security extensions
author Sebastien Decugis <sdecugis@nict.go.jp>
date Mon, 18 Aug 2008 18:28:22 +0900
parents d1cef88ac5f2
children f2cb50f9547c
line wrap: on
line source

/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
*													 *
* Copyright (c) 2008, WIDE Project and NICT								 *
* All rights reserved.											 *
* 													 *
* Redistribution and use of this software 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 the WIDE Project or NICT nor the 						 *
*   names of its contributors may be used to endorse or 						 *
*   promote products derived from this software without 						 *
*   specific prior written permission of WIDE Project and 						 *
*   NICT.												 *
* 													 *
* 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.								 *
*********************************************************************************************************/

/* This file contains the definitions of types and functions related to the security module
 * and that can be called by extensions. 
 */

/* The security module handles the messages and connections at the borders of the system, 
 * before any other handling when a message is received, and after all other processing 
 * when a message is emitted.
 * 
 * The security modules are provided by extensions (only). They have two main roles:
 * - indicate to the daemon if this security mechanism can handle a given peer or not.
 * - indicate to the daemon a priority for this module. See bellow for details.
 * - indicate to the daemon the value of Inband-Security-Id mechanism handled by this extension.
 * - handle the peer connection through some callbacks (when it indicated it can handle the peer):
 *   - when a message must be sent, callback to encrypt and send it
 *   - when a message must be received, callback to receive and decrypt it
 *   - when the peer state changes, callback to notify the module of the change.
 *      This callback should be used to initialize and terminate the cryptographic sessions.
 *
 * Note that when no security module is able to handle a connection to a peer, this connection
 * will be refused.
 *
 * Each security module provides a "priority" setting (that should be configurable by module or 
 * by peer in a configuration file) so that if several modules can handle a peer, the daemon will 
 * use the module with the biggest priority.
 *
 * Each security module also registers its value of "Inband-Security-Id". Only one module can
 * be registered for a given value. This value will be used in the CER/CEA exchanges.
 *
 * The following two modules are expected to be part of the waaad package:
 *  - no security (Inband-Security-Id = 0).
 *       This module simply sends the message buffer on the network with no security.
 *      The use of this module is expected when transparent security mechanisms are available (IPsec w/ IKEv2).
 *      The configuration file of the module will list explicitly all the authorized peers.
 *      This is so in order to avoid connecting without security to some remote peers.
 *      A better alternative to this module would be some bindings with the IPsec subsystem or IKE(v2) subsystem.
 *
 *  - TLS security (Inband-Security-Id = 1).
 *	 This module uses TLSv1.1 to protect exchanges with a remote peer.
 *      The module included in waaad will use the GNUtls library to do the actual TLS management. 
 *      This library is under the LGPL licence, so for environments where this licence is a problem, 
 *      contributors are welcomed to provide a replacement under a different licence.
 *      The callback of state change will be used in this module to initiate the handshake process.
 *
 * Note that the callbacks in each module will be called by several threads at the same time, so the callbacks
 * have to be re-entrant and thread-safe (sends and receives are handled by different threads).
 *
 */

#ifndef _SECURITY_API_H
#define _SECURITY_API_H

#include <sys/types.h>
#include <sys/socket.h>

#ifndef sSA_ALIASES
#define sSS	struct sockaddr_storage
#define sSA	struct sockaddr
#define sSA4	struct sockaddr_in
#define sSA6	struct sockaddr_in6
#define sSA_ALIASES
#endif /* sSA_ALIASES */

/* The following type represents a "connection" object (for example, a socket) */
typedef void sec_conn_t;

/* This is the prototype of the function that the daemon uses to send data on a TCP */
/* This function may be blocking. */
/* The parameters and return values are the same as the send() function defined in POSIX. */
typedef ssize_t (*sec_send_tcp_cb) (sec_conn_t *, void *, size_t);

/* This is the prototype of the function that the daemon uses to receive data from a TCP connection. 
 * This function may be blocking. */
/* The parameters and return values are the same as the recv() function defined in POSIX. */
typedef ssize_t (*sec_recv_tcp_cb) (sec_conn_t *, void *, size_t);

/* This is the prototype of the function that the daemon uses to send data on an SCTP connection */
/* The second parameter is the stream id on which the message is sent. 
    -1 means autorotate the streams, in which case the value is updated to the actual stream it was sent to.
    otherwise the value is unchanged. */
typedef ssize_t (*sec_send_sctp_cb) (sec_conn_t *, int *, void *, size_t);

/* This is the prototype of the function that the daemon uses to receive data from an SCTP connection. 
 * This function may be blocking. */
/* The first argument is a connection handle.
 * the second argument receives the stream id of a message on return.
 * the third argument is the data on return. it must be freed after use.
 * the last argument is the length of data.
 */
typedef ssize_t (*sec_recv_sctp_cb) (sec_conn_t *, int *, void **, size_t*);

/* The following enum represents the possible states of a peer with regards to the security module (PSS = peer security state) */
typedef enum {
	PSS_CLOSED = 1,		/* The peer is not connected */
	PSS_INITIAL,		/* The connection is in progress (CER/CEA, election, ...). */
	PSS_CONNECTED,		/* The connection is established, messages MUST be protected in this state */
	PSS_CLOSING		/* The connection is being shutdown, the security extension must proceed to the cleanup of the session */
} sec_pss_t;
	
/* The following type contains information about the connection to the peer. */
typedef struct {
	peer_t			*peer;		/* Reference to the peer to which this session applies */
	
	/* The next 3 fields are valid only in the PSS_INITIAL and PSS_CONNECTED states */
	sec_conn_t		*conn;		/* The connection for sending/receiving to/from this peer */
	int			 proto;		/* IPPROTO_TCP or IPPROTO_SCTP */
	union {
		struct {
			sec_send_tcp_cb	 send_data;	/* The callback function to send data to the peer */
			sec_recv_tcp_cb	 recv_data;	/* The callback function to receive data from the peer */
		} tcp;
		struct {
			sec_send_sctp_cb send_data;	/* The callback function to send data to the peer */
			sec_recv_sctp_cb recv_data;	/* The callback function to receive data from the peer */
		} sctp;
	} cbs;
} sec_session_t;


/* Bellow  are the prototypes of callbacks that the extension must provide. */

/*
 * CALLBACK:	sec_state_change_cb_t
 *
 * PARAMETERS:
 *   newstate   : The new state of the connection with the peer.
 *   oldstate   : The previous state of the connection.
 *   session    : pointer to information about the connection.
 *   ext_session: The extension may store additional information on the session in this location.
 *
 * DESCRIPTION: 
 *   This callback is called when a peer state changes (states are described in sec_pss_t type).
 *  The old and new states are provided.
 *  Notes: 
 *   Valid transitions are:
 *    PSS_CLOSED -> PSS_INITIAL		( A new connection has been established )
 *    PSS_INITIAL -> PSS_CONNECTED	( The CER / CEA exchange is successful )
 *    PSS_INITIAL -> PSS_CLOSING	( The CER / CEA exchange failed, the connection is terminating )
 *    PSS_INITIAL -> PSS_CLOSED		( The connection has closed unexpectedly )
 *    PSS_CONNECTED -> PSS_CLOSING	( The diameter exchange is terminated, connection is terminating )
 *    PSS_CONNECTED -> PSS_CLOSED       ( An unexpected error occurred, the transport-layer connection is not available for clean shutdown )
 *    PSS_CLOSING -> PSS_CLOSED		( The connection has been closed properly. The ext_session must be freed if not already )
 *
 *   The socket and send/receive functions are usable only in the INITIAL, CONNECTED and CLOSING states.
 *  The security module may store data in the ext_session parameter. This data MUST be freed
 *  when the new pss state is PSS_CLOSED.
 *
 *   The PSS_CLOSING state exists only to allow the security module to terminate a connection cleanly.
 * When a diameter exchange is being terminated (not aborted), the following sequence occurs:
 *       (peer in PSS_CONNECTED state)
 *     DPR / DPA exchange
 *     Initiate the disconnection of the peer (cleanup pending messages, and so on...)
 *     Last step of the disconnection, this callback is called with the newstate: PSS_CLOSING 
 *       (daemon expects that the security session terminates)
 *     When the callback returns, the socket is closed and the callback is called again with the newstate PSS_CLOSED.
 *     Then the session is discarded.
 *
 * RETURN VALUE:
 *  0      	: Operation complete.
 *  !0 		: An error occurred. If the newstate was not PSS_CLOSED, then a shutdown of the connection will happen
 *                and the callback will be called again with newstate PSS_CLOSED.
 */
typedef int (*sec_state_change_cb_t) (sec_pss_t newstate, sec_pss_t oldstate, sec_session_t * session, void ** ext_session);

/*
 * CALLBACK:	sec_send_protect_cb_t
 *
 * PARAMETERS:
 *   session    : pointer to information about the connection. The send_data and conn fields are always valid.
 *   ext_session: same pointer that was passed to sec_state_change_cb_t. The security extension may store its state here.
 *   data       : the location of the data that must be protected and sent.
 *   length     : the size of the data that must be sent.
 *
 * DESCRIPTION: 
 *   This callback is called when data must be sent to the remote peer. It will be called only when the 
 *  peer is in the PSS_CONNECTED state. The function must protect the content of the message 
 *  contained in the data parameter and send it using the send_data_fct_t callback provided in the session 
 *  parameter (the connection parameter to pass to this callback is also in the session parameter).
 *
 *   This function may be blocking in case of "head-of-the-line blocking".
 *
 * RETURN VALUE:
 *  0      	: Operation complete.
 *  !0 		: An error occurred.
 */
typedef int (*sec_send_protect_cb_t) (sec_session_t * session, void ** ext_session, void * data, size_t length);

/*
 * CALLBACK:	sec_recv_unprotect_cb_t
 *
 * PARAMETERS:
 *   session    : pointer to information about the connection. The recv_data and conn fields are always valid.
 *   ext_session: same pointer that was passed to sec_state_change_cb_t. The security extension may store its state here.
 *   data       : upon successful read and decrypt, the location to the malloc'd received message is stored here.
 *   length     : the size of the data buffer received.
 *
 * DESCRIPTION: 
 *   This callback is called when data is available for receiving. Upon successful reception and decryption of the content,
 *  a new buffer must be malloc'd to hold the received data and returned to the daemon.
 *  This callback, like send_protect_cb_t, will be called only in the PSS_CONNECTED state. It must use the recv_data and conn
 * fields of the session parameter to retrieve the data from the transport layer connection.
 *
 * RETURN VALUE:
 *  0      	: Operation complete.
 *  !0 		: An error occurred.
 */
typedef int (*sec_recv_unprotect_cb_t) (sec_session_t * session, void ** ext_session, void ** data, size_t *length);

/* The last callback is used to notify the daemon whether a given peer can be handled by the daemon or not.
 * This can be dependant on the configuration, or pre-established trust material (certificates, ...) or other
 * mechanism. */
/*
 * CALLBACK:	sec_is_supported_peer_cb_t
 *
 * PARAMETERS:
 *   diamid     : The supposed diameter-id of the peer. Before CER/CEA exchange, this may also be another fqdn of the peer.
 *                The real diameter-id of the peer is available by using the peer_t pointer from the sec_session_t later.
 *   sa         : Information about the location and port of the diameter peer we are wanting to connect to.
 *   priority   : Upon success, the priority of this module for handling this peer is written here. 
 *                Negative value means that the module can not handle this peer.
 *
 * DESCRIPTION: 
 *   This function is called when a new connection is established with a remote peer. It must write in the 
 *  "priority" parameter if this module can protect an exchange with that peer, and with what priority
 *  this module should be used compared to other modules.
 *
 * RETURN VALUE:
 *  0      	: Operation complete.
 *  !0 		: An error occurred. The module will not be used for this peer.
 */
typedef int (*sec_is_supported_peer_cb_t) (char * diamid, sSA * sa, int * priority);


/* The following type contains all the information needed to register a security module. */
typedef struct {
	uint32_t			sec_insecid;	/* The value of the Inband-Security-Id of this module. 
					  		The dictionary must contain a DICT_TYPE_ENUM object corresponding to this value. */
	/* The callbacks from this module, as defined previously */
	sec_is_supported_peer_cb_t	sec_is_supported_peer;
	sec_state_change_cb_t		sec_state_change;
	sec_send_protect_cb_t		sec_send_protect;
	sec_recv_unprotect_cb_t		sec_recv_unprotect;
} sec_module_t;

/* The following type represents a registered module, and must be passed to unregister a module. */
typedef void sec_mod_hdl_t;

#ifndef IN_EXTENSION

/*
 * FUNCTION:	sec_register
 *
 * PARAMETERS:
 *  module	  : Information about the module that must be registered.
 *  handler       : On success, a handler to the registered module is stored here. 
 *		   This handler will be used to deregister the module.
 *
 * DESCRIPTION: 
 *   Register a new security module to handle a security mechanism.
 *
 * RETURN VALUE:
 *  0      	: The module is registered.
 *  EINVAL 	: A parameter is invalid.
 *  ENOMEM	: Not enough memory to complete the operation
 *  EALREADY	: Another module is already registered with the same sec_insecid value.
 */
int sec_register ( sec_module_t * module, sec_mod_hdl_t ** handler );

/*
 * FUNCTION:	sec_unregister
 *
 * PARAMETERS:
 *  handler       : The module that must be unregistered.
 *
 * DESCRIPTION: 
 *   Removes a module from the daemon.
 *
 * RETURN VALUE:
 *  0      	: The callback is unregistered.
 *  EINVAL 	: A parameter is invalid.
 *  EAGAIN 	: The module is still in use and can not be unregistered yet. Retry when all peers are in the PSS_CLOSED state.
 */
int sec_unregister ( sec_mod_hdl_t * handler );

#endif /* ! IN_EXTENSION */


/* The version of this API, to check binary compatibility -- increment each time a change is made in api_sec_t */
#define WAAAD_API_SEC_VER	1

/* Now define the type of the structure that contains the callback to pass to extensions */
typedef struct {
	/* The header is common to all sub-API pieces */
	size_t	length;		/* The size of this structure, may be useful for extensions not using the facility */
	int	version;	/* The version of this API/ABI, must be WAAAD_API_SEC_VER */
	
	/* the remaining is security-specific */
	int (*sec_register)    ( sec_module_t * module, sec_mod_hdl_t ** handler );
	int (*sec_unregister)  ( sec_mod_hdl_t * handler );
} api_sec_t;

#ifdef IN_EXTENSION

/* From within the extensions, we register callbacks in the following global structure */
#ifdef DECLARE_API_POINTERS
api_sec_t * g_api_sec=NULL;
#else /* DECLARE_API_POINTERS */
extern api_sec_t * g_api_sec;
#endif /* DECLARE_API_POINTERS */

/* These defines allow to call functions from extension in the same way as in waaad */
#define sec_register		g_api_sec->sec_register
#define sec_unregister		g_api_sec->sec_unregister

#else /* IN_EXTENSION */

/* From the daemon, we must initialize the API object, in extension.c */
# define MY_WAAAD_API_SEC_VER 1
# if MY_WAAAD_API_SEC_VER != WAAAD_API_SEC_VER
#  error "You must update API_INIT_SEC also"
# endif

#define API_INIT_SEC( api_sec ) 			\
{							\
	(api_sec).length          = sizeof(api_sec_t);	\
	(api_sec).version         = WAAAD_API_SEC_VER;	\
	(api_sec).sec_register    = sec_register;	\
	(api_sec).sec_unregister  = sec_unregister;	\
}							

#endif /* IN_EXTENSION */

#endif /* _SECURITY_API_H */

"Welcome to our mercurial repository"