Digital DCE for OpenVMS VAX and OpenVMS Alpha
Product Guide

Previous Contents Index

Chapter 12
The Generic Security Service Application Programming Interface

The Generic Security Service (GSS) provides an application programming interface that lets you extend DCE security to distributed applications that handle network communications by themselves.

Figure 12-1 shows the relationships among the interfaces to the DCE security server and the relationship of Security interfaces to DCE applications.

Figure 12-1 DCE Security and the DCE Application Environment

This chapter provides the following information, which augments the information in the OSF DCE Application Development Guide:

For detailed information about the GSSAPI routines, see the Digital DCE for OpenVMS VAX and OpenVMS Alpha Reference Guide.

12.1 About the Generic Security Service API

With GSSAPI, you can include established applications in DCE and ensure the security and integrity of the applications and their data. The GSSAPI is defined in the Internet RFC 1508, Generic Security Service Application Programming Interface, and RFC 1509, Generic Security Service API : C-bindings. Additions have been made to the API to accommodate peer-to-peer applications in the DCE.

In communications between peer applications in a DCE environment, the application that establishes the secure connection is the context initiator or simply initiator. The context initiator is like a DCE RPC client. The application that accepts the secure connection is the context acceptor or simply acceptor. The context acceptor is like a DCE RPC server.

GSSAPI credentials enable applications to identify themselves as DCE principals.

The GSS available with DCE includes two sets of routines:

While some GSS routines use RPC themselves, applications that use GSS can themselves be designed and implemented without RPC and still run securely on DCE servers.

The GSSAPI combines authentication and authorization under a single security mechanism type. The security mechanism provides applications a choice of either authenticated Kerberos security or authenticated PAC authorization under DCE Security.

As an alternative to authenticated RPC, the GSSAPI provides an API to the DCE Authentication Service and Privilege Service. The Login facility and authenticated RPC or GSSAPI encapsulate interactions between a principal and the Privilege Service.

12.2 GSSAPI and Authentication

This section explains concepts related to authentication.

With authenticated RPC, you can choose the authentication protocol and authorization protocol that your applications use. With GSSAPI, you select one of the two supported security mechanisms: DCE Security or Kerberos. Both DCE Security and Kerberos use the DCE shared-secret authentication protocol. However, if you select DCE Security, your applications use the authenticated PAC authorization protocol, allowing the context acceptor to use DCE ACLs to determine whether access should be permitted. If you select Kerberos as the security mechanism, the applications use a name-based authorization protocol, where the context acceptor receives only the context initiator's registered name.

12.2.1 GSSAPI and Protection Levels

Protection levels specify how much of network messages exchanged by principals are encrypted. As a rule, the higher the protection level, the greater the negative impact on performance.

The DCE implementation of the GSSAPI supports only one level, or quality, of protection, which applications can apply using the GSSAPI per-message protection services. Applications request per-message protection using GSSAPI routines gss_sign( ) and gss_seal( ). The routines offer the following protection:

12.2.2 A Walkthrough of DCE Application Authentication Using GSSAPI

This section describes the process by which applications that manage network communications without RPC can use GSSAPI and DCE Security to authenticate the applications with which they communicate.

The peer applications establish a secure connection in the following way. The numbers of the stages described correspond to callouts in Figure 12-2.

Figure 12-2 The Context Initiator Authenticates a Context Acceptor

  1. The context initiator uses the gss_init_sec_context( ) routine to request a ticket from the DCE Security server that will allow the initiator to communicate with the context acceptor.
    The initiator's security runtime creates an envelope that contains:
    The security runtime sends the envelope to the Authentication Service. The Authentication Service does the following:
    The ticket contains the following:
    The Authentication Service then encrypts the ticket under the acceptor's secret key. It sends the ticket (encrypted under the acceptor's secret key) and the fourth conversation key (encrypted under the third conversation key) to the initiator's security runtime.
  2. The initiator's security runtime:
  3. GSSAPI holds onto the fourth conversation key and creates a token containing:
    It sends the token to the initiator, which forwards it to the acceptor.
  4. The acceptor calls a GSSAPI routine to separate the ticket and the encrypted timestamp, and send them to the acceptor's security runtime.
  5. The acceptor's security runtime:
  6. The acceptor's GSSAPI holds onto the fourth conversation key and the PAC, and creates a token containing a success message. It passes the token to the acceptor.
  7. The acceptor forwards the token to the initiator.
  8. The initiator passes the token to its GSSAPI to send to the security runtime.
  9. The security runtime tries to decrypt the message. If it can, it sends a message to the GSSAPI that the acceptor's identity is authenticated. If it cannot, it sends a failure message.
    The context acceptor and context initiator can use the fourth conversation key in future communications calling the gss_sign( ) and gss_seal( ) routines. The context acceptor can get the initiator's PAC, so it can identify the initiator, by calling the gss_extract_PAC routine to identify the initiator. If the context initiator wants to communicate with a new context acceptor, it must acquire a ticket to that context acceptor.

