Sun Guía de Sun Enterprise Authentication Mechanism

Capítulo 8 Programación segura en red con RPCSEC_GSS

Las aplicaciones que llevan a cabo operaciones de red a menudo deben asegurarse de que sus transacciones sean seguras. La interfaz de programación de aplicaciones (API) RPCSEC_GSS permite a los desarrolladores aprovechar una gran variedad de mecanismos de seguridad, que incluyen SEAM y Kerberos V5. Asimismo, RPCSEC_GSS incluye servicios de integridad y privacidad, que proporcionan una protección adicional a la autenticación. Aunque RPCSEC_GSS no es parte de SEAM ni es específico para éste, los programadores que deseen aprovechar Kerberos V5 en sus aplicaciones encontrarán que es una forma excelente para hacerlo. De hecho, como RPCSEC_GSS es independiente del mecanismo, los desarrolladores que no utilicen SEAM/Kerberos V5 como su mecanismo de seguridad pero que deseen aprovechar la privacidad y la integridad deberían considerar su uso.

Este capítulo asume que está familiarizado con la programación de RPC; para obtener información sobre RPC, véase ONC+ Developer's Guide. Además, este capítulo únicamente está pensado como una introducción; para obtener información sobre los aspectos específicos de RPCSEC_GSS, como sus funciones o sus estructuras de datos, véase la página del comando man rpcsec_gss(3N) o la página del comando man de cualquiera de las funciones descritas en este capítulo.

En este capítulo se tratan los temas siguientes:

Versiones de seguridad

Este apartado describe el desarrollo y la naturaleza de la API RPCSEC_GSS.

Seguridad anterior a RPCSEC_GSS

AUTH_SYS fue una de las primeras versiones de seguridad admitidas por RPC (conocida también como AUTH_UNIX); proporcionaba una credencial de tipo UNIX, mediante los ID de usuario y de grupo para identificar al remitente y al destinatario de un mensaje. AUTH_SYS es fácil de implementar; sin embargo, también es fácil de burlar, ya que no proporciona una verdadera autenticación (es decir, un servidor no puede verificar por ningún medio que un cliente es quien afirma ser). Por tanto, bajo AUTH_SYS es relativamente sencillo falsificar una solicitud de red.

Una versión de seguridad posterior, AUTH_DES, basada en la autenticación de clave pública, apareció después de AUTH_SYS; utiliza un intercambio de claves Diffie-Hellman para producir una clave común entre la clave privada de un cliente y la clave pública de un servidor. A continuación, se utiliza la clave común para encriptar una clave de sesión DES, que desencripta el servidor para establecer una sesión.

Aunque AUTH_DES representó un avance considerable sobre AUTH_SYS, tiene algunas limitaciones para su uso generalizado. La objeción principal para muchas personas es que el tamaño de la clave es demasiado pequeño, según los estándares de encriptación actuales.

Finalmente, se introdujo otra versión de seguridad de RPC. AUTH_KERB, basado en Kerberos V4, proporciona una seguridad superior a AUTH_DES o AUTH_SYS. Sin embargo, también se puede violar.

Para más información sobre estas versiones de seguridad, véase la ONC+ Developer's Guide.

Integridad y privacidad: la GSS-API

Para mejorar la seguridad, se ha agregado una nueva capa de seguridad, la API de estándar de seguridad general o GSS-API. La estructura de GSS-API ofrece dos servicios de seguridad adicionales además de la autenticación:


Nota -

Actualmente, la GSS-API no está expuesta. Sin embargo, algunas de sus funciones son "visibles" mediante las funciones de RPCSEC_GSS (pueden manipularse de forma "opaca"). El programador no debe preocuparse directamente de sus valores.


La API RPCSEC_GSS

La versión de seguridad RPCSEC_GSS permite a las aplicaciones RPC de ONC que aprovechen las funciones de GSS-API. RPCSEC_GSS está situada "sobre" la capa de GSS-API de la forma siguiente:

