Guide du mécanisme d'authentification pour l'entreprise de Sun

Chapitre 8 Programmation réseau sécurisée avec RPCSEC_GSS

Les applications effectuant des opérations réseau doivent fréquemment s'assurer que leurs transactions sont sécuritaires. L'API (Application Programming Interface) RPCSEC_GSS permet aux développeurs de profiter de divers mécanismes de sécurité, y compris SEAM et Kerberos V5. Ce qui est tout aussi important, RPCSEC_GSS inclut les services d'intégrité et de confidentialité, qui offrent une protection en plus de l'authentification. Bien que RPCSEC_GSS ne fasse pas partie de SEAM et ne soit pas propre à ce dernier, il offre un excellent moyen aux programmeurs de profiter de Kerberos V5 dans leurs applications. Comme RPCSEC_GSS ne dépend pas du mécanisme, les développeurs qui n'utilisent pas SEAM/Kerberos V5 comme mécanisme de sécurité mais qui souhaitent profiter de la confidentialité et de l'intégrité devraient songer à l'employer.

Ce chapitre suppose que vous connaissez la programmation RPC ; pour des renseignements sur le RPC, consultez le ONC+ Developer's Guide. En outre, ce chapitre ne présente qu'une vue d'ensemble ; pour des renseignements sur des aspects précis de RPCSEC_GSS, par exemple les fonctions ou les structures de données, consultez la page de manuel rpcsec_gss(3N) ou la page de manuel de toute fonction décrite dans ce chapitre.

Ce chapitre aborde les sujets suivants :

Types de sécurité

Cette section décrit le développement et la nature de l'API RPCSEC_GSS.

La sécurité avant RPCSEC_GSS

L'un des premiers types de sécurité pris en charge par RPC fut AUTH_SYS (également appelé AUTH_UNIX). AUTH_SYS fournissait un justificatif d'identité de type UNIX, employant les ID d'utilisateur et de groupe, afin d'identifier l'expéditeur et le destinataire d'un message. AUTH_SYS est facile à mettre en oeuvre ; cependant, il est aussi facile à contourner, puisqu'il n'assure pas une véritable authentification -- un serveur n'a aucun moyen de vérifier qu'un client est réellement ce qu'il prétend. Il est donc relativement simple de contrefaire une requête réseau avec AUTH_SYS.

Un autre type de sécurité, AUTH_DES, est apparu peu après AUTH_SYS. AUTH_DES est basé sur une authentification à clé publique -- il a recours à un échange de clés Diffie-Hellman pour produire une clé commune entre la clé privée d'un client et la clé publique d'un serveur. La clé commune est ensuite employée pour chiffrer une clé de session DES, laquelle est déchiffrée par un serveur pour l'établissement d'une session.

Bien que AUTH_DES constitue un progrès significatif par rapport à AUTH_SYS, il possède certaines limitations empêchant son utilisation répandue. La principale objection soulevée est que la taille des clés est faible par rapport aux normes de chiffrement actuelles.

Plus tard, un autre type de sécurité RPC fut introduit. AUTH_KERB, basé sur Kerberos V4, assure une sécurité encore meilleure que AUTH_DES ou AUTH_SYS. Toutefois, il peut aussi être exploité.

Pour de plus amples renseignements sur ces types de sécurité, consultez le ONC+ Developer's Guide.

Intégrité et confidentialité : l'API GSS

Pour améliorer la sécurité, une nouvelle couche réseau, l'API «Generic Security Standard», ou API GSS, a été ajoutée. La structure de l'API GSS offre deux services de sécurité supplémentaires en plus de l'authentification :


Remarque :

Actuellement, le GSS-API n'est pas exposé. Toutefois, certaines caractéristiques de l'API GSS sont "visibles" via les fonctions RPCSEC_GSS -- elles peuvent être manipulées de manière "opaque". Le programmeur n'a pas besoin de se préoccuper directement de leurs valeurs.


