Kernel subset design issues
nico at cryptonector.com
Mon Apr 25 20:09:32 EDT 2011
On Mon, Apr 25, 2011 at 6:46 PM, <ghudson at mit.edu> 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.
> 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
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
> 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.
More information about the krbdev