Figura 8-1 Capas de seguridad de GSS-API y RPCSEC_GSS

Graphic

Mediante la interfaz de programación para RPCSEC_GSS, las aplicaciones RPC de ONC pueden especificar:

mecanismo

Un paradigma de seguridad. Cada clase de mecanismo de seguridad ofrece un tipo diferente de protección de los datos, así como uno o varios niveles de protección de éstos. En este caso, cualquier mecanismo de seguridad admitido por GSS-API (Kerberos V5, clave pública RSA, etcétera).

servicio de seguridad

Privacidad o integridad (o ninguno). El predeterminado es la integridad. El servicio es independiente del mecanismo.

QOP

Calidad de protección. QOP especifica qué tipo de algoritmo criptográfico se utilizará para implementar los servicios de privacidad o integridad. Cada mecanismo de seguridad puede tener asociado con él uno o varios parámetros QOP.

Las aplicaciones pueden obtener listas de QOP y los mecanismos válidos mediante funciones que proporciona RPCSEC_GSS (Véase "Funciones varias"). Los desarrolladores deben evitar fijar los mecanismos y los parámetros QOP en sus aplicaciones, para así poder utilizar mecanismos o QOP diferentes sin tener que modificarlas.


Nota -

Históricamente, "versión de seguridad" y "versión de autenticación" han significado lo mismo. Con la introducción de RPCSEC_GSS, ahora "versión" tiene un significado algo distinto. Una versión puede incluir un servicio (integridad o privacidad) junto con la autenticación, aunque actualmente RPCSEC_GSS es la única versión que lo hace.


Mediante RPCSEC_GSS, las aplicaciones RPC de ONC establecen un contexto de seguridad como un igual, intercambian datos y destruyen el contexto, al igual que harían con otras versiones. Cuando se ha establecido un contexto, la aplicación puede cambiar QOP y el servicio para cada unidad de datos enviada.

Para obtener más información sobre RPCSEC_GSS, incluidos sus tipos de datos, véase la página del comando man rpcsec_gss(3N).

Rutinas de RPCSEC_GSS

Tabla 8-1 resume los comandos de RPCSEC_GSS. Está previsto como una visión general de las funciones de RPCSEC_GSS, en lugar de una descripción específica de cada una. Para más información sobre una función, consulte su página del comando man o consulte la página del comando man rpcsec_gss(3N) para obtener una visión general que incluye una lista de las estructuras de datos de RPCSEC_GSS.

Tabla 8-1 Funciones de RPCSEC_GSS
AcciónFunciónEntradaSalida
 Crear un contexto de seguridadrpc_gss_seccreate() Manejador CLIENT, nombre de principal, mecanismo, QOP, tipo de servicioManejador AUTH
 Cambiar QOP o el tipo de servicio para el contextorpc_gss_set_defaults() QOP antigua, servicio QOP nueva, servicio
 Mostrar el tamaño máximo para los datos antes de la transformación de seguridadrpc_gss_max_data_length() Tamaño de datos máximo permitido por el transporte Tamaño de datos máximo previo a la transformación
 Mostrar el tamaño máximo para los datos antes de la transformación de seguridadrpc_gss_svc_max_data_length() Tamaño de datos máximo permitido por el transporte Tamaño de datos máximo previo a la transformación
 Definir el nombre de los principales para que los represente el servidorrpc_gss_set_svc_name() Nombre de principal, programa RPC, números de versión TRUE si es satisfactorio
 Obtener las credenciales del llamante (cliente)rpc_gss_getcred()Puntero a la estructura svc_req Credenciales de UNIX, credenciales de RPCSEC_GSS, cookie
 Especificar una función de rellamada (escrita por el usuario)rpc_gss_set_callback() Puntero a la función de rellamada TRUE si es satisfactorio
 Crear una estructura RPCSEC_GSS para los nombres de principal a partir de parámetros únicosrpc_gss_get_principal_name() Mecanismo, nombre de usuario, nombre de máquina, nombre de dominio Estructura de nombre de principal de RPCSEC_GSS
 Recuperar un código de error cuando falla una rutina de RPCSEC_GSSrpc_gss_get_error()   Número de error de RPCSEC_GSS, número de error si se aplica
 Obtener cadenas para los mecanismos instaladosrpc_gss_get_mechanisms()    Lista de mecanismos válidos
 Obtener cadenas de QOP válidasrpc_gss_get_mech_info() Mecanismo QOP válidas para ese mecanismo
 Obtener los números de versión superior e inferior de RPCSEC_GSS admitidosrpc_gss_get_versions()    Versiones superior e inferior
 Comprobar si está instalado un mecanismorpc_gss_is_installed() Mecanismo TRUE si está instalado
 Convertir mecanismo ASCII en identificador de objeto de RPCrpc_gss_mech_to_oid() Mecanismo (en forma de cadena) Mecanismo (en forma de OID)
 Convertir QOP ASCII en enterorpc_gss_qop_to_num() QOP (en forma de cadena) QOP (en forma de entero)