L'API RPCSEC_GSS

Le type de sécurité RPCSEC_GSS permet aux applications RPC ONC de profiter des caractéristiques de l'API GSS. RPCSEC_GSS se situe "au-dessus" de la couche de l'API GSS :

Figure 8-1 Couches de sécurité API GSS et RPCSEC_GSS

Graphic

Avec l'interface de programmation de RPCSEC_GSS, les applications RPC ONC peuvent spécifier les éléments suivants :

mécanisme

Un paradigme de sécurité. Chaque type de mécanisme de sécurité offre un genre de protection des données différent, ainsi qu'un ou plusieurs niveaux de protection des données. Dans ce cas, tout mécanisme de sécurité pris en charge par l'API GSS (Kerberos V5, clé publique RSA, etc.).

service de sécurité

Soit confidentialité, soit intégrité (ou aucun des deux). La valeur par défaut est «intégrité». Le service est indépendant du mécanisme.

QOP

Qualité de protection. La qualité de protection indique le type d'algorithme cryptographique à employer pour mettre en oeuvre les services de confidentialité ou d'intégrité. Chaque mécanisme de sécurité peut être associé à une ou plusieurs qualités de protection.

Les applications peuvent obtenir des listes de qualités de protection valides et des mécanismes via des fonctions fournies par RPCSEC_GSS. (Voir "Fonctions diverses".) Les développeurs devraient éviter les mécanismes et les qualités de protection incorporés au programme dans leurs applications, afin qu'il ne soit pas nécessaire de modifier ces dernières pour utiliser des mécanismes et des qualités de protection nouveaux ou différents.


Remarque :

Dans le passé, les expressions "type de sécurité" et "type d'authentification" avaient le même sens. Mais depuis l'introduction de RPCSEC_GSS, le "type" a maintenant une signification légèrement différente. Un type peut maintenant inclure un service (intégrité ou confidentialité) ainsi qu'une authentification, bien que RPCSEC_GSS soit actuellement le seul type qui en inclue un.


Avec RPCSEC_GSS, les applications RPC ONC établissent un contexte de sécurité avec un homologue, échangent des données et détruisent le contexte, tout comme avec les autres types. Une fois un contexte établi, l'application peut changer la qualité de protection et le service pour chaque unité de données envoyée.

Pour de plus amples renseignements sur RPCSEC_GSS, y compris les types de données RPCSEC_GSS, consultez la page de manuel rpcsec_gss(3N).

Sous-programmes RPCSEC_GSS

Le Tableau 8-1 résume les commandes RPCSEC_GSS. Ce tableau donne un aperçu des fonctions RPCSEC_GSS, et non une description détaillée de chacune. Pour de plus amples renseignements sur les fonctions individuelles, consultez les pages de manuel correspondantes, ou la page de manuel rpcsec_gss(3N) pour obtenir une vue d'ensemble, y compris une liste des structures de données RPCSEC_GSS.