12.3 GSSAPI Credentials

A GSSAPI credential is a data structure that provides proof of an application's claim to a principal name. An application uses a credential to establish its global identity. The global identity can be, but is not necessarily, related to the local user name under which the application (either the initiator or the acceptor) is running.

A credential can consist of either of the following:

Table 12-1 lists the types of credentials.

Table 12-1 Types of Credentials
Credential Type Consists of... Identifies applications that...
INITIATE Login context only Only initiate security contexts
ACCEPT Principal name and associated entry key table Only accept security contexts
BOTH Login context and principal name with key table entry Can either initiate or accept security contexts

Credentials are maintained internally to GSSAPI. When they establish a security context, applications use credential handles to point to the credentials they need.

When an application initiates or accepts a security context, it can use GSSAPI routines with either a default credential or a specific credential handle. This chapter discusses how applications:

For detailed information on the GSSAPI routines referred to in this chapter, see the OSF DCE Application Development Reference.

12.3.1 Using Default Credentials

A default credential is a credential that is:

When an application calls the GSSAPI routine to either initiate (gss_init_sec_context( )) or accept (gss_accept_sec_context( )) a security context, it can specify the use of its default credential.

Use default credentials to help ensure the portability of your applications. Initiate a Security Context

To use a default credential when initiating a security context, an application calls the gss_init_sec_context( ) routine and specifies GSS_C_NO_CREDENTIAL as the input claimant credential handle to the routine. The routine uses the initiator's DCE default login context to generate the default credential. The credential is an INITIATE type credential.

You can change the default login context by calling the DCE sec_login routines. For information on the sec_login routines, see the OSF DCE Application Development Reference. Accept a Security Context

To use a default credential when accepting a security context, an application calls the gss_accept_security_context( ) routine and specifies GSS_C_NO_CREDENTIAL as the verifier credential handle to the routine. The GSSAPI uses a principal name registered for the context acceptor to generate the default credential handle. The credential is an ACCEPT credential type.

12.3.2 Creating New Credential Handles

An application can create a new credential handle to pass to the gss_init_sec_context( ) or gss_accept_sec_context( ) routines. An application might create a credential handle rather than use the default credential for the following reasons: Initiating a Security Context with New Credential Handles

To create a credential handle for an INITIATE credential type, the application calls the gssdce_login_context_to_cred( ) routine and specifies its login context as input to the routine. The routine creates a credential handle that points to the credential consisting of that login context.

An application can also use a BOTH type credential to initiate a security context. Use the gss_acquire_cred( ) routine to create a BOTH type credential, as explained in the next section.

When the application uses a BOTH credential, the gss_acquire_cred( ) routine creates a login context from the key table information. Then, it uses the login context to create the a credential. For more details, refer to the OSF DCE Application Development Reference. Accepting a Security Context Using New Credential Handles

To create new credential handle for an ACCEPT or BOTH type credential, an application calls the gss_acquire_cred( ) routine.

The gss_acquire_cred( ) routine uses a principal name and its entry in the key table to generate the credential handle. If the principal name has not yet been registered (using gssdce_register_acceptor_identity( ) or the rpc_server_register_auth_info( ) routines), the gss_acquire_cred( ) routine automatically registers it.

Chapter 13
Object-Oriented RPC

Digital DCE for OpenVMS VAX and OpenVMS Alpha contains the Interface Definition Language (IDL). The IDL supports a number of C++ language syntax features that provide a distributed object framework. The DCE RPC runtime environment supports C++ bindings to remote objects. The combination of these new features creates an Object-Oriented RPC.