Creación de un contexto

Los contextos se crean con la llamada rpc_gss_seccreate(). Esta función toma los argumentos siguientes:

Devuelve un manejador de autenticación AUTH. Ejemplo 8-1 muestra cómo se puede utilizar rpc_gss_seccreate() para crear un contexto mediante el mecanismo de seguridad Kerberos V5 y el servicio de integridad:


Ejemplo 8-1 rpc_gss_seccreate()

CLIENT *clnt;                    /* manejador de cliente */ 
char server_host[] = "foo"; 
char service_name[] = "nfs@eng.acme.com"; 
char mech[] = "kerberos_v5"; 

clnt = clnt_create(server_host, 
SERVER_PROG, SERV_VERS, "netpath"); 
clnt->clnt_auth = rpc_gss_seccreate(clnt, service_name, mech, 
rpc_gss_svc_integrity, NULL, NULL, NULL); . . .

Algunas de las cosas que se deben tener en cuenta sobre Ejemplo 8-1 son:

Para más información, véase la página del comando man de rpc_gss_seccreate(3N).

Cambio de valores y destrucción de un contexto

Una vez definido un contexto, puede que la aplicación necesite cambiar los valores de QOP y de servicio para las unidades de datos individuales que se están transmitiendo (por ejemplo, puede que desee que un programa encripte una contraseña pero no un nombre de inicio de sesión). rpc_gss_set_defaults() le permite hacer esto:


Ejemplo 8-2 rpc_gss_set_defaults()

rpc_gss_set_defaults(clnt->clnt_auth, rpc_gss_svc_privacy, qop); . . .

En este caso, el servicio de seguridad está establecido como la privacidad (véase "Creación de un contexto"). qop es un puntero a una cadena que nombra la nueva QOP.

Los contextos se destruyen de la forma habitual, con auth_destroy().

Para obtener más información sobre cómo cambiar el servicio y QOP, véase la página del comando man rpc_gss_set_defaults(3N).

Nombres de principal

Para establecer un contexto de seguridad son necesarios dos tipos de nombres de principal:

Establecimiento de nombres de principal de servidor

Los servidores necesitan conocer los nombres de los principales a los que representarán cuando se inicien (un servidor puede hacer de más de un principal). rpc_gss_set_svc_name() establece el nombre del principal o principales:


Ejemplo 8-3 rpc_gss_set_svc_name()

char *principal, *mechanism; 
u_int req_time; 

principal = "nfs@eng.acme.com"; 
mechanism = "kerberos_v5"; 
req_time = 10000;		/* tiempo durante el que debería ser válida la credencial */ 

rpc_gss_set_svc_name(principal, mechanism, req_time, SERV_PROG, SERV_VERS);