Tableau 8-1 Fonctions RPCSEC_GSS
ActionFonctionEntréeSortie
 Créer un contexte de sécuritérpc_gss_seccreate() Identificateur CLIENT, nom du principal, mécanisme, qualité de protection, type de serviceIdentificateur AUTH
 Changer la qualité de protection, le type de service pour le contexterpc_gss_set_defaults() Ancienne qualité de protection, service Nouvelle qualité de protection, service
 Afficher la taille maximale des données avant la transformation de sécuritérpc_gss_max_data_length() Taille maximale des données permise par le transport Taille maximale des données avant la transformation
 Afficher la taille maximale des données avant la transformation de sécuritérpc_gss_svc_max_data_length() Taille maximale des données permise par le transport Taille maximale des données avant la transformation
 Définir le nom du/des principal(aux) que le serveur doit représenterrpc_gss_set_svc_name() Nom du principal, programme RPC, nos de version VRAI si réussi
 Extraire les justificatifs d'identité du demandeur (client)rpc_gss_getcred()Pointeur de la structure svc_req Justificatifs d'identité UNIX, justificatifs d'identité RPCSEC_GSS, cookie
 Spécifier la fonction de rappel (écrite par l'utilisateur)rpc_gss_set_callback() Pointeur de la fonction de rappel VRAI si réussi
 Créer une structure RPCSEC_GSS pour les noms de principaux à partir de paramètres uniquesrpc_gss_get_principal_name() Mécanisme, nom de l'utilisateur, nom de l'ordinateur, nom du domaine Structure du nom de principal RPCSEC_GSS
 Extraire un code d'erreur lors d'un échec de sous-programme RPCSEC_GSSrpc_gss_get_error()   Numéro d'erreur RPCSEC_GSS, errno si applicable
 Obtenir des chaînes pour les mécanismes installésrpc_gss_get_mechanisms()    Liste des mécanismes valides
 Obtenir les chaînes de qualité de protection validesrpc_gss_get_mech_info() Mécanisme Qualités de protection valides pour ce mécanisme
 Obtenir les numéros de version supérieure et inférieure de RPCSEC_GSS pris en chargerpc_gss_get_versions()    Versions supérieures et inférieures
 Vérifiez si un mécanisme est installérpc_gss_is_installed() Mécanisme VRAI si installé
 Convertir un mécanisme ASCII en identificateur d'objet RPCrpc_gss_mech_to_oid() Mécanisme (en tant que chaîne) Mécanisme (en tant qu'OID)
 Convertir une qualité de protection ASCII en nombre entierrpc_gss_qop_to_num() Qualité de protection (en tant que chaîne) Qualité de protection (en tant que nombre entier)

Création d'un contexte

Les contextes sont créés au moyen de l'appel rpc_gss_seccreate(). Voici les arguments de cette fonction :

Cette fonction renvoie un identificateur d'authentification AUTH. Exemple 8-1 illustre la façon dont rpc_gss_seccreate() peut servir à créer un contexte au moyen du mécanisme de sécurité Kerberos V5 et du service d'intégrité :


Exemple 8-1 rpc_gss_seccreate()

CLIENT *clnt;                    /* client handle */
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);

. . .

Remarques à propos de Exemple 8-1 :

Pour de plus amples renseignements, consultez la page de manuel rpc_gss_seccreate(3N).

Changement de valeurs et destruction d'un contexte

Une fois qu'un contexte est défini, il se peut que l'application doive changer les valeurs de qualité de protection et de service pour des unités de données individuelles transmises. (Par exemple, vous pourriez vouloir qu'un programme chiffre un mot de passe mais pas un nom de connexion.) rpc_gss_set_defaults() vous permet de le faire :


Exemple 8-2 rpc_gss_set_defaults()

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

. . .

Dans ce cas, le service de sécurité est réglé à «confidentialité» (voir "Création d'un contexte"). qop est un pointeur d'une chaîne nommant la nouvelle qualité de protection.

Les contextes sont détruits de manière usuelle, avec auth_destroy().

Pour de plus amples renseignements sur le changement du service et de la qualité de protection, consultez la page de manuel rpc_gss_set_defaults(3N).

Nom de principal

Deux types de nom de principal sont requis pour établir et maintenir un contexte de sécurité :

Définition des noms de principal de serveurs

Un serveur doit connaître les noms des principaux qu'il représentera lors de son démarrage (un serveur peut agir comme plus d'un principal). rpc_gss_set_svc_name() définit le nom du/des principal(aux) :


Exemple 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;		/* temps durant lequel le justificatif d'identité doit être valide 
*/
rpc_gss_set_svc_name(principal, mécanisme, req_time, SERV_PROG, SERV_VERS);

