Movatterモバイル変換


[0]ホーム

URL:


Go to main content
oracle home

Developer's Guide to Oracle® Solaris 11.4 Security

Exit Print View

 
Search Scope:
  »  ...Documentation Home  »  Oracle Solaris 11.4 Information Library  »  Developer's Guide to Oracle® ...  »  GSS-API Server Example  »  Receiving Data From a Client
Updated: November 2020
 
 

Receiving Data From a Client

After checking forinetd, thegss-server program then callssign_server(), which does the main work of the program.sign_server() first establishes the context by callingserver_establish_context().

    sign_server() performs the following tasks:

  • Accepts the context

  • Unwraps the data

  • Signs the data

  • Returns the data

These tasks are described in the subsequent sections. The followingsource code illustrates thesign_server() function.

Example 22  GSSAPI Serversign_server() Function
int sign_server(s, server_creds)     int s;     gss_cred_id_t server_creds;{     gss_buffer_desc client_name, xmit_buf, msg_buf;     gss_ctx_id_t context;     OM_uint32 maj_stat, min_stat;     int i, conf_state, ret_flags;     char*cp;          /* Establish a context with the client */     if (server_establish_context(s, server_creds, &context,  &client_name, &ret_flags) < 0)return(-1);       printf("Accepted connection: \"%.*s\"\n",    (int) client_name.length, (char *) client_name.value);     (void) gss_release_buffer(&min_stat, &client_name);     for (i=0; i < 3; i++)     if (test_import_export_context(&context))     return -1;     /* Receive the sealed message token */     if (recv_token(s, &xmit_buf) < 0)return(-1);       if (verbose && log) {fprintf(log, "Sealed message token:\n");print_token(&xmit_buf);     }     maj_stat = gss_unwrap(&min_stat, context, &xmit_buf, &msg_buf,   &conf_state, (gss_qop_t *) NULL);     if (maj_stat != GSS_S_COMPLETE) {display_status("unsealing message", maj_stat, min_stat);return(-1);     } else if (! conf_state) {fprintf(stderr, "Warning!  Message not encrypted.\n");     }     (void) gss_release_buffer(&min_stat, &xmit_buf);     fprintf(log, "Received message: ");     cp = msg_buf.value;     if ((isprint(cp[0]) || isspace(cp[0])) && (isprint(cp[1]) || isspace(cp[1]))) {fprintf(log, "\"%.*s\"\n", msg_buf.length, msg_buf.value);     } else {printf("\n");print_token(&msg_buf);     }       /* Produce a signature block for the message */     maj_stat = gss_get_mic(&min_stat, context, GSS_C_QOP_DEFAULT,    &msg_buf, &xmit_buf);     if (maj_stat != GSS_S_COMPLETE) {display_status("signing message", maj_stat, min_stat);return(-1);     }     (void) gss_release_buffer(&min_stat, &msg_buf);     /* Send the signature block to the client */     if (send_token(s, &xmit_buf) < 0)return(-1);     (void) gss_release_buffer(&min_stat, &xmit_buf);     /* Delete context */     maj_stat = gss_delete_sec_context(&min_stat, &context, NULL);     if (maj_stat != GSS_S_COMPLETE) {display_status("deleting context", maj_stat, min_stat);return(-1);     }     fflush(log);     return(0);}

Accepting a Context

Establishing a contexttypically involves a series of token exchanges between the client and theserver. Both context acceptance and context initialization should be performedin loops to maintain program portability. The loop for accepting a contextis very similar to the loop for establishing a context, although in reverse.Compare withEstablishing a Security Context With the Server.

The following source code illustrates theserver_establish_context() function.

