TLS certificates for NFS-over-TLS floating client

Rick Macklem rmacklem at
Sat Mar 28 16:11:22 UTC 2020

John-Mark Gurney wrote:
>Rick Macklem wrote this message on Thu, Mar 26, 2020 at 14:33 +0000:
>> John-Mark Gurney wrote:
>> [lots of stuff snipped]
>> >Rick Macklem wrote:
>> >> I had originally planned on some "secret" in the certificate (like a CN name
>> >> that satisfies some regular expression or ???) but others convinced me that
>> >> that wouldn't provide anything beyond knowing that the certificate was
>> >> signed by the appropriate CA, so I have not implemented anything.
>> >
>> >Yeah, having a "secret" in the CN doesn't make sense, but what does make
>> >sense is allowing the exports line to specify what the CN should contain
>> >to be authenticated...
>> >
>> >Say as a corp, you issue personal certificates to everyone.  This is
>> >because you require everyone to sign and/or encrypt their email w/
>> >S/MIME.  Each cert includes the email address of that person, so you
>> >could simply do something like:
>> >/home/alice -tlscert -tlsroot /etc/company.pem -email alice at
>> >
>> >And anyone who has the certificate w/ alice at that was signed
>> >by the public key in /etc/company.pem would be granted access to the
>> >export /home/alice.
>> >
>> >If it allowed ANY cert signed by the CA specified, then that introduces
>> >an authentication problem, as now if Malory is a coworker of Alice
>> >could also access Alice's home directory...
>> >
>> >IMO, this is one auth feature that MUST be supported...
Here's what I have just coded up:
- If an option is set for the server TLS handshake daemon and it gets a verified
  certificate from the client
  - It looks at the CN and if it is of the form "user at domain", it tries to translate
    "user at domain" to a POSIX <uid,gid_list> using the same mechanism that
    nfsuserd(8) currently uses. ("user at domain" is what NFSv4 uses for a file Owner.)
    - Then all RPCs on this TCP connection are done using the <uid,gid_list> above,
       ignoring the authenticator in the RPC message header. (Yes, similar to the
       -mapall exports option.)
I have also added a "-tlscnuser" exports option that would require all clients
to have the above form of certificate. (Without this exports option, the above
would work assuming the daemon option is set, but other mounts would be
allowed as well.)

The problem of handling multiple "user" domains has never been solved.
(That is what your -tlsroot option was intended to do assuming a 1 to 1
 relationship between CA root and username domains, I think?)
The problem is that getpwnam(3) needs to know how to look up user names
for these different "domain" values. (Now, both nfsused(8) and this daemon
only strips off the default domain, if it matches, and then hands the rest of
the string to getpwnam(2).)

Although "user at domain" isn't exactly an email address, they often are the
same string in practice.

I have not yet posted to nfsv4 at to see what they think.
However, I don't think there is any changes in the draft required to do this.
Also, I think interoperability should be ok, since it is controlled by whoever
issues the certificate for the client and the NFS client will normally just
handle this certificate opaquely.

Btw, the server TLS handshake daemon does do a SSL_CTX_set_client_CA_list(),
so it tells the client which CA (usually only one) that it wants a certificate for.