(Kerberos ne tient pas compte du paramètre req_time, mais d'autres systèmes d'authentification peuvent l'utiliser.)

Pour de plus amples renseignements, consultez la page de manuel rpc_gss_set_svc_name(3N).

Création de noms de principal de clients

Les serveurs doivent pouvoir agir sur le nom de principal d'un client -- par exemple, pour comparer le nom de principal d'un client à une liste de contrôle d'accès, ou pour consulter un justificatif d'identité UNIX relativement à ce client, si un tel justificatif d'identité existe. Ces noms de principal sont conservés sous la forme d'un pointeur de structure rpc_gss_principal_t. (Consultez la page de manuel rpcsec_gss(3N) pour plus de détails sur rpc_gss_principal_t.) Si un serveur veut comparer un nom de principal reçu au nom d'une entité connue, il doit pouvoir générer un nom de principal dans cette forme.

L'appel rpc_gss_get_principal_name() a comme entrées plusieurs paramètres identifiant de manière unique une personne sur un réseau, et génère un nom de principal comme pointeur de structure rpc_gss_principal_t :


Exemple 8-4 rpc_gss_get_principal_name()

rpc_gss_principal_t *principal;

rpc_gss_get_principal_name(principal, mécanisme, nom, noeud, domaine),
. . .

Voici les arguments de rpc_gss_get_principal_name() :

Chaque mécanisme de sécurité exige des paramètres d'identification différents. Par exemple, Kerberos V5 exige un nom d'utilisateur et, facultativement, des noms de domaine et de noeud qualifiés (dans la terminologie Kerberos, des noms d'hôte et de secteur).

Pour de plus amples renseignements, consultez la page de manuel rpc_gss_get_principal_name(3N).

Libération de noms de principal

Les noms de principal sont libérés au moyen de l'appel de bibliothèque free().

Réception de justificatifs d'identité au serveur

Un serveur doit pouvoir extraire les justificatifs d'identité d'un client. La fonction rpc_gss_getcred(), illustrée dans Exemple 8-5, permet au serveur de récupérer des justificatifs d'identité UNIX ou RPCSEC_GSS (ou les deux). Pour ce faire, il utilise deux arguments qui sont définis si la fonction réussit. L'un d'eux est un pointeur de structure rpc_gss_ucred_t, qui contient les justificatifs d'identité UNIX du demandeur, s'ils existent :

typedef struct {
    uid_t   uid;          /* ID d'utilisateur */
    gid_t   gid;          /* ID de groupe */
    short   gidlen;       
    git_t   *gidlist;     /* liste des groupes */
} rpc_gss_ucred_t;

L'autre argument est un pointeur de structure rpc_gss_raw_cred_t, dont voici un exemple :

typedef struct { 
   u_int                  version ;               /* Version du programme RPCSEC_GSS */
   char                   *mechanism;
   char                   *qop ;
   rpc_gss_principal_t    client_principal;     /* nom du principal de client */
   char                   *svc_principal;        /* nom de principal du serveur */
   rpc_gss_service_t		  service ;               /* confidentialité, enum d'intégrité */
} rpc_gss_rawcred_t;
(Voir "Création de noms de principal de clients" pour une description de la structure rpc_gss_principal_t et de sa création.) Comme rpc_gss_rawcred_t contient les noms de principal du client et du serveur, rpc_gss_getcred() peut renvoyer ces deux noms.

Exemple 8-5 est un exemple de procédure d'expédition côté serveur simple, où le serveur obtient les justificatifs d'identité du demandeur. La procédure obtient les justificatifs d'identité UNIX du demandeur, puis vérifie son identité à l'aide du mécanisme, de la qualité de protection et du type de service indiqué dans l'argument rpc_gss_rcred_t.


Exemple 8-5 Obtention des justificatifs d'identité

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; 
    } 
    /*
     * authentifier toutes les autres requêtes */
     */

    switch (rqstp->rq_cred.oa_flavor) {
    case RPCSEC_GSS:
       /*
        * obtenir les informations sur les justificatifs d'identité
        */
       rpc_gss_getcred(rqstp, &rcred, &ucred, NULL); 
       /*
       * vérifier que l'utilisateur est autorisé à accéder
       * au moyen des paramètres de sécurité reçus en
       * lisant le fichier de configuration
       */
       if (!authenticate_user(ucred->uid, rcred->mechanism,
          rcred->qop, rcred->service)) {
          svcerr_weakauth(xprt);
          return;
       }
       break; 	/* permettre à l'utilisateur d'entrer */
    default:
       svcerr_weakauth(xprt);
       return;
    } /* fin du commutateur */

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

    /* traitement de requête ordinaire ; envoyer une réponse ... */

    return;

}

