Kernel subset design issues

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Kernel subset design issues

Greg Hudson
One of our promises for 1.10 is to make it easier to implement NFSv4
in kernels using our code.  Typically a user-space daemon establishes
a GSS security context, then conveys that to the kernel which uses it
to wrap/unwrap/get_mic/verify_mic messages.  I have some design issues
I'd like to discuss, in descending order of scope.

1. What to deliver

I'm envisioning that there will be a new directory
src/util/gss-kernel-lib.  During "make all" nothing will happen there.
During "make check" the Makefile will copy some source and generated
headers to the current directory, build them with gcc
-I. -DKRB5_KERNEL, link them into a static library named libkgss.a,
and then compile and run some simple tests against it.

This will serve to identify the necessary files for a kernel subset
and to ensure that unwanted dependencies don't creep in.  To make the
subset self-contained, I'll move code around and, very judiciously,
use #ifndef KRB5_KERNEL to excise unwanted dependencies from files.

2. The crypto library

To wrap/unwrap/get_mic/verify_mic, we need approximately ten files
from lib/gssapi/krb5 and lib/gssapi/generic, nothing from libkrb5, and
then basically all of libk5crypto.  The string-to-key routines and
some surface-level APIs could be excised, but the core encryption and
checksumming code that remains is about 90% of the library.  A kernel
integrator would probably want to replace the builtin crypto module
with a module using the kernel's native crypto primitives, and would
definitely want to replace the default PRNG implementation.

The simplest option for us is to include no libk5crypto stuff in
libkgss.a and just link against libk5crypto for tests.  That doesn't
provide a lot of guidance to kernel integrators in the crypto area.
We could perhaps provide that guidance in the form of text rather than
build system stuff.

The most complicated option would be to copy in every necessary file
from libk5crypto, including the builtin crypto module and default
PRNG, and use that for testing.  The identified set of files would
include a lot of stuff which a real kernel integration would want to
cut out, and util/gss-kernel-lib would become highly dependent on the
structure of libk5crypto.  Also, because we have a vtable structure
for each enctype, the surgery necessary to excise string-to-key isn't
very pretty.  (Perhaps there's a way to alter the structures to make
it prettier.)

Basically, I'm open to ideas in this area.

3. Transporting the GSS security context

Solaris NFS uses a standard
gss_export_sec_context/gss_import_sec_context to transport the GSS
context into the kernel.  The serialized GSS context includes a
serialized krb5 context which isn't actually needed by the crypto
routines.  The upshot is that there are around 23 files from libkrb5
in the Solaris kernel, none of which have to do with wrapping and
unwrapping messages.

Linux NFS exports a "lucid" sec context
(gss_krb5_export_lucid_sec_context), which is basically a
stripped-down krb5_gss_ctx_id_rec represented in native binary.  The
Linux kernel code (which is only distantly based on MIT krb5) converts
that into its own internal context structure.

My preference here is to write code to convert a lucid sec context
into a krb5_gss_ctx_id_rec (relying on the unadvertised fact that
libk5crypto works with a null krb5_context) and include that in
libkgss.

4. k5-int.h and its dependencies

Like most code in our tree, the gss-krb5 code includes k5-int.h, which
relies on about 15 subsidiary headers, including some stuff decidedly
uninteresting to the kernel subset (k5-int-pkinit.h, port-sockets.h,
krb5/preauth_plugin.h, etc.).

We can tolerate this, we can use #ifndef KRB5_KERNEL to pare down the
dependencies, or we can further decompose k5-int.h and make it so that
the files in the kernel subset can include only the parts of k5-int.h
they need.

5. IOV or not

krb5 1.7 added a bunch of IOV encryption code to gss-krb5.  A bunch of
the associated utility functions live alongside non-IOV code in
util_crypt.c.  My best understanding is that the IOV interfaces are
not needed in the kernel.  I plan to create util_crypt_iov.c and move
the IOV code in there.

6. Nitty details