(Kerberos ignora el parámetro req_time. Es posible que otros sistemas de autenticación lo utilicen).

Para obtener más información, véase la página del comando man de rpc_gss_set_svc_name(3N).

Generación de nombres de principal de cliente

Los servidores necesitan poder trabajar con el nombre de principal de un cliente; por ejemplo, para comparar el nombre de principal de un cliente con una lista de control de acceso o para consultar una credencial de UNIX para ese cliente, en caso de que exista. Estos nombres de principal se mantienen en forma de un puntero a una estructura rpc_gss_principal_t. (Para obtener más información sobre rpc_gss_principal_t, véase la página del comando man rpcsec_gss(3N)). Si un servidor desea comparar un nombre de principal recibido con el nombre de una entidad conocida, necesita poder generar un nombre de principal en ese formato.

La llamada rpc_gss_get_principal_name() toma varios parámetros de entrada que identifican de forma única a una persona de la red y genera un nombre de principal como un puntero de estructura rpc_gss_principal_t:


Ejemplo 8-4 rpc_gss_get_principal_name()

rpc_gss_principal_t *principal; 

rpc_gss_get_principal_name(principal, mecanismo, nombre, nodo, dominio); 
. . .

Los argumentos de rpc_gss_get_principal_name() son los siguientes:

Cada mecanismo de seguridad necesita parámetros de identificación diferentes. Por ejemplo, Kerberos V5 necesita un nombre de usuario y, sólo de forma opcional, nombres completos de nombre y de dominio (en términos de Kerberos, nombres de sistema y de ámbito).

Para obtener más información, véase la página del comando man de rpc_gss_get_principal_name(3N).

Liberación de nombres de principal

Los nombres de principal se liberan mediante la llamada de biblioteca free().

Recepción de credenciales en el servidor

Un servidor debe poder recuperar las credenciales de un cliente. La función rpc_gss_getcred(), que se muestra en Ejemplo 8-5, permite al servidor que recupere las credenciales de UNIX o las de RPCSEC_GSS (o ambas). Lo hace mediante dos argumentos, que estarán definidos si la función es satisfactoria. Uno es un puntero a una estructura rpc_gss_ucred_t, que contiene las credenciales de UNIX del llamante en caso que existan:

typedef struct { 
uid_t   uid;          /* ID de usuario */ gid_t   
gid;          /* ID de grupo */ short   gidlen;       
git_t   *gidlist;     /* lista de grupos */ 
} rpc_gss_ucred_t;

El otro argumento es un puntero a una estructura rpc_gss_raw_cred_t, que tiene el aspecto siguiente:

typedef struct { u_int     version;           /* versión de programa de RPCSEC_GSS */ 
char                   *mechanism; char                   *qop; 
rpc_gss_principal_t    client_principal;     /* nombre de principal 
de cliente */ 
char                   *svc_principal;        /* nombre de principal de servicio */ 
rpc_gss_service_t			service;               /* enum de privacidad e integridad */ 
} rpc_gss_rawcred_t;
(Véase "Generación de nombres de principal de cliente" para obtener una descripción de la estructura rpc_gss_principal_t y de cómo se crea). Como rpc_gss_rawcred_t contiene los nombres de principal del cliente y del servidor, rpc_gss_getcred() puede devolver ambos.

Ejemplo 8-5 ilustra un procedimiento sencillo de despacho del lado del servidor, en el que el servidor obtiene las credenciales del llamante. El procedimiento obtiene las credenciales de UNIX del llamante y luego verifica la identidad del usuario mediante mediante el mecanismo, QOP y el tipo de servicio encontrados en el argumento rpc_gss_rcred_t.


Ejemplo 8-5 Obtención de credenciales

