/** * shishi_tgs: * @handle: shishi handle as allocated by shishi_init(). * @tgs: holds pointer to newly allocate Shishi_tgs structure. * * Allocate a new TGS exchange variable. * * Return value: Returns SHISHI_OK iff successful. **/ int shishi_tgs (Shishi * handle, Shishi_tgs ** tgs) { Shishi_tgs *ltgs; int res; *tgs = xcalloc (1, sizeof (**tgs)); ltgs = *tgs; ltgs->handle = handle; ltgs->tgsreq = shishi_tgsreq (handle); if (ltgs->tgsreq == NULL) { shishi_error_printf (handle, "Could not create TGS-REQ: %s\n", shishi_error (handle)); return SHISHI_ASN1_ERROR; } ltgs->tgsrep = shishi_tgsrep (handle); if (ltgs->tgsreq == NULL) { shishi_error_printf (handle, "Could not create TGS-REP: %s\n", shishi_error (handle)); return SHISHI_ASN1_ERROR; } ltgs->krberror = shishi_krberror (handle); if (ltgs->krberror == NULL) { shishi_error_printf (handle, "Could not create KRB-ERROR: %s\n", shishi_error (handle)); return SHISHI_ASN1_ERROR; } res = shishi_ap_nosubkey (handle, <gs->ap); if (res != SHISHI_OK) return res; res = shishi_authenticator_remove_subkey (handle, shishi_ap_authenticator (ltgs->ap)); if (res != SHISHI_OK) return res; res = shishi_tkt (handle, <gs->tkt); if (res != SHISHI_OK) return res; return SHISHI_OK; }
/** * shishi_tgs_rep_process: * @tgs: structure that holds information about TGS exchange * * Process new TGS-REP and set ticket. The key to decrypt the TGS-REP * is taken from the EncKDCRepPart of the TGS tgticket. * * Return value: Returns SHISHI_OK iff successful. **/ int shishi_tgs_rep_process (Shishi_tgs * tgs) { Shishi_asn1 kdcreppart, ticket; int res; if (VERBOSE (tgs->handle)) printf ("Processing TGS-REQ and TGS-REP...\n"); res = shishi_tgs_process (tgs->handle, tgs->tgsreq, tgs->tgsrep, shishi_ap_authenticator (tgs->ap), shishi_tkt_enckdcreppart (tgs->tgtkt), &kdcreppart); if (res != SHISHI_OK) { shishi_error_printf (tgs->handle, "Could not process TGS: %s", shishi_strerror (res)); return res; } if (VERBOSE (tgs->handle)) printf ("Got EncKDCRepPart...\n"); if (VERBOSEASN1 (tgs->handle)) shishi_enckdcreppart_print (tgs->handle, stdout, kdcreppart); res = shishi_kdcrep_get_ticket (tgs->handle, tgs->tgsrep, &ticket); if (res != SHISHI_OK) { shishi_error_printf (tgs->handle, "Could not extract ticket from TGS-REP: %s", shishi_strerror (res)); return res; } if (VERBOSE (tgs->handle)) printf ("Got Ticket...\n"); if (VERBOSEASN1 (tgs->handle)) shishi_ticket_print (tgs->handle, stdout, ticket); /* XXX */ tgs->tkt = shishi_tkt2 (tgs->handle, ticket, kdcreppart, tgs->tgsrep); return SHISHI_OK; }
/* shishi authentication */ int auth (Shishi * h, int verbose, const char *cname, const char *sname, int sock, char *cmd, char *port, Shishi_key ** enckey, Shishi_key * deckey) { Shishi_ap *ap; Shishi_tkt *tkt; Shishi_tkts_hint hint; int rc; char *out; int outlen; int krb5len, msglen; char auth; /* KERBEROS 5 SENDAUTH MESSAGE */ char krb5sendauth[] = "KRB5_SENDAUTH_V1.0"; /* PROTOCOL VERSION */ char krb5sendclient[] = "KCMDV0.2"; /* to store error msg sent by server */ char errormsg[101]; char cksumdata[101]; /* size of KRB5 auth message */ krb5len = strlen (krb5sendauth) + 1; msglen = htonl (krb5len); safewrite (sock, &msglen, sizeof (int)); /* KRB5 authentication message */ safewrite (sock, krb5sendauth, krb5len); /* size of client message */ krb5len = strlen (krb5sendclient) + 1; msglen = htonl (krb5len); safewrite (sock, &msglen, sizeof (int)); /* KRB5 client message */ safewrite (sock, krb5sendclient, krb5len); /* get answer from server 0 = ok, 1 = error with message */ read (sock, &auth, 1); if (auth) { read (sock, errormsg, 100); errormsg[100] = '\0'; printf ("Error during server authentication : %s\n", errormsg); return 1; } if (verbose) { printf ("Client: %s\n", cname); printf ("Server: %s\n", sname); } /* Get a ticket for the server. */ memset (&hint, 0, sizeof (hint)); hint.client = (char *) cname; hint.server = (char *) sname; tkt = shishi_tkts_get (shishi_tkts_default (h), &hint); if (!tkt) { printf ("cannot find ticket for \"%s\"\n", sname); return 1; } if (verbose) shishi_tkt_pretty_print (tkt, stderr); /* Create Authentication context */ rc = shishi_ap_tktoptions (h, &ap, tkt, SHISHI_APOPTIONS_MUTUAL_REQUIRED); if (rc != SHISHI_OK) { printf ("cannot create authentication context\n"); return 1; } /* checksum = port: terminal name */ snprintf (cksumdata, 100, "%s:%s%s", port, cmd, cname); /* add checksum to authenticator */ shishi_ap_authenticator_cksumdata_set (ap, cksumdata, strlen (cksumdata)); /* To be compatible with MIT rlogind */ shishi_ap_authenticator_cksumtype_set (ap, SHISHI_RSA_MD5); /* create der encoded AP-REQ */ rc = shishi_ap_req_der (ap, &out, &outlen); if (rc != SHISHI_OK) { printf ("cannot build authentication request: %s\n", shishi_strerror (rc)); return 1; } if (verbose) shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap)); /* extract subkey if present from ap exchange for secure connection */ shishi_authenticator_get_subkey (h, shishi_ap_authenticator (ap), enckey); /* send size of AP-REQ to the server */ msglen = htonl (outlen); safewrite (sock, (char *) &msglen, sizeof (int)); /* send AP-REQ to the server */ safewrite (sock, out, outlen); /* read a respond from server - what ? */ read (sock, &auth, sizeof (int)); /* For mutual authentication, wait for server reply. */ if (shishi_apreq_mutual_required_p (h, shishi_ap_req (ap))) { if (verbose) printf ("Waiting for server to authenticate itself...\n"); /* read size of the AP-REP */ read (sock, (char *) &outlen, sizeof (int)); /* read AP-REP */ outlen = ntohl (outlen); outlen = read (sock, out, outlen); rc = shishi_ap_rep_verify_der (ap, out, outlen); if (rc == SHISHI_OK) { if (verbose) printf ("AP-REP verification OK...\n"); } else { if (rc == SHISHI_APREP_VERIFY_FAILED) printf ("AP-REP verification failed...\n"); else printf ("AP-REP verification error: %s\n", shishi_strerror (rc)); return 1; } /* The server is authenticated. */ if (verbose) printf ("Server authenticated.\n"); } /* We are now authenticated. */ if (verbose) printf ("User authenticated.\n"); return AUTH_OK; }
static Shishi_ap * auth (Shishi * h, int verbose, const char *cname, const char *sname) { Shishi_ap *ap; Shishi_tkt *tkt; Shishi_tkts_hint hint; int rc; printf ("Client: %s\n", cname); printf ("Server: %s\n", sname); /* Get a ticket for the server. */ memset (&hint, 0, sizeof (hint)); hint.client = (char *) cname; hint.server = (char *) sname; tkt = shishi_tkts_get (shishi_tkts_default (h), &hint); if (!tkt) { printf ("cannot find ticket for \"%s\"\n", sname); return NULL; } if (verbose) shishi_tkt_pretty_print (tkt, stderr); /* Create Authentication context */ rc = shishi_ap_tktoptions (h, &ap, tkt, SHISHI_APOPTIONS_MUTUAL_REQUIRED); if (rc != SHISHI_OK) { printf ("cannot create authentication context\n"); return NULL; } /* Build Authentication request */ rc = shishi_ap_req_build (ap); if (rc != SHISHI_OK) { printf ("cannot build authentication request: %s\n", shishi_strerror (rc)); return NULL; } if (verbose) shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap)); /* Authentication ourself to server */ shishi_apreq_print (h, stdout, shishi_ap_req (ap)); /* Note: to get the binary blob to send, use: * * char *out; int outlen; * ... * rc = shishi_ap_req_der (ap, &out, &outlen); * ... * write(fd, out, outlen); */ /* For mutual authentication, wait for server reply. */ if (shishi_apreq_mutual_required_p (h, shishi_ap_req (ap))) { Shishi_asn1 aprep; printf ("Waiting for server to authenticate itself...\n"); rc = shishi_aprep_parse (h, stdin, &aprep); if (rc != SHISHI_OK) { printf ("Cannot parse AP-REP from server: %s\n", shishi_strerror (rc)); return NULL; } rc = shishi_ap_rep_verify_asn1 (ap, aprep); if (rc == SHISHI_OK) printf ("AP-REP verification OK...\n"); else { if (rc == SHISHI_APREP_VERIFY_FAILED) printf ("AP-REP verification failed...\n"); else printf ("AP-REP verification error: %s\n", shishi_strerror (rc)); return NULL; } /* The server is authenticated. */ printf ("Server authenticated.\n"); } /* We are now authenticated. */ printf ("User authenticated.\n"); return ap; }
int _gsasl_kerberos_v5_client_step (Gsasl_session * sctx, void *mech_data, const char *input, size_t input_len, char *output, size_t * output_len) { struct _Gsasl_kerberos_v5_client_state *state = mech_data; Gsasl_client_callback_authentication_id cb_authentication_id; Gsasl_client_callback_authorization_id cb_authorization_id; Gsasl_client_callback_qop cb_qop; Gsasl_client_callback_realm cb_realm; Gsasl_client_callback_password cb_password; Gsasl_client_callback_service cb_service; Gsasl_client_callback_maxbuf cb_maxbuf; Gsasl_ctx *ctx; int res; int len; ctx = gsasl_client_ctx_get (sctx); if (ctx == NULL) return GSASL_CANNOT_GET_CTX; /* These are optional */ cb_realm = gsasl_client_callback_realm_get (ctx); cb_service = gsasl_client_callback_service_get (ctx); cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx); cb_authorization_id = gsasl_client_callback_authorization_id_get (ctx); cb_qop = gsasl_client_callback_qop_get (ctx); cb_maxbuf = gsasl_client_callback_maxbuf_get (ctx); /* Only optionally needed in infrastructure mode */ cb_password = gsasl_client_callback_password_get (ctx); if (cb_password == NULL) return GSASL_NEED_CLIENT_PASSWORD_CALLBACK; /* I think we really need this one */ cb_service = gsasl_client_callback_service_get (ctx); if (cb_service == NULL) return GSASL_NEED_CLIENT_SERVICE_CALLBACK; switch (state->step) { case STEP_FIRST: if (input == NULL) { *output_len = 0; return GSASL_NEEDS_MORE; } if (input_len != SERVER_HELLO_LEN) return GSASL_MECHANISM_PARSE_ERROR; memcpy (state->serverhello, input, input_len); { unsigned char serverbitmap; memcpy (&serverbitmap, input, BITMAP_LEN); state->serverqops = 0; if (serverbitmap & GSASL_QOP_AUTH) state->serverqops |= GSASL_QOP_AUTH; if (serverbitmap & GSASL_QOP_AUTH_INT) state->serverqops |= GSASL_QOP_AUTH_INT; if (serverbitmap & GSASL_QOP_AUTH_CONF) state->serverqops |= GSASL_QOP_AUTH_CONF; if (serverbitmap & MUTUAL) state->servermutual = 1; } memcpy (&state->servermaxbuf, &input[BITMAP_LEN], MAXBUF_LEN); state->servermaxbuf = ntohl (state->servermaxbuf); if (cb_qop) state->clientqop = cb_qop (sctx, state->serverqops); if (!(state->serverqops & state->clientqop & (GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))) return GSASL_AUTHENTICATION_ERROR; /* XXX for now we require server authentication */ if (!state->servermutual) return GSASL_AUTHENTICATION_ERROR; /* Decide policy here: non-infrastructure, infrastructure or proxy. * * A callback to decide should be added, but without the default * should be: * * IF shishi_tktset_get_for_server() THEN * INFRASTRUCTURE MODE * ELSE IF shishi_realm_for_server(server) THEN * PROXY INFRASTRUCTURE (then fallback to NIM?) * ELSE * NON-INFRASTRUCTURE MODE */ state->step = STEP_NONINFRA_SEND_APREQ; /* only NIM for now.. */ /* fall through */ case STEP_NONINFRA_SEND_ASREQ: res = shishi_as (state->sh, &state->as); if (res) return GSASL_KERBEROS_V5_INTERNAL_ERROR; if (cb_authentication_id) /* Shishi defaults to one otherwise */ { len = *output_len - 1; res = cb_authentication_id (sctx, output, &len); if (res != GSASL_OK) return res; output[len] = '\0'; res = shishi_kdcreq_set_cname (state->sh, shishi_as_req (state->as), SHISHI_NT_UNKNOWN, output); if (res != GSASL_OK) return res; } if (cb_realm) { len = *output_len - 1; res = cb_realm (sctx, output, &len); if (res != GSASL_OK) return res; } else len = 0; output[len] = '\0'; res = shishi_kdcreq_set_realm (state->sh, shishi_as_req (state->as), output); if (res != GSASL_OK) return res; if (cb_service) { char *sname[3]; size_t servicelen = 0; size_t hostnamelen = 0; res = cb_service (sctx, NULL, &servicelen, NULL, &hostnamelen, /* XXX support servicename a'la DIGEST-MD5 too? */ NULL, NULL); if (res != GSASL_OK) return res; if (*output_len < servicelen + 1 + hostnamelen + 1) return GSASL_TOO_SMALL_BUFFER; sname[0] = &output[0]; sname[1] = &output[servicelen + 2]; sname[2] = NULL; res = cb_service (sctx, sname[0], &servicelen, sname[1], &hostnamelen, NULL, NULL); if (res != GSASL_OK) return res; sname[0][servicelen] = '\0'; sname[1][hostnamelen] = '\0'; res = shishi_kdcreq_set_sname (state->sh, shishi_as_req (state->as), SHISHI_NT_UNKNOWN, sname); if (res != GSASL_OK) return res; } /* XXX query application for encryption types and set the etype field? Already configured by shishi though... */ res = shishi_a2d (state->sh, shishi_as_req (state->as), output, output_len); if (res != SHISHI_OK) return GSASL_KERBEROS_V5_INTERNAL_ERROR; state->step = STEP_NONINFRA_WAIT_ASREP; res = GSASL_NEEDS_MORE; break; case STEP_NONINFRA_WAIT_ASREP: if (shishi_as_rep_der_set (state->as, input, input_len) != SHISHI_OK) return GSASL_MECHANISM_PARSE_ERROR; /* XXX? password stored in callee's output buffer */ len = *output_len - 1; res = cb_password (sctx, output, &len); if (res != GSASL_OK && res != GSASL_NEEDS_MORE) return res; output[len] = '\0'; res = shishi_as_rep_process (state->as, NULL, output); if (res != SHISHI_OK) return GSASL_AUTHENTICATION_ERROR; state->step = STEP_NONINFRA_SEND_APREQ; /* fall through */ case STEP_NONINFRA_SEND_APREQ: if (*output_len <= CLIENT_HELLO_LEN + SERVER_HELLO_LEN) return GSASL_TOO_SMALL_BUFFER; if (!(state->clientqop & ~GSASL_QOP_AUTH)) state->clientmaxbuf = 0; else if (cb_maxbuf) state->clientmaxbuf = cb_maxbuf (sctx, state->servermaxbuf); else state->clientmaxbuf = MAXBUF_DEFAULT; /* XXX for now we require server authentication */ output[0] = state->clientqop | MUTUAL; { uint32_t tmp; tmp = ntohl (state->clientmaxbuf); memcpy (&output[BITMAP_LEN], &tmp, MAXBUF_LEN); } memcpy (&output[CLIENT_HELLO_LEN], state->serverhello, SERVER_HELLO_LEN); if (cb_authorization_id) { len = *output_len - CLIENT_HELLO_LEN + SERVER_HELLO_LEN; res = cb_authorization_id (sctx, &output[CLIENT_HELLO_LEN + SERVER_HELLO_LEN], &len); } else len = 0; len += CLIENT_HELLO_LEN + SERVER_HELLO_LEN; res = shishi_ap_tktoptionsdata (state->sh, &state->ap, shishi_as_tkt (state->as), SHISHI_APOPTIONS_MUTUAL_REQUIRED, output, len); if (res != SHISHI_OK) return GSASL_KERBEROS_V5_INTERNAL_ERROR; res = shishi_authenticator_add_authorizationdata (state->sh, shishi_ap_authenticator (state->ap), -1, output, len); if (res != SHISHI_OK) return GSASL_KERBEROS_V5_INTERNAL_ERROR; /* XXX set realm in AP-REQ and Authenticator */ res = shishi_ap_req_der (state->ap, output, output_len); if (res != SHISHI_OK) return GSASL_KERBEROS_V5_INTERNAL_ERROR; state->step = STEP_NONINFRA_WAIT_APREP; res = GSASL_NEEDS_MORE; break; case STEP_NONINFRA_WAIT_APREP: if (shishi_ap_rep_der_set (state->ap, input, input_len) != SHISHI_OK) return GSASL_MECHANISM_PARSE_ERROR; res = shishi_ap_rep_verify (state->ap); if (res != SHISHI_OK) return GSASL_AUTHENTICATION_ERROR; state->step = STEP_SUCCESS; /* XXX support AP session keys */ state->sessionkey = shishi_tkt_key (shishi_as_tkt (state->as)); *output_len = 0; res = GSASL_OK; break; default: res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES; break; } return res; }
/* Request part of gss_krb5_init_sec_context. Assumes that context_handle is valid, and has krb5 specific structure, and that output_token is valid and cleared. */ static OM_uint32 init_request (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; char *cksum, *der; size_t cksumlen; int rc; OM_uint32 maj_stat; gss_buffer_desc tmp; Shishi_tkts_hint hint; /* Get service ticket. */ maj_stat = gss_krb5_canonicalize_name (minor_status, target_name, GSS_C_NO_OID, &k5->peerptr); if (GSS_ERROR (maj_stat)) return maj_stat; memset (&hint, 0, sizeof (hint)); hint.server = k5->peerptr->value; hint.endtime = time_req; k5->tkt = shishi_tkts_get (shishi_tkts_default (k5->sh), &hint); if (!k5->tkt) { if (minor_status) *minor_status = GSS_KRB5_S_KG_CCACHE_NOMATCH; return GSS_S_NO_CRED; } /* Create Authenticator checksum field. */ maj_stat = _gss_krb5_checksum_pack (minor_status, initiator_cred_handle, context_handle, input_chan_bindings, req_flags, &cksum, &cksumlen); if (GSS_ERROR (maj_stat)) return maj_stat; /* Create AP-REQ in output_token. */ rc = shishi_ap_tktoptionsraw (k5->sh, &k5->ap, k5->tkt, SHISHI_APOPTIONS_MUTUAL_REQUIRED, 0x8003, cksum, cksumlen); free (cksum); if (rc != SHISHI_OK) return GSS_S_FAILURE; rc = shishi_authenticator_seqnumber_get (k5->sh, shishi_ap_authenticator (k5->ap), &k5->initseqnr); if (rc != SHISHI_OK) return GSS_S_FAILURE; rc = shishi_ap_req_der (k5->ap, &der, &tmp.length); if (rc != SHISHI_OK) return GSS_S_FAILURE; tmp.value = der; rc = gss_encapsulate_token_prefix (&tmp, TOK_AP_REQ, TOK_LEN, GSS_KRB5, output_token); free (der); if (!rc) return GSS_S_FAILURE; if (req_flags & GSS_C_MUTUAL_FLAG) return GSS_S_CONTINUE_NEEDED; return GSS_S_COMPLETE; }
/* 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; }
/* authentication, server side */ int get_auth (int infd, krb5_context *ctx, krb5_auth_context *actx, krb5_keyblock **key, const char **err_msg, int *protoversion, int *cksumtype, char **cksum, size_t *cksumlen, char *srvname) { char *out; size_t outlen; char *buf; int buflen; int len; int rc; int error; /* KERBEROS 5 SENDAUTH MESSAGE */ char krb5sendauth[] = "KRB5_SENDAUTH_V1.0"; /* PROTOCOL VERSION */ char krb5kcmd1[] = "KCMDV0.1"; char krb5kcmd2[] = "KCMDV0.2"; char *servername, *server = NULL, *realm = NULL; *err_msg = NULL; /* Get key for the server. */ # if 0 /* * XXX: Taken straight from the version for libshishi. * XXX: No adaptions yet. */ rc = shishi_init_server (handle); if (rc != SHISHI_OK) return rc; if (srvname && *srvname) { rc = shishi_parse_name (*handle, srvname, &server, &realm); if (rc != SHISHI_OK) { *err_msg = shishi_strerror (rc); return rc; } } if (server && *server) { char *p; servername = malloc (sizeof (SERVICE) + strlen (server) + 2); if (!servername) { *err_msg = "Not enough memory"; return SHISHI_TOO_SMALL_BUFFER; } p = strchr (server, '/'); if (p && (p != server)) sprintf (servername, "%s", server); /* Non-empty prefix. */ else sprintf (servername, "%s/%s", SERVICE, server + (p ? 1 : 0)); /* Remove initial slash. */ } else servername = shishi_server_for_local_service (*handle, SERVICE); if (realm && *realm) shishi_realm_default_set (*handle, realm); free (server); free (realm); /* Enable use of `~/.k5login'. */ if (shishi_check_version ("1.0.2")) /* Faulty in version 1.0.1. */ { rc = shishi_cfg_authorizationtype_set (*handle, "k5login basic"); if (rc != SHISHI_OK) { *err_msg = shishi_error (*handle); return rc; } } key = shishi_hostkeys_for_serverrealm (*handle, servername, shishi_realm_default (*handle)); free (servername); if (!key) { *err_msg = shishi_error (*handle); return SHISHI_INVALID_KEY; } /* Read Kerberos 5 sendauth message */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading message size"; return SHISHI_IO_ERROR; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return SHISHI_TOO_SMALL_BUFFER; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading authentication message"; return SHISHI_IO_ERROR; } len = strlen (krb5sendauth); rc = strncmp (buf, krb5sendauth, buflen >= len ? len : buflen); if (rc) { *err_msg = "Invalid authentication type"; /* Authentication type is wrong. */ write (infd, "\001", 1); return SHISHI_VERIFY_FAILED; } free (buf); /* Read protocol version */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading protocol message size"; return SHISHI_IO_ERROR; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return SHISHI_TOO_SMALL_BUFFER; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading protocol message"; return SHISHI_IO_ERROR; } len = strlen (krb5kcmd1); rc = strncmp (buf, krb5kcmd1, buflen >= len ? len : buflen); if (rc) { len = strlen (krb5kcmd2); rc = strncmp (buf, krb5kcmd2, buflen >= len ? len : buflen); if (rc) { *err_msg = "Protocol version not supported"; /* Protocol version is wrong. */ write (infd, "\002", 1); return SHISHI_VERIFY_FAILED; } *protoversion = 2; } else *protoversion = 1; free (buf); /* Authentication type is ok */ write (infd, "\0", 1); /* Read Authentication request from client */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading authentication request size"; return SHISHI_IO_ERROR; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return SHISHI_TOO_SMALL_BUFFER; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading authentication request"; return SHISHI_IO_ERROR; } /* Create Authentication context */ rc = shishi_ap_nosubkey (*handle, ap); if (rc != SHISHI_OK) return rc; /* Store request in context */ rc = shishi_ap_req_der_set (*ap, buf, buflen); if (rc != SHISHI_OK) return rc; free (buf); /* Process authentication request */ rc = shishi_ap_req_process (*ap, key); if (rc != SHISHI_OK) return rc; # ifdef ENCRYPTION /* extract subkey if present from ap exchange for secure connection */ if (*protoversion == 2) { *enckey = NULL; shishi_authenticator_get_subkey (*handle, shishi_ap_authenticator (*ap), enckey); } # endif /* Get authenticator checksum */ rc = shishi_authenticator_cksum (*handle, shishi_ap_authenticator (*ap), cksumtype, cksum, cksumlen); if (rc != SHISHI_OK) return rc; /* User is authenticated. */ error = 0; write (infd, &error, sizeof (int)); /* Authenticate ourself to client, if requested. */ if (shishi_apreq_mutual_required_p (*handle, shishi_ap_req (*ap))) { int len; rc = shishi_ap_rep_der (*ap, &out, &outlen); if (rc != SHISHI_OK) return rc; len = outlen; len = htonl (len); rc = write (infd, &len, sizeof (len)); if (rc != sizeof (int)) { *err_msg = "Error sending AP-REP"; free (out); return SHISHI_IO_ERROR; } rc = write (infd, out, ntohl (len)); if (rc != (int) ntohl (len)) { *err_msg = "Error sending AP-REP"; free (out); return SHISHI_IO_ERROR; } free (out); /* We are authenticated to client */ } # ifdef ENCRYPTION if (*protoversion == 1) { Shishi_tkt *tkt; tkt = shishi_ap_tkt (*ap); if (tkt == NULL) { *err_msg = "Could not get tkt from AP-REQ"; return SHISHI_INVALID_TICKET; } rc = shishi_encticketpart_get_key (*handle, shishi_tkt_encticketpart (tkt), enckey); if (rc != SHISHI_OK) return rc; } # endif /* ENCRYPTION */ return 0; # else return -1; # endif }
static Shishi_ap * auth (Shishi * h, int verbose, const char *cname, const char *sname) { Shishi_key *key; Shishi_ap *ap; Shishi_asn1 apreq; char *buf; size_t buflen; int rc; printf ("Client: %s\n", cname); printf ("Server: %s\n", sname); /* Get key for the server. */ key = shishi_hostkeys_for_server (h, sname); if (!key) { printf ("could not find key: %s\n", shishi_error (h)); return NULL; } if (verbose) shishi_key_print (h, stderr, key); /* Read Authentication request from client */ printf ("Waiting for client to authenticate itself...\n"); rc = shishi_apreq_parse (h, stdin, &apreq); if (rc != SHISHI_OK) { printf ("could not read AP-REQ: %s\n", shishi_strerror (rc)); return NULL; } /* Create Authentication context */ rc = shishi_ap (h, &ap); if (rc != SHISHI_OK) { printf ("Could not create AP: %s\n", shishi_strerror (rc)); return NULL; } /* Store request in context */ shishi_ap_req_set (ap, apreq); /* Process authentication request */ rc = shishi_ap_req_process (ap, key); if (rc != SHISHI_OK) { printf ("Could not process AP-REQ: %s\n", shishi_strerror (rc)); return NULL; } if (verbose) shishi_authenticator_print (h, stderr, shishi_ap_authenticator (ap)); rc = shishi_authenticator_client (h, shishi_ap_authenticator (ap), &buf, &buflen); printf ("Client name (from authenticator): %.*s\n", (int) buflen, buf); free (buf); rc = shishi_encticketpart_clientrealm (h, shishi_tkt_encticketpart (shishi_ap_tkt (ap)), &buf, &buflen); printf ("Client name (from encticketpart): %.*s\n", (int) buflen, buf); free (buf); rc = shishi_ticket_server (h, shishi_tkt_ticket (shishi_ap_tkt (ap)), &buf, &buflen); printf ("Server name (from ticket): %.*s\n", (int) buflen, buf); free (buf); /* User is authenticated. */ printf ("User authenticated.\n"); /* Authenticate ourself to client, if request */ if (shishi_apreq_mutual_required_p (h, apreq)) { Shishi_asn1 aprep; printf ("Mutual authentication required.\n"); rc = shishi_ap_rep_asn1 (ap, &aprep); if (rc != SHISHI_OK) { printf ("Error creating AP-REP: %s\n", shishi_strerror (rc)); return NULL; } if (verbose) shishi_encapreppart_print (h, stderr, shishi_ap_encapreppart (ap)); shishi_aprep_print (h, stdout, aprep); /* We are authenticated to client */ } return ap; }
int get_auth (int infd, Shishi ** handle, Shishi_ap ** ap, Shishi_key ** enckey, const char **err_msg, int *protoversion, int *cksumtype, char **cksum, int *cksumlen) { Shishi_key *key; char *out; int outlen; char *buf; int buflen; int len; int rc; int i; int error; /* KERBEROS 5 SENDAUTH MESSAGE */ char krb5sendauth[] = "KRB5_SENDAUTH_V1.0"; /* PROTOCOL VERSION */ char krb5kcmd1[] = "KCMDV0.1"; char krb5kcmd2[] = "KCMDV0.2"; int auth_correct = 0; char *servername; *err_msg = NULL; /* Get key for the server. */ if (!shishi_check_version (SHISHI_VERSION)) { *err_msg = "shishi_check_version() failed: header file incompatible with shared library."; return 1; } rc = shishi_init_server (handle); if (rc != SHISHI_OK) return rc; servername = shishi_server_for_local_service (*handle, SERVICE); key = shishi_hostkeys_for_server (*handle, servername); if (!key) { *err_msg = shishi_error (*handle); return 1; } /* Read Kerberos 5 sendauth message */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading message size"; return 1; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return 1; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading authentication message"; return 1; } len = strlen (krb5sendauth); rc = strncmp (buf, krb5sendauth, buflen >= len ? len : buflen); if (rc) { *err_msg = "Invalid authentication type"; return 1; } free (buf); /* Read protocol version */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading protocol message size"; return 1; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return 1; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading protocol message"; return 1; } len = strlen (krb5kcmd1); rc = strncmp (buf, krb5kcmd1, buflen >= len ? len : buflen); if (rc) { len = strlen (krb5kcmd2); rc = strncmp (buf, krb5kcmd2, buflen >= len ? len : buflen); if (rc) { *err_msg = "Protocol version not supported"; return 1; } *protoversion = 2; } else *protoversion = 1; free (buf); /* Authentication type is ok */ write (infd, "\0", 1); /* Read Authentication request from client */ rc = read (infd, &len, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error reading authentication request size"; return 1; } buflen = ntohl (len); buf = malloc (buflen); if (!buf) { *err_msg = "Not enough memory"; return 1; } rc = read (infd, buf, buflen); if (rc != buflen) { *err_msg = "Error reading authentication request"; return 1; } /* Create Authentication context */ rc = shishi_ap_nosubkey (*handle, ap); if (rc != SHISHI_OK) return rc; /* Store request in context */ shishi_ap_req_der_set (*ap, buf, buflen); if (rc != SHISHI_OK) return rc; free (buf); /* Process authentication request */ rc = shishi_ap_req_process (*ap, key); if (rc != SHISHI_OK) return rc; # ifdef ENCRYPTION /* extract subkey if present from ap exchange for secure connection */ if (*protoversion == 2) { *enckey = NULL; shishi_authenticator_get_subkey (*handle, shishi_ap_authenticator (*ap), enckey); } # endif /* Get authenticator checksum */ rc = shishi_authenticator_cksum (*handle, shishi_ap_authenticator (*ap), cksumtype, cksum, cksumlen); if (rc != SHISHI_OK) return rc; /* User is authenticated. */ error = 0; write (infd, &error, sizeof (int)); /* Authenticate ourself to client, if request */ if (shishi_apreq_mutual_required_p (*handle, shishi_ap_req (*ap))) { rc = shishi_ap_rep_der (*ap, &out, &outlen); if (rc != SHISHI_OK) return rc; outlen = htonl (outlen); rc = write (infd, &outlen, sizeof (int)); if (rc != sizeof (int)) { *err_msg = "Error sending AP-REP"; free (out); return 1; } rc = write (infd, out, ntohl (outlen)); if (rc != ntohl (outlen)) { *err_msg = "Error sending AP-REP"; free (out); return 1; } free (out); /* We are authenticated to client */ } # ifdef ENCRYPTION if (*protoversion == 1) { Shishi_tkt *tkt; tkt = shishi_ap_tkt (*ap); if (tkt == NULL) { *err_msg = "Could not get tkt from AP-REQ"; return 1; } rc = shishi_encticketpart_get_key (*handle, shishi_tkt_encticketpart (tkt), enckey); if (rc != SHISHI_OK) return rc; } # endif return SHISHI_OK; }