logo_kerberos.gif

Difference between revisions of "Projects/Acceptor Names"

From K5Wiki
Jump to: navigation, search
(Overview)
(Eliminate the idea of trying with multiple hostname forms)
Line 8: Line 8:
 
* We will stop using the domain_realm map or default realm to determine the realm of host-based GSS acceptor names. Instead, we will allow any keytab entry matching the other constraints of the host-based name, regardless of realm.
 
* We will stop using the domain_realm map or default realm to determine the realm of host-based GSS acceptor names. Instead, we will allow any keytab entry matching the other constraints of the host-based name, regardless of realm.
 
* If the host-based acceptor name contains a service name but no hostname, we will allow any keytab entry matching the service name, regardless of its hostname or realm.
 
* If the host-based acceptor name contains a service name but no hostname, we will allow any keytab entry matching the service name, regardless of its hostname or realm.
* If the host-based acceptor name contains a service@hostname pair, we will allow a keytab entry matching the service name and either the original or canonicalized hostname. (XXX should we also allow the forward-canonicalized hostname? That has significant implications for the implementation design. Also, how valuable is this given that the client also has to determine the proper name, and only really gets one shot?)
 
 
* If the new profile variable ignore_acceptor_hostname is set, we will disregard the hostname part of a service@hostname pair and allow any keytab entry matching the service name.
 
* If the new profile variable ignore_acceptor_hostname is set, we will disregard the hostname part of a service@hostname pair and allow any keytab entry matching the service name.
   
Line 34: Line 33:
 
==Implementation Design==
 
==Implementation Design==
   
When we create a krb5 mechanism name from a host-based GSS name, we should record the service name and hostname (if given). If ignore_acceptor_hostname is set in the profile, we should discard the hostname at this time. If a hostname is given and not ignored, we should attempt to canonicalize it and record the canonicalized name as well. (NOTE: this will be the first time the gss-krb5 code directly consults the profile.)
+
When we create a krb5 mechanism name from a host-based GSS name, we should record the service name and hostname (if given). If ignore_acceptor_hostname is set in the profile, we should discard the hostname at this time. (NOTE: this will be the first time the gss-krb5 code directly consults the profile.)
   
If the name is used on the initiator path (as an initiator name or target name), we should convert from the recorded form to the principal we would construct with today's code.
+
If the name is used on the initiator path (as an initiator name or target name) or is exported, we should convert from the recorded form to the principal we would construct with today's code, using krb5_sname_to_principal.
   
If the name is imported for an acceptor cred, we should construct one or two partial principals: service/@ (empty hostname and realm) if no hostname was given, service/orighostname@ (empty realm) and service/canonhostname@ (empty realm) if one was given. We should scan the keytab to make sure one of the partial principals is matched by a keytab entry.
+
If the name is used in an acceptor cred, we should construct a "matching principal" service/hostname@ (empty realm) or service/@ (empty hostname and realm) depending on whether a name was recorded. We should scan the keytab to make sure the matching principal is matched by a keytab entry. If the keytab has no iteration support, we should just skip this check.
   
When an acceptor cred with an imported host-based name is used to accept a security context, we should try krb5_rd_req with the first partial principal and, if that fails, try again with the second (if there is one). (If the keytab has no iterator function, we should probably just skip this check.)
+
When an acceptor cred with an imported host-based name is used to accept a security context, we should try krb5_rd_req with the matching principal. krb5_rd_req should treat matching principals as restrictions on the keytab scan it already performs when no principal is passed in. If the keytab has no iterator function, then krb5_rd_req should check that the principal asserted by the client matches the partial host-based principal, and look up that principal in the keytab.
   
krb5_rd_req should treat partial host-based principals as restrictions on the keytab scan it already performs when no principal is passed in. (If the keytab has no iterator function, then krb5_rd_req should check that the principal asserted by the client matches the partial host-based principal, and look up that principal in the keytab.)
 
 
We will need a new krb5 library interface for matching a principal against a partial principal, following the same rules as krb5_rd_req will apply. The proposed API for this function is:
 