* The relevant parts of the gss-krb5 code use just three krb5_free_*
  functions (krb5_free_data, krb5_free_checksum_contents, and
  krb5_free_keyblock).  My preference is to just duplicate these in
  libkgss rather than mucking about with kfree.c, since their
  implementations are short and stable.  Another option is to try to
  avoid using them, or use the private interfaces from libk5crypto
  instead.  Or kfree.c could be decomposed, but the decomposition into
  "used by NFS kernel code" and "not used by NFS kernel code" isn't
  very natural, and putting each function into a separate file would
  be kind of awful.

* The gss-krb5 code uses krb5_gss_save_error_info() to save extended
  error messages in a global table so that it can be retrieved by
  display_status (which will be using a different krb5 context).  We
  could reduce the need for this by implementing a global
  thread-specific krb5 context--something I've wanted to do for a
  while--but then we'd just have that framework as an unwanted
  dependency.  For the moment I'm going to just use KRB5_KERNEL to
  null out the definition of save_error_info().  A third option is to
  decide that encryption functions never produce very interesting
  extended error messages and stop calling save_error_info() in the
  wrap/unwrap/get_mic/verify_mic code.

* One of the older DES signing algorithms uses a different ivec if the
  mech used was gss_mech_krb5_old.  gss_mech_krb5_old is defined in
  gssapi_krb5.c, which is of course ruinous for limiting dependencies.
  My preference is to duplicate the definition in libkgss.a.

  We could also try to get rid of the dependency by adding a flag to
  the context structure, which gets set at context creation time
  (i.e. not in the kernel subset).

  Of note: the lucid context structure doesn't contain information
  about what mech was used.  The Linux NFS code appears not to support
  the gss_mech_krb5_old case (that is, it always uses a null IV).
_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev
Reply | Threaded
Open this post in threaded view
|

Re: Kernel subset design issues

Nico Williams
On Mon, Apr 25, 2011 at 6:46 PM,  <[hidden email]> wrote:

> One of our promises for 1.10 is to make it easier to implement NFSv4
> in kernels using our code.  Typically a user-space daemon establishes
> a GSS security context, then conveys that to the kernel which uses it
> to wrap/unwrap/get_mic/verify_mic messages.  I have some design issues
> I'd like to discuss, in descending order of scope.
>
> 1. What to deliver
>
> I'm envisioning that there will be a new directory
> src/util/gss-kernel-lib.  During "make all" nothing will happen there.
> During "make check" the Makefile will copy some source and generated
> headers to the current directory, build them with gcc
> -I. -DKRB5_KERNEL, link them into a static library named libkgss.a,
> and then compile and run some simple tests against it.
>
> This will serve to identify the necessary files for a kernel subset
> and to ensure that unwanted dependencies don't creep in.  To make the
> subset self-contained, I'll move code around and, very judiciously,
> use #ifndef KRB5_KERNEL to excise unwanted dependencies from files.

One major difference between Solaris' kernel- and user-land
environments has to do with the allocator's free() routine: in
kernel-mode the free function takes a length argument.  Take that for
what it's worth.  Perhaps you'll want to have wrappers around the
allocator to abstract out this difference (i.e., in libkrb5 and
crypto, use a krb5_*alloc/free() where the free function takes a
length and always pass in a correct length).  Or perhaps not.  Or
perhaps just in crypto and the mech.

> 2. The crypto library
>
> To wrap/unwrap/get_mic/verify_mic, we need approximately ten files
> from lib/gssapi/krb5 and lib/gssapi/generic, nothing from libkrb5, and
> then basically all of libk5crypto.  The string-to-key routines and
> some surface-level APIs could be excised, but the core encryption and
> checksumming code that remains is about 90% of the library.  A kernel
> integrator would probably want to replace the builtin crypto module
> with a module using the kernel's native crypto primitives, and would
> definitely want to replace the default PRNG implementation.

I'm not sure that it's always going to be the case that an integrator
will want to replace the crypto bits, but the PRNG, almost certainly.