In an object-oriented application, the implementation details of data are hidden. The developer can model data as objects that provide their own interfaces and implementation. Objects can be reused as building blocks or components in a solution to complex problems.

The Interface Definition Language allows the DCE application developer to define an interface to remote procedures. With Object-Oriented RPC, you can use the IDL language to define an interface to remote objects. The interface is treated as an abstract class and its operations are treated like the public methods exported by the class.

When you write a distributed application using Object-Oriented RPC, you can do the following:

This chapter contains the following sections:

Appendix A describes two examples that implement a 2x2 matrix in a server application. The examples also allow the client application to manipulate the matrix with an IDL interface.

The Digital DCE for OpenVMS VAX and OpenVMS Alpha Reference Guide contains reference information (IDL-supplied member functions, ACF attributes, and exceptions) for Object-Oriented RPC.

13.1 Overview of C++

This section presents a brief overview of the C++ language for DCE application developers who are unfamiliar with C++. If you are familiar with C++, you can skip this section. Refer to the C++ reference documentation for more specific details of the language.

13.1.1 Class Definition

A class definition is used to define a new data type to the compiler. Class definitions are more powerful than traditional data type definitions because they allow data and functions to be grouped together. They also offer protection levels for the data and functions they contain to control how the elements of the class can be accessed.

A C++ class definition defines the operations (also known as methods) and data supported by a particular class. Each operation and data element may have one of three different protection attributes associated with it. A public protection attribute is the most open protection level because it allows free access to the operation or data element it represents. Protected and private protection levels are more restrictive in allowing access to the elements with which they are associated.

A common object-oriented technique is to define a public interface for an object and to make that interface available to users. In C++ this is done by creating an abstract class and using the polymorphic behavior of the language to implement the methods defined in the abstract or interface class. (See Section 13.1.4 for more information about polymorphic behavior.)

13.1.2 Objects

An instantiation of a C++ class is called an object. There can be any number of objects of the same class type in a program, limited only by the amount of memory available to run the program. Each object has its own exclusive data members. Access to the object's data and operations is governed by the protection attribute of the data or operation.

A C++ object has an implied this pointer associated with it. The this pointer distinguishes one object from another at runtime and requires no user intervention when invoking operations or accessing data. The C++ compiler generates code that supplies the implied this pointer.

In the following code fragment, the class type Test contains an operation and data element that can be referenced by any object of type Test. The variable f is an object or class instantiation. A message is sent to f asking for the value of its encapsulated data.

class Test { 
 int x; 
 int getData() { return x; } 
int data; 
Test f;              // f is an object 
data = f.getData();  // send a message to f 

13.1.3 Class Inheritance

C++ supports the concept of class inheritance. If class B inherits from class A, then class B is termed a derived class and class A is a base class. A derived class inherits all of the public member functions and data from the base class. This allows access to the base class members from an object that has a derived class type. A derived class is said to have an is-a relationship with the base class. This means that an object of class type B can also be considered as an object of class type A. A B object can be assigned to a variable of type A.

13.1.4 Polymorphic Operations

Polymorphism means many forms. The major benefits of polymorphism are that it makes objects more independent of each other and it allows new objects to be added with minimal changes to existing objects.

For example, when the same operation is defined in both the base class and derived class, associating the virtual keyword with the operation name in the base class causes an invocation of the operation from a base class pointer or reference to automatically forward the call to the derived object. This is desirable in the case where a derived object is assigned to a base object, because it allows the programmer to interact with the base definition but allows the runtime support to interact with the multitude of different objects that may be derived from the base class.

The following code fragment illustrates inheritance and virtual functions.

class Base { 
     virtual void op1() { cout << "I'm in Base::op1()n";  } 
     void op2()         { cout << "I'm in Base::op2()n";  } 
class Derived : public Base { 
     void op1()         { cout << "I'm in Derived::op1()n";  } 
     void op2()         { cout << "I'm in Derived::op2()n";  } 
Derived d; 
Base    *pb = &d; // pointer to the Base part of object d 
Derived *pd = &d; // pointer to the Derived part of object d 
pd-) op1();        // prints "I'm in Derived::op1()" 
pd->op2();        // prints "I'm in Derived::op2()" 
pb->op1();        // prints "I'm in Derived::op1()" 
pb->op2();        // prints "I'm in Base::op2()" 

Previous Next Contents Index