GSSAPIHandler.cc

Go to the documentation of this file.
00001 // ----------------------------------------------------------------------------
00002 // CERTI - HLA RunTime Infrastructure
00003 // Copyright (C) 2002, 2003  ONERA
00004 //
00005 // This file is part of CERTI-libCERTI
00006 //
00007 // CERTI-libCERTI is free software ; you can redistribute it and/or
00008 // modify it under the terms of the GNU Lesser General Public License
00009 // as published by the Free Software Foundation ; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // CERTI-libCERTI is distributed in the hope that it will be useful, but
00013 // WITHOUT ANY WARRANTY ; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00015 // Lesser General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU Lesser General Public
00018 // License along with this program ; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00020 // USA
00021 //
00022 // $Id: GSSAPIHandler.cc,v 3.7 2008/12/07 20:16:14 gotthardp Exp $
00023 // ----------------------------------------------------------------------------
00024 
00025 #ifdef WITH_GSSAPI
00026 
00027 #include "GSSAPIHandler.hh"
00028 #include "PrettyDebug.hh"
00029 #include "SocketTCP.hh"
00030 
00031 namespace certi {
00032 
00033 static pdCDebug D("HLAGSSAPI", "(H-GSSAPI) - ");
00034 
00035 // ----------------------------------------------------------------------------
00039 void GSSAPIHandler::acquireCred(int InitOrAccept)
00040 {
00041     D.Out(pdInit, "GSSAPI: Acquire Credential.");
00042 
00043     Code = gss_acquire_cred(&Minor,
00044                             LocalName, // Principal Name
00045                             HLA_GSS_SESSION_DURATION, // Expiration delay
00046                             GSS_C_NULL_OID_SET,
00047                             InitOrAccept, // Cred. used to init.
00048                             &Credential, // Returned Credential
00049                             NULL,
00050                             NULL);
00051 
00052     detectError("GSSAPI: Acquire Credential");
00053 
00054 }
00055 
00056 // ----------------------------------------------------------------------------
00061 void GSSAPIHandler::acceptSecContext(SocketTCP *Socket)
00062 {
00063     // The Input and Output Buffers used by the initial Handshake.
00064 
00065     gss_buffer_desc InputToken = GSS_C_EMPTY_BUFFER ;
00066     gss_buffer_desc OutputToken = GSS_C_EMPTY_BUFFER ;
00067 
00068     int ReturnedFlags = 0 ;
00069     OM_uint32 TimeRec = 0 ;
00070 
00071     gss_cred_id_t DelegCredential ;
00072 
00073     // Prevent Re-entrant calls
00074 
00075     if (InitSecContext_Started == RTI_TRUE) {
00076         D.Out(pdExcept, "GSSAPI: Reentrant call of GSSHandler::InitSecContext.");
00077         printf("GSSAPI Fatal Error : Reentrant call in InitSecContext.\n");
00078         throw NetworkError("Reentrant call of InitSecContext.");
00079     }
00080 
00081     InitSecContext_Started = RTI_TRUE ;
00082     IsClient = RTI_FALSE ;
00083 
00084     // Check Local Principal Name
00085 
00086     if (LocalName == GSS_C_NO_NAME) {
00087         printf("GSSAPI: Local Name must be set before accept_sec_ctxt.\n");
00088         throw NetworkError("GSSAPI: Accept_Sec_Context: No name set.");
00089     }
00090 
00091 
00092     // Retrieve Credential
00093 
00094     acquireCred(GSS_C_ACCEPT);
00095 
00096 
00097     // Accept Security Context(Server Side)
00098 
00099     do {
00100 
00101         // Wait for peer's response if needed(InputToken may be allocated)
00102 
00103         getToken(Socket, InputToken);
00104 
00105         D.Out(pdInit, "GSSAPI: Received Security Context Token(%d bytes)",
00106               InputToken.length);
00107 
00108         // Accept Token
00109 
00110         Code = gss_accept_sec_context(&Minor,
00111                                       &Context, // Initially no context
00112                                       Credential,
00113                                       &InputToken, // Client Token
00114                                       GSS_C_NO_CHANNEL_BINDINGS,
00115                                       &RemoteName, // Client Name or NULL
00116                                       &MechType,
00117                                       &OutputToken,
00118                                       &ReturnedFlags,
00119                                       &TimeRec,
00120                                       &DelegCredential);
00121 
00122         detectError("GSSAPI: Accept Security Context");
00123 
00124         // If the Credential was delegated, print a warning.
00125 
00126         if (DelegCredential != GSS_C_NO_CREDENTIAL) {
00127             printf("GSSAPI: Warning : Client has delegated his credential.\n");
00128             gss_release_cred(&Minor, &DelegCredential);
00129         }
00130 
00131         // If a service was requested but is not available, print a warning.
00132 
00133         if (HLA_GSS_FLAGS & !ReturnedFlags) {
00134             printf("GSSAPI: Some unavailable service was requested.\n");
00135             printf("GSSAPI: Returned service flags are : 0x%X\n", ReturnedFlags);
00136         }
00137 
00138         D.Out(pdInit, "GSSAPI: Security Context accepted.");
00139 
00140         // Free Input Token
00141 
00142         if (InputToken.value != NULL)
00143             free(InputToken.value);
00144 
00145         InputToken.length = 0 ;
00146         InputToken.value = NULL ;
00147 
00148         // Send Output token to peer and then release it.
00149 
00150         if (OutputToken.length > 0) {
00151 
00152             D.Out(pdInit,
00153                   "GSSAPI: Accept Sec Context sending answer Token(%d bytes).",
00154                   OutputToken.length);
00155 
00156             sendToken(Socket, OutputToken);
00157 
00158             gss_release_buffer(&Minor, &OutputToken);
00159 
00160             OutputToken.length = 0 ;
00161             OutputToken.value = NULL ;
00162         }
00163 
00164     } while (Code != GSS_S_COMPLETE); // Loop until no response is needed
00165 
00166 }
00167 
00168 // ----------------------------------------------------------------------------
00170 GSSAPIHandler::GSSAPIHandler()
00171 {
00172     InitSecContext_Started = RTI_FALSE ;
00173 
00174     LocalName = GSS_C_NO_NAME ;
00175     RemoteName = GSS_C_NO_NAME ;
00176 
00177     Credential = GSS_C_NO_CREDENTIAL ;
00178     Context = GSS_C_NO_CONTEXT ;
00179 
00180     MechType = GSS_C_NULL_OID ;
00181 
00182     IsClient = RTI_FALSE ; // Reset by Init and Accept Sec. Context
00183 }
00184 
00185 // ----------------------------------------------------------------------------
00187 GSSAPIHandler::~GSSAPIHandler()
00188 {
00189     D.Out(pdTerm, "GSSAPI: Releasing GSSAPI objects.");
00190 
00191     // Release Names
00192 
00193     if (LocalName != GSS_C_NO_NAME) {
00194         gss_release_name(&Minor, &LocalName);
00195         LocalName = GSS_C_NO_NAME ;
00196     }
00197 
00198     if (RemoteName != GSS_C_NO_NAME) {
00199         gss_release_name(&Minor, &RemoteName);
00200         RemoteName = GSS_C_NO_NAME ;
00201     }
00202 
00203     // Release Credential
00204 
00205     if (Credential != GSS_C_NO_CREDENTIAL) {
00206         gss_release_cred(&Minor, &Credential);
00207         Credential = GSS_C_NO_CREDENTIAL ;
00208     }
00209 
00210     // Release Context(Client only)
00211 
00212     if ((IsClient == RTI_TRUE) && (Context != GSS_C_NO_CONTEXT)) {
00213 
00214         gss_delete_sec_context(&Minor, &Context, GSS_C_NO_BUFFER);
00215 
00216         D.Out(pdTerm, "GSSAPI: Released Context.");
00217 
00218         Context = GSS_C_NO_CONTEXT ;
00219     }
00220 }
00221 
00222 // ----------------------------------------------------------------------------
00226 void GSSAPIHandler::detectError(char *ContextString)
00227 {
00228     gss_buffer_desc ErrorMessage ;
00229 
00230     if (GSS_ERROR(Code)) {
00231 
00232         gss_display_status(&Minor, Code,
00233                            GSS_C_GSS_CODE, GSS_MECH_DES,
00234                            NULL, &ErrorMessage);
00235 
00236         if (ContextString != NULL)
00237             printf("%s: %s\n", ContextString, (char *)ErrorMessage.value);
00238         else
00239             printf("GSSAPI: %s\n", (char *)ErrorMessage.value);
00240 
00241         gss_release_buffer(&Minor, &ErrorMessage);
00242 
00243         throw NetworkError("Error in GSSAPI(see console output)");
00244     }
00245 
00246 }
00247 
00248 // ----------------------------------------------------------------------------
00252 void GSSAPIHandler::getMessage(SocketTCP *Socket,
00253                                gss_buffer_t IncomingBuffer)
00254 {
00255     gss_buffer_desc SealedToken ;
00256     gss_buffer_desc Signature ;
00257 
00258     int ConfWasUsed ;
00259     int QOPState ;
00260 
00261     switch(RTI_GSSAPI_USAGE) {
00262 
00263       case RTI_GSS_NOTHING:
00264         // Get non-encrypted token.
00265         getToken(Socket, SealedToken);
00266 
00267         // 'Copy' non encrypted Token into Incoming Buffer(just change pointers)
00268         IncomingBuffer->value = SealedToken.value ;
00269         IncomingBuffer->length = SealedToken.length ;
00270 
00271         // Don't free SealedToken ! IncomingBuffer will be freed by a call
00272         // to GSSAPIHandler::ReleaseBuffer.
00273         break ;
00274 
00275       case RTI_GSS_SIGN_ONLY:
00276         // Get Token(ie "Buffer Length" + "Buffer" + "Signature Token")
00277         getToken(Socket, SealedToken);
00278 
00279         // Get Buffer length
00280         memcpy(& (IncomingBuffer->length), SealedToken.value, sizeof(OM_uint32));
00281 
00282         // Get Buffer
00283         IncomingBuffer->value
00284             = (void *) calloc(IncomingBuffer->length, sizeof(char));
00285 
00286         memcpy(IncomingBuffer->value,
00287                (char *) SealedToken.value + sizeof(OM_uint32),
00288                IncomingBuffer->length);
00289 
00290         // Check Signature
00291         Signature.value
00292             = (char *)SealedToken.value + sizeof(OM_uint32) + IncomingBuffer->length ;
00293         Signature.length
00294             = SealedToken.length - sizeof(OM_uint32) - IncomingBuffer->length ;
00295 
00296         Code = gss_verify(&Minor,
00297                           Context,
00298                           IncomingBuffer,
00299                           &Signature,
00300                           &QOPState);
00301 
00302         detectError("GSSAPI: Get Message[verify]");
00303 
00304         // Free memory
00305         free(SealedToken.value);
00306 
00307         break ;
00308 
00309       case RTI_GSS_ENCRYPT:
00310 
00311         // Get encrypted token.
00312         getToken(Socket, SealedToken);
00313 
00314         // Decrypt Token
00315         Code = gss_unseal(&Minor,
00316                           Context,
00317                           &SealedToken,
00318                           IncomingBuffer,
00319                           &ConfWasUsed,
00320                           &QOPState);
00321 
00322         free(SealedToken.value);
00323         break ;
00324 
00325       default:
00326         printf("BAD VALUE FOR RTI_GSSAPI_USAGE\n");
00327         throw RTIinternalError();
00328     }
00329 
00330     detectError("GSSAPI: Get Message[unseal]");
00331 }
00332 
00333 // ----------------------------------------------------------------------------
00339 char *GSSAPIHandler::getRemoteName()
00340 {
00341     gss_buffer_desc OutputName ;
00342     gss_OID OutputNameType ;
00343     char *Buffer ;
00344 
00345     gss_display_name(&Minor,
00346                      RemoteName,
00347                      &OutputName,
00348                      &OutputNameType);
00349 
00350     detectError("GSSAPI: GetRemoteName");
00351 
00352     // Copy OutputName into char buffer.
00353 
00354     Buffer = (char *) malloc((OutputName.length + 1) * sizeof(char));
00355     strncpy(Buffer, (char *) OutputName.value, OutputName.length);
00356     Buffer[OutputName.length] = '\0' ;
00357 
00358     releaseBuffer(&OutputName);
00359 
00360     // Remove any '@'(network address part)
00361 
00362     if (strchr(Buffer, '@') != NULL)
00363         strchr(Buffer, '@')[0] = '\0' ;
00364 
00365     D.Out(pdInit, "GSSAPI: Peer is %s.", Buffer);
00366 
00367     return Buffer ;
00368 }
00369 
00370 // ----------------------------------------------------------------------------
00378 void GSSAPIHandler::getToken(SocketTCP *Socket, gss_buffer_desc &Buffer)
00379 {
00380     // Read Token size.
00381     Socket->SocketTCP::receive((void *) &Buffer.length,
00382                                sizeof(Buffer.length));
00383 
00384     // Allocate memory for content.
00385     Buffer.value = (void *) calloc(Buffer.length, sizeof(char));
00386 
00387     // Read content.
00388     Socket->SocketTCP::receive((void *) Buffer.value,
00389                                Buffer.length);
00390 }
00391 
00392 // ----------------------------------------------------------------------------
00397 void GSSAPIHandler::initSecContext(SocketTCP *Socket)
00398 {
00399     // The Input and Output Buffers used by the initial Handshake.
00400 
00401     gss_buffer_desc InputToken = GSS_C_EMPTY_BUFFER ;
00402     gss_buffer_desc OutputToken = GSS_C_EMPTY_BUFFER ;
00403 
00404     gss_buffer_t InputTokenPtr = GSS_C_NO_BUFFER ;
00405 
00406     int ReturnedFlags = 0 ;
00407     OM_uint32 ContextValidity = 0 ;
00408 
00409     // Prevent Re-entrant calls
00410 
00411     if (InitSecContext_Started == RTI_TRUE) {
00412         D.Out(pdExcept, "GSSAPI: Reentrant call of GSSHandler::InitSecContext.");
00413         printf("GSSAPI Fatal Error : Reentrant call in InitSecContext.\n");
00414         throw NetworkError("Reentrant call of InitSecContext.");
00415     }
00416 
00417     InitSecContext_Started = RTI_TRUE ;
00418     IsClient = RTI_TRUE ;
00419 
00420     // Check Local and Remote Names
00421 
00422     if ((LocalName == GSS_C_NO_NAME) || (RemoteName == GSS_C_NO_NAME)) {
00423         printf("GSSAPI: Local/Remote Name must be set before init_sec_ctxt.\n");
00424         throw NetworkError("GSSAPI: Init_Sec_Context: No name set.");
00425     }
00426 
00427 
00428     // Retrieve Credential
00429 
00430     acquireCred(GSS_C_INITIATE);
00431 
00432     D.Out(pdInit, "GSSAPI: Init Sec Context.");
00433 
00434     // Get Security Context(Client Side)
00435 
00436     do {
00437 
00438         if (InputToken.length != 0)
00439             InputTokenPtr = &InputToken ;
00440         else
00441             InputTokenPtr = GSS_C_NO_BUFFER ;
00442 
00443         Code = gss_init_sec_context(&Minor,
00444                                     Credential,
00445                                     &Context,
00446                                     RemoteName,
00447                                     GSS_C_NULL_OID,
00448                                     HLA_GSS_FLAGS, // See RTIconfig.hh
00449                                     HLA_GSS_SESSION_DURATION, // See RTIconfig.hh
00450                                     GSS_C_NO_CHANNEL_BINDINGS,
00451                                     InputTokenPtr,
00452                                     &MechType,
00453                                     &OutputToken,
00454                                     &ReturnedFlags,
00455                                     &ContextValidity);
00456 
00457         detectError("GSSAPI: Init Security Context");
00458 
00459         // If a service was requested but is not available, print a warning.
00460 
00461         if (HLA_GSS_FLAGS & !ReturnedFlags) {
00462             printf("GSSAPI: Some unavailable service was requested.\n");
00463             printf("GSSAPI: Returned service flags are : 0x%X\n", ReturnedFlags);
00464         }
00465 
00466         D.Out(pdInit, "GSSAPI: Security Context initiated(Validity: %d).",
00467               ContextValidity);
00468 
00469         // Free Input Token(allocated in a previous loop)
00470 
00471         if (InputToken.value != NULL)
00472             free(InputToken.value);
00473 
00474         InputToken.length = 0 ;
00475         InputToken.value = NULL ;
00476 
00477         // Send Output token to peer and then release it.
00478 
00479         if (OutputToken.length > 0) {
00480 
00481             D.Out(pdInit, "GSSAPI: Init Sec Context sending Token(%d bytes).",
00482                   OutputToken.length);
00483 
00484             sendToken(Socket, OutputToken);
00485 
00486             gss_release_buffer(&Minor, &OutputToken);
00487 
00488             OutputToken.length = 0 ;
00489             OutputToken.value = NULL ;
00490         }
00491 
00492         // Wait for peer's response if needed(InputToken may be allocated)
00493 
00494         if (Code==GSS_S_CONTINUE_NEEDED) {
00495 
00496             D.Out(pdInit, "GSSAPI: Init Sec Context waiting for server answer...");
00497 
00498             getToken(Socket, InputToken);
00499         }
00500 
00501     } while (Code != GSS_S_COMPLETE); // Loop until no response is needed
00502 
00503 }
00504 
00505 // ----------------------------------------------------------------------------
00509 void GSSAPIHandler::releaseBuffer(gss_buffer_t IncomingBuffer)
00510 {
00511     switch(RTI_GSSAPI_USAGE) {
00512 
00513       case RTI_GSS_NOTHING:
00514       case RTI_GSS_SIGN_ONLY:
00515         // Buffer was allocated by GetToken
00516         free(IncomingBuffer->value);
00517         IncomingBuffer->value = NULL ;
00518         IncomingBuffer->length = 0 ;
00519         break ;
00520 
00521       case RTI_GSS_ENCRYPT:
00522         gss_release_buffer(&Minor, IncomingBuffer);
00523     }
00524 }
00525 
00526 // ----------------------------------------------------------------------------
00528 void
00529 GSSAPIHandler::sendMessage(SocketTCP *Socket,
00530                            gss_buffer_t OutcomingBuffer)
00531 {
00532     gss_buffer_desc SealedToken ;
00533     gss_buffer_desc SignatureToken ;
00534 
00535     OM_uint32 OutLength = OutcomingBuffer->length ;
00536     void *OutValue = OutcomingBuffer->value ;
00537     int ConfState ;
00538 
00539     detectError("GSSAPI: Seal Message");
00540 
00541     switch(RTI_GSSAPI_USAGE) {
00542 
00543       case RTI_GSS_NOTHING:
00544         // Send clear-text message.
00545         sendToken(Socket, *OutcomingBuffer);
00546         break ;
00547 
00548       case RTI_GSS_SIGN_ONLY:
00549         // Compute Signature Token
00550         Code = gss_sign(&Minor,
00551                         Context,
00552                         GSS_C_QOP_DEFAULT,
00553                         OutcomingBuffer,
00554                         &SignatureToken);
00555 
00556         detectError("GSSAPI: Send Message[sign]");
00557 
00558         // Compute SealedToken : "Buffer Length" + "Buffer" + "Signature Token"
00559         SealedToken.length = sizeof(OM_uint32);
00560         SealedToken.length += OutLength ;
00561         SealedToken.length += SignatureToken.length ;
00562 
00563         SealedToken.value = (void *) calloc(SealedToken.length, sizeof(char));
00564 
00565         // Copy OutcomingBuffer length
00566         memcpy(SealedToken.value, & (OutLength), sizeof(OM_uint32));
00567 
00568         // Copy OutcomingBuffer
00569         memcpy((char *) SealedToken.value + sizeof(OM_uint32),
00570                OutValue, OutLength);
00571 
00572         // Copy SignatureToken
00573         memcpy((char *) SealedToken.value + sizeof(OM_uint32) + OutLength,
00574                SignatureToken.value, SignatureToken.length);
00575 
00576         // Send resulting Token
00577         sendToken(Socket, SealedToken);
00578 
00579         // Free memory
00580         free(SealedToken.value);
00581         gss_release_buffer(&Minor, &SignatureToken);
00582 
00583         break ;
00584 
00585       case RTI_GSS_ENCRYPT:
00586 
00587         Code = gss_seal(&Minor,
00588                         Context,
00589                         RTI_TRUE,
00590                         GSS_C_QOP_DEFAULT,
00591                         OutcomingBuffer,
00592                         &ConfState,
00593                         &SealedToken);
00594 
00595         detectError("GSSAPI: Send Message[seal]");
00596 
00597         sendToken(Socket, SealedToken);
00598         gss_release_buffer(&Minor, &SealedToken);
00599     }
00600 
00601 }
00602 
00603 // ----------------------------------------------------------------------------
00611 void GSSAPIHandler::sendToken(SocketTCP *Socket, gss_buffer_desc Buffer)
00612 {
00613     // Write Token Length
00614     Socket->SocketTCP::send((void *) &Buffer.length,
00615                             sizeof(Buffer.length));
00616 
00617     // Write Token Content
00618     Socket->SocketTCP::send((void *) Buffer.value,
00619                             Buffer.length);
00620 }
00621 
00622 // ----------------------------------------------------------------------------
00624 void GSSAPIHandler::setLocalName(char *PrincipalName)
00625 {
00626     char *p ;
00627     char bidon[80] ;
00628 
00629     gss_buffer_desc LocalBuffer = GSS_C_EMPTY_BUFFER ;
00630 
00631     strcpy(bidon, PrincipalName);
00632 
00633     // Put Principal Name in GSSAPI buffer
00634 
00635     if ((PrincipalName == NULL) || (strlen(PrincipalName) == 0))
00636         throw NetworkError("Bad Local Principal Name.");
00637 
00638     // Remove any machine name(like in rtip@jocaste)
00639     p = strchr(bidon, '@');
00640     if (p != NULL) {
00641         *p = '\0' ;
00642     }
00643 
00644     LocalBuffer.value = bidon ;
00645     LocalBuffer.length = strlen(bidon) + 1 ;
00646 
00647     // Give Name to GSSAPI
00648 
00649     Code = gss_import_name(&Minor,
00650                            (gss_buffer_t) &LocalBuffer,
00651                            GSS_C_NULL_OID,
00652                            &LocalName);
00653 
00654     D.Out(pdInit, "GSSAPI: Local Name set to %s.", bidon);
00655 
00656     detectError("GSSAPI/setLocalName");
00657 }
00658 
00659 // ----------------------------------------------------------------------------
00661 
00663 void GSSAPIHandler::setRemoteName(char *PrincipalName)
00664 {
00665     gss_buffer_desc LocalBuffer = GSS_C_EMPTY_BUFFER ;
00666 
00667     // Put Principal Name in GSSAPI buffer
00668 
00669     if ((PrincipalName == NULL) || (strlen(PrincipalName) == 0))
00670         throw NetworkError("Bad Local Principal Name.");
00671 
00672     LocalBuffer.value = PrincipalName ;
00673     LocalBuffer.length = strlen(PrincipalName) + 1 ;
00674 
00675     // Give Name to GSSAPI
00676 
00677     Code = gss_import_name(&Minor,
00678                            (gss_buffer_t) &LocalBuffer,
00679                            GSS_C_NULL_OID,
00680                            &RemoteName);
00681 
00682     D.Out(pdInit, "GSSAPI: Remote Name set to %s.", PrincipalName);
00683 
00684     detectError("GSSAPI/setRemoteName");
00685 }
00686 
00687 }
00688 
00689 #endif // WITH_GSSAPI
00690 
00691 // $Id: GSSAPIHandler.cc,v 3.7 2008/12/07 20:16:14 gotthardp Exp $

Generated on Thu Apr 30 15:53:49 2009 for CERTIDeveloperDocumentation by doxygen 1.5.5