> The simplest option for us is to include no libk5crypto stuff in
> libkgss.a and just link against libk5crypto for tests.  That doesn't
> provide a lot of guidance to kernel integrators in the crypto area.
> We could perhaps provide that guidance in the form of text rather than
> build system stuff.

Sure.

> 3. Transporting the GSS security context
>
> Solaris NFS uses a standard
> gss_export_sec_context/gss_import_sec_context to transport the GSS
> context into the kernel.  The serialized GSS context includes a
> serialized krb5 context which isn't actually needed by the crypto
> routines.  The upshot is that there are around 23 files from libkrb5
> in the Solaris kernel, none of which have to do with wrapping and
> unwrapping messages.

Why is that serialized krb5 context there at all??

> Linux NFS exports a "lucid" sec context
> (gss_krb5_export_lucid_sec_context), which is basically a
> stripped-down krb5_gss_ctx_id_rec represented in native binary.  The
> Linux kernel code (which is only distantly based on MIT krb5) converts
> that into its own internal context structure.

I never understood why we need to distinguish between "exported sec
context" and "exported lucid sec context", except as a way to avoid
cleaning up the existing sec context export/import functions...
Here's your chance to make that distinction go away.

I could see an exported sec context token including information that
some consumers might not care about, such as authorization data from
the Ticket and Authenticator from the AP-REQ, but why should this not
be simple to skip when importing an exported sec context token in a
kernel-mode consumer that doesn't care for such data?

> My preference here is to write code to convert a lucid sec context
> into a krb5_gss_ctx_id_rec (relying on the unadvertised fact that
> libk5crypto works with a null krb5_context) and include that in
> libkgss.

Sounds about right, but see above.

> 4. k5-int.h and its dependencies
>
> Like most code in our tree, the gss-krb5 code includes k5-int.h, which
> relies on about 15 subsidiary headers, including some stuff decidedly
> uninteresting to the kernel subset (k5-int-pkinit.h, port-sockets.h,
> krb5/preauth_plugin.h, etc.).
>
> We can tolerate this, we can use #ifndef KRB5_KERNEL to pare down the
> dependencies, or we can further decompose k5-int.h and make it so that
> the files in the kernel subset can include only the parts of k5-int.h
> they need.

And you could minimize the need for internal krb5 APIs in the
mechanism...  (this would be ideal, IMO).

> 5. IOV or not
>
> krb5 1.7 added a bunch of IOV encryption code to gss-krb5.  A bunch of
> the associated utility functions live alongside non-IOV code in
> util_crypt.c.  My best understanding is that the IOV interfaces are
> not needed in the kernel.  I plan to create util_crypt_iov.c and move
> the IOV code in there.

Oh no, IOV is most useful in kernel-mode!  Existing implementations
may not have the IOV interfaces in kernel-mode, but I'm sure the
implementors miss them :)

Incidentally, there are other consumers of kernel-mode GSS than NFS
(Lustre comes to mind).

> 6. Nitty details
>
> * The relevant parts of the gss-krb5 code use just three krb5_free_*
>  functions (krb5_free_data, krb5_free_checksum_contents, and
>  krb5_free_keyblock).  My preference is to just duplicate these in
>  libkgss rather than mucking about with kfree.c, since their
>  implementations are short and stable.  Another option is to try to
>  avoid using them, or use the private interfaces from libk5crypto
>  instead.  Or kfree.c could be decomposed, but the decomposition into
>  "used by NFS kernel code" and "not used by NFS kernel code" isn't
>  very natural, and putting each function into a separate file would
>  be kind of awful.

Just copy them and leave breadcrumbs in the comments.  I know, it's
not ideal, but this little code it should do.