Example 23  GSSAPI Serverserver_establish_context() Function
/* * Function: server_establish_context * * Purpose: establishes a GSS-API context as a specified service with * an incoming client, and returns the context handle and associated * client name * * Arguments: * *      s               (r) an established TCP connection to the client *      service_creds   (r) server credentials, from gss_acquire_cred *      context         (w) the established GSS-API context *      client_name     (w) the client's ASCII name * * Returns: 0 on success, -1 on failure * * Effects: * * Any valid client request is accepted.  If a context is established, * its handle is returned in context and the client name is returned * in client_name and 0 is returned.  If unsuccessful, an error * message is displayed and -1 is returned. */int server_establish_context(s, server_creds, context, client_name, ret_flags)     int s;     gss_cred_id_t server_creds;     gss_ctx_id_t *context;     gss_buffer_t client_name;     OM_uint32 *ret_flags;{     gss_buffer_desc send_tok, recv_tok;     gss_name_t client;     gss_OID doid;     OM_uint32 maj_stat, min_stat, acc_sec_min_stat;     gss_buffer_desc    oid_name;     *context = GSS_C_NO_CONTEXT;          do {          if (recv_token(s, &recv_tok) < 0)               return -1;          if (verbose && log) {              fprintf(log, "Received token (size=%d): \n", recv_tok.length);              print_token(&recv_tok);          }          maj_stat =               gss_accept_sec_context(&acc_sec_min_stat,                                      context,                                      server_creds,                                      &recv_tok,                                      GSS_C_NO_CHANNEL_BINDINGS,                                      &client,                                      &doid,                                      &send_tok,                                      ret_flags,                                      NULL,     /* ignore time_rec */                                      NULL);    /* ignore del_cred_handle */          (void) gss_release_buffer(&min_stat, &recv_tok);          if (send_tok.length != 0) {               if (verbose && log) {                    fprintf(log,                          "Sending accept_sec_context token (size=%d):\n",                          send_tok.length);                    print_token(&send_tok);               }               if (send_token(s, &send_tok) < 0) {                    fprintf(log, "failure sending token\n");                    return -1;               }               (void) gss_release_buffer(&min_stat, &send_tok);          }          if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {               display_status("accepting context", maj_stat,                              acc_sec_min_stat);               if (*context == GSS_C_NO_CONTEXT)                       gss_delete_sec_context(&min_stat, context,                                              GSS_C_NO_BUFFER);               return -1;          }          if (verbose && log) {              if (maj_stat == GSS_S_CONTINUE_NEEDED)                  fprintf(log, "continue needed...\n");              else                  fprintf(log, "\n");              fflush(log);          }     } while (maj_stat == GSS_S_CONTINUE_NEEDED);     /* display the flags */     display_ctx_flags(*ret_flags);     if (verbose && log) {         maj_stat = gss_oid_to_str(&min_stat, doid, &oid_name);         if (maj_stat != GSS_S_COMPLETE) {             display_status("converting oid->string", maj_stat, min_stat);             return -1;         }         fprintf(log, "Accepted connection using mechanism OID %.*s.\n",                 (int) oid_name.length, (char *) oid_name.value);         (void) gss_release_buffer(&min_stat, &oid_name);     }     maj_stat = gss_display_name(&min_stat, client, client_name, &doid);     if (maj_stat != GSS_S_COMPLETE) {          display_status("displaying name", maj_stat, min_stat);          return -1;     }     maj_stat = gss_release_name(&min_stat, &client);     if (maj_stat != GSS_S_COMPLETE) {          display_status("releasing name", maj_stat, min_stat);          return -1;     }     return 0;}

Thesign_server() function uses the following sourcecode to callserver_establish_context() to accept the context.

/* Establish a context with the client */     if (server_establish_context(s, server_creds, &context,  &client_name, &ret_flags) < 0)return(-1);

