static int doit (Shishi * h, Shishi_ap * ap, int verbose) { Shishi_asn1 asn1safe; Shishi_safe *safe; char *userdata; size_t userdatalen; int res; printf ("Application exchange start. Press ^D to finish.\n"); while ((res = shishi_safe_parse (h, stdin, &asn1safe)) == SHISHI_OK) { if (res != SHISHI_OK) { fprintf (stderr, "Could not read SAFE:\n%s\n%s\n", shishi_strerror (res), shishi_error (h)); return 1; } res = shishi_safe (h, &safe); if (res != SHISHI_OK) { fprintf (stderr, "Could not create SAFE:\n%s\n%s\n", shishi_strerror (res), shishi_error (h)); return 1; } shishi_safe_safe_set (safe, asn1safe); res = shishi_safe_verify (safe, shishi_ap_key (ap)); if (res != SHISHI_OK) { fprintf (stderr, "Could not verify SAFE:\n%s\n%s\n", shishi_strerror (res), shishi_error (h)); return 1; } printf ("Verified SAFE successfully...\n"); res = shishi_safe_user_data (h, asn1safe, &userdata, &userdatalen); if (res != SHISHI_OK) { fprintf (stderr, "Could not extract user data:\n%s\n%s\n", shishi_strerror (res), shishi_error (h)); return 1; } userdata[userdatalen] = '\0'; printf ("user data: `%s'\n", userdata); } if (ferror (stdin)) { printf ("error reading stdin\n"); return 1; } return 0; }
static int doit (Shishi * handle, Shishi_ap * ap, int verbose) { char line[BUFSIZ]; int res; printf ("Application exchange start. Press ^D to finish.\n"); while (fgets (line, sizeof (line), stdin)) { Shishi_safe *safe; line[strlen(line)-1] = '\0'; printf ("read: %s\n", line); res = shishi_safe (handle, &safe); if (res != SHISHI_OK) { printf ("Could not build SAFE: %s\n", shishi_strerror (res)); return res; } res = shishi_safe_set_user_data (handle, shishi_safe_safe (safe), line, strlen (line)); if (res != SHISHI_OK) { printf ("Could not set application data in SAFE: %s\n", shishi_strerror (res)); return res; } res = shishi_safe_build (safe, shishi_ap_key (ap)); if (res != SHISHI_OK) { printf ("Could not build SAFE: %s\n", shishi_strerror (res)); return res; } res = shishi_safe_print (handle, stdout, shishi_safe_safe (safe)); if (res != SHISHI_OK) { printf ("Could not print SAFE: %s\n", shishi_strerror (res)); return res; } } if (ferror (stdin)) { printf ("error reading stdin\n"); return 1; } return 0; }
/* Allows a remotely initiated security context between the application and a remote peer to be established, using krb5. Assumes context_handle is valid. */ OM_uint32 gss_krb5_accept_sec_context (OM_uint32 * minor_status, gss_ctx_id_t * context_handle, const gss_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t * src_name, gss_OID * mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec, gss_cred_id_t * delegated_cred_handle) { gss_buffer_desc data; char *in; size_t inlen; gss_ctx_id_t cx; _gss_krb5_ctx_t cxk5; _gss_krb5_cred_t crk5; int rc; if (minor_status) *minor_status = 0; if (ret_flags) *ret_flags = 0; if (!acceptor_cred_handle) /* XXX support GSS_C_NO_CREDENTIAL: acquire_cred() default server */ return GSS_S_NO_CRED; if (*context_handle) return GSS_S_FAILURE; crk5 = acceptor_cred_handle->krb5; cx = calloc (sizeof (*cx), 1); if (!cx) { if (minor_status) *minor_status = ENOMEM; return GSS_S_FAILURE; } cxk5 = calloc (sizeof (*cxk5), 1); if (!cxk5) { free (cx); if (minor_status) *minor_status = ENOMEM; return GSS_S_FAILURE; } cx->mech = GSS_KRB5; cx->krb5 = cxk5; /* XXX cx->peer?? */ *context_handle = cx; cxk5->sh = crk5->sh; cxk5->key = crk5->key; cxk5->acceptor = 1; rc = shishi_ap (cxk5->sh, &cxk5->ap); if (rc != SHISHI_OK) return GSS_S_FAILURE; rc = gss_decapsulate_token (input_token_buffer, GSS_KRB5, &in, &inlen); if (!rc) return GSS_S_BAD_MIC; if (inlen < TOK_LEN) return GSS_S_BAD_MIC; if (memcmp (in, TOK_AP_REQ, TOK_LEN) != 0) return GSS_S_BAD_MIC; rc = shishi_ap_req_der_set (cxk5->ap, in + TOK_LEN, inlen - TOK_LEN); if (rc != SHISHI_OK) return GSS_S_FAILURE; rc = shishi_ap_req_process (cxk5->ap, crk5->key); if (rc != SHISHI_OK) { if (minor_status) *minor_status = GSS_KRB5_S_G_VALIDATE_FAILED; return GSS_S_FAILURE; } rc = shishi_authenticator_seqnumber_get (cxk5->sh, shishi_ap_authenticator (cxk5->ap), &cxk5->initseqnr); if (rc != SHISHI_OK) return GSS_S_FAILURE; rc = _gss_krb5_checksum_parse (minor_status, context_handle, input_chan_bindings); if (rc != GSS_S_COMPLETE) return GSS_S_FAILURE; cxk5->tkt = shishi_ap_tkt (cxk5->ap); cxk5->key = shishi_ap_key (cxk5->ap); if (shishi_apreq_mutual_required_p (crk5->sh, shishi_ap_req (cxk5->ap))) { Shishi_asn1 aprep; rc = shishi_ap_rep_asn1 (cxk5->ap, &aprep); if (rc != SHISHI_OK) { printf ("Error creating AP-REP: %s\n", shishi_strerror (rc)); return GSS_S_FAILURE; } rc = shishi_encapreppart_seqnumber_get (cxk5->sh, shishi_ap_encapreppart (cxk5-> ap), &cxk5->acceptseqnr); if (rc != SHISHI_OK) { /* A strict 1964 implementation would return GSS_S_DEFECTIVE_TOKEN here. gssapi-cfx permit absent sequence number, though. */ cxk5->acceptseqnr = 0; } { char *der; size_t len; rc = shishi_asn1_to_der (crk5->sh, aprep, &der, &len); if (rc != SHISHI_OK) { printf ("Error der encoding aprep: %s\n", shishi_strerror (rc)); return GSS_S_FAILURE; } data.value = der; data.length = len; } rc = gss_encapsulate_token_prefix (&data, TOK_AP_REP, TOK_LEN, GSS_KRB5, output_token); if (!rc) return GSS_S_FAILURE; if (ret_flags) *ret_flags = GSS_C_MUTUAL_FLAG; } else { output_token->value = NULL; output_token->length = 0; } if (src_name) { gss_name_t p; p = malloc (sizeof (*p)); if (!p) { if (minor_status) *minor_status = ENOMEM; return GSS_S_FAILURE; } rc = shishi_encticketpart_client (cxk5->sh, shishi_tkt_encticketpart (cxk5->tkt), &p->value, &p->length); if (rc != SHISHI_OK) return GSS_S_FAILURE; p->type = GSS_KRB5_NT_PRINCIPAL_NAME; *src_name = p; } /* PROT_READY is not mentioned in 1964/gssapi-cfx but we support it anyway. */ if (ret_flags) *ret_flags |= GSS_C_PROT_READY_FLAG; if (minor_status) *minor_status = 0; return GSS_S_COMPLETE; }
/* Initiates the establishment of a krb5 security context between the application and a remote peer. Assumes that context_handle and output_token are valid and cleared. */ OM_uint32 gss_krb5_init_sec_context (OM_uint32 * minor_status, const gss_cred_id_t initiator_cred_handle, gss_ctx_id_t * context_handle, const gss_name_t target_name, const gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, const gss_channel_bindings_t input_chan_bindings, const gss_buffer_t input_token, gss_OID * actual_mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec) { gss_ctx_id_t ctx = *context_handle; _gss_krb5_ctx_t k5 = ctx->krb5; OM_uint32 maj_stat; int rc; if (minor_status) *minor_status = 0; if (initiator_cred_handle) { /* We only support the default initiator. See k5internal.h for adding a Shishi_tkt to the credential structure. I'm not sure what the use would be -- user-to-user authentication perhaps? Later: if you have tickets for foo@BAR and bar@FOO, it may be useful to call gss_acquire_cred first to chose which one to initiate the context with. Not many applications need this. */ return GSS_S_NO_CRED; } if (k5 == NULL) { k5 = ctx->krb5 = calloc (sizeof (*k5), 1); if (!k5) { if (minor_status) *minor_status = ENOMEM; return GSS_S_FAILURE; } rc = shishi_init (&k5->sh); if (rc != SHISHI_OK) return GSS_S_FAILURE; } if (!k5->reqdone) { maj_stat = init_request (minor_status, initiator_cred_handle, context_handle, target_name, mech_type, req_flags, time_req, input_chan_bindings, input_token, actual_mech_type, output_token, ret_flags, time_rec); if (GSS_ERROR (maj_stat)) return maj_stat; k5->flags = req_flags & ( /* GSS_C_DELEG_FLAG | */ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG); /* PROT_READY is not mentioned in 1964/gssapi-cfx but we support it anyway. */ k5->flags |= GSS_C_PROT_READY_FLAG; if (ret_flags) *ret_flags = k5->flags; k5->key = shishi_ap_key (k5->ap); k5->reqdone = 1; } else if (k5->reqdone && k5->flags & GSS_C_MUTUAL_FLAG && !k5->repdone) { maj_stat = init_reply (minor_status, initiator_cred_handle, context_handle, target_name, mech_type, req_flags, time_req, input_chan_bindings, input_token, actual_mech_type, output_token, ret_flags, time_rec); if (GSS_ERROR (maj_stat)) return maj_stat; if (ret_flags) *ret_flags = k5->flags; k5->repdone = 1; } else maj_stat = GSS_S_FAILURE; if (time_rec) *time_rec = gss_krb5_tktlifetime (k5->tkt); return maj_stat; }