> * The gss-krb5 code uses krb5_gss_save_error_info() to save extended
>  error messages in a global table so that it can be retrieved by
>  display_status (which will be using a different krb5 context).  We
>  could reduce the need for this by implementing a global
>  thread-specific krb5 context--something I've wanted to do for a
>  while--but then we'd just have that framework as an unwanted
>  dependency.  For the moment I'm going to just use KRB5_KERNEL to
>  null out the definition of save_error_info().  A third option is to
>  decide that encryption functions never produce very interesting
>  extended error messages and stop calling save_error_info() in the
>  wrap/unwrap/get_mic/verify_mic code.

I prefer the second option.  Integrators that wish to do better could
work this out and contribute a better solution.  In practice, however,
I think that kernel-mode GSS-API applications will be happy with the
traditional, not-terribly-informative major and minor status codes.

> * One of the older DES signing algorithms uses a different ivec if the
>  mech used was gss_mech_krb5_old.  gss_mech_krb5_old is defined in
>  gssapi_krb5.c, which is of course ruinous for limiting dependencies.
>  My preference is to duplicate the definition in libkgss.a.
>
>  We could also try to get rid of the dependency by adding a flag to
>  the context structure, which gets set at context creation time
>  (i.e. not in the kernel subset).

I say: it's time to get rid of gss_mech_krb5_old, at least for the
kernel-mode mechanism.

>  Of note: the lucid context structure doesn't contain information
>  about what mech was used.  The Linux NFS code appears not to support
>  the gss_mech_krb5_old case (that is, it always uses a null IV).

Well, there's one problem with the lucid context thing...

Incidentally, will you implement a kernel-mode mechglue as well?  I
imagine that's out of scope.

Nico
--

_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev
Reply | Threaded
Open this post in threaded view
|

Re: Kernel subset design issues

hartmans
In reply to this post by Greg Hudson
Does anyone plan to do a kernel CIFS implementation or a kernel
implementation requiring parts of DCE RPC?
If so, the IOV routines will be needed.
Also, if your kernel can support it, it seems like doing in-place crypto
would be a real win, and thus IOV would be desirable.
Why not only use IOV and enable the #define to do everything in terms of
iov instead of having iov and non-iov wrap implementations?

--Sam

l
_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev
Reply | Threaded
Open this post in threaded view
|

Re: Kernel subset design issues

hartmans
In reply to this post by Nico Williams
>>>>> "Nico" == Nico Williams <[hidden email]> writes:


    Nico> I never understood why we need to distinguish between
    Nico> "exported sec context" and "exported lucid sec context",
    Nico> except as a way to avoid cleaning up the existing sec context
    Nico> export/import functions...  Here's your chance to make that
    Nico> distinction go away.

At the time we didn't want to standardize  our export token format.

In the lucid structure, the userspace code is responsible for making the
exported context right for what the kernel supports.
If we standardize something we'd need to standardize something
extensible and  the kernel would need to skip parts of it.

Here, note that by standardize I mean write down, not something within
the IETF.
_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev
Reply | Threaded
Open this post in threaded view
|

Re: Kernel subset design issues

Nico Williams
On Tue, Apr 26, 2011 at 3:19 AM, Sam Hartman <[hidden email]> wrote:

>    Nico> I never understood why we need to distinguish between
>    Nico> "exported sec context" and "exported lucid sec context",
>    Nico> except as a way to avoid cleaning up the existing sec context
>    Nico> export/import functions...  Here's your chance to make that
>    Nico> distinction go away.
>
> At the time we didn't want to standardize  our export token format.
>
> In the lucid structure, the userspace code is responsible for making the
> exported context right for what the kernel supports.
> If we standardize something we'd need to standardize something
> extensible and  the kernel would need to skip parts of it.
>
> Here, note that by standardize I mean write down, not something within
> the IETF.

So you thought that the exported security context token format was
unstable, likely to be unstable, and at that too unstable to
coordinate with the one kernel-mode consumer that existed?

Well, whatever.  It is what it is.  But now is a good chance to
actually change the exported context token format into something that
would do.

Nico
--

_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev
Reply | Threaded
Open this post in threaded view
|

Re: Kernel subset design issues