Theserver_establish_context() function first looksfor a token that the client sends as part of the context initialization process.Because, GSS-API does not send or receive tokens itself, programs must havetheir own routines for performing these tasks. The server usesrecv_token() for receiving the token:

     do {          if (recv_token(s, &recv_tok) < 0)               return -1;

Next,server_establish_context() calls the GSS-APIfunctiongss_accept_sec_context():

     maj_stat = gss_accept_sec_context(&min_stat,                                      context,                                      server_creds,                                      &recv_tok,                                      GSS_C_NO_CHANNEL_BINDINGS,                                      &client,                                      &doid,                                      &send_tok,                                      ret_flags,                                      NULL,     /* ignore time_rec */                                      NULL);    /* ignore del_cred_handle */
  • min_stat is the error status returnedby the underlying mechanism.

  • context is the context being established.

  • server_creds is the credentialfor the service to be provided (seeAcquiring Credentials).

  • recv_tok is the token receivedfrom the client byrecv_token().

  • GSS_C_NO_CHANNEL_BINDINGS is aflag indicating not to use channel bindings (seeUsing Channel Bindings in GSS-API).

  • client is the ASCII name of theclient.

  • oid is the mechanism (in OID format).

  • send_tok is the token to send tothe client.

  • ret_flags are various flags indicatingwhether the context supports a given option, such asmessage-sequence-detection.

  • The two NULL arguments indicate that the program does notneed to know the length of time that the context will be valid, or whetherthe server can act as a client's proxy.

The acceptance loop continues, barring any errors, as long asgss_accept_sec_context() setsmaj_stat toGSS_S_CONTINUE_NEEDED. Ifmaj_stat is not equal to that valueor toGSS_S_COMPLETE, a problem exists and the loop exits.

gss_accept_sec_context() returns a positive value for the length ofsend_tok whethera token exists to send back to the client. The next step is to see a tokenexists to be sent, and, if so, to send the token:

     if (send_tok.length != 0) {          . . .          if (send_token(s, &send_tok) < 0) {               fprintf(log, "failure sending token\n");               return -1;          }          (void) gss_release_buffer(&min_stat, &send_tok);          }

Unwrapping the Message

After accepting the context, thesign_server() receives the message that has been sent by the client. Because the GSS-API does not provide a function for receiving tokens, the program uses therecv_token() function:

if (recv_token(s, &xmit_buf) < 0)     return(-1);

Because the message might be encrypted, the program uses the GSS-APIfunctiongss_unwrap() for unwrapping:

maj_stat = gss_unwrap(&min_stat, context, &xmit_buf, &msg_buf,                           &conf_state, (gss_qop_t *) NULL);     if (maj_stat != GSS_S_COMPLETE) {        display_status("unwrapping message", maj_stat, min_stat);        return(-1);     } else if (! conf_state) {        fprintf(stderr, "Warning!  Message not encrypted.\n");     }     (void) gss_release_buffer(&min_stat, &xmit_buf);

gss_unwrap() takes the message thatrecv_token() has placed inxmit_buf, translatesthe message, and puts the result inmsg_buf. Twoarguments togss_unwrap() are noteworthy.conf_state is a flag to indicate whether confidentiality, that is, encryption,has been applied to this message. The final NULL indicates that the programdoes not need to know that the QOP that was used to protect the message.

Signing and Returning the Message

At this point, thesign_server() function needs to sign the message. Signing a message entails returning the message's Message Integrity Code or MIC to the client. Returning the message proves that the message was sent and was unwrapped successfully. To obtain the MIC,sign_server() uses the functiongss_get_mic():

maj_stat = gss_get_mic(&min_stat, context, GSS_C_QOP_DEFAULT,                            &msg_buf, &xmit_buf);

gss_get_mic() looks at the message inmsg_buf, produces the MIC, and stores the MIC inxmit_buf.The server then sends the MIC back to the client withsend_token().The client verifies the MIC withgss_verify_mic(). SeeReading and Verifying a Signature Block From a GSS-API Client.

Finally,sign_server() performs some cleanup.sign_server() releases the GSS-API buffersmsg_buf andxmit_buf withgss_release_buffer(). Thensign_server() destroys the context withgss_delete_sec_context().

Using thetest_import_export_context() Function

GSS-API allows you to export and import contexts. These activities enableyou to share a context between different processes in a multiprocess program.sign_server() contains a proof-of-concept function,test_import_export_context(), that illustrates how exporting and importing contexts works.test_import_export_context() does not pass a context between processes.Instead,test_import_export_context() displays the amountof time to export and then import a context. Although an artificial function,test_import_export_context() does indicate how to use the GSS-APIimporting and exporting functions.test_import_export_context() alsoshows how to use timestamps with regard to manipulating contexts.

The source code fortest_import_export_context() isshown in the following example.

Example 24  GSSAPI Servertest_import_export_context() Function
int test_import_export_context(context)        gss_ctx_id_t *context;{        OM_uint32       min_stat, maj_stat;        gss_buffer_desc context_token, copied_token;        struct timeval tm1, tm2;        /*         * Attempt to save and then restore the context.         */        gettimeofday(&tm1, (struct timezone *)0);        maj_stat = gss_export_sec_context(&min_stat, context, &context_token);        if (maj_stat != GSS_S_COMPLETE) {                display_status("exporting context", maj_stat, min_stat);                return 1;        }        gettimeofday(&tm2, (struct timezone *)0);        if (verbose && log)                fprintf(log, "Exported context: %d bytes, %7.4f seconds\n",                        context_token.length, timeval_subtract(&tm2, &tm1));        copied_token.length = context_token.length;        copied_token.value = malloc(context_token.length);        if (copied_token.value == 0) {            fprintf(log, "Couldn't allocate memory to copy context token.\n");            return 1;        }        memcpy(copied_token.value, context_token.value, copied_token.length);        maj_stat = gss_import_sec_context(&min_stat, &copied_token, context);        if (maj_stat != GSS_S_COMPLETE) {                display_status("importing context", maj_stat, min_stat);                return 1;        }        free(copied_token.value);        gettimeofday(&tm1, (struct timezone *)0);        if (verbose && log)                fprintf(log, "Importing context: %7.4f seconds\n",                        timeval_subtract(&tm1, &tm2));        (void) gss_release_buffer(&min_stat, &context_token);        return 0;}
Copyright © 2000, 2020, Oracle and/or its affiliates. 
Previous
Next

[8]ページ先頭

©2009-2025 Movatter.jp