>> The draft does not address user authentication, only machine authentication.
>> --> ie. The certificate is used to decide if a system can do a mount.
>>       Users are still identified via user credentials in the RPC message header.
>>       For AUTH_SYS, that still means <uid,gid,...>.
>>       Otherwise, you need to use Kerberos (sec=krb5[ip]).
>>       You could use "tls,sec=krb5" for a mount, but the only advantage that
>>       might have over "sec=krb5p" is performance, if there is hardware assist
>>       for TLS or something like that.
>> >Now that I reread your comments, it sounds like any certificate would be
>> >allowed in #2 as long as it is valid, and that would only be marginally
>> >better than verification by IP, and in some ways worse, in that now any
>> >user could pretend to be any other user, or you have to do something
>> >crazy like have a CA per user.
>> The case where I see #2 is useful is where this discussion started some weeks ago.
>> The example I started with was:
>> /home -tls -network -mask
>> /home -tlscert
>> This says that machines on the local lan can mount and do not need to have
>> certificates, but must use TLS so data is encrypted on the wire.
>> Mounts from anywhere else (presumably laptops) are allowed so long as they have a
>> certificate signed by me (as in the site local CA).
>> I trust these machines enough that I am willing to allow them to use AUTH_SYS,
>> which is what 99.9...% of NFS mounts do now.
>> (So, I'd agree that the site local certificate is not a lot better than IP address
>>  for client machine identity, just that it is an alternative that can be useful.
>>  Without TLS, a line like "/home" allows anyone to mount /home from anywhere
>>  and I think you'd agree that few NFS admins. will want to do that. I'm assuming
>>  no external firewall for this example.)
>> Now, your suggestion of identifying a user via the CN and then having the
>> server do all RPCs for the mount as that user is an interesting one.
>> My concern w.r.t. implementing it would be interoperability.
>> Put another way, if other servers such as Linux, Netapp,... don't adopt it
>> (and they won't until there is a draft/RFC specifying it), it would be
>> FreeBSD server specific and I'd like to avoid that.
>> There was some discussion w.r.t. user authentication via certificates
>> during development of the draft, but they decided to defer that work for
>> now, so they could get something in place for machine authentication first.
>> (If I understood the discussion on nfsv4 at
>There's a fine line between machine and user authentication when you can
>add -mapall=someuser.  :)
Yes, I agree. You can argue what I've coded as explained above is just server
implementation and has nothing to do with the draft, which covers what goes
"on-the-wire", similar to "-mapall".

>Yes, a certificate may be used to identify a machine, but if any machine
>can be identified by any cert as it appears that #2 is proposed to do, then
>you're not actually identifying a machine, you're identifying group of
>machines...  Though per the draft, this is explicitly allowed.
>It'd be nice to be able to identify particular machines though, and be
>able to set the options based upon that..
Well, the only thing the server has to use for exports(5) is the client's IP address.
In a sense, you can say that "alice at" identifies the machine that
Alice uses.

At least, it means that if the certificate with "alice at" in it is copied
to a different machine, that machine will access the NFS server as "alice" as well
and cannot access files that Alice cannot access.

>> >I'm wonder if your use of the term secret was the problem, and not the
>> >idea...  Anything that goes in the client cert is by definition public...
>> >TLS prior to 1.3 sends the client cert in clear text...  But keying
>> >based upon the contents of the cert is fine, as that's the point of
>> >what a cert is..  It's trusting the CA to say that the CN and other
>> >fields in the cert corresponds to this user, and you can use parts of
>> >the cert, like the CN to decide which user the public key in the cert
>> >corresponds to.
>Rick Macklem wrote this message on Thu, Mar 26, 2020 at 14:59 +0000:
>> Sorry about the top post, but I thought of a few things to add to my
>> last post to this thread...
>> 1 - I agree that for systems like laptops, the line between machine and
>>      user authentication is fuzzy.
>yep, exactly.  IMO, laptops are more important for this work, and where
>you want to identify per machine at a finer grain level than server
>> 2 - I do like your idea of having an exports(5) option that specifies a CN
>>       that identifies a user and then does all RPCs as that user.
>>       I'm not sure if an issuer needs to be specified (or even can be specified),
>>       since the CAfile argument to the rpctlssd daemon determines if a certificate
>>       from a particular CA will verify and the verification must happen before the
>>       exports(5) export options can be applied. (Basically, certificate verification
>>       happens via a NULL RPC that does a STARTTLS when a TCP connection to
>>       the server is first established.)
>Yeah, this will need some work, but IMO is fine as a future
>Yeah, this could be a bit tricky from a code perspective.. I don't know
>how well most SSL libraries are being able to auth client certs via
>different roots after the fact...  One option, but maybe not a great
>option would be to verify the cert after the connection is established..
>You could extract the cert identify the candidate export lines, and
>then attempt a cert verification w/ a specified root if a default one
>isn't specified...  Not exactly clean, but as long as the client can't
>proceed without this check, shouldn't be a major problem...
Well, the certificate verification normally occurs during the handshake
using the location information provided via SSL_CTX_load_verify_locations().
However, this does not included checking for specific fields in the certificate.

The daemon could pass the subjectName from the certificate into the kernel
for use by the exports(5) handling code later, but then another upcall to a
daemon needs to be done to translate the subjectName to <uid,gid_list>.
Since even nfsuserd(8) only knows how to do this for a default domain,
that would be a lot more work and I don't think it gains anything at this
getpwnam(3) needs to be done in userland and is a little bit scary to do,
since it could get hung on a broken LDAP server or similar.
If done by the TLS handshake daemon, that means new mounts hang, but
at least current mounts keep working.

>> 3 - I'll post to nfsv4 at to see what others think of this, since it would not
>>       require any changes to the draft/RFC.
>> 4 - Although it does require a revision to the export_args structure, I think it is
>>      worth doing even if others don't implement it.
Oh, and implementing what is described above did not require the export_args structure to be revised.


Thanks.  Let me know if you'd like code reviews as well...

> Again, thanks for your comments, rick

And thanks for doing the work!

  John-Mark Gurney                              Voice: +1 415 225 5579

     "All that I will do, has been done, All that I have, has not."

More information about the freebsd-current mailing list