Simo Sorce
In reply to this post by hartmans
On Tue, 2011-04-26 at 04:16 -0400, Sam Hartman wrote:
> Does anyone plan to do a kernel CIFS implementation or a kernel
> implementation requiring parts of DCE RPC?

Afaik Solaris has a kernel CIFS *server* implementation.
This will probbaly require DCE RPC.

Linux has a CIFS *client* implementation.
This doesn;t so far, but might at some point.

> If so, the IOV routines will be needed.
> Also, if your kernel can support it, it seems like doing in-place crypto
> would be a real win, and thus IOV would be desirable.

Yes, this is true.

> Why not only use IOV and enable the #define to do everything in terms of
> iov instead of having iov and non-iov wrap implementations?

Sounds like a good idea to me.

Simo.

--
Simo Sorce * Red Hat, Inc * New York

_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev
Reply | Threaded
Open this post in threaded view
|

Re: Kernel subset design issues

Volker Lendecke
On Tue, Apr 26, 2011 at 09:41:49AM -0400, Simo Sorce wrote:
> On Tue, 2011-04-26 at 04:16 -0400, Sam Hartman wrote:
> > Does anyone plan to do a kernel CIFS implementation or a kernel
> > implementation requiring parts of DCE RPC?
>
> Afaik Solaris has a kernel CIFS *server* implementation.
> This will probbaly require DCE RPC.

If I remember correctly last time I looked the RPC traffic
was handed out to user space. But I might have gotten it
wrong and it's a while ago.

Volker
_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev
Reply | Threaded
Open this post in threaded view
|

Re: Kernel subset design issues

Greg Hudson
In reply to this post by hartmans
On Tue, 2011-04-26 at 04:16 -0400, Sam Hartman wrote:
> Why not only use IOV and enable the #define to do everything in terms of
> iov instead of having iov and non-iov wrap implementations?

It's not quite that simple (the fallback you're thinking of is
implemented in the mechglue, and also there are no IOV versions of
get_mic/verify_mic), but with a little work I think it should be
possible to just have the IOV code in libkgss with wrappers for non-IOV
operations.  Based on the feedback so far, I'm assuming this is the
direction I should go.

Adding the IOV code raises another nitty detail, which is that the IOV
code makes three calls to gss_release_buffer() (because of
GSS_IOV_BUFFER_FLAG_ALLOCATE) which is implemented in the mechglue.  I
have a not-too-horrible workaround for that, which is to funnel two of
the calls through kg_release_iov() and have kg_release_iov do the buffer
manipulation directly.

Nico wrote:
> Why is that serialized krb5 context there at all??
[...]
> I never understood why we need to distinguish between "exported sec
> context" and "exported lucid sec context",

I'm not really prepared to defend the serialization approach to
gss_export_sec_context, but I'd also not prepared to throw it out within
the scope of this project.  (I realize that taking this attitude means
some stuff stays ugly for much longer than it really should, but it's
necessary to actually get things done on a reasonable schedule.)

> And you could minimize the need for internal krb5 APIs in the
> mechanism...  (this would be ideal, IMO).

We need at least krb5int_arcfour_gsscrypt(), as gss-krb5 doesn't use the
same RC4 token format as the RFC 3961 profile does.  We also need
krb5int_c_mandatory_cksumtype(), which should probably just be a public
API.

It's more that code in the krb5 tree includes k5-int.h as a matter of
course; that's just how we do platform portability, helper static inline
functions, etc..  It's very convenient in general, but for the current
purpose it might be nice if the files in the kernel subset were more
selective about what they included.  To make that possible, k5-int.h
will have to be decomposed a bit so that you can get access to, say, the
prototypes for the non-public libk5crypto APIs by themselves.

> Incidentally, will you implement a kernel-mode mechglue as well?  I
> imagine that's out of scope.

I wasn't planning on it; I don't feel like we could do a great job of
that.


_______________________________________________
krbdev mailing list             [hidden email]
https://mailman.mit.edu/mailman/listinfo/krbdev