We will need new krb5 library interfaces for:
 
 
* Canonicalizing a hostname according to the sn2princ rules, honoring the profile "rdns" setting.
 
* Building a principal according to the sn2princ rules, with the canonicalized hostname already known. (sn2princ will be reimplemented in terms of this and the previous interface.)
 
* Matching a principal against a partial principal, following the same rules as krb5_rd_req will apply.
 
 
Proposed APIs for these functions:
 
   
 
krb5_error_code
 
krb5_error_code
krb5_sname_canonhost(krb5_context context, const char *host, const char **canonhost_out);
+
krb5_sname_match(krb5_context context, krb5_const_principal matching, krb5_const_principal princ);
   
krb5_error_code
 
  +
==Rejected Ideas==
krb5_sname_to_princ_canon(krb5_context context, const char *canonhost, const char *sname, krb5_int32 type,
 
krb5_principal *princ_out);
 
   
krb5_error_code
 
  +
If a server imports a host-based name containing a hostname, we could try the uncanonicalized, forward-canonicalized, and reverse-canonicalized forms of the hostname. Upon discussion of this idea, we decided that it would add significant complexity to the code, and we would be better off encouraging GSS server applications to import just the service name (without the local hostname attached).
krb5_sname_match(krb5_context context, krb5_const_principal partial, krb5_const_principal full);
 
   
 
==Future Considerations==
 
==Future Considerations==
   
For security reasons, we have long desired to get away from canonicalizing hostnames since it generally uses insecure DNS, but we have been unwilling to break existing deployments by simply turning it off. One possibility is to allow a KDC to assert that it should be responsible for host canonicalization, communicated as a ticket flag which would be stored in the credentials cache.
+
For security reasons, we have long desired to get away from canonicalizing hostnames since it generally uses insecure DNS, but we have been unwilling to break existing deployments by simply turning it off. One possibility is to allow a KDC to assert that it should be responsible for host canonicalization, communicated as a flag stored in the ccache.
   
The implementation design of this project could, as a side effect, allow a GSSAPI initiator to honor this ticket flag.
 
  +
The changes proposed in this project should further that goal. By recording the original hostname when a host-based name is imported into the mechanism, we make it possible for the GSSAPI initiator code to use that information if the ccache indicates that it should.
The initiator would consult the ticket cache and simply avoid calling krb5_sname_canonhost() before calling
 

Revision as of 13:58, 1 February 2011

This is an early stage project for MIT Kerberos. It is being fleshed out by its proponents. Feel free to help flesh out the details of this project. After the project is ready, it will be presented for review and approval.


This project is targeted at release 1.10.


Overview

The goal of this project is to improve the likelihood that a GSS server application will be able to use the correct entries from a keytab when accepting authentication. Specifically:

  • We will stop using the domain_realm map or default realm to determine the realm of host-based GSS acceptor names. Instead, we will allow any keytab entry matching the other constraints of the host-based name, regardless of realm.
  • If the host-based acceptor name contains a service name but no hostname, we will allow any keytab entry matching the service name, regardless of its hostname or realm.
  • If the new profile variable ignore_acceptor_hostname is set, we will disregard the hostname part of a service@hostname pair and allow any keytab entry matching the service name.

It is not required that this new flexibility extend to non-GSS krb5 servers, although it is acceptable if it flows naturally from the implementation.

Current Behavior

A GSSAPI server may invoke gss_accept_context with GSS_C_NO_CREDENTIAL, or with a credential acquired with GSS_C_NO_NAME, then we place no restrictions on the keytab entry used to decrypt the sender's ticket; we scan each keytab entry until we find one which can decrypt it. No changes are proposed in this case.