Pour de plus amples renseignements, consultez la page de manuel rpc_gss_getcred(3N)

Cookies

Dans Exemple 8-5, le dernier argument de rpc_gss_getcred() (ici, NULL) est un cookie défini par l'utilisateur, dont la valeur de retour sera celle spécifiée par le serveur lors de la création du contexte. Ce cookie, une valeur à quatre octets, peut être employé de n'importe quelle manière convenant à l'application -- RPC ne l'interprète pas. Par exemple, le cookie peut être un pointeur ou un index relatif à une structure qui représente l'initiateur du contexte. Plutôt que de calculer cette valeur lors de chaque requête, le serveur la calcule au moment de la création du contexte (afin de réduire le temps de traitement des requêtes).

Rappels

Les cookies peuvent également être utilisés dans les rappels. Un serveur peut spécifier un rappel (défini par l'utilisateur) de manière à connaître le moment de la première utilisation d'un contexte, au moyen de la fonction rpc_gss_set_callback(). Le rappel est effectué la première fois qu'un contexte est utilisé pour l'échange de données, après que le contexte ait été établi pour le programme et la version spécifiés.

Le sous-programme de rappel défini par l'utilisateur a la forme suivante :

Les deuxième et troisième arguments, deleg et gss_context, sont des types de données de l'API GSS qui ne sont pas actuellement exposés, donc la fonction de rappel n'a pas à en tenir compte. (En bref, deleg est l'identité d'un homologue délégué, tandis que gss_context est un pointeur de contexte d'API GSS, au cas où le programme souhaite effectuer des opérations d'API GSS sur le contexte -- c'est-à-dire tester les critères d'acceptation.) L'argument cookie a déjà été décrit.

L'argument lock est un pointeur de structure rpc_gss_lock_t :

typedef struct {
bool_t              locked;
rpc_gss_rawcred_t   *raw_cred;
} rpc_gss_lock_t;
Ce paramètre permet à un serveur de mettre en oeuvre une qualité de protection et un service particuliers pour la session. La qualité de protection et le service sont indiqués dans la structure rpc_gss_rawcred_t décrite dans Exemple 8-5. (Un serveur ne doit pas changer les valeurs de service et de qualité de protection.) Lorsque le rappel défini par l'utilisateur est effectué, le champ locked est réglé à FALSE. Si le serveur règle le champ locked à TRUE, seules les requêtes ayant des valeurs de qualité de protection et de service correspondant à celles de la structure rpc_gss_rawcred_t seront acceptées.

Pour de plus amples renseignements, consultez la page de manuel rpc_gss_set_callback(3N).

Taille maximale des données

Deux fonctions -- rpc_gss_max_data_length() et rpc_gss_svc_max_data_length() -- permettent de déterminer la longueur maximale de données avant leur transformation par des mesures de sécurité et leur envoi "en ligne." Un processus de transformation de sécurité tel que le chiffrement change habituellement la taille des données transmises (la plupart du temps en les élargissant). Pour faire en sorte que les données ne soient pas élargies au point d'être inutilisables, ces deux fonctions -- la première étant la version côté client, et la deuxième la version côté serveur -- indiquent la taille maximale de pré-transformation pour un transport particulier.

Pour de plus amples renseignements, consultez les pages de manuel rpc_gss_max_data_length(3N) et rpc_gss_svc_max_data_length(3N).

Fonctions diverses

Plusieurs fonctions sont utiles pour obtenir des renseignements sur le système de sécurité installé :

Ces fonctions donnent au programmeur une certaine latitude afin d'éviter les paramètres de sécurité incorporés au programme dans ses applications. (Voir le Tableau 8-1 et la page de manuel rpcsec_gss(3N) pour la liste des fonctions RPCSEC_GSS.)

Fichiers connexes

RPCSEC_GSS utilise certains fichiers pour stocker des informations.

La table gsscred

Lorsqu'un serveur extrait les justificatifs d'identité de client associés à une requête, il peut obtenir soit le nom de principal du client (sous forme d'un pointeur de structure rpc_gss_principal_t), soit les justificatifs d'identité UNIX locaux (UID) de ce client. Des services tels que NFS exigent un justificatif d'identité UNIX local pour la vérification d'accès, mais d'autres non ; ils peuvent, par exemple, enregistrer le nom de principal, en tant que structure rpc_gss_principal_t, directement dans leurs propres listes de contrôle d'accès.


Remarque :

La correspondance entre le justificatif d'identité réseau d'un client (son nom de principal) et tout justificatif d'identité UNIX local n'est pas automatique -- elle doit être explicitement définie par l'administrateur de sécurité local.


Le fichier gsscred contient les justificatifs d'identité UNIX et réseau du client (par exemple, Kerberos V5). (Ce dernier est la représentation hexadécimale-ASCII de la structure rpc_gss_principal_t.) On y accède via XFN ; par conséquent, cette table peut être mise en oeuvre pour des fichiers, NIS ou NIS+, ou tout autre service de nom ultérieur pris en charge par XFN. Dans la hiérarchie XFN, cette table est identifiée comme this_org_unit/service /gsscred. La table gsscred est maintenue au moyen de l'utilitaire gsscred, qui permet aux administrateurs d'ajouter et de supprimer des utilisateurs et des mécanismes.

/etc/gss/qop et /etc/gss/mech

Pour fins de commodité, RPCSEC_GSS utilise des constantes de chaîne pour représenter des mécanismes et des paramètres de qualité de protection. Toutefois, les mécanismes sous-jacents exigent eux-mêmes que les mécanismes soient représentés en tant qu'identificateurs d'objets, et les qualités de protection sous forme de nombres entiers à 32-bits. En outre, pour chaque mécanisme, la bibliothèque partagée mettant en oeuvre les services pour ce mécanisme doit être spécifiée.

Le fichier /etc/gss/mech enregistre les informations suivantes sur tous les mécanismes installés sur un système : le nom du mécanisme, en format ASCII ; l'OID du mécanisme ; la bibliothèque partagée mettant en oeuvre les services fournis par ce mécanisme ; et, facultativement, le module de noyau mettant le service en oeuvre. Voici un exemple de ligne :


kerberos_v5   1.2.840.113554.1.2.2    gl/mech_krb5.so gl_kmech_krb5

Le fichier /etc/gss/qop enregistre, pour tous les mécanismes installés, toutes les qualités de protection prises en charge par chaque mécanisme, sous forme de chaîne ASCII et du nombre entier à 32-bits correspondant.

Les fichiers /etc/gss/mech et /etc/gss/qop sont créés lors de l'installation initiale des mécanismes de sécurité sur un système particulier.

Puisque plusieurs des sous-programmes RPC intégrés au noyau emploient des valeurs autres que des chaînes pour représenter le mécanisme et la qualité de protection, les applications peuvent utiliser les fonctions rpc_gss_mech_to_oid() et rpc_gss_qop_to_num() pour obtenir les équivalents de ces paramètres en format autre qu'une chaîne afin de tirer parti de ces sous-programmes.