static void server_prog(struct svc_req *rqstp, SVCXPRT *xprt) 
{ 
rpc_gss_ucred_t *ucred; 
rpc_gss_rawcred_t *rcred; 

if (rqst->rq_proq == NULLPROC) { 
svc_sendreply(xprt, xdr_void, NULL); 
return; 
} 
/* 
* autenticar el resto de solicitudes 
*/ 
*/ 

switch (rqstp->rq
_cred.oa_flavor) { 
case RPCSEC_GSS: 
/* 
* obtener la información de credenciales 
*/
 rpc_gss_getcred(rqstp, &rcred, &ucred, NULL); 
/* 
* verificar que el usuario tiene el permiso de acceso 
* mediante los parámetros de seguridad recibidos 
* examinando mi archivo de configuración 
*/ 
if (!authenticate_user(ucred->uid, rcred->mechanism, 
rcred->qop, rcred->service)) { 
svcerr_weakauth(xprt); 
return; 
} 
break; 	/* permitir la entrada del usuario 
*/ default: 
svcerr_weakauth(xprt); 
return; 
} /* fin de switch */ 

switch (rqstp->rq_proq) { 
case SERV_PROC1: 
. . . 
} 

/* proceso habitual de solicitudes; enviar respuesta ... */ 

return; 

}

Para obtener más información, véase la página del comando man rpc_gss_getcred(3N).

Cookies

En Ejemplo 8-5, el último argumento de rpc_gss_getcred() (en este caso, NULL) es una cookie definida por el usuario, cuyo valor al retornar será lo que especificó el servidor cuando se creó el contexto. Esta cookie, un valor de cuatro bytes, se puede utilizar como se considere apropiado para la aplicación; RPC no lo interpreta. Por ejemplo, la cookie puede ser un puntero o un índice a una estructura que representa al iniciador del contexto; en lugar de calcular este valor para cada solicitud, el servidor lo calcula en el momento de la creación del contexto (con lo que ahorra así tiempo de proceso de solicitudes).

Rellamadas

Otro lugar donde se pueden utilizar las cookies son las rellamadas. Un servidor puede especificar una rellamada (definida por el usuario) de forma que sepa cuándo se utiliza un contexto por primera vez mediante la función rpc_gss_set_callback(). Cuando se utiliza un contexto por primera vez para el intercambio de datos, después de que se establezca para el programa y la versión especificados, se invocará a la rellamada.

La rutina de rellamada definida por el usuario tiene el formato siguiente:

El segundo y el tercer argumento, deleg y gss_context, son tipos de datos de GSS-API y actualmente no están expuestos, de forma que la función de rellamada puede ignorarlos. (brevemente, deleg es la identidad de cualquier delegado igual, mientras que gss_context es un puntero al contexto de GSS-API, por si el programa deseara realizar operaciones de GSS-API en el contexto, es decir, para probar los criterios de aceptación). El argumento cookie ya se ha comentado.

El argumento lock es un puntero a una estructura rpc_gss_lock_t:

typedef struct { 
bool_t              locked;. 
rpc_gss_rawcred_t   *raw_cred; 
} rpc_gss_lock_t;
Este parámetro permite a un servidor aplicar QOP y un servicio determinados para la sesión. QOP y el servicio se encuentran en la estructura rpc_gss_rawcred_t descrita en Ejemplo 8-5 (un servidor no debería cambiar los valores para el servicio y QOP). Cuando se invoca la rellamada definida por el usuario, se define el campo locked como FALSE. Si el servidor define locked como TRUE, sólo se aceptarán las solicitudes con valores de QOP y de servicio que concuerden con los de la estructura rpc_gss_rawcred_t.