If a server calls gss_import_name with the name type GSS_C_NT_HOSTBASED_SERVICE, it supplies a service name and optionally a hostname. When a credential is acquired with this name, the mechglue will invoke krb5_gss_import_name() to create the mechanism name. This function calls krb5_sname_to_principal() to construct the principal, passing NULL for the hostname if none was supplied. krb5_sname_to_principal() does the following:

  1. If the hostname is NULL, calls gethostname() to get an initial value for the hostname.
  2. Canonicalizes the hostname using getaddrinfo() and possibly getnameinfo().
  3. Attempts to map the hostname to a realm using krb5_get_host_realm(). This will consult the profile domain_realm map, and will return the referral (empty) realm if no mapping exists.
  4. Constructs a principal servicename/canonicalized-hostname@realm.

When acceptor credentials are acquired using the mechanism name, acquire_accept_cred() looks up the principal in the host's keytab, and returns an error if it is not found. The keytab lookup code translates from the empty realm to the default realm.

When gss_accept_sec_context() is invoked, krb5_rd_req() looks up the principal in the host's keytab again, and uses it to decrypt the ticket.

Note that the principal resulting from krb5_sname_to_principal() may be used in the initiator code path as either an initiator or target name. If used as an initiator name, it is looked up in the credential cache, or passed to krb5_get_init_creds_password(). If used as a target name, it is passed to krb5_get_credentials() as the server name.

The principal resulting from krb5_sname_to_principal() may also be used by gss_export_name(). RFC 2744 section 5.5 mandates that gss_canonicalize_name and gss_export_name produce the same result as would be produced by using the name as an initiator name, establishing a security context, and exporting the authenticated name on the acceptor. There is no requirement that canonicalize/export match the result of accepting a security context with an acceptor name and querying the acceptor name of the resulting context.

Implementation Design

When we create a krb5 mechanism name from a host-based GSS name, we should record the service name and hostname (if given). If ignore_acceptor_hostname is set in the profile, we should discard the hostname at this time. (NOTE: this will be the first time the gss-krb5 code directly consults the profile.)

If the name is used on the initiator path (as an initiator name or target name) or is exported, we should convert from the recorded form to the principal we would construct with today's code, using krb5_sname_to_principal.

If the name is used in an acceptor cred, we should construct a "matching principal" service/hostname@ (empty realm) or service/@ (empty hostname and realm) depending on whether a name was recorded. We should scan the keytab to make sure the matching principal is matched by a keytab entry. If the keytab has no iteration support, we should just skip this check.

When an acceptor cred with an imported host-based name is used to accept a security context, we should try krb5_rd_req with the matching principal. krb5_rd_req should treat matching principals as restrictions on the keytab scan it already performs when no principal is passed in. If the keytab has no iterator function, then krb5_rd_req should check that the principal asserted by the client matches the partial host-based principal, and look up that principal in the keytab.

We will need a new krb5 library interface for matching a principal against a partial principal, following the same rules as krb5_rd_req will apply. The proposed API for this function is:

 krb5_error_code
 krb5_sname_match(krb5_context context, krb5_const_principal matching, krb5_const_principal princ);

Rejected Ideas

If a server imports a host-based name containing a hostname, we could try the uncanonicalized, forward-canonicalized, and reverse-canonicalized forms of the hostname. Upon discussion of this idea, we decided that it would add significant complexity to the code, and we would be better off encouraging GSS server applications to import just the service name (without the local hostname attached).

Future Considerations

For security reasons, we have long desired to get away from canonicalizing hostnames since it generally uses insecure DNS, but we have been unwilling to break existing deployments by simply turning it off. One possibility is to allow a KDC to assert that it should be responsible for host canonicalization, communicated as a flag stored in the ccache.

The changes proposed in this project should further that goal. By recording the original hostname when a host-based name is imported into the mechanism, we make it possible for the GSSAPI initiator code to use that information if the ccache indicates that it should.