Para obtener más información, véase la página del comando man rpc_gss_set_callback(3N.

Tamaño de datos máximo

Dos funciones, rpc_gss_max_data_length() y rpc_gss_svc_max_data_length(), son útiles para determinar cuál puede ser el tamaño máximo de un bloque de datos antes de que se transforme por las medidas de seguridad y se envíe "a través del cable". Es decir, habitualmente las transformaciones de seguridad, como la encriptación, cambian el tamaño de un bloque de datos transmitido (a menudo haciéndolo más grande). Para asegurarse de que los datos no crezcan más allá de un tamaño útil, estas dos funciones (la primera es la versión del lado del cliente y la segunda la del lado del servidor) devuelven el tamaño previo a la transformación para un transporte dado.

Para obtener más información, véase las páginas del comando man rpc_gss_max_data_length(3N) y rpc_gss_svc_max_data_length(3N).

Funciones varias

Hay varias funciones que resultan útiles para obtener información sobre el sistema de seguridad instalado:

El uso de estas funciones proporciona al programador la libertad para evitar fijar los parámetros de seguridad en las aplicaciones (véase Tabla 8-1 y la página del comando man rpcsec_gss(3N) para obtener una lista de todas las funciones de RPCSEC_GSS).

Archivos asociados

RPCSEC_GSS utiliza determinados archivos para almacenar información.

La tabla gsscred

Cuando un servidor recupera las credenciales de un cliente asociadas con una solicitud, puede obtener el nombre de principal del cliente (en forma de un puntero a una estructura rpc_gss_principal_t) o las credenciales de UNIX locales (UID) para ese cliente. Los servicios como NFS necesitan una credencial de UNIX local para la comprobación del acceso, pero puede que otros no; por ejemplo, pueden almacenar el nombre de principal directamente en sus propias listas de control de acceso, como una estructura rpc_gss_principal_t.


Nota -

La correspondencia entre la credencial de red de un cliente (su nombre de principal) y cualquier credencial de UNIX local no es automática; debe haber sido definida de forma explícita por el administrador de seguridad local.


El archivo gsscred contiene las credenciales de UNIX y de red (por ejemplo, las de Kerberos V5) del cliente (las segundas credenciales son la representación Hexadecimal-ASCII de la estructura rpc_gss_principal_t). Se accede a través de XFN; por tanto, esta tabla se puede implementar a través de files, NIS, NIS+ o cualquier servicio de nombres futuro que admita XFN. Esta tabla aparece en la jerarquía de XFN como esta_unidad_org/service/gsscred. La tabla gsscred se mantiene mediante la utilidad gsscred, que permite a los administradores agregar y suprimir usuarios y mecanismos.

/etc/gss/qop y /etc/gss/mech

Por comodidad, RPCSEC_GSS utiliza literales de cadena para representar a los parámetros de los mecanismos y la Calidad de protección (QOP). Sin embargo, los mecanismos subyacentes propiamente dichos, necesitan que los mecanismos estén representados por identificadores de objetos y QOP por enteros de 32 bits. Además, debe especificarse para cada mecanismo la biblioteca compartida que implementa sus servicios.

El archivo /etc/gss/mech almacena la información siguiente sobre todos los mecanismos instalados en un sistema: el nombre del mecanismo en ASCII; su OID; la biblioteca compartida que implementa los servicios que proporciona este mecanismo; y, opcionalmente, el módulo del núcleo que implementa el servicio. Una línea de ejemplo puede tener el aspecto siguiente:


kerberos_v5   1.2.840.113554.1.2.2    gl/mech_krb5.so gl_kmech_krb5

El archivo /etc/gss/qop almacena, para todos los mecanismos instalados, todas las QOP admitidas por cada mecanismo como una cadena ASCII y como su correspondiente entero de 32 bits.

Tanto /etc/gss/mech como /etc/gss/qop se crean cuando se instalan los mecanismos de seguridad por primera vez en un sistema dado.

Como muchas de las rutinas de RPC del núcleo utilizan valores de no cadena para representar el mecanismo y la QOP, las aplicaciones pueden utilizar las funciones rpc_gss_mech_to_oid() y rpc_gss_qop_to_num() para obtener los equivalentes de no cadena para estos parámetros, en caso que necesiten aprovechar estas rutinas del núcleo.